TOMOYO: Simplify policy reader.
[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 /* The list for "struct tomoyo_domain_info". */
23 LIST_HEAD(tomoyo_domain_list);
24 DECLARE_RWSEM(tomoyo_domain_list_lock);
25
26 /* Structure for "initialize_domain" and "no_initialize_domain" keyword. */
27 struct tomoyo_domain_initializer_entry {
28         struct list_head list;
29         const struct tomoyo_path_info *domainname;    /* This may be NULL */
30         const struct tomoyo_path_info *program;
31         bool is_deleted;
32         bool is_not;       /* True if this entry is "no_initialize_domain".  */
33         /* True if the domainname is tomoyo_get_last_name(). */
34         bool is_last_name;
35 };
36
37 /* Structure for "keep_domain" and "no_keep_domain" keyword. */
38 struct tomoyo_domain_keeper_entry {
39         struct list_head list;
40         const struct tomoyo_path_info *domainname;
41         const struct tomoyo_path_info *program;       /* This may be NULL */
42         bool is_deleted;
43         bool is_not;       /* True if this entry is "no_keep_domain".        */
44         /* True if the domainname is tomoyo_get_last_name(). */
45         bool is_last_name;
46 };
47
48 /* Structure for "alias" keyword. */
49 struct tomoyo_alias_entry {
50         struct list_head list;
51         const struct tomoyo_path_info *original_name;
52         const struct tomoyo_path_info *aliased_name;
53         bool is_deleted;
54 };
55
56 /**
57  * tomoyo_set_domain_flag - Set or clear domain's attribute flags.
58  *
59  * @domain:    Pointer to "struct tomoyo_domain_info".
60  * @is_delete: True if it is a delete request.
61  * @flags:     Flags to set or clear.
62  *
63  * Returns nothing.
64  */
65 void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain,
66                             const bool is_delete, const u8 flags)
67 {
68         /* We need to serialize because this is bitfield operation. */
69         static DEFINE_SPINLOCK(lock);
70         spin_lock(&lock);
71         if (!is_delete)
72                 domain->flags |= flags;
73         else
74                 domain->flags &= ~flags;
75         spin_unlock(&lock);
76 }
77
78 /**
79  * tomoyo_get_last_name - Get last component of a domainname.
80  *
81  * @domain: Pointer to "struct tomoyo_domain_info".
82  *
83  * Returns the last component of the domainname.
84  */
85 const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain)
86 {
87         const char *cp0 = domain->domainname->name;
88         const char *cp1 = strrchr(cp0, ' ');
89
90         if (cp1)
91                 return cp1 + 1;
92         return cp0;
93 }
94
95 /* The list for "struct tomoyo_domain_initializer_entry". */
96 static LIST_HEAD(tomoyo_domain_initializer_list);
97 static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock);
98
99 /**
100  * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list.
101  *
102  * @domainname: The name of domain. May be NULL.
103  * @program:    The name of program.
104  * @is_not:     True if it is "no_initialize_domain" entry.
105  * @is_delete:  True if it is a delete request.
106  *
107  * Returns 0 on success, negative value otherwise.
108  */
109 static int tomoyo_update_domain_initializer_entry(const char *domainname,
110                                                   const char *program,
111                                                   const bool is_not,
112                                                   const bool is_delete)
113 {
114         struct tomoyo_domain_initializer_entry *new_entry;
115         struct tomoyo_domain_initializer_entry *ptr;
116         const struct tomoyo_path_info *saved_program;
117         const struct tomoyo_path_info *saved_domainname = NULL;
118         int error = -ENOMEM;
119         bool is_last_name = false;
120
121         if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__))
122                 return -EINVAL; /* No patterns allowed. */
123         if (domainname) {
124                 if (!tomoyo_is_domain_def(domainname) &&
125                     tomoyo_is_correct_path(domainname, 1, -1, -1, __func__))
126                         is_last_name = true;
127                 else if (!tomoyo_is_correct_domain(domainname, __func__))
128                         return -EINVAL;
129                 saved_domainname = tomoyo_save_name(domainname);
130                 if (!saved_domainname)
131                         return -ENOMEM;
132         }
133         saved_program = tomoyo_save_name(program);
134         if (!saved_program)
135                 return -ENOMEM;
136         down_write(&tomoyo_domain_initializer_list_lock);
137         list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) {
138                 if (ptr->is_not != is_not ||
139                     ptr->domainname != saved_domainname ||
140                     ptr->program != saved_program)
141                         continue;
142                 ptr->is_deleted = is_delete;
143                 error = 0;
144                 goto out;
145         }
146         if (is_delete) {
147                 error = -ENOENT;
148                 goto out;
149         }
150         new_entry = tomoyo_alloc_element(sizeof(*new_entry));
151         if (!new_entry)
152                 goto out;
153         new_entry->domainname = saved_domainname;
154         new_entry->program = saved_program;
155         new_entry->is_not = is_not;
156         new_entry->is_last_name = is_last_name;
157         list_add_tail(&new_entry->list, &tomoyo_domain_initializer_list);
158         error = 0;
159  out:
160         up_write(&tomoyo_domain_initializer_list_lock);
161         return error;
162 }
163
164 /**
165  * tomoyo_read_domain_initializer_policy - Read "struct tomoyo_domain_initializer_entry" list.
166  *
167  * @head: Pointer to "struct tomoyo_io_buffer".
168  *
169  * Returns true on success, false otherwise.
170  */
171 bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head)
172 {
173         struct list_head *pos;
174         bool done = true;
175
176         down_read(&tomoyo_domain_initializer_list_lock);
177         list_for_each_cookie(pos, head->read_var2,
178                              &tomoyo_domain_initializer_list) {
179                 const char *no;
180                 const char *from = "";
181                 const char *domain = "";
182                 struct tomoyo_domain_initializer_entry *ptr;
183                 ptr = list_entry(pos, struct tomoyo_domain_initializer_entry,
184                                   list);
185                 if (ptr->is_deleted)
186                         continue;
187                 no = ptr->is_not ? "no_" : "";
188                 if (ptr->domainname) {
189                         from = " from ";
190                         domain = ptr->domainname->name;
191                 }
192                 done = tomoyo_io_printf(head,
193                                         "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN
194                                         "%s%s%s\n", no, ptr->program->name,
195                                         from, domain);
196                 if (!done)
197                         break;
198         }
199         up_read(&tomoyo_domain_initializer_list_lock);
200         return done;
201 }
202
203 /**
204  * tomoyo_write_domain_initializer_policy - Write "struct tomoyo_domain_initializer_entry" list.
205  *
206  * @data:      String to parse.
207  * @is_not:    True if it is "no_initialize_domain" entry.
208  * @is_delete: True if it is a delete request.
209  *
210  * Returns 0 on success, negative value otherwise.
211  */
212 int tomoyo_write_domain_initializer_policy(char *data, const bool is_not,
213                                            const bool is_delete)
214 {
215         char *cp = strstr(data, " from ");
216
217         if (cp) {
218                 *cp = '\0';
219                 return tomoyo_update_domain_initializer_entry(cp + 6, data,
220                                                               is_not,
221                                                               is_delete);
222         }
223         return tomoyo_update_domain_initializer_entry(NULL, data, is_not,
224                                                       is_delete);
225 }
226
227 /**
228  * tomoyo_is_domain_initializer - Check whether the given program causes domainname reinitialization.
229  *
230  * @domainname: The name of domain.
231  * @program:    The name of program.
232  * @last_name:  The last component of @domainname.
233  *
234  * Returns true if executing @program reinitializes domain transition,
235  * false otherwise.
236  */
237 static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info *
238                                          domainname,
239                                          const struct tomoyo_path_info *program,
240                                          const struct tomoyo_path_info *
241                                          last_name)
242 {
243         struct tomoyo_domain_initializer_entry *ptr;
244         bool flag = false;
245
246         down_read(&tomoyo_domain_initializer_list_lock);
247         list_for_each_entry(ptr,  &tomoyo_domain_initializer_list, list) {
248                 if (ptr->is_deleted)
249                         continue;
250                 if (ptr->domainname) {
251                         if (!ptr->is_last_name) {
252                                 if (ptr->domainname != domainname)
253                                         continue;
254                         } else {
255                                 if (tomoyo_pathcmp(ptr->domainname, last_name))
256                                         continue;
257                         }
258                 }
259                 if (tomoyo_pathcmp(ptr->program, program))
260                         continue;
261                 if (ptr->is_not) {
262                         flag = false;
263                         break;
264                 }
265                 flag = true;
266         }
267         up_read(&tomoyo_domain_initializer_list_lock);
268         return flag;
269 }
270
271 /* The list for "struct tomoyo_domain_keeper_entry". */
272 static LIST_HEAD(tomoyo_domain_keeper_list);
273 static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock);
274
275 /**
276  * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list.
277  *
278  * @domainname: The name of domain.
279  * @program:    The name of program. May be NULL.
280  * @is_not:     True if it is "no_keep_domain" entry.
281  * @is_delete:  True if it is a delete request.
282  *
283  * Returns 0 on success, negative value otherwise.
284  */
285 static int tomoyo_update_domain_keeper_entry(const char *domainname,
286                                              const char *program,
287                                              const bool is_not,
288                                              const bool is_delete)
289 {
290         struct tomoyo_domain_keeper_entry *new_entry;
291         struct tomoyo_domain_keeper_entry *ptr;
292         const struct tomoyo_path_info *saved_domainname;
293         const struct tomoyo_path_info *saved_program = NULL;
294         int error = -ENOMEM;
295         bool is_last_name = false;
296
297         if (!tomoyo_is_domain_def(domainname) &&
298             tomoyo_is_correct_path(domainname, 1, -1, -1, __func__))
299                 is_last_name = true;
300         else if (!tomoyo_is_correct_domain(domainname, __func__))
301                 return -EINVAL;
302         if (program) {
303                 if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__))
304                         return -EINVAL;
305                 saved_program = tomoyo_save_name(program);
306                 if (!saved_program)
307                         return -ENOMEM;
308         }
309         saved_domainname = tomoyo_save_name(domainname);
310         if (!saved_domainname)
311                 return -ENOMEM;
312         down_write(&tomoyo_domain_keeper_list_lock);
313         list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
314                 if (ptr->is_not != is_not ||
315                     ptr->domainname != saved_domainname ||
316                     ptr->program != saved_program)
317                         continue;
318                 ptr->is_deleted = is_delete;
319                 error = 0;
320                 goto out;
321         }
322         if (is_delete) {
323                 error = -ENOENT;
324                 goto out;
325         }
326         new_entry = tomoyo_alloc_element(sizeof(*new_entry));
327         if (!new_entry)
328                 goto out;
329         new_entry->domainname = saved_domainname;
330         new_entry->program = saved_program;
331         new_entry->is_not = is_not;
332         new_entry->is_last_name = is_last_name;
333         list_add_tail(&new_entry->list, &tomoyo_domain_keeper_list);
334         error = 0;
335  out:
336         up_write(&tomoyo_domain_keeper_list_lock);
337         return error;
338 }
339
340 /**
341  * tomoyo_write_domain_keeper_policy - Write "struct tomoyo_domain_keeper_entry" list.
342  *
343  * @data:      String to parse.
344  * @is_not:    True if it is "no_keep_domain" entry.
345  * @is_delete: True if it is a delete request.
346  *
347  */
348 int tomoyo_write_domain_keeper_policy(char *data, const bool is_not,
349                                       const bool is_delete)
350 {
351         char *cp = strstr(data, " from ");
352
353         if (cp) {
354                 *cp = '\0';
355                 return tomoyo_update_domain_keeper_entry(cp + 6, data, is_not,
356                                                          is_delete);
357         }
358         return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete);
359 }
360
361 /**
362  * tomoyo_read_domain_keeper_policy - Read "struct tomoyo_domain_keeper_entry" list.
363  *
364  * @head: Pointer to "struct tomoyo_io_buffer".
365  *
366  * Returns true on success, false otherwise.
367  */
368 bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head)
369 {
370         struct list_head *pos;
371         bool done = true;
372
373         down_read(&tomoyo_domain_keeper_list_lock);
374         list_for_each_cookie(pos, head->read_var2,
375                              &tomoyo_domain_keeper_list) {
376                 struct tomoyo_domain_keeper_entry *ptr;
377                 const char *no;
378                 const char *from = "";
379                 const char *program = "";
380
381                 ptr = list_entry(pos, struct tomoyo_domain_keeper_entry, list);
382                 if (ptr->is_deleted)
383                         continue;
384                 no = ptr->is_not ? "no_" : "";
385                 if (ptr->program) {
386                         from = " from ";
387                         program = ptr->program->name;
388                 }
389                 done = tomoyo_io_printf(head,
390                                         "%s" TOMOYO_KEYWORD_KEEP_DOMAIN
391                                         "%s%s%s\n", no, program, from,
392                                         ptr->domainname->name);
393                 if (!done)
394                         break;
395         }
396         up_read(&tomoyo_domain_keeper_list_lock);
397         return done;
398 }
399
400 /**
401  * tomoyo_is_domain_keeper - Check whether the given program causes domain transition suppression.
402  *
403  * @domainname: The name of domain.
404  * @program:    The name of program.
405  * @last_name:  The last component of @domainname.
406  *
407  * Returns true if executing @program supresses domain transition,
408  * false otherwise.
409  */
410 static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
411                                     const struct tomoyo_path_info *program,
412                                     const struct tomoyo_path_info *last_name)
413 {
414         struct tomoyo_domain_keeper_entry *ptr;
415         bool flag = false;
416
417         down_read(&tomoyo_domain_keeper_list_lock);
418         list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) {
419                 if (ptr->is_deleted)
420                         continue;
421                 if (!ptr->is_last_name) {
422                         if (ptr->domainname != domainname)
423                                 continue;
424                 } else {
425                         if (tomoyo_pathcmp(ptr->domainname, last_name))
426                                 continue;
427                 }
428                 if (ptr->program && tomoyo_pathcmp(ptr->program, program))
429                         continue;
430                 if (ptr->is_not) {
431                         flag = false;
432                         break;
433                 }
434                 flag = true;
435         }
436         up_read(&tomoyo_domain_keeper_list_lock);
437         return flag;
438 }
439
440 /* The list for "struct tomoyo_alias_entry". */
441 static LIST_HEAD(tomoyo_alias_list);
442 static DECLARE_RWSEM(tomoyo_alias_list_lock);
443
444 /**
445  * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list.
446  *
447  * @original_name: The original program's real name.
448  * @aliased_name:  The symbolic program's symbolic link's name.
449  * @is_delete:     True if it is a delete request.
450  *
451  * Returns 0 on success, negative value otherwise.
452  */
453 static int tomoyo_update_alias_entry(const char *original_name,
454                                      const char *aliased_name,
455                                      const bool is_delete)
456 {
457         struct tomoyo_alias_entry *new_entry;
458         struct tomoyo_alias_entry *ptr;
459         const struct tomoyo_path_info *saved_original_name;
460         const struct tomoyo_path_info *saved_aliased_name;
461         int error = -ENOMEM;
462
463         if (!tomoyo_is_correct_path(original_name, 1, -1, -1, __func__) ||
464             !tomoyo_is_correct_path(aliased_name, 1, -1, -1, __func__))
465                 return -EINVAL; /* No patterns allowed. */
466         saved_original_name = tomoyo_save_name(original_name);
467         saved_aliased_name = tomoyo_save_name(aliased_name);
468         if (!saved_original_name || !saved_aliased_name)
469                 return -ENOMEM;
470         down_write(&tomoyo_alias_list_lock);
471         list_for_each_entry(ptr, &tomoyo_alias_list, list) {
472                 if (ptr->original_name != saved_original_name ||
473                     ptr->aliased_name != saved_aliased_name)
474                         continue;
475                 ptr->is_deleted = is_delete;
476                 error = 0;
477                 goto out;
478         }
479         if (is_delete) {
480                 error = -ENOENT;
481                 goto out;
482         }
483         new_entry = tomoyo_alloc_element(sizeof(*new_entry));
484         if (!new_entry)
485                 goto out;
486         new_entry->original_name = saved_original_name;
487         new_entry->aliased_name = saved_aliased_name;
488         list_add_tail(&new_entry->list, &tomoyo_alias_list);
489         error = 0;
490  out:
491         up_write(&tomoyo_alias_list_lock);
492         return error;
493 }
494
495 /**
496  * tomoyo_read_alias_policy - Read "struct tomoyo_alias_entry" list.
497  *
498  * @head: Pointer to "struct tomoyo_io_buffer".
499  *
500  * Returns true on success, false otherwise.
501  */
502 bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head)
503 {
504         struct list_head *pos;
505         bool done = true;
506
507         down_read(&tomoyo_alias_list_lock);
508         list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) {
509                 struct tomoyo_alias_entry *ptr;
510
511                 ptr = list_entry(pos, struct tomoyo_alias_entry, list);
512                 if (ptr->is_deleted)
513                         continue;
514                 done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n",
515                                         ptr->original_name->name,
516                                         ptr->aliased_name->name);
517                 if (!done)
518                         break;
519         }
520         up_read(&tomoyo_alias_list_lock);
521         return done;
522 }
523
524 /**
525  * tomoyo_write_alias_policy - Write "struct tomoyo_alias_entry" list.
526  *
527  * @data:      String to parse.
528  * @is_delete: True if it is a delete request.
529  *
530  * Returns 0 on success, negative value otherwise.
531  */
532 int tomoyo_write_alias_policy(char *data, const bool is_delete)
533 {
534         char *cp = strchr(data, ' ');
535
536         if (!cp)
537                 return -EINVAL;
538         *cp++ = '\0';
539         return tomoyo_update_alias_entry(data, cp, is_delete);
540 }
541
542 /* Domain create/delete handler. */
543
544 /**
545  * tomoyo_delete_domain - Delete a domain.
546  *
547  * @domainname: The name of domain.
548  *
549  * Returns 0.
550  */
551 int tomoyo_delete_domain(char *domainname)
552 {
553         struct tomoyo_domain_info *domain;
554         struct tomoyo_path_info name;
555
556         name.name = domainname;
557         tomoyo_fill_path_info(&name);
558         down_write(&tomoyo_domain_list_lock);
559         /* Is there an active domain? */
560         list_for_each_entry(domain, &tomoyo_domain_list, list) {
561                 /* Never delete tomoyo_kernel_domain */
562                 if (domain == &tomoyo_kernel_domain)
563                         continue;
564                 if (domain->is_deleted ||
565                     tomoyo_pathcmp(domain->domainname, &name))
566                         continue;
567                 domain->is_deleted = true;
568                 break;
569         }
570         up_write(&tomoyo_domain_list_lock);
571         return 0;
572 }
573
574 /**
575  * tomoyo_find_or_assign_new_domain - Create a domain.
576  *
577  * @domainname: The name of domain.
578  * @profile:    Profile number to assign if the domain was newly created.
579  *
580  * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
581  */
582 struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
583                                                             domainname,
584                                                             const u8 profile)
585 {
586         struct tomoyo_domain_info *domain = NULL;
587         const struct tomoyo_path_info *saved_domainname;
588
589         down_write(&tomoyo_domain_list_lock);
590         domain = tomoyo_find_domain(domainname);
591         if (domain)
592                 goto out;
593         if (!tomoyo_is_correct_domain(domainname, __func__))
594                 goto out;
595         saved_domainname = tomoyo_save_name(domainname);
596         if (!saved_domainname)
597                 goto out;
598         /* Can I reuse memory of deleted domain? */
599         list_for_each_entry(domain, &tomoyo_domain_list, list) {
600                 struct task_struct *p;
601                 struct tomoyo_acl_info *ptr;
602                 bool flag;
603                 if (!domain->is_deleted ||
604                     domain->domainname != saved_domainname)
605                         continue;
606                 flag = false;
607                 read_lock(&tasklist_lock);
608                 for_each_process(p) {
609                         if (tomoyo_real_domain(p) != domain)
610                                 continue;
611                         flag = true;
612                         break;
613                 }
614                 read_unlock(&tasklist_lock);
615                 if (flag)
616                         continue;
617                 list_for_each_entry(ptr, &domain->acl_info_list, list) {
618                         ptr->type |= TOMOYO_ACL_DELETED;
619                 }
620                 tomoyo_set_domain_flag(domain, true, domain->flags);
621                 domain->profile = profile;
622                 domain->quota_warned = false;
623                 mb(); /* Avoid out-of-order execution. */
624                 domain->is_deleted = false;
625                 goto out;
626         }
627         /* No memory reusable. Create using new memory. */
628         domain = tomoyo_alloc_element(sizeof(*domain));
629         if (domain) {
630                 INIT_LIST_HEAD(&domain->acl_info_list);
631                 domain->domainname = saved_domainname;
632                 domain->profile = profile;
633                 list_add_tail(&domain->list, &tomoyo_domain_list);
634         }
635  out:
636         up_write(&tomoyo_domain_list_lock);
637         return domain;
638 }
639
640 /**
641  * tomoyo_find_next_domain - Find a domain.
642  *
643  * @bprm:           Pointer to "struct linux_binprm".
644  * @next_domain:    Pointer to pointer to "struct tomoyo_domain_info".
645  *
646  * Returns 0 on success, negative value otherwise.
647  */
648 int tomoyo_find_next_domain(struct linux_binprm *bprm,
649                             struct tomoyo_domain_info **next_domain)
650 {
651         /*
652          * This function assumes that the size of buffer returned by
653          * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN.
654          */
655         struct tomoyo_page_buffer *tmp = tomoyo_alloc(sizeof(*tmp));
656         struct tomoyo_domain_info *old_domain = tomoyo_domain();
657         struct tomoyo_domain_info *domain = NULL;
658         const char *old_domain_name = old_domain->domainname->name;
659         const char *original_name = bprm->filename;
660         char *new_domain_name = NULL;
661         char *real_program_name = NULL;
662         char *symlink_program_name = NULL;
663         const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE);
664         const bool is_enforce = (mode == 3);
665         int retval = -ENOMEM;
666         struct tomoyo_path_info r; /* real name */
667         struct tomoyo_path_info s; /* symlink name */
668         struct tomoyo_path_info l; /* last name */
669         static bool initialized;
670
671         if (!tmp)
672                 goto out;
673
674         if (!initialized) {
675                 /*
676                  * Built-in initializers. This is needed because policies are
677                  * not loaded until starting /sbin/init.
678                  */
679                 tomoyo_update_domain_initializer_entry(NULL, "/sbin/hotplug",
680                                                        false, false);
681                 tomoyo_update_domain_initializer_entry(NULL, "/sbin/modprobe",
682                                                        false, false);
683                 initialized = true;
684         }
685
686         /* Get tomoyo_realpath of program. */
687         retval = -ENOENT;
688         /* I hope tomoyo_realpath() won't fail with -ENOMEM. */
689         real_program_name = tomoyo_realpath(original_name);
690         if (!real_program_name)
691                 goto out;
692         /* Get tomoyo_realpath of symbolic link. */
693         symlink_program_name = tomoyo_realpath_nofollow(original_name);
694         if (!symlink_program_name)
695                 goto out;
696
697         r.name = real_program_name;
698         tomoyo_fill_path_info(&r);
699         s.name = symlink_program_name;
700         tomoyo_fill_path_info(&s);
701         l.name = tomoyo_get_last_name(old_domain);
702         tomoyo_fill_path_info(&l);
703
704         /* Check 'alias' directive. */
705         if (tomoyo_pathcmp(&r, &s)) {
706                 struct tomoyo_alias_entry *ptr;
707                 /* Is this program allowed to be called via symbolic links? */
708                 down_read(&tomoyo_alias_list_lock);
709                 list_for_each_entry(ptr, &tomoyo_alias_list, list) {
710                         if (ptr->is_deleted ||
711                             tomoyo_pathcmp(&r, ptr->original_name) ||
712                             tomoyo_pathcmp(&s, ptr->aliased_name))
713                                 continue;
714                         memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN);
715                         strncpy(real_program_name, ptr->aliased_name->name,
716                                 TOMOYO_MAX_PATHNAME_LEN - 1);
717                         tomoyo_fill_path_info(&r);
718                         break;
719                 }
720                 up_read(&tomoyo_alias_list_lock);
721         }
722
723         /* Check execute permission. */
724         retval = tomoyo_check_exec_perm(old_domain, &r, tmp);
725         if (retval < 0)
726                 goto out;
727
728         new_domain_name = tmp->buffer;
729         if (tomoyo_is_domain_initializer(old_domain->domainname, &r, &l)) {
730                 /* Transit to the child of tomoyo_kernel_domain domain. */
731                 snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
732                          TOMOYO_ROOT_NAME " " "%s", real_program_name);
733         } else if (old_domain == &tomoyo_kernel_domain &&
734                    !tomoyo_policy_loaded) {
735                 /*
736                  * Needn't to transit from kernel domain before starting
737                  * /sbin/init. But transit from kernel domain if executing
738                  * initializers because they might start before /sbin/init.
739                  */
740                 domain = old_domain;
741         } else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) {
742                 /* Keep current domain. */
743                 domain = old_domain;
744         } else {
745                 /* Normal domain transition. */
746                 snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
747                          "%s %s", old_domain_name, real_program_name);
748         }
749         if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
750                 goto done;
751         down_read(&tomoyo_domain_list_lock);
752         domain = tomoyo_find_domain(new_domain_name);
753         up_read(&tomoyo_domain_list_lock);
754         if (domain)
755                 goto done;
756         if (is_enforce)
757                 goto done;
758         domain = tomoyo_find_or_assign_new_domain(new_domain_name,
759                                                   old_domain->profile);
760  done:
761         if (domain)
762                 goto out;
763         printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
764                new_domain_name);
765         if (is_enforce)
766                 retval = -EPERM;
767         else
768                 tomoyo_set_domain_flag(old_domain, false,
769                                        TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED);
770  out:
771         tomoyo_free(real_program_name);
772         tomoyo_free(symlink_program_name);
773         *next_domain = domain ? domain : old_domain;
774         tomoyo_free(tmp);
775         return retval;
776 }