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