cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

domain.c (25962B)


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