]> bbs.cooldavid.org Git - net-next-2.6.git/blob - security/tomoyo/domain.c
TOMOYO: Use RCU primitives for list operation
[net-next-2.6.git] / security / tomoyo / domain.c
1 /*
2  * security/tomoyo/domain.c
3  *
4  * Implementation of the Domain-Based Mandatory Access Control.
5  *
6  * Copyright (C) 2005-2009  NTT DATA CORPORATION
7  *
8  * Version: 2.2.0   2009/04/01
9  *
10  */
11
12 #include "common.h"
13 #include "tomoyo.h"
14 #include "realpath.h"
15 #include <linux/binfmts.h>
16
17 /* Variables definitions.*/
18
19 /* The initial domain. */
20 struct tomoyo_domain_info tomoyo_kernel_domain;
21
22 /*
23  * tomoyo_domain_list is used for holding list of domains.
24  * The ->acl_info_list of "struct tomoyo_domain_info" is used for holding
25  * permissions (e.g. "allow_read /lib/libc-2.5.so") given to each domain.
26  *
27  * An entry is added by
28  *
29  * # ( echo "<kernel>"; echo "allow_execute /sbin/init" ) > \
30  *                                  /sys/kernel/security/tomoyo/domain_policy
31  *
32  * and is deleted by
33  *
34  * # ( echo "<kernel>"; echo "delete allow_execute /sbin/init" ) > \
35  *                                  /sys/kernel/security/tomoyo/domain_policy
36  *
37  * and all entries are retrieved by
38  *
39  * # cat /sys/kernel/security/tomoyo/domain_policy
40  *
41  * A domain is added by
42  *
43  * # echo "<kernel>" > /sys/kernel/security/tomoyo/domain_policy
44  *
45  * and is deleted by
46  *
47  * # echo "delete <kernel>" > /sys/kernel/security/tomoyo/domain_policy
48  *
49  * and all domains are retrieved by
50  *
51  * # grep '^<kernel>' /sys/kernel/security/tomoyo/domain_policy
52  *
53  * Normally, a domainname is monotonically getting longer because a domainname
54  * which the process will belong to if an execve() operation succeeds is
55  * defined as a concatenation of "current domainname" + "pathname passed to
56  * execve()".
57  * See tomoyo_domain_initializer_list and tomoyo_domain_keeper_list for
58  * exceptions.
59  */
60 LIST_HEAD(tomoyo_domain_list);
61 DECLARE_RWSEM(tomoyo_domain_list_lock);
62
63 /*
64  * tomoyo_domain_initializer_entry is a structure which is used for holding
65  * "initialize_domain" and "no_initialize_domain" entries.
66  * It has following fields.
67  *
68  *  (1) "list" which is linked to tomoyo_domain_initializer_list .
69  *  (2) "domainname" which is "a domainname" or "the last component of a
70  *      domainname". This field is NULL if "from" clause is not specified.
71  *  (3) "program" which is a program's pathname.
72  *  (4) "is_deleted" is a bool which is true if marked as deleted, false
73  *      otherwise.
74  *  (5) "is_not" is a bool which is true if "no_initialize_domain", false
75  *      otherwise.
76  *  (6) "is_last_name" is a bool which is true if "domainname" is "the last
77  *      component of a domainname", false otherwise.
78  */
79 struct tomoyo_domain_initializer_entry {
80         struct list_head list;
81         const struct tomoyo_path_info *domainname;    /* This may be NULL */
82         const struct tomoyo_path_info *program;
83         bool is_deleted;
84         bool is_not;       /* True if this entry is "no_initialize_domain".  */
85         /* True if the domainname is tomoyo_get_last_name(). */
86         bool is_last_name;
87 };
88
89 /*
90  * tomoyo_domain_keeper_entry is a structure which is used for holding
91  * "keep_domain" and "no_keep_domain" entries.
92  * It has following fields.
93  *
94  *  (1) "list" which is linked to tomoyo_domain_keeper_list .
95  *  (2) "domainname" which is "a domainname" or "the last component of a
96  *      domainname".
97  *  (3) "program" which is a program's pathname.
98  *      This field is NULL if "from" clause is not specified.
99  *  (4) "is_deleted" is a bool which is true if marked as deleted, false
100  *      otherwise.
101  *  (5) "is_not" is a bool which is true if "no_initialize_domain", false
102  *      otherwise.
103  *  (6) "is_last_name" is a bool which is true if "domainname" is "the last
104  *      component of a domainname", false otherwise.
105  */
106 struct tomoyo_domain_keeper_entry {
107         struct list_head list;
108         const struct tomoyo_path_info *domainname;
109         const struct tomoyo_path_info *program;       /* This may be NULL */
110         bool is_deleted;
111         bool is_not;       /* True if this entry is "no_keep_domain".        */
112         /* True if the domainname is tomoyo_get_last_name(). */
113         bool is_last_name;
114 };
115
116 /*
117  * tomoyo_alias_entry is a structure which is used for holding "alias" entries.
118  * It has following fields.
119  *
120  *  (1) "list" which is linked to tomoyo_alias_list .
121  *  (2) "original_name" which is a dereferenced pathname.
122  *  (3) "aliased_name" which is a symlink's pathname.
123  *  (4) "is_deleted" is a bool which is true if marked as deleted, false
124  *      otherwise.
125  */
126 struct tomoyo_alias_entry {
127         struct list_head list;
128         const struct tomoyo_path_info *original_name;
129         const struct tomoyo_path_info *aliased_name;
130         bool is_deleted;
131 };
132
133 /**
134  * tomoyo_set_domain_flag - Set or clear domain's attribute flags.
135  *
136  * @domain:    Pointer to "struct tomoyo_domain_info".
137  * @is_delete: True if it is a delete request.
138  * @flags:     Flags to set or clear.
139  *
140  * Returns nothing.
141  */
142 void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain,
143                             const bool is_delete, const u8 flags)
144 {
145         /* We need to serialize because this is bitfield operation. */
146         static DEFINE_SPINLOCK(lock);
147         spin_lock(&lock);
148         if (!is_delete)
149                 domain->flags |= flags;
150         else
151                 domain->flags &= ~flags;
152         spin_unlock(&lock);
153 }
154
155 /**
156  * tomoyo_get_last_name - Get last component of a domainname.
157  *
158  * @domain: Pointer to "struct tomoyo_domain_info".
159  *
160  * Returns the last component of the domainname.
161  */
162 const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain)
163 {
164         const char *cp0 = domain->domainname->name;
165         const char *cp1 = strrchr(cp0, ' ');
166
167         if (cp1)
168                 return cp1 + 1;
169         return cp0;
170 }
171
172 /*
173  * tomoyo_domain_initializer_list is used for holding list of programs which
174  * triggers reinitialization of domainname. Normally, a domainname is
175  * monotonically getting longer. But sometimes, we restart daemon programs.
176  * It would be convenient for us that "a daemon started upon system boot" and
177  * "the daemon restarted from console" belong to the same domain. Thus, TOMOYO
178  * provides a way to shorten domainnames.
179  *
180  * An entry is added by
181  *
182  * # echo 'initialize_domain /usr/sbin/httpd' > \
183  *                               /sys/kernel/security/tomoyo/exception_policy
184  *
185  * and is deleted by
186  *
187  * # echo 'delete initialize_domain /usr/sbin/httpd' > \
188  *                               /sys/kernel/security/tomoyo/exception_policy
189  *
190  * and all entries are retrieved by
191  *
192  * # grep ^initialize_domain /sys/kernel/security/tomoyo/exception_policy
193  *
194  * In the example above, /usr/sbin/httpd will belong to
195  * "<kernel> /usr/sbin/httpd" domain.
196  *
197  * You may specify a domainname using "from" keyword.
198  * "initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd"
199  * will cause "/usr/sbin/httpd" executed from "<kernel> /etc/rc.d/init.d/httpd"
200  * domain to belong to "<kernel> /usr/sbin/httpd" domain.
201  *
202  * You may add "no_" prefix to "initialize_domain".
203  * "initialize_domain /usr/sbin/httpd" and
204  * "no_initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd"
205  * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain
206  * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain.
207  */
208 static LIST_HEAD(tomoyo_domain_initializer_list);
209 static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock);
210
211 /**
212  * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list.
213  *
214  * @domainname: The name of domain. May be NULL.
215  * @program:    The name of program.
216  * @is_not:     True if it is "no_initialize_domain" entry.
217  * @is_delete:  True if it is a delete request.
218  *
219  * Returns 0 on success, negative value otherwise.
220  *
221  * Caller holds tomoyo_read_lock().
222  */
223 static int tomoyo_update_domain_initializer_entry(const char *domainname,
224                                                   const char *program,
225                                                   const bool is_not,
226                                                   const bool is_delete)
227 {
228         struct tomoyo_domain_initializer_entry *new_entry;
229         struct tomoyo_domain_initializer_entry *ptr;
230         const struct tomoyo_path_info *saved_program;
231         const struct tomoyo_path_info *saved_domainname = NULL;
232         int error = -ENOMEM;
233         bool is_last_name = false;
234
235         if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__))
236                 return -EINVAL; /* No patterns allowed. */
237         if (domainname) {
238                 if (!tomoyo_is_domain_def(domainname) &&
239                     tomoyo_is_correct_path(domainname, 1, -1, -1, __func__))
240                         is_last_name = true;
241                 else if (!tomoyo_is_correct_domain(domainname, __func__))
242                         return -EINVAL;
243                 saved_domainname = tomoyo_save_name(domainname);
244                 if (!saved_domainname)
245                         return -ENOMEM;
246         }
247         saved_program = tomoyo_save_name(program);
248         if (!saved_program)
249                 return -ENOMEM;
250         down_write(&tomoyo_domain_initializer_list_lock);
251         list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
252                 if (ptr->is_not != is_not ||
253                     ptr->domainname != saved_domainname ||
254                     ptr->program != saved_program)
255                         continue;
256                 ptr->is_deleted = is_delete;
257                 error = 0;
258                 goto out;
259         }
260         if (is_delete) {
261                 error = -ENOENT;
262                 goto out;
263         }
264         new_entry = tomoyo_alloc_element(sizeof(*new_entry));
265         if (!new_entry)
266                 goto out;
267         new_entry->domainname = saved_domainname;
268         new_entry->program = saved_program;
269         new_entry->is_not = is_not;
270         new_entry->is_last_name = is_last_name;
271         list_add_tail_rcu(&new_entry->list, &tomoyo_domain_initializer_list);
272         error = 0;
273  out:
274         up_write(&tomoyo_domain_initializer_list_lock);
275         return error;
276 }
277
278 /**
279  * tomoyo_read_domain_initializer_policy - Read "struct tomoyo_domain_initializer_entry" list.
280  *
281  * @head: Pointer to "struct tomoyo_io_buffer".
282  *
283  * Returns true on success, false otherwise.
284  *
285  * Caller holds tomoyo_read_lock().
286  */
287 bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
288 {
289         struct list_head *pos;
290         bool done = true;
291
292         list_for_each_cookie(pos, head->read_var2,
293                              &tomoyo_domain_initializer_list) {
294                 const char *no;
295                 const char *from = "";
296                 const char *domain = "";
297                 struct tomoyo_domain_initializer_entry *ptr;
298                 ptr = list_entry(pos, struct tomoyo_domain_initializer_entry,
299                                   list);
300                 if (ptr->is_deleted)
301                         continue;
302                 no = ptr->is_not ? "no_" : "";
303                 if (ptr->domainname) {
304                         from = " from ";
305                         domain = ptr->domainname->name;
306                 }
307                 done = tomoyo_io_printf(head,
308                                         "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN
309                                         "%s%s%s\n", no, ptr->program->name,
310                                         from, domain);
311                 if (!done)
312                         break;
313         }
314         return done;
315 }
316
317 /**
318  * tomoyo_write_domain_initializer_policy - Write "struct tomoyo_domain_initializer_entry" list.
319  *
320  * @data:      String to parse.
321  * @is_not:    True if it is "no_initialize_domain" entry.
322  * @is_delete: True if it is a delete request.
323  *
324  * Returns 0 on success, negative value otherwise.
325  *
326  * Caller holds tomoyo_read_lock().
327  */
328 int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
329                                            const bool is_delete)
330 {
331         char *cp = strstr(data, " from ");
332
333         if (cp) {
334                 *cp = '\0';
335                 return tomoyo_update_domain_initializer_entry(cp + 6, data,
336                                                               is_not,
337                                                               is_delete);
338         }
339         return tomoyo_update_domain_initializer_entry(NULL, data, is_not,
340                                                       is_delete);
341 }
342
343 /**
344  * tomoyo_is_domain_initializer - Check whether the given program causes domainname reinitialization.
345  *
346  * @domainname: The name of domain.
347  * @program:    The name of program.
348  * @last_name:  The last component of @domainname.
349  *
350  * Returns true if executing @program reinitializes domain transition,
351  * false otherwise.
352  *
353  * Caller holds tomoyo_read_lock().
354  */
355 static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
356                                          domainname,
357                                          const struct tomoyo_path_info *program,
358                                          const struct tomoyo_path_info *
359                                          last_name)
360 {
361         struct tomoyo_domain_initializer_entry *ptr;
362         bool flag = false;
363
364         list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
365                 if (ptr->is_deleted)
366                         continue;
367                 if (ptr->domainname) {
368                         if (!ptr->is_last_name) {
369                                 if (ptr->domainname != domainname)
370                                         continue;
371                         } else {
372                                 if (tomoyo_pathcmp(ptr->domainname, last_name))
373                                         continue;
374                         }
375                 }
376                 if (tomoyo_pathcmp(ptr->program, program))
377                         continue;
378                 if (ptr->is_not) {
379                         flag = false;
380                         break;
381                 }
382                 flag = true;
383         }
384         return flag;
385 }
386
387 /*
388  * tomoyo_domain_keeper_list is used for holding list of domainnames which
389  * suppresses domain transition. Normally, a domainname is monotonically
390  * getting longer. But sometimes, we want to suppress domain transition.
391  * It would be convenient for us that programs executed from a login session
392  * belong to the same domain. Thus, TOMOYO provides a way to suppress domain
393  * transition.
394  *
395  * An entry is added by
396  *
397  * # echo 'keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \
398  *                              /sys/kernel/security/tomoyo/exception_policy
399  *
400  * and is deleted by
401  *
402  * # echo 'delete keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \
403  *                              /sys/kernel/security/tomoyo/exception_policy
404  *
405  * and all entries are retrieved by
406  *
407  * # grep ^keep_domain /sys/kernel/security/tomoyo/exception_policy
408  *
409  * In the example above, any process which belongs to
410  * "<kernel> /usr/sbin/sshd /bin/bash" domain will remain in that domain,
411  * unless explicitly specified by "initialize_domain" or "no_keep_domain".
412  *
413  * You may specify a program using "from" keyword.
414  * "keep_domain /bin/pwd from <kernel> /usr/sbin/sshd /bin/bash"
415  * will cause "/bin/pwd" executed from "<kernel> /usr/sbin/sshd /bin/bash"
416  * domain to remain in "<kernel> /usr/sbin/sshd /bin/bash" domain.
417  *
418  * You may add "no_" prefix to "keep_domain".
419  * "keep_domain <kernel> /usr/sbin/sshd /bin/bash" and
420  * "no_keep_domain /usr/bin/passwd from <kernel> /usr/sbin/sshd /bin/bash" will
421  * cause "/usr/bin/passwd" to belong to
422  * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless
423  * explicitly specified by "initialize_domain".
424  */
425 static LIST_HEAD(tomoyo_domain_keeper_list);
426 static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock);
427
428 /**
429  * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list.
430  *
431  * @domainname: The name of domain.
432  * @program:    The name of program. May be NULL.
433  * @is_not:     True if it is "no_keep_domain" entry.
434  * @is_delete:  True if it is a delete request.
435  *
436  * Returns 0 on success, negative value otherwise.
437  *
438  * Caller holds tomoyo_read_lock().
439  */
440 static int tomoyo_update_domain_keeper_entry(const char *domainname,
441                                              const char *program,
442                                              const bool is_not,
443                                              const bool is_delete)
444 {
445         struct tomoyo_domain_keeper_entry *new_entry;
446         struct tomoyo_domain_keeper_entry *ptr;
447         const struct tomoyo_path_info *saved_domainname;
448         const struct tomoyo_path_info *saved_program = NULL;
449         int error = -ENOMEM;
450         bool is_last_name = false;
451
452         if (!tomoyo_is_domain_def(domainname) &&
453             tomoyo_is_correct_path(domainname, 1, -1, -1, __func__))
454                 is_last_name = true;
455         else if (!tomoyo_is_correct_domain(domainname, __func__))
456                 return -EINVAL;
457         if (program) {
458                 if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__))
459                         return -EINVAL;
460                 saved_program = tomoyo_save_name(program);
461                 if (!saved_program)
462                         return -ENOMEM;
463         }
464         saved_domainname = tomoyo_save_name(domainname);
465         if (!saved_domainname)
466                 return -ENOMEM;
467         down_write(&tomoyo_domain_keeper_list_lock);
468         list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
469                 if (ptr->is_not != is_not ||
470                     ptr->domainname != saved_domainname ||
471                     ptr->program != saved_program)
472                         continue;
473                 ptr->is_deleted = is_delete;
474                 error = 0;
475                 goto out;
476         }
477         if (is_delete) {
478                 error = -ENOENT;
479                 goto out;
480         }
481         new_entry = tomoyo_alloc_element(sizeof(*new_entry));
482         if (!new_entry)
483                 goto out;
484         new_entry->domainname = saved_domainname;
485         new_entry->program = saved_program;
486         new_entry->is_not = is_not;
487         new_entry->is_last_name = is_last_name;
488         list_add_tail_rcu(&new_entry->list, &tomoyo_domain_keeper_list);
489         error = 0;
490  out:
491         up_write(&tomoyo_domain_keeper_list_lock);
492         return error;
493 }
494
495 /**
496  * tomoyo_write_domain_keeper_policy - Write "struct tomoyo_domain_keeper_entry" list.
497  *
498  * @data:      String to parse.
499  * @is_not:    True if it is "no_keep_domain" entry.
500  * @is_delete: True if it is a delete request.
501  *
502  * Caller holds tomoyo_read_lock().
503  */
504 int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
505                                       const bool is_delete)
506 {
507         char *cp = strstr(data, " from ");
508
509         if (cp) {
510                 *cp = '\0';
511                 return tomoyo_update_domain_keeper_entry(cp + 6, data, is_not,
512                                                          is_delete);
513         }
514         return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete);
515 }
516
517 /**
518  * tomoyo_read_domain_keeper_policy - Read "struct tomoyo_domain_keeper_entry" list.
519  *
520  * @head: Pointer to "struct tomoyo_io_buffer".
521  *
522  * Returns true on success, false otherwise.
523  *
524  * Caller holds tomoyo_read_lock().
525  */
526 bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
527 {
528         struct list_head *pos;
529         bool done = true;
530
531         list_for_each_cookie(pos, head->read_var2,
532                              &tomoyo_domain_keeper_list) {
533                 struct tomoyo_domain_keeper_entry *ptr;
534                 const char *no;
535                 const char *from = "";
536                 const char *program = "";
537
538                 ptr = list_entry(pos, struct tomoyo_domain_keeper_entry, list);
539                 if (ptr->is_deleted)
540                         continue;
541                 no = ptr->is_not ? "no_" : "";
542                 if (ptr->program) {
543                         from = " from ";
544                         program = ptr->program->name;
545                 }
546                 done = tomoyo_io_printf(head,
547                                         "%s" TOMOYO_KEYWORD_KEEP_DOMAIN
548                                         "%s%s%s\n", no, program, from,
549                                         ptr->domainname->name);
550                 if (!done)
551                         break;
552         }
553         return done;
554 }
555
556 /**
557  * tomoyo_is_domain_keeper - Check whether the given program causes domain transition suppression.
558  *
559  * @domainname: The name of domain.
560  * @program:    The name of program.
561  * @last_name:  The last component of @domainname.
562  *
563  * Returns true if executing @program supresses domain transition,
564  * false otherwise.
565  *
566  * Caller holds tomoyo_read_lock().
567  */
568 static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
569                                     const struct tomoyo_path_info *program,
570                                     const struct tomoyo_path_info *last_name)
571 {
572         struct tomoyo_domain_keeper_entry *ptr;
573         bool flag = false;
574
575         list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
576                 if (ptr->is_deleted)
577                         continue;
578                 if (!ptr->is_last_name) {
579                         if (ptr->domainname != domainname)
580                                 continue;
581                 } else {
582                         if (tomoyo_pathcmp(ptr->domainname, last_name))
583                                 continue;
584                 }
585                 if (ptr->program && tomoyo_pathcmp(ptr->program, program))
586                         continue;
587                 if (ptr->is_not) {
588                         flag = false;
589                         break;
590                 }
591                 flag = true;
592         }
593         return flag;
594 }
595
596 /*
597  * tomoyo_alias_list is used for holding list of symlink's pathnames which are
598  * allowed to be passed to an execve() request. Normally, the domainname which
599  * the current process will belong to after execve() succeeds is calculated
600  * using dereferenced pathnames. But some programs behave differently depending
601  * on the name passed to argv[0]. For busybox, calculating domainname using
602  * dereferenced pathnames will cause all programs in the busybox to belong to
603  * the same domain. Thus, TOMOYO provides a way to allow use of symlink's
604  * pathname for checking execve()'s permission and calculating domainname which
605  * the current process will belong to after execve() succeeds.
606  *
607  * An entry is added by
608  *
609  * # echo 'alias /bin/busybox /bin/cat' > \
610  *                            /sys/kernel/security/tomoyo/exception_policy
611  *
612  * and is deleted by
613  *
614  * # echo 'delete alias /bin/busybox /bin/cat' > \
615  *                            /sys/kernel/security/tomoyo/exception_policy
616  *
617  * and all entries are retrieved by
618  *
619  * # grep ^alias /sys/kernel/security/tomoyo/exception_policy
620  *
621  * In the example above, if /bin/cat is a symlink to /bin/busybox and execution
622  * of /bin/cat is requested, permission is checked for /bin/cat rather than
623  * /bin/busybox and domainname which the current process will belong to after
624  * execve() succeeds is calculated using /bin/cat rather than /bin/busybox .
625  */
626 static LIST_HEAD(tomoyo_alias_list);
627 static DECLARE_RWSEM(tomoyo_alias_list_lock);
628
629 /**
630  * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list.
631  *
632  * @original_name: The original program's real name.
633  * @aliased_name:  The symbolic program's symbolic link's name.
634  * @is_delete:     True if it is a delete request.
635  *
636  * Returns 0 on success, negative value otherwise.
637  *
638  * Caller holds tomoyo_read_lock().
639  */
640 static int tomoyo_update_alias_entry(const char *original_name,
641                                      const char *aliased_name,
642                                      const bool is_delete)
643 {
644         struct tomoyo_alias_entry *new_entry;
645         struct tomoyo_alias_entry *ptr;
646         const struct tomoyo_path_info *saved_original_name;
647         const struct tomoyo_path_info *saved_aliased_name;
648         int error = -ENOMEM;
649
650         if (!tomoyo_is_correct_path(original_name, 1, -1, -1, __func__) ||
651             !tomoyo_is_correct_path(aliased_name, 1, -1, -1, __func__))
652                 return -EINVAL; /* No patterns allowed. */
653         saved_original_name = tomoyo_save_name(original_name);
654         saved_aliased_name = tomoyo_save_name(aliased_name);
655         if (!saved_original_name || !saved_aliased_name)
656                 return -ENOMEM;
657         down_write(&tomoyo_alias_list_lock);
658         list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
659                 if (ptr->original_name != saved_original_name ||
660                     ptr->aliased_name != saved_aliased_name)
661                         continue;
662                 ptr->is_deleted = is_delete;
663                 error = 0;
664                 goto out;
665         }
666         if (is_delete) {
667                 error = -ENOENT;
668                 goto out;
669         }
670         new_entry = tomoyo_alloc_element(sizeof(*new_entry));
671         if (!new_entry)
672                 goto out;
673         new_entry->original_name = saved_original_name;
674         new_entry->aliased_name = saved_aliased_name;
675         list_add_tail_rcu(&new_entry->list, &tomoyo_alias_list);
676         error = 0;
677  out:
678         up_write(&tomoyo_alias_list_lock);
679         return error;
680 }
681
682 /**
683  * tomoyo_read_alias_policy - Read "struct tomoyo_alias_entry" list.
684  *
685  * @head: Pointer to "struct tomoyo_io_buffer".
686  *
687  * Returns true on success, false otherwise.
688  *
689  * Caller holds tomoyo_read_lock().
690  */
691 bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
692 {
693         struct list_head *pos;
694         bool done = true;
695
696         list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) {
697                 struct tomoyo_alias_entry *ptr;
698
699                 ptr = list_entry(pos, struct tomoyo_alias_entry, list);
700                 if (ptr->is_deleted)
701                         continue;
702                 done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n",
703                                         ptr->original_name->name,
704                                         ptr->aliased_name->name);
705                 if (!done)
706                         break;
707         }
708         return done;
709 }
710
711 /**
712  * tomoyo_write_alias_policy - Write "struct tomoyo_alias_entry" list.
713  *
714  * @data:      String to parse.
715  * @is_delete: True if it is a delete request.
716  *
717  * Returns 0 on success, negative value otherwise.
718  *
719  * Caller holds tomoyo_read_lock().
720  */
721 int tomoyo_write_alias_policy(char *data, const bool is_delete)
722 {
723         char *cp = strchr(data, ' ');
724
725         if (!cp)
726                 return -EINVAL;
727         *cp++ = '\0';
728         return tomoyo_update_alias_entry(data, cp, is_delete);
729 }
730
731 /**
732  * tomoyo_find_or_assign_new_domain - Create a domain.
733  *
734  * @domainname: The name of domain.
735  * @profile:    Profile number to assign if the domain was newly created.
736  *
737  * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
738  *
739  * Caller holds tomoyo_read_lock().
740  */
741 struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
742                                                             domainname,
743                                                             const u8 profile)
744 {
745         struct tomoyo_domain_info *domain = NULL;
746         const struct tomoyo_path_info *saved_domainname;
747
748         down_write(&tomoyo_domain_list_lock);
749         domain = tomoyo_find_domain(domainname);
750         if (domain)
751                 goto out;
752         if (!tomoyo_is_correct_domain(domainname, __func__))
753                 goto out;
754         saved_domainname = tomoyo_save_name(domainname);
755         if (!saved_domainname)
756                 goto out;
757         /* Can I reuse memory of deleted domain? */
758         list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
759                 struct task_struct *p;
760                 struct tomoyo_acl_info *ptr;
761                 bool flag;
762                 if (!domain->is_deleted ||
763                     domain->domainname != saved_domainname)
764                         continue;
765                 flag = false;
766                 read_lock(&tasklist_lock);
767                 for_each_process(p) {
768                         if (tomoyo_real_domain(p) != domain)
769                                 continue;
770                         flag = true;
771                         break;
772                 }
773                 read_unlock(&tasklist_lock);
774                 if (flag)
775                         continue;
776                 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
777                         ptr->type |= TOMOYO_ACL_DELETED;
778                 }
779                 tomoyo_set_domain_flag(domain, true, domain->flags);
780                 domain->profile = profile;
781                 domain->quota_warned = false;
782                 mb(); /* Avoid out-of-order execution. */
783                 domain->is_deleted = false;
784                 goto out;
785         }
786         /* No memory reusable. Create using new memory. */
787         domain = tomoyo_alloc_element(sizeof(*domain));
788         if (domain) {
789                 INIT_LIST_HEAD(&domain->acl_info_list);
790                 domain->domainname = saved_domainname;
791                 domain->profile = profile;
792                 list_add_tail_rcu(&domain->list, &tomoyo_domain_list);
793         }
794  out:
795         up_write(&tomoyo_domain_list_lock);
796         return domain;
797 }
798
799 /**
800  * tomoyo_find_next_domain - Find a domain.
801  *
802  * @bprm: Pointer to "struct linux_binprm".
803  *
804  * Returns 0 on success, negative value otherwise.
805  *
806  * Caller holds tomoyo_read_lock().
807  */
808 int tomoyo_find_next_domain(struct linux_binprm *bprm)
809 {
810         /*
811          * This function assumes that the size of buffer returned by
812          * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN.
813          */
814         struct tomoyo_page_buffer *tmp = tomoyo_alloc(sizeof(*tmp));
815         struct tomoyo_domain_info *old_domain = tomoyo_domain();
816         struct tomoyo_domain_info *domain = NULL;
817         const char *old_domain_name = old_domain->domainname->name;
818         const char *original_name = bprm->filename;
819         char *new_domain_name = NULL;
820         char *real_program_name = NULL;
821         char *symlink_program_name = NULL;
822         const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE);
823         const bool is_enforce = (mode == 3);
824         int retval = -ENOMEM;
825         struct tomoyo_path_info r; /* real name */
826         struct tomoyo_path_info s; /* symlink name */
827         struct tomoyo_path_info l; /* last name */
828         static bool initialized;
829
830         if (!tmp)
831                 goto out;
832
833         if (!initialized) {
834                 /*
835                  * Built-in initializers. This is needed because policies are
836                  * not loaded until starting /sbin/init.
837                  */
838                 tomoyo_update_domain_initializer_entry(NULL, "/sbin/hotplug",
839                                                        false, false);
840                 tomoyo_update_domain_initializer_entry(NULL, "/sbin/modprobe",
841                                                        false, false);
842                 initialized = true;
843         }
844
845         /* Get tomoyo_realpath of program. */
846         retval = -ENOENT;
847         /* I hope tomoyo_realpath() won't fail with -ENOMEM. */
848         real_program_name = tomoyo_realpath(original_name);
849         if (!real_program_name)
850                 goto out;
851         /* Get tomoyo_realpath of symbolic link. */
852         symlink_program_name = tomoyo_realpath_nofollow(original_name);
853         if (!symlink_program_name)
854                 goto out;
855
856         r.name = real_program_name;
857         tomoyo_fill_path_info(&r);
858         s.name = symlink_program_name;
859         tomoyo_fill_path_info(&s);
860         l.name = tomoyo_get_last_name(old_domain);
861         tomoyo_fill_path_info(&l);
862
863         /* Check 'alias' directive. */
864         if (tomoyo_pathcmp(&r, &s)) {
865                 struct tomoyo_alias_entry *ptr;
866                 /* Is this program allowed to be called via symbolic links? */
867                 list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
868                         if (ptr->is_deleted ||
869                             tomoyo_pathcmp(&r, ptr->original_name) ||
870                             tomoyo_pathcmp(&s, ptr->aliased_name))
871                                 continue;
872                         memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN);
873                         strncpy(real_program_name, ptr->aliased_name->name,
874                                 TOMOYO_MAX_PATHNAME_LEN - 1);
875                         tomoyo_fill_path_info(&r);
876                         break;
877                 }
878         }
879
880         /* Check execute permission. */
881         retval = tomoyo_check_exec_perm(old_domain, &r);
882         if (retval < 0)
883                 goto out;
884
885         new_domain_name = tmp->buffer;
886         if (tomoyo_is_domain_initializer(old_domain->domainname, &r, &l)) {
887                 /* Transit to the child of tomoyo_kernel_domain domain. */
888                 snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
889                          TOMOYO_ROOT_NAME " " "%s", real_program_name);
890         } else if (old_domain == &tomoyo_kernel_domain &&
891                    !tomoyo_policy_loaded) {
892                 /*
893                  * Needn't to transit from kernel domain before starting
894                  * /sbin/init. But transit from kernel domain if executing
895                  * initializers because they might start before /sbin/init.
896                  */
897                 domain = old_domain;
898         } else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) {
899                 /* Keep current domain. */
900                 domain = old_domain;
901         } else {
902                 /* Normal domain transition. */
903                 snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
904                          "%s %s", old_domain_name, real_program_name);
905         }
906         if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
907                 goto done;
908         domain = tomoyo_find_domain(new_domain_name);
909         if (domain)
910                 goto done;
911         if (is_enforce)
912                 goto done;
913         domain = tomoyo_find_or_assign_new_domain(new_domain_name,
914                                                   old_domain->profile);
915  done:
916         if (domain)
917                 goto out;
918         printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
919                new_domain_name);
920         if (is_enforce)
921                 retval = -EPERM;
922         else
923                 tomoyo_set_domain_flag(old_domain, false,
924                                        TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED);
925  out:
926         if (!domain)
927                 domain = old_domain;
928         bprm->cred->security = domain;
929         tomoyo_free(real_program_name);
930         tomoyo_free(symlink_program_name);
931         tomoyo_free(tmp);
932         return retval;
933 }