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