domain.c revision 97fb35e413f256ded07b88c73b3d932ec31ea84e
1/*
2 * security/tomoyo/domain.c
3 *
4 * Domain transition functions for TOMOYO.
5 *
6 * Copyright (C) 2005-2010  NTT DATA CORPORATION
7 */
8
9#include "common.h"
10#include <linux/binfmts.h>
11#include <linux/slab.h>
12
13/* Variables definitions.*/
14
15/* The initial domain. */
16struct tomoyo_domain_info tomoyo_kernel_domain;
17
18/**
19 * tomoyo_update_policy - Update an entry for exception policy.
20 *
21 * @new_entry:       Pointer to "struct tomoyo_acl_info".
22 * @size:            Size of @new_entry in bytes.
23 * @param:           Pointer to "struct tomoyo_acl_param".
24 * @check_duplicate: Callback function to find duplicated entry.
25 *
26 * Returns 0 on success, negative value otherwise.
27 *
28 * Caller holds tomoyo_read_lock().
29 */
30int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
31			 struct tomoyo_acl_param *param,
32			 bool (*check_duplicate) (const struct tomoyo_acl_head
33						  *,
34						  const struct tomoyo_acl_head
35						  *))
36{
37	int error = param->is_delete ? -ENOENT : -ENOMEM;
38	struct tomoyo_acl_head *entry;
39	struct list_head *list = param->list;
40
41	if (mutex_lock_interruptible(&tomoyo_policy_lock))
42		return -ENOMEM;
43	list_for_each_entry_rcu(entry, list, list) {
44		if (!check_duplicate(entry, new_entry))
45			continue;
46		entry->is_deleted = param->is_delete;
47		error = 0;
48		break;
49	}
50	if (error && !param->is_delete) {
51		entry = tomoyo_commit_ok(new_entry, size);
52		if (entry) {
53			list_add_tail_rcu(&entry->list, list);
54			error = 0;
55		}
56	}
57	mutex_unlock(&tomoyo_policy_lock);
58	return error;
59}
60
61/**
62 * tomoyo_same_acl_head - Check for duplicated "struct tomoyo_acl_info" entry.
63 *
64 * @a: Pointer to "struct tomoyo_acl_info".
65 * @b: Pointer to "struct tomoyo_acl_info".
66 *
67 * Returns true if @a == @b, false otherwise.
68 */
69static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a,
70					const struct tomoyo_acl_info *b)
71{
72	return a->type == b->type && a->cond == b->cond;
73}
74
75/**
76 * tomoyo_update_domain - Update an entry for domain policy.
77 *
78 * @new_entry:       Pointer to "struct tomoyo_acl_info".
79 * @size:            Size of @new_entry in bytes.
80 * @param:           Pointer to "struct tomoyo_acl_param".
81 * @check_duplicate: Callback function to find duplicated entry.
82 * @merge_duplicate: Callback function to merge duplicated entry.
83 *
84 * Returns 0 on success, negative value otherwise.
85 *
86 * Caller holds tomoyo_read_lock().
87 */
88int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
89			 struct tomoyo_acl_param *param,
90			 bool (*check_duplicate) (const struct tomoyo_acl_info
91						  *,
92						  const struct tomoyo_acl_info
93						  *),
94			 bool (*merge_duplicate) (struct tomoyo_acl_info *,
95						  struct tomoyo_acl_info *,
96						  const bool))
97{
98	const bool is_delete = param->is_delete;
99	int error = is_delete ? -ENOENT : -ENOMEM;
100	struct tomoyo_acl_info *entry;
101	struct list_head * const list = param->list;
102
103	if (param->data[0]) {
104		new_entry->cond = tomoyo_get_condition(param);
105		if (!new_entry->cond)
106			return -EINVAL;
107	}
108	if (mutex_lock_interruptible(&tomoyo_policy_lock))
109		goto out;
110	list_for_each_entry_rcu(entry, list, list) {
111		if (!tomoyo_same_acl_head(entry, new_entry) ||
112		    !check_duplicate(entry, new_entry))
113			continue;
114		if (merge_duplicate)
115			entry->is_deleted = merge_duplicate(entry, new_entry,
116							    is_delete);
117		else
118			entry->is_deleted = is_delete;
119		error = 0;
120		break;
121	}
122	if (error && !is_delete) {
123		entry = tomoyo_commit_ok(new_entry, size);
124		if (entry) {
125			list_add_tail_rcu(&entry->list, list);
126			error = 0;
127		}
128	}
129	mutex_unlock(&tomoyo_policy_lock);
130out:
131	tomoyo_put_condition(new_entry->cond);
132	return error;
133}
134
135/**
136 * tomoyo_check_acl - Do permission check.
137 *
138 * @r:           Pointer to "struct tomoyo_request_info".
139 * @check_entry: Callback function to check type specific parameters.
140 *
141 * Returns 0 on success, negative value otherwise.
142 *
143 * Caller holds tomoyo_read_lock().
144 */
145void tomoyo_check_acl(struct tomoyo_request_info *r,
146		      bool (*check_entry) (struct tomoyo_request_info *,
147					   const struct tomoyo_acl_info *))
148{
149	const struct tomoyo_domain_info *domain = r->domain;
150	struct tomoyo_acl_info *ptr;
151	bool retried = false;
152	const struct list_head *list = &domain->acl_info_list;
153
154retry:
155	list_for_each_entry_rcu(ptr, list, list) {
156		if (ptr->is_deleted || ptr->type != r->param_type)
157			continue;
158		if (!check_entry(r, ptr))
159			continue;
160		if (!tomoyo_condition(r, ptr->cond))
161			continue;
162		r->granted = true;
163		return;
164	}
165	if (!retried) {
166		retried = true;
167		list = &domain->ns->acl_group[domain->group];
168		goto retry;
169	}
170	r->granted = false;
171}
172
173/* The list for "struct tomoyo_domain_info". */
174LIST_HEAD(tomoyo_domain_list);
175
176/**
177 * tomoyo_last_word - Get last component of a domainname.
178 *
179 * @name: Domainname to check.
180 *
181 * Returns the last word of @domainname.
182 */
183static const char *tomoyo_last_word(const char *name)
184{
185        const char *cp = strrchr(name, ' ');
186        if (cp)
187                return cp + 1;
188        return name;
189}
190
191/**
192 * tomoyo_same_transition_control - Check for duplicated "struct tomoyo_transition_control" entry.
193 *
194 * @a: Pointer to "struct tomoyo_acl_head".
195 * @b: Pointer to "struct tomoyo_acl_head".
196 *
197 * Returns true if @a == @b, false otherwise.
198 */
199static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a,
200					   const struct tomoyo_acl_head *b)
201{
202	const struct tomoyo_transition_control *p1 = container_of(a,
203								  typeof(*p1),
204								  head);
205	const struct tomoyo_transition_control *p2 = container_of(b,
206								  typeof(*p2),
207								  head);
208	return p1->type == p2->type && p1->is_last_name == p2->is_last_name
209		&& p1->domainname == p2->domainname
210		&& p1->program == p2->program;
211}
212
213/**
214 * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list.
215 *
216 * @param: Pointer to "struct tomoyo_acl_param".
217 * @type:  Type of this entry.
218 *
219 * Returns 0 on success, negative value otherwise.
220 */
221int tomoyo_write_transition_control(struct tomoyo_acl_param *param,
222				    const u8 type)
223{
224	struct tomoyo_transition_control e = { .type = type };
225	int error = param->is_delete ? -ENOENT : -ENOMEM;
226	char *program = param->data;
227	char *domainname = strstr(program, " from ");
228	if (domainname) {
229		*domainname = '\0';
230		domainname += 6;
231	} else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP ||
232		   type == TOMOYO_TRANSITION_CONTROL_KEEP) {
233		domainname = program;
234		program = NULL;
235	}
236	if (program && strcmp(program, "any")) {
237		if (!tomoyo_correct_path(program))
238			return -EINVAL;
239		e.program = tomoyo_get_name(program);
240		if (!e.program)
241			goto out;
242	}
243	if (domainname && strcmp(domainname, "any")) {
244		if (!tomoyo_correct_domain(domainname)) {
245			if (!tomoyo_correct_path(domainname))
246				goto out;
247			e.is_last_name = true;
248		}
249		e.domainname = tomoyo_get_name(domainname);
250		if (!e.domainname)
251			goto out;
252	}
253	param->list = &param->ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL];
254	error = tomoyo_update_policy(&e.head, sizeof(e), param,
255				     tomoyo_same_transition_control);
256out:
257	tomoyo_put_name(e.domainname);
258	tomoyo_put_name(e.program);
259	return error;
260}
261
262/**
263 * tomoyo_scan_transition - Try to find specific domain transition type.
264 *
265 * @list:       Pointer to "struct list_head".
266 * @domainname: The name of current domain.
267 * @program:    The name of requested program.
268 * @last_name:  The last component of @domainname.
269 * @type:       One of values in "enum tomoyo_transition_type".
270 *
271 * Returns true if found one, false otherwise.
272 *
273 * Caller holds tomoyo_read_lock().
274 */
275static inline bool tomoyo_scan_transition
276(const struct list_head *list, const struct tomoyo_path_info *domainname,
277 const struct tomoyo_path_info *program, const char *last_name,
278 const enum tomoyo_transition_type type)
279{
280	const struct tomoyo_transition_control *ptr;
281	list_for_each_entry_rcu(ptr, list, head.list) {
282		if (ptr->head.is_deleted || ptr->type != type)
283			continue;
284		if (ptr->domainname) {
285			if (!ptr->is_last_name) {
286				if (ptr->domainname != domainname)
287					continue;
288			} else {
289				/*
290				 * Use direct strcmp() since this is
291				 * unlikely used.
292				 */
293				if (strcmp(ptr->domainname->name, last_name))
294					continue;
295			}
296		}
297		if (ptr->program && tomoyo_pathcmp(ptr->program, program))
298			continue;
299		return true;
300	}
301	return false;
302}
303
304/**
305 * tomoyo_transition_type - Get domain transition type.
306 *
307 * @ns:         Pointer to "struct tomoyo_policy_namespace".
308 * @domainname: The name of current domain.
309 * @program:    The name of requested program.
310 *
311 * Returns TOMOYO_TRANSITION_CONTROL_TRANSIT if executing @program causes
312 * domain transition across namespaces, TOMOYO_TRANSITION_CONTROL_INITIALIZE if
313 * executing @program reinitializes domain transition within that namespace,
314 * TOMOYO_TRANSITION_CONTROL_KEEP if executing @program stays at @domainname ,
315 * others otherwise.
316 *
317 * Caller holds tomoyo_read_lock().
318 */
319static enum tomoyo_transition_type tomoyo_transition_type
320(const struct tomoyo_policy_namespace *ns,
321 const struct tomoyo_path_info *domainname,
322 const struct tomoyo_path_info *program)
323{
324	const char *last_name = tomoyo_last_word(domainname->name);
325	enum tomoyo_transition_type type = TOMOYO_TRANSITION_CONTROL_NO_RESET;
326	while (type < TOMOYO_MAX_TRANSITION_TYPE) {
327		const struct list_head * const list =
328			&ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL];
329		if (!tomoyo_scan_transition(list, domainname, program,
330					    last_name, type)) {
331			type++;
332			continue;
333		}
334		if (type != TOMOYO_TRANSITION_CONTROL_NO_RESET &&
335		    type != TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE)
336			break;
337		/*
338		 * Do not check for reset_domain if no_reset_domain matched.
339		 * Do not check for initialize_domain if no_initialize_domain
340		 * matched.
341		 */
342		type++;
343		type++;
344	}
345	return type;
346}
347
348/**
349 * tomoyo_same_aggregator - Check for duplicated "struct tomoyo_aggregator" entry.
350 *
351 * @a: Pointer to "struct tomoyo_acl_head".
352 * @b: Pointer to "struct tomoyo_acl_head".
353 *
354 * Returns true if @a == @b, false otherwise.
355 */
356static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a,
357				   const struct tomoyo_acl_head *b)
358{
359	const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1),
360							  head);
361	const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2),
362							  head);
363	return p1->original_name == p2->original_name &&
364		p1->aggregated_name == p2->aggregated_name;
365}
366
367/**
368 * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list.
369 *
370 * @param: Pointer to "struct tomoyo_acl_param".
371 *
372 * Returns 0 on success, negative value otherwise.
373 *
374 * Caller holds tomoyo_read_lock().
375 */
376int tomoyo_write_aggregator(struct tomoyo_acl_param *param)
377{
378	struct tomoyo_aggregator e = { };
379	int error = param->is_delete ? -ENOENT : -ENOMEM;
380	const char *original_name = tomoyo_read_token(param);
381	const char *aggregated_name = tomoyo_read_token(param);
382	if (!tomoyo_correct_word(original_name) ||
383	    !tomoyo_correct_path(aggregated_name))
384		return -EINVAL;
385	e.original_name = tomoyo_get_name(original_name);
386	e.aggregated_name = tomoyo_get_name(aggregated_name);
387	if (!e.original_name || !e.aggregated_name ||
388	    e.aggregated_name->is_patterned) /* No patterns allowed. */
389		goto out;
390	param->list = &param->ns->policy_list[TOMOYO_ID_AGGREGATOR];
391	error = tomoyo_update_policy(&e.head, sizeof(e), param,
392				     tomoyo_same_aggregator);
393out:
394	tomoyo_put_name(e.original_name);
395	tomoyo_put_name(e.aggregated_name);
396	return error;
397}
398
399/**
400 * tomoyo_find_namespace - Find specified namespace.
401 *
402 * @name: Name of namespace to find.
403 * @len:  Length of @name.
404 *
405 * Returns pointer to "struct tomoyo_policy_namespace" if found,
406 * NULL otherwise.
407 *
408 * Caller holds tomoyo_read_lock().
409 */
410static struct tomoyo_policy_namespace *tomoyo_find_namespace
411(const char *name, const unsigned int len)
412{
413	struct tomoyo_policy_namespace *ns;
414	list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) {
415		if (strncmp(name, ns->name, len) ||
416		    (name[len] && name[len] != ' '))
417			continue;
418		return ns;
419	}
420	return NULL;
421}
422
423/**
424 * tomoyo_assign_namespace - Create a new namespace.
425 *
426 * @domainname: Name of namespace to create.
427 *
428 * Returns pointer to "struct tomoyo_policy_namespace" on success,
429 * NULL otherwise.
430 *
431 * Caller holds tomoyo_read_lock().
432 */
433struct tomoyo_policy_namespace *tomoyo_assign_namespace(const char *domainname)
434{
435	struct tomoyo_policy_namespace *ptr;
436	struct tomoyo_policy_namespace *entry;
437	const char *cp = domainname;
438	unsigned int len = 0;
439	while (*cp && *cp++ != ' ')
440		len++;
441	ptr = tomoyo_find_namespace(domainname, len);
442	if (ptr)
443		return ptr;
444	if (len >= TOMOYO_EXEC_TMPSIZE - 10 || !tomoyo_domain_def(domainname))
445		return NULL;
446	entry = kzalloc(sizeof(*entry) + len + 1, GFP_NOFS);
447	if (!entry)
448		return NULL;
449	if (mutex_lock_interruptible(&tomoyo_policy_lock))
450		goto out;
451	ptr = tomoyo_find_namespace(domainname, len);
452	if (!ptr && tomoyo_memory_ok(entry)) {
453		char *name = (char *) (entry + 1);
454		ptr = entry;
455		memmove(name, domainname, len);
456		name[len] = '\0';
457		entry->name = name;
458		tomoyo_init_policy_namespace(entry);
459		entry = NULL;
460	}
461	mutex_unlock(&tomoyo_policy_lock);
462out:
463	kfree(entry);
464	return ptr;
465}
466
467/**
468 * tomoyo_namespace_jump - Check for namespace jump.
469 *
470 * @domainname: Name of domain.
471 *
472 * Returns true if namespace differs, false otherwise.
473 */
474static bool tomoyo_namespace_jump(const char *domainname)
475{
476	const char *namespace = tomoyo_current_namespace()->name;
477	const int len = strlen(namespace);
478	return strncmp(domainname, namespace, len) ||
479		(domainname[len] && domainname[len] != ' ');
480}
481
482/**
483 * tomoyo_assign_domain - Create a domain or a namespace.
484 *
485 * @domainname: The name of domain.
486 * @transit:    True if transit to domain found or created.
487 *
488 * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
489 *
490 * Caller holds tomoyo_read_lock().
491 */
492struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
493						const bool transit)
494{
495	struct tomoyo_domain_info e = { };
496	struct tomoyo_domain_info *entry = tomoyo_find_domain(domainname);
497	bool created = false;
498	if (entry) {
499		if (transit) {
500			/*
501			 * Since namespace is created at runtime, profiles may
502			 * not be created by the moment the process transits to
503			 * that domain. Do not perform domain transition if
504			 * profile for that domain is not yet created.
505			 */
506			if (!entry->ns->profile_ptr[entry->profile])
507				return NULL;
508		}
509		return entry;
510	}
511	/* Requested domain does not exist. */
512	/* Don't create requested domain if domainname is invalid. */
513	if (strlen(domainname) >= TOMOYO_EXEC_TMPSIZE - 10 ||
514	    !tomoyo_correct_domain(domainname))
515		return NULL;
516	/*
517	 * Since definition of profiles and acl_groups may differ across
518	 * namespaces, do not inherit "use_profile" and "use_group" settings
519	 * by automatically creating requested domain upon domain transition.
520	 */
521	if (transit && tomoyo_namespace_jump(domainname))
522		return NULL;
523	e.ns = tomoyo_assign_namespace(domainname);
524	if (!e.ns)
525		return NULL;
526	/*
527	 * "use_profile" and "use_group" settings for automatically created
528	 * domains are inherited from current domain. These are 0 for manually
529	 * created domains.
530	 */
531	if (transit) {
532		const struct tomoyo_domain_info *domain = tomoyo_domain();
533		e.profile = domain->profile;
534		e.group = domain->group;
535	}
536	e.domainname = tomoyo_get_name(domainname);
537	if (!e.domainname)
538		return NULL;
539	if (mutex_lock_interruptible(&tomoyo_policy_lock))
540		goto out;
541	entry = tomoyo_find_domain(domainname);
542	if (!entry) {
543		entry = tomoyo_commit_ok(&e, sizeof(e));
544		if (entry) {
545			INIT_LIST_HEAD(&entry->acl_info_list);
546			list_add_tail_rcu(&entry->list, &tomoyo_domain_list);
547			created = true;
548		}
549	}
550	mutex_unlock(&tomoyo_policy_lock);
551out:
552	tomoyo_put_name(e.domainname);
553	if (entry && transit) {
554		if (created) {
555			struct tomoyo_request_info r;
556			tomoyo_init_request_info(&r, entry,
557						 TOMOYO_MAC_FILE_EXECUTE);
558			r.granted = false;
559			tomoyo_write_log(&r, "use_profile %u\n",
560					 entry->profile);
561			tomoyo_write_log(&r, "use_group %u\n", entry->group);
562		}
563	}
564	return entry;
565}
566
567/**
568 * tomoyo_find_next_domain - Find a domain.
569 *
570 * @bprm: Pointer to "struct linux_binprm".
571 *
572 * Returns 0 on success, negative value otherwise.
573 *
574 * Caller holds tomoyo_read_lock().
575 */
576int tomoyo_find_next_domain(struct linux_binprm *bprm)
577{
578	struct tomoyo_domain_info *old_domain = tomoyo_domain();
579	struct tomoyo_domain_info *domain = NULL;
580	const char *original_name = bprm->filename;
581	int retval = -ENOMEM;
582	bool need_kfree = false;
583	bool reject_on_transition_failure = false;
584	struct tomoyo_path_info rn = { }; /* real name */
585	struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS);
586	if (!ee)
587		return -ENOMEM;
588	ee->tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
589	if (!ee->tmp) {
590		kfree(ee);
591		return -ENOMEM;
592	}
593	/* ee->dump->data is allocated by tomoyo_dump_page(). */
594	tomoyo_init_request_info(&ee->r, NULL, TOMOYO_MAC_FILE_EXECUTE);
595	ee->r.ee = ee;
596	ee->bprm = bprm;
597	ee->r.obj = &ee->obj;
598	ee->obj.path1 = bprm->file->f_path;
599 retry:
600	if (need_kfree) {
601		kfree(rn.name);
602		need_kfree = false;
603	}
604	/* Get symlink's pathname of program. */
605	retval = -ENOENT;
606	rn.name = tomoyo_realpath_nofollow(original_name);
607	if (!rn.name)
608		goto out;
609	tomoyo_fill_path_info(&rn);
610	need_kfree = true;
611
612	/* Check 'aggregator' directive. */
613	{
614		struct tomoyo_aggregator *ptr;
615		struct list_head *list =
616			&old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR];
617		/* Check 'aggregator' directive. */
618		list_for_each_entry_rcu(ptr, list, head.list) {
619			if (ptr->head.is_deleted ||
620			    !tomoyo_path_matches_pattern(&rn,
621							 ptr->original_name))
622				continue;
623			kfree(rn.name);
624			need_kfree = false;
625			/* This is OK because it is read only. */
626			rn = *ptr->aggregated_name;
627			break;
628		}
629	}
630
631	/* Check execute permission. */
632	retval = tomoyo_path_permission(&ee->r, TOMOYO_TYPE_EXECUTE, &rn);
633	if (retval == TOMOYO_RETRY_REQUEST)
634		goto retry;
635	if (retval < 0)
636		goto out;
637	/*
638	 * To be able to specify domainnames with wildcards, use the
639	 * pathname specified in the policy (which may contain
640	 * wildcard) rather than the pathname passed to execve()
641	 * (which never contains wildcard).
642	 */
643	if (ee->r.param.path.matched_path) {
644		if (need_kfree)
645			kfree(rn.name);
646		need_kfree = false;
647		/* This is OK because it is read only. */
648		rn = *ee->r.param.path.matched_path;
649	}
650
651	/* Calculate domain to transit to. */
652	switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname,
653				       &rn)) {
654	case TOMOYO_TRANSITION_CONTROL_RESET:
655		/* Transit to the root of specified namespace. */
656		snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", rn.name);
657		/*
658		 * Make do_execve() fail if domain transition across namespaces
659		 * has failed.
660		 */
661		reject_on_transition_failure = true;
662		break;
663	case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
664		/* Transit to the child of current namespace's root. */
665		snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
666			 old_domain->ns->name, rn.name);
667		break;
668	case TOMOYO_TRANSITION_CONTROL_KEEP:
669		/* Keep current domain. */
670		domain = old_domain;
671		break;
672	default:
673		if (old_domain == &tomoyo_kernel_domain &&
674		    !tomoyo_policy_loaded) {
675			/*
676			 * Needn't to transit from kernel domain before
677			 * starting /sbin/init. But transit from kernel domain
678			 * if executing initializers because they might start
679			 * before /sbin/init.
680			 */
681			domain = old_domain;
682		} else {
683			/* Normal domain transition. */
684			snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
685				 old_domain->domainname->name, rn.name);
686		}
687		break;
688	}
689	if (!domain)
690		domain = tomoyo_assign_domain(ee->tmp, true);
691	if (domain)
692		retval = 0;
693	else if (reject_on_transition_failure) {
694		printk(KERN_WARNING "ERROR: Domain '%s' not ready.\n",
695		       ee->tmp);
696		retval = -ENOMEM;
697	} else if (ee->r.mode == TOMOYO_CONFIG_ENFORCING)
698		retval = -ENOMEM;
699	else {
700		retval = 0;
701		if (!old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED]) {
702			old_domain->flags[TOMOYO_DIF_TRANSITION_FAILED] = true;
703			ee->r.granted = false;
704			tomoyo_write_log(&ee->r, "%s", tomoyo_dif
705					 [TOMOYO_DIF_TRANSITION_FAILED]);
706			printk(KERN_WARNING
707			       "ERROR: Domain '%s' not defined.\n", ee->tmp);
708		}
709	}
710 out:
711	if (!domain)
712		domain = old_domain;
713	/* Update reference count on "struct tomoyo_domain_info". */
714	atomic_inc(&domain->users);
715	bprm->cred->security = domain;
716	if (need_kfree)
717		kfree(rn.name);
718	kfree(ee->tmp);
719	kfree(ee->dump.data);
720	kfree(ee);
721	return retval;
722}
723
724/**
725 * tomoyo_dump_page - Dump a page to buffer.
726 *
727 * @bprm: Pointer to "struct linux_binprm".
728 * @pos:  Location to dump.
729 * @dump: Poiner to "struct tomoyo_page_dump".
730 *
731 * Returns true on success, false otherwise.
732 */
733bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
734		      struct tomoyo_page_dump *dump)
735{
736	struct page *page;
737	/* dump->data is released by tomoyo_finish_execve(). */
738	if (!dump->data) {
739		dump->data = kzalloc(PAGE_SIZE, GFP_NOFS);
740		if (!dump->data)
741			return false;
742	}
743	/* Same with get_arg_page(bprm, pos, 0) in fs/exec.c */
744#ifdef CONFIG_MMU
745	if (get_user_pages(current, bprm->mm, pos, 1, 0, 1, &page, NULL) <= 0)
746		return false;
747#else
748	page = bprm->page[pos / PAGE_SIZE];
749#endif
750	if (page != dump->page) {
751		const unsigned int offset = pos % PAGE_SIZE;
752		/*
753		 * Maybe kmap()/kunmap() should be used here.
754		 * But remove_arg_zero() uses kmap_atomic()/kunmap_atomic().
755		 * So do I.
756		 */
757		char *kaddr = kmap_atomic(page, KM_USER0);
758		dump->page = page;
759		memcpy(dump->data + offset, kaddr + offset,
760		       PAGE_SIZE - offset);
761		kunmap_atomic(kaddr, KM_USER0);
762	}
763	/* Same with put_arg_page(page) in fs/exec.c */
764#ifdef CONFIG_MMU
765	put_page(page);
766#endif
767	return true;
768}
769