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