domain.c revision bcb86975dbcc24f820f1a37918d53914af29ace7
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	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 */
85const 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". */
96static LIST_HEAD(tomoyo_domain_initializer_list);
97static 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 */
109static 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 */
171bool 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 */
212int 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 */
237static 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". */
272static LIST_HEAD(tomoyo_domain_keeper_list);
273static 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 */
285static 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 */
348int 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 */
368bool 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 */
410static 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". */
441static LIST_HEAD(tomoyo_alias_list);
442static 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 */
453static 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 */
502bool 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 */
532int 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 */
551int 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 */
582struct 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 */
648int 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);
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}
777