]> bbs.cooldavid.org Git - net-next-2.6.git/blob - security/tomoyo/domain.c
Merge branch 'master' into next
[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
62 /*
63  * tomoyo_domain_initializer_entry is a structure which is used for holding
64  * "initialize_domain" and "no_initialize_domain" entries.
65  * It has following fields.
66  *
67  *  (1) "list" which is linked to tomoyo_domain_initializer_list .
68  *  (2) "domainname" which is "a domainname" or "the last component of a
69  *      domainname". This field is NULL if "from" clause is not specified.
70  *  (3) "program" which is a program's pathname.
71  *  (4) "is_deleted" is a bool which is true if marked as deleted, false
72  *      otherwise.
73  *  (5) "is_not" is a bool which is true if "no_initialize_domain", false
74  *      otherwise.
75  *  (6) "is_last_name" is a bool which is true if "domainname" is "the last
76  *      component of a domainname", false otherwise.
77  */
78 struct tomoyo_domain_initializer_entry {
79         struct list_head list;
80         const struct tomoyo_path_info *domainname;    /* This may be NULL */
81         const struct tomoyo_path_info *program;
82         bool is_deleted;
83         bool is_not;       /* True if this entry is "no_initialize_domain".  */
84         /* True if the domainname is tomoyo_get_last_name(). */
85         bool is_last_name;
86 };
87
88 /*
89  * tomoyo_domain_keeper_entry is a structure which is used for holding
90  * "keep_domain" and "no_keep_domain" entries.
91  * It has following fields.
92  *
93  *  (1) "list" which is linked to tomoyo_domain_keeper_list .
94  *  (2) "domainname" which is "a domainname" or "the last component of a
95  *      domainname".
96  *  (3) "program" which is a program's pathname.
97  *      This field is NULL if "from" clause is not specified.
98  *  (4) "is_deleted" is a bool which is true if marked as deleted, false
99  *      otherwise.
100  *  (5) "is_not" is a bool which is true if "no_initialize_domain", false
101  *      otherwise.
102  *  (6) "is_last_name" is a bool which is true if "domainname" is "the last
103  *      component of a domainname", false otherwise.
104  */
105 struct tomoyo_domain_keeper_entry {
106         struct list_head list;
107         const struct tomoyo_path_info *domainname;
108         const struct tomoyo_path_info *program;       /* This may be NULL */
109         bool is_deleted;
110         bool is_not;       /* True if this entry is "no_keep_domain".        */
111         /* True if the domainname is tomoyo_get_last_name(). */
112         bool is_last_name;
113 };
114
115 /*
116  * tomoyo_alias_entry is a structure which is used for holding "alias" entries.
117  * It has following fields.
118  *
119  *  (1) "list" which is linked to tomoyo_alias_list .
120  *  (2) "original_name" which is a dereferenced pathname.
121  *  (3) "aliased_name" which is a symlink's pathname.
122  *  (4) "is_deleted" is a bool which is true if marked as deleted, false
123  *      otherwise.
124  */
125 struct tomoyo_alias_entry {
126         struct list_head list;
127         const struct tomoyo_path_info *original_name;
128         const struct tomoyo_path_info *aliased_name;
129         bool is_deleted;
130 };
131
132 /**
133  * tomoyo_set_domain_flag - Set or clear domain's attribute flags.
134  *
135  * @domain:    Pointer to "struct tomoyo_domain_info".
136  * @is_delete: True if it is a delete request.
137  * @flags:     Flags to set or clear.
138  *
139  * Returns nothing.
140  */
141 void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain,
142                             const bool is_delete, const u8 flags)
143 {
144         /* We need to serialize because this is bitfield operation. */
145         static DEFINE_SPINLOCK(lock);
146         spin_lock(&lock);
147         if (!is_delete)
148                 domain->flags |= flags;
149         else
150                 domain->flags &= ~flags;
151         spin_unlock(&lock);
152 }
153
154 /**
155  * tomoyo_get_last_name - Get last component of a domainname.
156  *
157  * @domain: Pointer to "struct tomoyo_domain_info".
158  *
159  * Returns the last component of the domainname.
160  */
161 const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain)
162 {
163         const char *cp0 = domain->domainname->name;
164         const char *cp1 = strrchr(cp0, ' ');
165
166         if (cp1)
167                 return cp1 + 1;
168         return cp0;
169 }
170
171 /*
172  * tomoyo_domain_initializer_list is used for holding list of programs which
173  * triggers reinitialization of domainname. Normally, a domainname is
174  * monotonically getting longer. But sometimes, we restart daemon programs.
175  * It would be convenient for us that "a daemon started upon system boot" and
176  * "the daemon restarted from console" belong to the same domain. Thus, TOMOYO
177  * provides a way to shorten domainnames.
178  *
179  * An entry is added by
180  *
181  * # echo 'initialize_domain /usr/sbin/httpd' > \
182  *                               /sys/kernel/security/tomoyo/exception_policy
183  *
184  * and is deleted by
185  *
186  * # echo 'delete initialize_domain /usr/sbin/httpd' > \
187  *                               /sys/kernel/security/tomoyo/exception_policy
188  *
189  * and all entries are retrieved by
190  *
191  * # grep ^initialize_domain /sys/kernel/security/tomoyo/exception_policy
192  *
193  * In the example above, /usr/sbin/httpd will belong to
194  * "<kernel> /usr/sbin/httpd" domain.
195  *
196  * You may specify a domainname using "from" keyword.
197  * "initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd"
198  * will cause "/usr/sbin/httpd" executed from "<kernel> /etc/rc.d/init.d/httpd"
199  * domain to belong to "<kernel> /usr/sbin/httpd" domain.
200  *
201  * You may add "no_" prefix to "initialize_domain".
202  * "initialize_domain /usr/sbin/httpd" and
203  * "no_initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd"
204  * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain
205  * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain.
206  */
207 static LIST_HEAD(tomoyo_domain_initializer_list);
208
209 /**
210  * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list.
211  *
212  * @domainname: The name of domain. May be NULL.
213  * @program:    The name of program.
214  * @is_not:     True if it is "no_initialize_domain" entry.
215  * @is_delete:  True if it is a delete request.
216  *
217  * Returns 0 on success, negative value otherwise.
218  *
219  * Caller holds tomoyo_read_lock().
220  */
221 static int tomoyo_update_domain_initializer_entry(const char *domainname,
222                                                   const char *program,
223                                                   const bool is_not,
224                                                   const bool is_delete)
225 {
226         struct tomoyo_domain_initializer_entry *new_entry;
227         struct tomoyo_domain_initializer_entry *ptr;
228         const struct tomoyo_path_info *saved_program;
229         const struct tomoyo_path_info *saved_domainname = NULL;
230         int error = -ENOMEM;
231         bool is_last_name = false;
232
233         if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__))
234                 return -EINVAL; /* No patterns allowed. */
235         if (domainname) {
236                 if (!tomoyo_is_domain_def(domainname) &&
237                     tomoyo_is_correct_path(domainname, 1, -1, -1, __func__))
238                         is_last_name = true;
239                 else if (!tomoyo_is_correct_domain(domainname, __func__))
240                         return -EINVAL;
241                 saved_domainname = tomoyo_save_name(domainname);
242                 if (!saved_domainname)
243                         return -ENOMEM;
244         }
245         saved_program = tomoyo_save_name(program);
246         if (!saved_program)
247                 return -ENOMEM;
248         new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
249         mutex_lock(&tomoyo_policy_lock);
250         list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) {
251                 if (ptr->is_not != is_not ||
252                     ptr->domainname != saved_domainname ||
253                     ptr->program != saved_program)
254                         continue;
255                 ptr->is_deleted = is_delete;
256                 error = 0;
257                 goto out;
258         }
259         if (is_delete) {
260                 error = -ENOENT;
261                 goto out;
262         }
263         if (!tomoyo_memory_ok(new_entry))
264                 goto out;
265         new_entry->domainname = saved_domainname;
266         new_entry->program = saved_program;
267         new_entry->is_not = is_not;
268         new_entry->is_last_name = is_last_name;
269         list_add_tail_rcu(&new_entry->list, &tomoyo_domain_initializer_list);
270         new_entry = NULL;
271         error = 0;
272  out:
273         mutex_unlock(&tomoyo_policy_lock);
274         kfree(new_entry);
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
427 /**
428  * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list.
429  *
430  * @domainname: The name of domain.
431  * @program:    The name of program. May be NULL.
432  * @is_not:     True if it is "no_keep_domain" entry.
433  * @is_delete:  True if it is a delete request.
434  *
435  * Returns 0 on success, negative value otherwise.
436  *
437  * Caller holds tomoyo_read_lock().
438  */
439 static int tomoyo_update_domain_keeper_entry(const char *domainname,
440                                              const char *program,
441                                              const bool is_not,
442                                              const bool is_delete)
443 {
444         struct tomoyo_domain_keeper_entry *new_entry;
445         struct tomoyo_domain_keeper_entry *ptr;
446         const struct tomoyo_path_info *saved_domainname;
447         const struct tomoyo_path_info *saved_program = NULL;
448         int error = -ENOMEM;
449         bool is_last_name = false;
450
451         if (!tomoyo_is_domain_def(domainname) &&
452             tomoyo_is_correct_path(domainname, 1, -1, -1, __func__))
453                 is_last_name = true;
454         else if (!tomoyo_is_correct_domain(domainname, __func__))
455                 return -EINVAL;
456         if (program) {
457                 if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__))
458                         return -EINVAL;
459                 saved_program = tomoyo_save_name(program);
460                 if (!saved_program)
461                         return -ENOMEM;
462         }
463         saved_domainname = tomoyo_save_name(domainname);
464         if (!saved_domainname)
465                 return -ENOMEM;
466         new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
467         mutex_lock(&tomoyo_policy_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         if (!tomoyo_memory_ok(new_entry))
482                 goto out;
483         new_entry->domainname = saved_domainname;
484         new_entry->program = saved_program;
485         new_entry->is_not = is_not;
486         new_entry->is_last_name = is_last_name;
487         list_add_tail_rcu(&new_entry->list, &tomoyo_domain_keeper_list);
488         new_entry = NULL;
489         error = 0;
490  out:
491         mutex_unlock(&tomoyo_policy_lock);
492         kfree(new_entry);
493         return error;
494 }
495
496 /**
497  * tomoyo_write_domain_keeper_policy - Write "struct tomoyo_domain_keeper_entry" list.
498  *
499  * @data:      String to parse.
500  * @is_not:    True if it is "no_keep_domain" entry.
501  * @is_delete: True if it is a delete request.
502  *
503  * Caller holds tomoyo_read_lock().
504  */
505 int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
506                                       const bool is_delete)
507 {
508         char *cp = strstr(data, " from ");
509
510         if (cp) {
511                 *cp = '\0';
512                 return tomoyo_update_domain_keeper_entry(cp + 6, data, is_not,
513                                                          is_delete);
514         }
515         return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete);
516 }
517
518 /**
519  * tomoyo_read_domain_keeper_policy - Read "struct tomoyo_domain_keeper_entry" list.
520  *
521  * @head: Pointer to "struct tomoyo_io_buffer".
522  *
523  * Returns true on success, false otherwise.
524  *
525  * Caller holds tomoyo_read_lock().
526  */
527 bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
528 {
529         struct list_head *pos;
530         bool done = true;
531
532         list_for_each_cookie(pos, head->read_var2,
533                              &tomoyo_domain_keeper_list) {
534                 struct tomoyo_domain_keeper_entry *ptr;
535                 const char *no;
536                 const char *from = "";
537                 const char *program = "";
538
539                 ptr = list_entry(pos, struct tomoyo_domain_keeper_entry, list);
540                 if (ptr->is_deleted)
541                         continue;
542                 no = ptr->is_not ? "no_" : "";
543                 if (ptr->program) {
544                         from = " from ";
545                         program = ptr->program->name;
546                 }
547                 done = tomoyo_io_printf(head,
548                                         "%s" TOMOYO_KEYWORD_KEEP_DOMAIN
549                                         "%s%s%s\n", no, program, from,
550                                         ptr->domainname->name);
551                 if (!done)
552                         break;
553         }
554         return done;
555 }
556
557 /**
558  * tomoyo_is_domain_keeper - Check whether the given program causes domain transition suppression.
559  *
560  * @domainname: The name of domain.
561  * @program:    The name of program.
562  * @last_name:  The last component of @domainname.
563  *
564  * Returns true if executing @program supresses domain transition,
565  * false otherwise.
566  *
567  * Caller holds tomoyo_read_lock().
568  */
569 static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
570                                     const struct tomoyo_path_info *program,
571                                     const struct tomoyo_path_info *last_name)
572 {
573         struct tomoyo_domain_keeper_entry *ptr;
574         bool flag = false;
575
576         list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) {
577                 if (ptr->is_deleted)
578                         continue;
579                 if (!ptr->is_last_name) {
580                         if (ptr->domainname != domainname)
581                                 continue;
582                 } else {
583                         if (tomoyo_pathcmp(ptr->domainname, last_name))
584                                 continue;
585                 }
586                 if (ptr->program && tomoyo_pathcmp(ptr->program, program))
587                         continue;
588                 if (ptr->is_not) {
589                         flag = false;
590                         break;
591                 }
592                 flag = true;
593         }
594         return flag;
595 }
596
597 /*
598  * tomoyo_alias_list is used for holding list of symlink's pathnames which are
599  * allowed to be passed to an execve() request. Normally, the domainname which
600  * the current process will belong to after execve() succeeds is calculated
601  * using dereferenced pathnames. But some programs behave differently depending
602  * on the name passed to argv[0]. For busybox, calculating domainname using
603  * dereferenced pathnames will cause all programs in the busybox to belong to
604  * the same domain. Thus, TOMOYO provides a way to allow use of symlink's
605  * pathname for checking execve()'s permission and calculating domainname which
606  * the current process will belong to after execve() succeeds.
607  *
608  * An entry is added by
609  *
610  * # echo 'alias /bin/busybox /bin/cat' > \
611  *                            /sys/kernel/security/tomoyo/exception_policy
612  *
613  * and is deleted by
614  *
615  * # echo 'delete alias /bin/busybox /bin/cat' > \
616  *                            /sys/kernel/security/tomoyo/exception_policy
617  *
618  * and all entries are retrieved by
619  *
620  * # grep ^alias /sys/kernel/security/tomoyo/exception_policy
621  *
622  * In the example above, if /bin/cat is a symlink to /bin/busybox and execution
623  * of /bin/cat is requested, permission is checked for /bin/cat rather than
624  * /bin/busybox and domainname which the current process will belong to after
625  * execve() succeeds is calculated using /bin/cat rather than /bin/busybox .
626  */
627 static LIST_HEAD(tomoyo_alias_list);
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         new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
658         mutex_lock(&tomoyo_policy_lock);
659         list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
660                 if (ptr->original_name != saved_original_name ||
661                     ptr->aliased_name != saved_aliased_name)
662                         continue;
663                 ptr->is_deleted = is_delete;
664                 error = 0;
665                 goto out;
666         }
667         if (is_delete) {
668                 error = -ENOENT;
669                 goto out;
670         }
671         if (!tomoyo_memory_ok(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         new_entry = NULL;
677         error = 0;
678  out:
679         mutex_unlock(&tomoyo_policy_lock);
680         kfree(new_entry);
681         return error;
682 }
683
684 /**
685  * tomoyo_read_alias_policy - Read "struct tomoyo_alias_entry" list.
686  *
687  * @head: Pointer to "struct tomoyo_io_buffer".
688  *
689  * Returns true on success, false otherwise.
690  *
691  * Caller holds tomoyo_read_lock().
692  */
693 bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
694 {
695         struct list_head *pos;
696         bool done = true;
697
698         list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) {
699                 struct tomoyo_alias_entry *ptr;
700
701                 ptr = list_entry(pos, struct tomoyo_alias_entry, list);
702                 if (ptr->is_deleted)
703                         continue;
704                 done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n",
705                                         ptr->original_name->name,
706                                         ptr->aliased_name->name);
707                 if (!done)
708                         break;
709         }
710         return done;
711 }
712
713 /**
714  * tomoyo_write_alias_policy - Write "struct tomoyo_alias_entry" list.
715  *
716  * @data:      String to parse.
717  * @is_delete: True if it is a delete request.
718  *
719  * Returns 0 on success, negative value otherwise.
720  *
721  * Caller holds tomoyo_read_lock().
722  */
723 int tomoyo_write_alias_policy(char *data, const bool is_delete)
724 {
725         char *cp = strchr(data, ' ');
726
727         if (!cp)
728                 return -EINVAL;
729         *cp++ = '\0';
730         return tomoyo_update_alias_entry(data, cp, is_delete);
731 }
732
733 /**
734  * tomoyo_find_or_assign_new_domain - Create a domain.
735  *
736  * @domainname: The name of domain.
737  * @profile:    Profile number to assign if the domain was newly created.
738  *
739  * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
740  *
741  * Caller holds tomoyo_read_lock().
742  */
743 struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
744                                                             domainname,
745                                                             const u8 profile)
746 {
747         struct tomoyo_domain_info *domain;
748         const struct tomoyo_path_info *saved_domainname;
749
750         mutex_lock(&tomoyo_policy_lock);
751         domain = tomoyo_find_domain(domainname);
752         if (domain)
753                 goto out;
754         if (!tomoyo_is_correct_domain(domainname, __func__))
755                 goto out;
756         saved_domainname = tomoyo_save_name(domainname);
757         if (!saved_domainname)
758                 goto out;
759         domain = kmalloc(sizeof(*domain), GFP_KERNEL);
760         if (tomoyo_memory_ok(domain)) {
761                 INIT_LIST_HEAD(&domain->acl_info_list);
762                 domain->domainname = saved_domainname;
763                 domain->profile = profile;
764                 list_add_tail_rcu(&domain->list, &tomoyo_domain_list);
765         } else {
766                 kfree(domain);
767                 domain = NULL;
768         }
769
770  out:
771         mutex_unlock(&tomoyo_policy_lock);
772         return domain;
773 }
774
775 /**
776  * tomoyo_find_next_domain - Find a domain.
777  *
778  * @bprm: Pointer to "struct linux_binprm".
779  *
780  * Returns 0 on success, negative value otherwise.
781  *
782  * Caller holds tomoyo_read_lock().
783  */
784 int tomoyo_find_next_domain(struct linux_binprm *bprm)
785 {
786         /*
787          * This function assumes that the size of buffer returned by
788          * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN.
789          */
790         struct tomoyo_page_buffer *tmp = tomoyo_alloc(sizeof(*tmp));
791         struct tomoyo_domain_info *old_domain = tomoyo_domain();
792         struct tomoyo_domain_info *domain = NULL;
793         const char *old_domain_name = old_domain->domainname->name;
794         const char *original_name = bprm->filename;
795         char *new_domain_name = NULL;
796         char *real_program_name = NULL;
797         char *symlink_program_name = NULL;
798         const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE);
799         const bool is_enforce = (mode == 3);
800         int retval = -ENOMEM;
801         struct tomoyo_path_info r; /* real name */
802         struct tomoyo_path_info s; /* symlink name */
803         struct tomoyo_path_info l; /* last name */
804         static bool initialized;
805
806         if (!tmp)
807                 goto out;
808
809         if (!initialized) {
810                 /*
811                  * Built-in initializers. This is needed because policies are
812                  * not loaded until starting /sbin/init.
813                  */
814                 tomoyo_update_domain_initializer_entry(NULL, "/sbin/hotplug",
815                                                        false, false);
816                 tomoyo_update_domain_initializer_entry(NULL, "/sbin/modprobe",
817                                                        false, false);
818                 initialized = true;
819         }
820
821         /* Get tomoyo_realpath of program. */
822         retval = -ENOENT;
823         /* I hope tomoyo_realpath() won't fail with -ENOMEM. */
824         real_program_name = tomoyo_realpath(original_name);
825         if (!real_program_name)
826                 goto out;
827         /* Get tomoyo_realpath of symbolic link. */
828         symlink_program_name = tomoyo_realpath_nofollow(original_name);
829         if (!symlink_program_name)
830                 goto out;
831
832         r.name = real_program_name;
833         tomoyo_fill_path_info(&r);
834         s.name = symlink_program_name;
835         tomoyo_fill_path_info(&s);
836         l.name = tomoyo_get_last_name(old_domain);
837         tomoyo_fill_path_info(&l);
838
839         /* Check 'alias' directive. */
840         if (tomoyo_pathcmp(&r, &s)) {
841                 struct tomoyo_alias_entry *ptr;
842                 /* Is this program allowed to be called via symbolic links? */
843                 list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
844                         if (ptr->is_deleted ||
845                             tomoyo_pathcmp(&r, ptr->original_name) ||
846                             tomoyo_pathcmp(&s, ptr->aliased_name))
847                                 continue;
848                         memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN);
849                         strncpy(real_program_name, ptr->aliased_name->name,
850                                 TOMOYO_MAX_PATHNAME_LEN - 1);
851                         tomoyo_fill_path_info(&r);
852                         break;
853                 }
854         }
855
856         /* Check execute permission. */
857         retval = tomoyo_check_exec_perm(old_domain, &r);
858         if (retval < 0)
859                 goto out;
860
861         new_domain_name = tmp->buffer;
862         if (tomoyo_is_domain_initializer(old_domain->domainname, &r, &l)) {
863                 /* Transit to the child of tomoyo_kernel_domain domain. */
864                 snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
865                          TOMOYO_ROOT_NAME " " "%s", real_program_name);
866         } else if (old_domain == &tomoyo_kernel_domain &&
867                    !tomoyo_policy_loaded) {
868                 /*
869                  * Needn't to transit from kernel domain before starting
870                  * /sbin/init. But transit from kernel domain if executing
871                  * initializers because they might start before /sbin/init.
872                  */
873                 domain = old_domain;
874         } else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) {
875                 /* Keep current domain. */
876                 domain = old_domain;
877         } else {
878                 /* Normal domain transition. */
879                 snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
880                          "%s %s", old_domain_name, real_program_name);
881         }
882         if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
883                 goto done;
884         domain = tomoyo_find_domain(new_domain_name);
885         if (domain)
886                 goto done;
887         if (is_enforce)
888                 goto done;
889         domain = tomoyo_find_or_assign_new_domain(new_domain_name,
890                                                   old_domain->profile);
891  done:
892         if (domain)
893                 goto out;
894         printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
895                new_domain_name);
896         if (is_enforce)
897                 retval = -EPERM;
898         else
899                 tomoyo_set_domain_flag(old_domain, false,
900                                        TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED);
901  out:
902         if (!domain)
903                 domain = old_domain;
904         bprm->cred->security = domain;
905         tomoyo_free(real_program_name);
906         tomoyo_free(symlink_program_name);
907         tomoyo_free(tmp);
908         return retval;
909 }