162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * security/tomoyo/condition.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2005-2011  NTT DATA CORPORATION
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "common.h"
962306a36Sopenharmony_ci#include <linux/slab.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/* List of "struct tomoyo_condition". */
1262306a36Sopenharmony_ciLIST_HEAD(tomoyo_condition_list);
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/**
1562306a36Sopenharmony_ci * tomoyo_argv - Check argv[] in "struct linux_binbrm".
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * @index:   Index number of @arg_ptr.
1862306a36Sopenharmony_ci * @arg_ptr: Contents of argv[@index].
1962306a36Sopenharmony_ci * @argc:    Length of @argv.
2062306a36Sopenharmony_ci * @argv:    Pointer to "struct tomoyo_argv".
2162306a36Sopenharmony_ci * @checked: Set to true if @argv[@index] was found.
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * Returns true on success, false otherwise.
2462306a36Sopenharmony_ci */
2562306a36Sopenharmony_cistatic bool tomoyo_argv(const unsigned int index, const char *arg_ptr,
2662306a36Sopenharmony_ci			const int argc, const struct tomoyo_argv *argv,
2762306a36Sopenharmony_ci			u8 *checked)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	int i;
3062306a36Sopenharmony_ci	struct tomoyo_path_info arg;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	arg.name = arg_ptr;
3362306a36Sopenharmony_ci	for (i = 0; i < argc; argv++, checked++, i++) {
3462306a36Sopenharmony_ci		bool result;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci		if (index != argv->index)
3762306a36Sopenharmony_ci			continue;
3862306a36Sopenharmony_ci		*checked = 1;
3962306a36Sopenharmony_ci		tomoyo_fill_path_info(&arg);
4062306a36Sopenharmony_ci		result = tomoyo_path_matches_pattern(&arg, argv->value);
4162306a36Sopenharmony_ci		if (argv->is_not)
4262306a36Sopenharmony_ci			result = !result;
4362306a36Sopenharmony_ci		if (!result)
4462306a36Sopenharmony_ci			return false;
4562306a36Sopenharmony_ci	}
4662306a36Sopenharmony_ci	return true;
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci/**
5062306a36Sopenharmony_ci * tomoyo_envp - Check envp[] in "struct linux_binbrm".
5162306a36Sopenharmony_ci *
5262306a36Sopenharmony_ci * @env_name:  The name of environment variable.
5362306a36Sopenharmony_ci * @env_value: The value of environment variable.
5462306a36Sopenharmony_ci * @envc:      Length of @envp.
5562306a36Sopenharmony_ci * @envp:      Pointer to "struct tomoyo_envp".
5662306a36Sopenharmony_ci * @checked:   Set to true if @envp[@env_name] was found.
5762306a36Sopenharmony_ci *
5862306a36Sopenharmony_ci * Returns true on success, false otherwise.
5962306a36Sopenharmony_ci */
6062306a36Sopenharmony_cistatic bool tomoyo_envp(const char *env_name, const char *env_value,
6162306a36Sopenharmony_ci			const int envc, const struct tomoyo_envp *envp,
6262306a36Sopenharmony_ci			u8 *checked)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	int i;
6562306a36Sopenharmony_ci	struct tomoyo_path_info name;
6662306a36Sopenharmony_ci	struct tomoyo_path_info value;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	name.name = env_name;
6962306a36Sopenharmony_ci	tomoyo_fill_path_info(&name);
7062306a36Sopenharmony_ci	value.name = env_value;
7162306a36Sopenharmony_ci	tomoyo_fill_path_info(&value);
7262306a36Sopenharmony_ci	for (i = 0; i < envc; envp++, checked++, i++) {
7362306a36Sopenharmony_ci		bool result;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci		if (!tomoyo_path_matches_pattern(&name, envp->name))
7662306a36Sopenharmony_ci			continue;
7762306a36Sopenharmony_ci		*checked = 1;
7862306a36Sopenharmony_ci		if (envp->value) {
7962306a36Sopenharmony_ci			result = tomoyo_path_matches_pattern(&value,
8062306a36Sopenharmony_ci							     envp->value);
8162306a36Sopenharmony_ci			if (envp->is_not)
8262306a36Sopenharmony_ci				result = !result;
8362306a36Sopenharmony_ci		} else {
8462306a36Sopenharmony_ci			result = true;
8562306a36Sopenharmony_ci			if (!envp->is_not)
8662306a36Sopenharmony_ci				result = !result;
8762306a36Sopenharmony_ci		}
8862306a36Sopenharmony_ci		if (!result)
8962306a36Sopenharmony_ci			return false;
9062306a36Sopenharmony_ci	}
9162306a36Sopenharmony_ci	return true;
9262306a36Sopenharmony_ci}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/**
9562306a36Sopenharmony_ci * tomoyo_scan_bprm - Scan "struct linux_binprm".
9662306a36Sopenharmony_ci *
9762306a36Sopenharmony_ci * @ee:   Pointer to "struct tomoyo_execve".
9862306a36Sopenharmony_ci * @argc: Length of @argc.
9962306a36Sopenharmony_ci * @argv: Pointer to "struct tomoyo_argv".
10062306a36Sopenharmony_ci * @envc: Length of @envp.
10162306a36Sopenharmony_ci * @envp: Pointer to "struct tomoyo_envp".
10262306a36Sopenharmony_ci *
10362306a36Sopenharmony_ci * Returns true on success, false otherwise.
10462306a36Sopenharmony_ci */
10562306a36Sopenharmony_cistatic bool tomoyo_scan_bprm(struct tomoyo_execve *ee,
10662306a36Sopenharmony_ci			     const u16 argc, const struct tomoyo_argv *argv,
10762306a36Sopenharmony_ci			     const u16 envc, const struct tomoyo_envp *envp)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	struct linux_binprm *bprm = ee->bprm;
11062306a36Sopenharmony_ci	struct tomoyo_page_dump *dump = &ee->dump;
11162306a36Sopenharmony_ci	char *arg_ptr = ee->tmp;
11262306a36Sopenharmony_ci	int arg_len = 0;
11362306a36Sopenharmony_ci	unsigned long pos = bprm->p;
11462306a36Sopenharmony_ci	int offset = pos % PAGE_SIZE;
11562306a36Sopenharmony_ci	int argv_count = bprm->argc;
11662306a36Sopenharmony_ci	int envp_count = bprm->envc;
11762306a36Sopenharmony_ci	bool result = true;
11862306a36Sopenharmony_ci	u8 local_checked[32];
11962306a36Sopenharmony_ci	u8 *checked;
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if (argc + envc <= sizeof(local_checked)) {
12262306a36Sopenharmony_ci		checked = local_checked;
12362306a36Sopenharmony_ci		memset(local_checked, 0, sizeof(local_checked));
12462306a36Sopenharmony_ci	} else {
12562306a36Sopenharmony_ci		checked = kzalloc(argc + envc, GFP_NOFS);
12662306a36Sopenharmony_ci		if (!checked)
12762306a36Sopenharmony_ci			return false;
12862306a36Sopenharmony_ci	}
12962306a36Sopenharmony_ci	while (argv_count || envp_count) {
13062306a36Sopenharmony_ci		if (!tomoyo_dump_page(bprm, pos, dump)) {
13162306a36Sopenharmony_ci			result = false;
13262306a36Sopenharmony_ci			goto out;
13362306a36Sopenharmony_ci		}
13462306a36Sopenharmony_ci		pos += PAGE_SIZE - offset;
13562306a36Sopenharmony_ci		while (offset < PAGE_SIZE) {
13662306a36Sopenharmony_ci			/* Read. */
13762306a36Sopenharmony_ci			const char *kaddr = dump->data;
13862306a36Sopenharmony_ci			const unsigned char c = kaddr[offset++];
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci			if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) {
14162306a36Sopenharmony_ci				if (c == '\\') {
14262306a36Sopenharmony_ci					arg_ptr[arg_len++] = '\\';
14362306a36Sopenharmony_ci					arg_ptr[arg_len++] = '\\';
14462306a36Sopenharmony_ci				} else if (c > ' ' && c < 127) {
14562306a36Sopenharmony_ci					arg_ptr[arg_len++] = c;
14662306a36Sopenharmony_ci				} else {
14762306a36Sopenharmony_ci					arg_ptr[arg_len++] = '\\';
14862306a36Sopenharmony_ci					arg_ptr[arg_len++] = (c >> 6) + '0';
14962306a36Sopenharmony_ci					arg_ptr[arg_len++] =
15062306a36Sopenharmony_ci						((c >> 3) & 7) + '0';
15162306a36Sopenharmony_ci					arg_ptr[arg_len++] = (c & 7) + '0';
15262306a36Sopenharmony_ci				}
15362306a36Sopenharmony_ci			} else {
15462306a36Sopenharmony_ci				arg_ptr[arg_len] = '\0';
15562306a36Sopenharmony_ci			}
15662306a36Sopenharmony_ci			if (c)
15762306a36Sopenharmony_ci				continue;
15862306a36Sopenharmony_ci			/* Check. */
15962306a36Sopenharmony_ci			if (argv_count) {
16062306a36Sopenharmony_ci				if (!tomoyo_argv(bprm->argc - argv_count,
16162306a36Sopenharmony_ci						 arg_ptr, argc, argv,
16262306a36Sopenharmony_ci						 checked)) {
16362306a36Sopenharmony_ci					result = false;
16462306a36Sopenharmony_ci					break;
16562306a36Sopenharmony_ci				}
16662306a36Sopenharmony_ci				argv_count--;
16762306a36Sopenharmony_ci			} else if (envp_count) {
16862306a36Sopenharmony_ci				char *cp = strchr(arg_ptr, '=');
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci				if (cp) {
17162306a36Sopenharmony_ci					*cp = '\0';
17262306a36Sopenharmony_ci					if (!tomoyo_envp(arg_ptr, cp + 1,
17362306a36Sopenharmony_ci							 envc, envp,
17462306a36Sopenharmony_ci							 checked + argc)) {
17562306a36Sopenharmony_ci						result = false;
17662306a36Sopenharmony_ci						break;
17762306a36Sopenharmony_ci					}
17862306a36Sopenharmony_ci				}
17962306a36Sopenharmony_ci				envp_count--;
18062306a36Sopenharmony_ci			} else {
18162306a36Sopenharmony_ci				break;
18262306a36Sopenharmony_ci			}
18362306a36Sopenharmony_ci			arg_len = 0;
18462306a36Sopenharmony_ci		}
18562306a36Sopenharmony_ci		offset = 0;
18662306a36Sopenharmony_ci		if (!result)
18762306a36Sopenharmony_ci			break;
18862306a36Sopenharmony_ci	}
18962306a36Sopenharmony_ciout:
19062306a36Sopenharmony_ci	if (result) {
19162306a36Sopenharmony_ci		int i;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci		/* Check not-yet-checked entries. */
19462306a36Sopenharmony_ci		for (i = 0; i < argc; i++) {
19562306a36Sopenharmony_ci			if (checked[i])
19662306a36Sopenharmony_ci				continue;
19762306a36Sopenharmony_ci			/*
19862306a36Sopenharmony_ci			 * Return true only if all unchecked indexes in
19962306a36Sopenharmony_ci			 * bprm->argv[] are not matched.
20062306a36Sopenharmony_ci			 */
20162306a36Sopenharmony_ci			if (argv[i].is_not)
20262306a36Sopenharmony_ci				continue;
20362306a36Sopenharmony_ci			result = false;
20462306a36Sopenharmony_ci			break;
20562306a36Sopenharmony_ci		}
20662306a36Sopenharmony_ci		for (i = 0; i < envc; envp++, i++) {
20762306a36Sopenharmony_ci			if (checked[argc + i])
20862306a36Sopenharmony_ci				continue;
20962306a36Sopenharmony_ci			/*
21062306a36Sopenharmony_ci			 * Return true only if all unchecked environ variables
21162306a36Sopenharmony_ci			 * in bprm->envp[] are either undefined or not matched.
21262306a36Sopenharmony_ci			 */
21362306a36Sopenharmony_ci			if ((!envp->value && !envp->is_not) ||
21462306a36Sopenharmony_ci			    (envp->value && envp->is_not))
21562306a36Sopenharmony_ci				continue;
21662306a36Sopenharmony_ci			result = false;
21762306a36Sopenharmony_ci			break;
21862306a36Sopenharmony_ci		}
21962306a36Sopenharmony_ci	}
22062306a36Sopenharmony_ci	if (checked != local_checked)
22162306a36Sopenharmony_ci		kfree(checked);
22262306a36Sopenharmony_ci	return result;
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci/**
22662306a36Sopenharmony_ci * tomoyo_scan_exec_realpath - Check "exec.realpath" parameter of "struct tomoyo_condition".
22762306a36Sopenharmony_ci *
22862306a36Sopenharmony_ci * @file:  Pointer to "struct file".
22962306a36Sopenharmony_ci * @ptr:   Pointer to "struct tomoyo_name_union".
23062306a36Sopenharmony_ci * @match: True if "exec.realpath=", false if "exec.realpath!=".
23162306a36Sopenharmony_ci *
23262306a36Sopenharmony_ci * Returns true on success, false otherwise.
23362306a36Sopenharmony_ci */
23462306a36Sopenharmony_cistatic bool tomoyo_scan_exec_realpath(struct file *file,
23562306a36Sopenharmony_ci				      const struct tomoyo_name_union *ptr,
23662306a36Sopenharmony_ci				      const bool match)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	bool result;
23962306a36Sopenharmony_ci	struct tomoyo_path_info exe;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	if (!file)
24262306a36Sopenharmony_ci		return false;
24362306a36Sopenharmony_ci	exe.name = tomoyo_realpath_from_path(&file->f_path);
24462306a36Sopenharmony_ci	if (!exe.name)
24562306a36Sopenharmony_ci		return false;
24662306a36Sopenharmony_ci	tomoyo_fill_path_info(&exe);
24762306a36Sopenharmony_ci	result = tomoyo_compare_name_union(&exe, ptr);
24862306a36Sopenharmony_ci	kfree(exe.name);
24962306a36Sopenharmony_ci	return result == match;
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci/**
25362306a36Sopenharmony_ci * tomoyo_get_dqword - tomoyo_get_name() for a quoted string.
25462306a36Sopenharmony_ci *
25562306a36Sopenharmony_ci * @start: String to save.
25662306a36Sopenharmony_ci *
25762306a36Sopenharmony_ci * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
25862306a36Sopenharmony_ci */
25962306a36Sopenharmony_cistatic const struct tomoyo_path_info *tomoyo_get_dqword(char *start)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	char *cp = start + strlen(start) - 1;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	if (cp == start || *start++ != '"' || *cp != '"')
26462306a36Sopenharmony_ci		return NULL;
26562306a36Sopenharmony_ci	*cp = '\0';
26662306a36Sopenharmony_ci	if (*start && !tomoyo_correct_word(start))
26762306a36Sopenharmony_ci		return NULL;
26862306a36Sopenharmony_ci	return tomoyo_get_name(start);
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci/**
27262306a36Sopenharmony_ci * tomoyo_parse_name_union_quoted - Parse a quoted word.
27362306a36Sopenharmony_ci *
27462306a36Sopenharmony_ci * @param: Pointer to "struct tomoyo_acl_param".
27562306a36Sopenharmony_ci * @ptr:   Pointer to "struct tomoyo_name_union".
27662306a36Sopenharmony_ci *
27762306a36Sopenharmony_ci * Returns true on success, false otherwise.
27862306a36Sopenharmony_ci */
27962306a36Sopenharmony_cistatic bool tomoyo_parse_name_union_quoted(struct tomoyo_acl_param *param,
28062306a36Sopenharmony_ci					   struct tomoyo_name_union *ptr)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	char *filename = param->data;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	if (*filename == '@')
28562306a36Sopenharmony_ci		return tomoyo_parse_name_union(param, ptr);
28662306a36Sopenharmony_ci	ptr->filename = tomoyo_get_dqword(filename);
28762306a36Sopenharmony_ci	return ptr->filename != NULL;
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci/**
29162306a36Sopenharmony_ci * tomoyo_parse_argv - Parse an argv[] condition part.
29262306a36Sopenharmony_ci *
29362306a36Sopenharmony_ci * @left:  Lefthand value.
29462306a36Sopenharmony_ci * @right: Righthand value.
29562306a36Sopenharmony_ci * @argv:  Pointer to "struct tomoyo_argv".
29662306a36Sopenharmony_ci *
29762306a36Sopenharmony_ci * Returns true on success, false otherwise.
29862306a36Sopenharmony_ci */
29962306a36Sopenharmony_cistatic bool tomoyo_parse_argv(char *left, char *right,
30062306a36Sopenharmony_ci			      struct tomoyo_argv *argv)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	if (tomoyo_parse_ulong(&argv->index, &left) !=
30362306a36Sopenharmony_ci	    TOMOYO_VALUE_TYPE_DECIMAL || *left++ != ']' || *left)
30462306a36Sopenharmony_ci		return false;
30562306a36Sopenharmony_ci	argv->value = tomoyo_get_dqword(right);
30662306a36Sopenharmony_ci	return argv->value != NULL;
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci/**
31062306a36Sopenharmony_ci * tomoyo_parse_envp - Parse an envp[] condition part.
31162306a36Sopenharmony_ci *
31262306a36Sopenharmony_ci * @left:  Lefthand value.
31362306a36Sopenharmony_ci * @right: Righthand value.
31462306a36Sopenharmony_ci * @envp:  Pointer to "struct tomoyo_envp".
31562306a36Sopenharmony_ci *
31662306a36Sopenharmony_ci * Returns true on success, false otherwise.
31762306a36Sopenharmony_ci */
31862306a36Sopenharmony_cistatic bool tomoyo_parse_envp(char *left, char *right,
31962306a36Sopenharmony_ci			      struct tomoyo_envp *envp)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	const struct tomoyo_path_info *name;
32262306a36Sopenharmony_ci	const struct tomoyo_path_info *value;
32362306a36Sopenharmony_ci	char *cp = left + strlen(left) - 1;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	if (*cp-- != ']' || *cp != '"')
32662306a36Sopenharmony_ci		goto out;
32762306a36Sopenharmony_ci	*cp = '\0';
32862306a36Sopenharmony_ci	if (!tomoyo_correct_word(left))
32962306a36Sopenharmony_ci		goto out;
33062306a36Sopenharmony_ci	name = tomoyo_get_name(left);
33162306a36Sopenharmony_ci	if (!name)
33262306a36Sopenharmony_ci		goto out;
33362306a36Sopenharmony_ci	if (!strcmp(right, "NULL")) {
33462306a36Sopenharmony_ci		value = NULL;
33562306a36Sopenharmony_ci	} else {
33662306a36Sopenharmony_ci		value = tomoyo_get_dqword(right);
33762306a36Sopenharmony_ci		if (!value) {
33862306a36Sopenharmony_ci			tomoyo_put_name(name);
33962306a36Sopenharmony_ci			goto out;
34062306a36Sopenharmony_ci		}
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci	envp->name = name;
34362306a36Sopenharmony_ci	envp->value = value;
34462306a36Sopenharmony_ci	return true;
34562306a36Sopenharmony_ciout:
34662306a36Sopenharmony_ci	return false;
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci/**
35062306a36Sopenharmony_ci * tomoyo_same_condition - Check for duplicated "struct tomoyo_condition" entry.
35162306a36Sopenharmony_ci *
35262306a36Sopenharmony_ci * @a: Pointer to "struct tomoyo_condition".
35362306a36Sopenharmony_ci * @b: Pointer to "struct tomoyo_condition".
35462306a36Sopenharmony_ci *
35562306a36Sopenharmony_ci * Returns true if @a == @b, false otherwise.
35662306a36Sopenharmony_ci */
35762306a36Sopenharmony_cistatic inline bool tomoyo_same_condition(const struct tomoyo_condition *a,
35862306a36Sopenharmony_ci					 const struct tomoyo_condition *b)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	return a->size == b->size && a->condc == b->condc &&
36162306a36Sopenharmony_ci		a->numbers_count == b->numbers_count &&
36262306a36Sopenharmony_ci		a->names_count == b->names_count &&
36362306a36Sopenharmony_ci		a->argc == b->argc && a->envc == b->envc &&
36462306a36Sopenharmony_ci		a->grant_log == b->grant_log && a->transit == b->transit &&
36562306a36Sopenharmony_ci		!memcmp(a + 1, b + 1, a->size - sizeof(*a));
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci/**
36962306a36Sopenharmony_ci * tomoyo_condition_type - Get condition type.
37062306a36Sopenharmony_ci *
37162306a36Sopenharmony_ci * @word: Keyword string.
37262306a36Sopenharmony_ci *
37362306a36Sopenharmony_ci * Returns one of values in "enum tomoyo_conditions_index" on success,
37462306a36Sopenharmony_ci * TOMOYO_MAX_CONDITION_KEYWORD otherwise.
37562306a36Sopenharmony_ci */
37662306a36Sopenharmony_cistatic u8 tomoyo_condition_type(const char *word)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	u8 i;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	for (i = 0; i < TOMOYO_MAX_CONDITION_KEYWORD; i++) {
38162306a36Sopenharmony_ci		if (!strcmp(word, tomoyo_condition_keyword[i]))
38262306a36Sopenharmony_ci			break;
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci	return i;
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci/* Define this to enable debug mode. */
38862306a36Sopenharmony_ci/* #define DEBUG_CONDITION */
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci#ifdef DEBUG_CONDITION
39162306a36Sopenharmony_ci#define dprintk printk
39262306a36Sopenharmony_ci#else
39362306a36Sopenharmony_ci#define dprintk(...) do { } while (0)
39462306a36Sopenharmony_ci#endif
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci/**
39762306a36Sopenharmony_ci * tomoyo_commit_condition - Commit "struct tomoyo_condition".
39862306a36Sopenharmony_ci *
39962306a36Sopenharmony_ci * @entry: Pointer to "struct tomoyo_condition".
40062306a36Sopenharmony_ci *
40162306a36Sopenharmony_ci * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
40262306a36Sopenharmony_ci *
40362306a36Sopenharmony_ci * This function merges duplicated entries. This function returns NULL if
40462306a36Sopenharmony_ci * @entry is not duplicated but memory quota for policy has exceeded.
40562306a36Sopenharmony_ci */
40662306a36Sopenharmony_cistatic struct tomoyo_condition *tomoyo_commit_condition
40762306a36Sopenharmony_ci(struct tomoyo_condition *entry)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	struct tomoyo_condition *ptr;
41062306a36Sopenharmony_ci	bool found = false;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	if (mutex_lock_interruptible(&tomoyo_policy_lock)) {
41362306a36Sopenharmony_ci		dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
41462306a36Sopenharmony_ci		ptr = NULL;
41562306a36Sopenharmony_ci		found = true;
41662306a36Sopenharmony_ci		goto out;
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci	list_for_each_entry(ptr, &tomoyo_condition_list, head.list) {
41962306a36Sopenharmony_ci		if (!tomoyo_same_condition(ptr, entry) ||
42062306a36Sopenharmony_ci		    atomic_read(&ptr->head.users) == TOMOYO_GC_IN_PROGRESS)
42162306a36Sopenharmony_ci			continue;
42262306a36Sopenharmony_ci		/* Same entry found. Share this entry. */
42362306a36Sopenharmony_ci		atomic_inc(&ptr->head.users);
42462306a36Sopenharmony_ci		found = true;
42562306a36Sopenharmony_ci		break;
42662306a36Sopenharmony_ci	}
42762306a36Sopenharmony_ci	if (!found) {
42862306a36Sopenharmony_ci		if (tomoyo_memory_ok(entry)) {
42962306a36Sopenharmony_ci			atomic_set(&entry->head.users, 1);
43062306a36Sopenharmony_ci			list_add(&entry->head.list, &tomoyo_condition_list);
43162306a36Sopenharmony_ci		} else {
43262306a36Sopenharmony_ci			found = true;
43362306a36Sopenharmony_ci			ptr = NULL;
43462306a36Sopenharmony_ci		}
43562306a36Sopenharmony_ci	}
43662306a36Sopenharmony_ci	mutex_unlock(&tomoyo_policy_lock);
43762306a36Sopenharmony_ciout:
43862306a36Sopenharmony_ci	if (found) {
43962306a36Sopenharmony_ci		tomoyo_del_condition(&entry->head.list);
44062306a36Sopenharmony_ci		kfree(entry);
44162306a36Sopenharmony_ci		entry = ptr;
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci	return entry;
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci/**
44762306a36Sopenharmony_ci * tomoyo_get_transit_preference - Parse domain transition preference for execve().
44862306a36Sopenharmony_ci *
44962306a36Sopenharmony_ci * @param: Pointer to "struct tomoyo_acl_param".
45062306a36Sopenharmony_ci * @e:     Pointer to "struct tomoyo_condition".
45162306a36Sopenharmony_ci *
45262306a36Sopenharmony_ci * Returns the condition string part.
45362306a36Sopenharmony_ci */
45462306a36Sopenharmony_cistatic char *tomoyo_get_transit_preference(struct tomoyo_acl_param *param,
45562306a36Sopenharmony_ci					   struct tomoyo_condition *e)
45662306a36Sopenharmony_ci{
45762306a36Sopenharmony_ci	char * const pos = param->data;
45862306a36Sopenharmony_ci	bool flag;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	if (*pos == '<') {
46162306a36Sopenharmony_ci		e->transit = tomoyo_get_domainname(param);
46262306a36Sopenharmony_ci		goto done;
46362306a36Sopenharmony_ci	}
46462306a36Sopenharmony_ci	{
46562306a36Sopenharmony_ci		char *cp = strchr(pos, ' ');
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci		if (cp)
46862306a36Sopenharmony_ci			*cp = '\0';
46962306a36Sopenharmony_ci		flag = tomoyo_correct_path(pos) || !strcmp(pos, "keep") ||
47062306a36Sopenharmony_ci			!strcmp(pos, "initialize") || !strcmp(pos, "reset") ||
47162306a36Sopenharmony_ci			!strcmp(pos, "child") || !strcmp(pos, "parent");
47262306a36Sopenharmony_ci		if (cp)
47362306a36Sopenharmony_ci			*cp = ' ';
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci	if (!flag)
47662306a36Sopenharmony_ci		return pos;
47762306a36Sopenharmony_ci	e->transit = tomoyo_get_name(tomoyo_read_token(param));
47862306a36Sopenharmony_cidone:
47962306a36Sopenharmony_ci	if (e->transit)
48062306a36Sopenharmony_ci		return param->data;
48162306a36Sopenharmony_ci	/*
48262306a36Sopenharmony_ci	 * Return a bad read-only condition string that will let
48362306a36Sopenharmony_ci	 * tomoyo_get_condition() return NULL.
48462306a36Sopenharmony_ci	 */
48562306a36Sopenharmony_ci	return "/";
48662306a36Sopenharmony_ci}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci/**
48962306a36Sopenharmony_ci * tomoyo_get_condition - Parse condition part.
49062306a36Sopenharmony_ci *
49162306a36Sopenharmony_ci * @param: Pointer to "struct tomoyo_acl_param".
49262306a36Sopenharmony_ci *
49362306a36Sopenharmony_ci * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
49462306a36Sopenharmony_ci */
49562306a36Sopenharmony_cistruct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param)
49662306a36Sopenharmony_ci{
49762306a36Sopenharmony_ci	struct tomoyo_condition *entry = NULL;
49862306a36Sopenharmony_ci	struct tomoyo_condition_element *condp = NULL;
49962306a36Sopenharmony_ci	struct tomoyo_number_union *numbers_p = NULL;
50062306a36Sopenharmony_ci	struct tomoyo_name_union *names_p = NULL;
50162306a36Sopenharmony_ci	struct tomoyo_argv *argv = NULL;
50262306a36Sopenharmony_ci	struct tomoyo_envp *envp = NULL;
50362306a36Sopenharmony_ci	struct tomoyo_condition e = { };
50462306a36Sopenharmony_ci	char * const start_of_string =
50562306a36Sopenharmony_ci		tomoyo_get_transit_preference(param, &e);
50662306a36Sopenharmony_ci	char * const end_of_string = start_of_string + strlen(start_of_string);
50762306a36Sopenharmony_ci	char *pos;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_cirerun:
51062306a36Sopenharmony_ci	pos = start_of_string;
51162306a36Sopenharmony_ci	while (1) {
51262306a36Sopenharmony_ci		u8 left = -1;
51362306a36Sopenharmony_ci		u8 right = -1;
51462306a36Sopenharmony_ci		char *left_word = pos;
51562306a36Sopenharmony_ci		char *cp;
51662306a36Sopenharmony_ci		char *right_word;
51762306a36Sopenharmony_ci		bool is_not;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci		if (!*left_word)
52062306a36Sopenharmony_ci			break;
52162306a36Sopenharmony_ci		/*
52262306a36Sopenharmony_ci		 * Since left-hand condition does not allow use of "path_group"
52362306a36Sopenharmony_ci		 * or "number_group" and environment variable's names do not
52462306a36Sopenharmony_ci		 * accept '=', it is guaranteed that the original line consists
52562306a36Sopenharmony_ci		 * of one or more repetition of $left$operator$right blocks
52662306a36Sopenharmony_ci		 * where "$left is free from '=' and ' '" and "$operator is
52762306a36Sopenharmony_ci		 * either '=' or '!='" and "$right is free from ' '".
52862306a36Sopenharmony_ci		 * Therefore, we can reconstruct the original line at the end
52962306a36Sopenharmony_ci		 * of dry run even if we overwrite $operator with '\0'.
53062306a36Sopenharmony_ci		 */
53162306a36Sopenharmony_ci		cp = strchr(pos, ' ');
53262306a36Sopenharmony_ci		if (cp) {
53362306a36Sopenharmony_ci			*cp = '\0'; /* Will restore later. */
53462306a36Sopenharmony_ci			pos = cp + 1;
53562306a36Sopenharmony_ci		} else {
53662306a36Sopenharmony_ci			pos = "";
53762306a36Sopenharmony_ci		}
53862306a36Sopenharmony_ci		right_word = strchr(left_word, '=');
53962306a36Sopenharmony_ci		if (!right_word || right_word == left_word)
54062306a36Sopenharmony_ci			goto out;
54162306a36Sopenharmony_ci		is_not = *(right_word - 1) == '!';
54262306a36Sopenharmony_ci		if (is_not)
54362306a36Sopenharmony_ci			*(right_word++ - 1) = '\0'; /* Will restore later. */
54462306a36Sopenharmony_ci		else if (*(right_word + 1) != '=')
54562306a36Sopenharmony_ci			*right_word++ = '\0'; /* Will restore later. */
54662306a36Sopenharmony_ci		else
54762306a36Sopenharmony_ci			goto out;
54862306a36Sopenharmony_ci		dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word,
54962306a36Sopenharmony_ci			is_not ? "!" : "", right_word);
55062306a36Sopenharmony_ci		if (!strcmp(left_word, "grant_log")) {
55162306a36Sopenharmony_ci			if (entry) {
55262306a36Sopenharmony_ci				if (is_not ||
55362306a36Sopenharmony_ci				    entry->grant_log != TOMOYO_GRANTLOG_AUTO)
55462306a36Sopenharmony_ci					goto out;
55562306a36Sopenharmony_ci				else if (!strcmp(right_word, "yes"))
55662306a36Sopenharmony_ci					entry->grant_log = TOMOYO_GRANTLOG_YES;
55762306a36Sopenharmony_ci				else if (!strcmp(right_word, "no"))
55862306a36Sopenharmony_ci					entry->grant_log = TOMOYO_GRANTLOG_NO;
55962306a36Sopenharmony_ci				else
56062306a36Sopenharmony_ci					goto out;
56162306a36Sopenharmony_ci			}
56262306a36Sopenharmony_ci			continue;
56362306a36Sopenharmony_ci		}
56462306a36Sopenharmony_ci		if (!strncmp(left_word, "exec.argv[", 10)) {
56562306a36Sopenharmony_ci			if (!argv) {
56662306a36Sopenharmony_ci				e.argc++;
56762306a36Sopenharmony_ci				e.condc++;
56862306a36Sopenharmony_ci			} else {
56962306a36Sopenharmony_ci				e.argc--;
57062306a36Sopenharmony_ci				e.condc--;
57162306a36Sopenharmony_ci				left = TOMOYO_ARGV_ENTRY;
57262306a36Sopenharmony_ci				argv->is_not = is_not;
57362306a36Sopenharmony_ci				if (!tomoyo_parse_argv(left_word + 10,
57462306a36Sopenharmony_ci						       right_word, argv++))
57562306a36Sopenharmony_ci					goto out;
57662306a36Sopenharmony_ci			}
57762306a36Sopenharmony_ci			goto store_value;
57862306a36Sopenharmony_ci		}
57962306a36Sopenharmony_ci		if (!strncmp(left_word, "exec.envp[\"", 11)) {
58062306a36Sopenharmony_ci			if (!envp) {
58162306a36Sopenharmony_ci				e.envc++;
58262306a36Sopenharmony_ci				e.condc++;
58362306a36Sopenharmony_ci			} else {
58462306a36Sopenharmony_ci				e.envc--;
58562306a36Sopenharmony_ci				e.condc--;
58662306a36Sopenharmony_ci				left = TOMOYO_ENVP_ENTRY;
58762306a36Sopenharmony_ci				envp->is_not = is_not;
58862306a36Sopenharmony_ci				if (!tomoyo_parse_envp(left_word + 11,
58962306a36Sopenharmony_ci						       right_word, envp++))
59062306a36Sopenharmony_ci					goto out;
59162306a36Sopenharmony_ci			}
59262306a36Sopenharmony_ci			goto store_value;
59362306a36Sopenharmony_ci		}
59462306a36Sopenharmony_ci		left = tomoyo_condition_type(left_word);
59562306a36Sopenharmony_ci		dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, left_word,
59662306a36Sopenharmony_ci			left);
59762306a36Sopenharmony_ci		if (left == TOMOYO_MAX_CONDITION_KEYWORD) {
59862306a36Sopenharmony_ci			if (!numbers_p) {
59962306a36Sopenharmony_ci				e.numbers_count++;
60062306a36Sopenharmony_ci			} else {
60162306a36Sopenharmony_ci				e.numbers_count--;
60262306a36Sopenharmony_ci				left = TOMOYO_NUMBER_UNION;
60362306a36Sopenharmony_ci				param->data = left_word;
60462306a36Sopenharmony_ci				if (*left_word == '@' ||
60562306a36Sopenharmony_ci				    !tomoyo_parse_number_union(param,
60662306a36Sopenharmony_ci							       numbers_p++))
60762306a36Sopenharmony_ci					goto out;
60862306a36Sopenharmony_ci			}
60962306a36Sopenharmony_ci		}
61062306a36Sopenharmony_ci		if (!condp)
61162306a36Sopenharmony_ci			e.condc++;
61262306a36Sopenharmony_ci		else
61362306a36Sopenharmony_ci			e.condc--;
61462306a36Sopenharmony_ci		if (left == TOMOYO_EXEC_REALPATH ||
61562306a36Sopenharmony_ci		    left == TOMOYO_SYMLINK_TARGET) {
61662306a36Sopenharmony_ci			if (!names_p) {
61762306a36Sopenharmony_ci				e.names_count++;
61862306a36Sopenharmony_ci			} else {
61962306a36Sopenharmony_ci				e.names_count--;
62062306a36Sopenharmony_ci				right = TOMOYO_NAME_UNION;
62162306a36Sopenharmony_ci				param->data = right_word;
62262306a36Sopenharmony_ci				if (!tomoyo_parse_name_union_quoted(param,
62362306a36Sopenharmony_ci								    names_p++))
62462306a36Sopenharmony_ci					goto out;
62562306a36Sopenharmony_ci			}
62662306a36Sopenharmony_ci			goto store_value;
62762306a36Sopenharmony_ci		}
62862306a36Sopenharmony_ci		right = tomoyo_condition_type(right_word);
62962306a36Sopenharmony_ci		if (right == TOMOYO_MAX_CONDITION_KEYWORD) {
63062306a36Sopenharmony_ci			if (!numbers_p) {
63162306a36Sopenharmony_ci				e.numbers_count++;
63262306a36Sopenharmony_ci			} else {
63362306a36Sopenharmony_ci				e.numbers_count--;
63462306a36Sopenharmony_ci				right = TOMOYO_NUMBER_UNION;
63562306a36Sopenharmony_ci				param->data = right_word;
63662306a36Sopenharmony_ci				if (!tomoyo_parse_number_union(param,
63762306a36Sopenharmony_ci							       numbers_p++))
63862306a36Sopenharmony_ci					goto out;
63962306a36Sopenharmony_ci			}
64062306a36Sopenharmony_ci		}
64162306a36Sopenharmony_cistore_value:
64262306a36Sopenharmony_ci		if (!condp) {
64362306a36Sopenharmony_ci			dprintk(KERN_WARNING "%u: dry_run left=%u right=%u match=%u\n",
64462306a36Sopenharmony_ci				__LINE__, left, right, !is_not);
64562306a36Sopenharmony_ci			continue;
64662306a36Sopenharmony_ci		}
64762306a36Sopenharmony_ci		condp->left = left;
64862306a36Sopenharmony_ci		condp->right = right;
64962306a36Sopenharmony_ci		condp->equals = !is_not;
65062306a36Sopenharmony_ci		dprintk(KERN_WARNING "%u: left=%u right=%u match=%u\n",
65162306a36Sopenharmony_ci			__LINE__, condp->left, condp->right,
65262306a36Sopenharmony_ci			condp->equals);
65362306a36Sopenharmony_ci		condp++;
65462306a36Sopenharmony_ci	}
65562306a36Sopenharmony_ci	dprintk(KERN_INFO "%u: cond=%u numbers=%u names=%u ac=%u ec=%u\n",
65662306a36Sopenharmony_ci		__LINE__, e.condc, e.numbers_count, e.names_count, e.argc,
65762306a36Sopenharmony_ci		e.envc);
65862306a36Sopenharmony_ci	if (entry) {
65962306a36Sopenharmony_ci		BUG_ON(e.names_count | e.numbers_count | e.argc | e.envc |
66062306a36Sopenharmony_ci		       e.condc);
66162306a36Sopenharmony_ci		return tomoyo_commit_condition(entry);
66262306a36Sopenharmony_ci	}
66362306a36Sopenharmony_ci	e.size = sizeof(*entry)
66462306a36Sopenharmony_ci		+ e.condc * sizeof(struct tomoyo_condition_element)
66562306a36Sopenharmony_ci		+ e.numbers_count * sizeof(struct tomoyo_number_union)
66662306a36Sopenharmony_ci		+ e.names_count * sizeof(struct tomoyo_name_union)
66762306a36Sopenharmony_ci		+ e.argc * sizeof(struct tomoyo_argv)
66862306a36Sopenharmony_ci		+ e.envc * sizeof(struct tomoyo_envp);
66962306a36Sopenharmony_ci	entry = kzalloc(e.size, GFP_NOFS);
67062306a36Sopenharmony_ci	if (!entry)
67162306a36Sopenharmony_ci		goto out2;
67262306a36Sopenharmony_ci	*entry = e;
67362306a36Sopenharmony_ci	e.transit = NULL;
67462306a36Sopenharmony_ci	condp = (struct tomoyo_condition_element *) (entry + 1);
67562306a36Sopenharmony_ci	numbers_p = (struct tomoyo_number_union *) (condp + e.condc);
67662306a36Sopenharmony_ci	names_p = (struct tomoyo_name_union *) (numbers_p + e.numbers_count);
67762306a36Sopenharmony_ci	argv = (struct tomoyo_argv *) (names_p + e.names_count);
67862306a36Sopenharmony_ci	envp = (struct tomoyo_envp *) (argv + e.argc);
67962306a36Sopenharmony_ci	{
68062306a36Sopenharmony_ci		bool flag = false;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci		for (pos = start_of_string; pos < end_of_string; pos++) {
68362306a36Sopenharmony_ci			if (*pos)
68462306a36Sopenharmony_ci				continue;
68562306a36Sopenharmony_ci			if (flag) /* Restore " ". */
68662306a36Sopenharmony_ci				*pos = ' ';
68762306a36Sopenharmony_ci			else if (*(pos + 1) == '=') /* Restore "!=". */
68862306a36Sopenharmony_ci				*pos = '!';
68962306a36Sopenharmony_ci			else /* Restore "=". */
69062306a36Sopenharmony_ci				*pos = '=';
69162306a36Sopenharmony_ci			flag = !flag;
69262306a36Sopenharmony_ci		}
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci	goto rerun;
69562306a36Sopenharmony_ciout:
69662306a36Sopenharmony_ci	dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
69762306a36Sopenharmony_ci	if (entry) {
69862306a36Sopenharmony_ci		tomoyo_del_condition(&entry->head.list);
69962306a36Sopenharmony_ci		kfree(entry);
70062306a36Sopenharmony_ci	}
70162306a36Sopenharmony_ciout2:
70262306a36Sopenharmony_ci	tomoyo_put_name(e.transit);
70362306a36Sopenharmony_ci	return NULL;
70462306a36Sopenharmony_ci}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci/**
70762306a36Sopenharmony_ci * tomoyo_get_attributes - Revalidate "struct inode".
70862306a36Sopenharmony_ci *
70962306a36Sopenharmony_ci * @obj: Pointer to "struct tomoyo_obj_info".
71062306a36Sopenharmony_ci *
71162306a36Sopenharmony_ci * Returns nothing.
71262306a36Sopenharmony_ci */
71362306a36Sopenharmony_civoid tomoyo_get_attributes(struct tomoyo_obj_info *obj)
71462306a36Sopenharmony_ci{
71562306a36Sopenharmony_ci	u8 i;
71662306a36Sopenharmony_ci	struct dentry *dentry = NULL;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) {
71962306a36Sopenharmony_ci		struct inode *inode;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci		switch (i) {
72262306a36Sopenharmony_ci		case TOMOYO_PATH1:
72362306a36Sopenharmony_ci			dentry = obj->path1.dentry;
72462306a36Sopenharmony_ci			if (!dentry)
72562306a36Sopenharmony_ci				continue;
72662306a36Sopenharmony_ci			break;
72762306a36Sopenharmony_ci		case TOMOYO_PATH2:
72862306a36Sopenharmony_ci			dentry = obj->path2.dentry;
72962306a36Sopenharmony_ci			if (!dentry)
73062306a36Sopenharmony_ci				continue;
73162306a36Sopenharmony_ci			break;
73262306a36Sopenharmony_ci		default:
73362306a36Sopenharmony_ci			if (!dentry)
73462306a36Sopenharmony_ci				continue;
73562306a36Sopenharmony_ci			dentry = dget_parent(dentry);
73662306a36Sopenharmony_ci			break;
73762306a36Sopenharmony_ci		}
73862306a36Sopenharmony_ci		inode = d_backing_inode(dentry);
73962306a36Sopenharmony_ci		if (inode) {
74062306a36Sopenharmony_ci			struct tomoyo_mini_stat *stat = &obj->stat[i];
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci			stat->uid  = inode->i_uid;
74362306a36Sopenharmony_ci			stat->gid  = inode->i_gid;
74462306a36Sopenharmony_ci			stat->ino  = inode->i_ino;
74562306a36Sopenharmony_ci			stat->mode = inode->i_mode;
74662306a36Sopenharmony_ci			stat->dev  = inode->i_sb->s_dev;
74762306a36Sopenharmony_ci			stat->rdev = inode->i_rdev;
74862306a36Sopenharmony_ci			obj->stat_valid[i] = true;
74962306a36Sopenharmony_ci		}
75062306a36Sopenharmony_ci		if (i & 1) /* TOMOYO_PATH1_PARENT or TOMOYO_PATH2_PARENT */
75162306a36Sopenharmony_ci			dput(dentry);
75262306a36Sopenharmony_ci	}
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci/**
75662306a36Sopenharmony_ci * tomoyo_condition - Check condition part.
75762306a36Sopenharmony_ci *
75862306a36Sopenharmony_ci * @r:    Pointer to "struct tomoyo_request_info".
75962306a36Sopenharmony_ci * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
76062306a36Sopenharmony_ci *
76162306a36Sopenharmony_ci * Returns true on success, false otherwise.
76262306a36Sopenharmony_ci *
76362306a36Sopenharmony_ci * Caller holds tomoyo_read_lock().
76462306a36Sopenharmony_ci */
76562306a36Sopenharmony_cibool tomoyo_condition(struct tomoyo_request_info *r,
76662306a36Sopenharmony_ci		      const struct tomoyo_condition *cond)
76762306a36Sopenharmony_ci{
76862306a36Sopenharmony_ci	u32 i;
76962306a36Sopenharmony_ci	unsigned long min_v[2] = { 0, 0 };
77062306a36Sopenharmony_ci	unsigned long max_v[2] = { 0, 0 };
77162306a36Sopenharmony_ci	const struct tomoyo_condition_element *condp;
77262306a36Sopenharmony_ci	const struct tomoyo_number_union *numbers_p;
77362306a36Sopenharmony_ci	const struct tomoyo_name_union *names_p;
77462306a36Sopenharmony_ci	const struct tomoyo_argv *argv;
77562306a36Sopenharmony_ci	const struct tomoyo_envp *envp;
77662306a36Sopenharmony_ci	struct tomoyo_obj_info *obj;
77762306a36Sopenharmony_ci	u16 condc;
77862306a36Sopenharmony_ci	u16 argc;
77962306a36Sopenharmony_ci	u16 envc;
78062306a36Sopenharmony_ci	struct linux_binprm *bprm = NULL;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	if (!cond)
78362306a36Sopenharmony_ci		return true;
78462306a36Sopenharmony_ci	condc = cond->condc;
78562306a36Sopenharmony_ci	argc = cond->argc;
78662306a36Sopenharmony_ci	envc = cond->envc;
78762306a36Sopenharmony_ci	obj = r->obj;
78862306a36Sopenharmony_ci	if (r->ee)
78962306a36Sopenharmony_ci		bprm = r->ee->bprm;
79062306a36Sopenharmony_ci	if (!bprm && (argc || envc))
79162306a36Sopenharmony_ci		return false;
79262306a36Sopenharmony_ci	condp = (struct tomoyo_condition_element *) (cond + 1);
79362306a36Sopenharmony_ci	numbers_p = (const struct tomoyo_number_union *) (condp + condc);
79462306a36Sopenharmony_ci	names_p = (const struct tomoyo_name_union *)
79562306a36Sopenharmony_ci		(numbers_p + cond->numbers_count);
79662306a36Sopenharmony_ci	argv = (const struct tomoyo_argv *) (names_p + cond->names_count);
79762306a36Sopenharmony_ci	envp = (const struct tomoyo_envp *) (argv + argc);
79862306a36Sopenharmony_ci	for (i = 0; i < condc; i++) {
79962306a36Sopenharmony_ci		const bool match = condp->equals;
80062306a36Sopenharmony_ci		const u8 left = condp->left;
80162306a36Sopenharmony_ci		const u8 right = condp->right;
80262306a36Sopenharmony_ci		bool is_bitop[2] = { false, false };
80362306a36Sopenharmony_ci		u8 j;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci		condp++;
80662306a36Sopenharmony_ci		/* Check argv[] and envp[] later. */
80762306a36Sopenharmony_ci		if (left == TOMOYO_ARGV_ENTRY || left == TOMOYO_ENVP_ENTRY)
80862306a36Sopenharmony_ci			continue;
80962306a36Sopenharmony_ci		/* Check string expressions. */
81062306a36Sopenharmony_ci		if (right == TOMOYO_NAME_UNION) {
81162306a36Sopenharmony_ci			const struct tomoyo_name_union *ptr = names_p++;
81262306a36Sopenharmony_ci			struct tomoyo_path_info *symlink;
81362306a36Sopenharmony_ci			struct tomoyo_execve *ee;
81462306a36Sopenharmony_ci			struct file *file;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci			switch (left) {
81762306a36Sopenharmony_ci			case TOMOYO_SYMLINK_TARGET:
81862306a36Sopenharmony_ci				symlink = obj ? obj->symlink_target : NULL;
81962306a36Sopenharmony_ci				if (!symlink ||
82062306a36Sopenharmony_ci				    !tomoyo_compare_name_union(symlink, ptr)
82162306a36Sopenharmony_ci				    == match)
82262306a36Sopenharmony_ci					goto out;
82362306a36Sopenharmony_ci				break;
82462306a36Sopenharmony_ci			case TOMOYO_EXEC_REALPATH:
82562306a36Sopenharmony_ci				ee = r->ee;
82662306a36Sopenharmony_ci				file = ee ? ee->bprm->file : NULL;
82762306a36Sopenharmony_ci				if (!tomoyo_scan_exec_realpath(file, ptr,
82862306a36Sopenharmony_ci							       match))
82962306a36Sopenharmony_ci					goto out;
83062306a36Sopenharmony_ci				break;
83162306a36Sopenharmony_ci			}
83262306a36Sopenharmony_ci			continue;
83362306a36Sopenharmony_ci		}
83462306a36Sopenharmony_ci		/* Check numeric or bit-op expressions. */
83562306a36Sopenharmony_ci		for (j = 0; j < 2; j++) {
83662306a36Sopenharmony_ci			const u8 index = j ? right : left;
83762306a36Sopenharmony_ci			unsigned long value = 0;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci			switch (index) {
84062306a36Sopenharmony_ci			case TOMOYO_TASK_UID:
84162306a36Sopenharmony_ci				value = from_kuid(&init_user_ns, current_uid());
84262306a36Sopenharmony_ci				break;
84362306a36Sopenharmony_ci			case TOMOYO_TASK_EUID:
84462306a36Sopenharmony_ci				value = from_kuid(&init_user_ns, current_euid());
84562306a36Sopenharmony_ci				break;
84662306a36Sopenharmony_ci			case TOMOYO_TASK_SUID:
84762306a36Sopenharmony_ci				value = from_kuid(&init_user_ns, current_suid());
84862306a36Sopenharmony_ci				break;
84962306a36Sopenharmony_ci			case TOMOYO_TASK_FSUID:
85062306a36Sopenharmony_ci				value = from_kuid(&init_user_ns, current_fsuid());
85162306a36Sopenharmony_ci				break;
85262306a36Sopenharmony_ci			case TOMOYO_TASK_GID:
85362306a36Sopenharmony_ci				value = from_kgid(&init_user_ns, current_gid());
85462306a36Sopenharmony_ci				break;
85562306a36Sopenharmony_ci			case TOMOYO_TASK_EGID:
85662306a36Sopenharmony_ci				value = from_kgid(&init_user_ns, current_egid());
85762306a36Sopenharmony_ci				break;
85862306a36Sopenharmony_ci			case TOMOYO_TASK_SGID:
85962306a36Sopenharmony_ci				value = from_kgid(&init_user_ns, current_sgid());
86062306a36Sopenharmony_ci				break;
86162306a36Sopenharmony_ci			case TOMOYO_TASK_FSGID:
86262306a36Sopenharmony_ci				value = from_kgid(&init_user_ns, current_fsgid());
86362306a36Sopenharmony_ci				break;
86462306a36Sopenharmony_ci			case TOMOYO_TASK_PID:
86562306a36Sopenharmony_ci				value = tomoyo_sys_getpid();
86662306a36Sopenharmony_ci				break;
86762306a36Sopenharmony_ci			case TOMOYO_TASK_PPID:
86862306a36Sopenharmony_ci				value = tomoyo_sys_getppid();
86962306a36Sopenharmony_ci				break;
87062306a36Sopenharmony_ci			case TOMOYO_TYPE_IS_SOCKET:
87162306a36Sopenharmony_ci				value = S_IFSOCK;
87262306a36Sopenharmony_ci				break;
87362306a36Sopenharmony_ci			case TOMOYO_TYPE_IS_SYMLINK:
87462306a36Sopenharmony_ci				value = S_IFLNK;
87562306a36Sopenharmony_ci				break;
87662306a36Sopenharmony_ci			case TOMOYO_TYPE_IS_FILE:
87762306a36Sopenharmony_ci				value = S_IFREG;
87862306a36Sopenharmony_ci				break;
87962306a36Sopenharmony_ci			case TOMOYO_TYPE_IS_BLOCK_DEV:
88062306a36Sopenharmony_ci				value = S_IFBLK;
88162306a36Sopenharmony_ci				break;
88262306a36Sopenharmony_ci			case TOMOYO_TYPE_IS_DIRECTORY:
88362306a36Sopenharmony_ci				value = S_IFDIR;
88462306a36Sopenharmony_ci				break;
88562306a36Sopenharmony_ci			case TOMOYO_TYPE_IS_CHAR_DEV:
88662306a36Sopenharmony_ci				value = S_IFCHR;
88762306a36Sopenharmony_ci				break;
88862306a36Sopenharmony_ci			case TOMOYO_TYPE_IS_FIFO:
88962306a36Sopenharmony_ci				value = S_IFIFO;
89062306a36Sopenharmony_ci				break;
89162306a36Sopenharmony_ci			case TOMOYO_MODE_SETUID:
89262306a36Sopenharmony_ci				value = S_ISUID;
89362306a36Sopenharmony_ci				break;
89462306a36Sopenharmony_ci			case TOMOYO_MODE_SETGID:
89562306a36Sopenharmony_ci				value = S_ISGID;
89662306a36Sopenharmony_ci				break;
89762306a36Sopenharmony_ci			case TOMOYO_MODE_STICKY:
89862306a36Sopenharmony_ci				value = S_ISVTX;
89962306a36Sopenharmony_ci				break;
90062306a36Sopenharmony_ci			case TOMOYO_MODE_OWNER_READ:
90162306a36Sopenharmony_ci				value = 0400;
90262306a36Sopenharmony_ci				break;
90362306a36Sopenharmony_ci			case TOMOYO_MODE_OWNER_WRITE:
90462306a36Sopenharmony_ci				value = 0200;
90562306a36Sopenharmony_ci				break;
90662306a36Sopenharmony_ci			case TOMOYO_MODE_OWNER_EXECUTE:
90762306a36Sopenharmony_ci				value = 0100;
90862306a36Sopenharmony_ci				break;
90962306a36Sopenharmony_ci			case TOMOYO_MODE_GROUP_READ:
91062306a36Sopenharmony_ci				value = 0040;
91162306a36Sopenharmony_ci				break;
91262306a36Sopenharmony_ci			case TOMOYO_MODE_GROUP_WRITE:
91362306a36Sopenharmony_ci				value = 0020;
91462306a36Sopenharmony_ci				break;
91562306a36Sopenharmony_ci			case TOMOYO_MODE_GROUP_EXECUTE:
91662306a36Sopenharmony_ci				value = 0010;
91762306a36Sopenharmony_ci				break;
91862306a36Sopenharmony_ci			case TOMOYO_MODE_OTHERS_READ:
91962306a36Sopenharmony_ci				value = 0004;
92062306a36Sopenharmony_ci				break;
92162306a36Sopenharmony_ci			case TOMOYO_MODE_OTHERS_WRITE:
92262306a36Sopenharmony_ci				value = 0002;
92362306a36Sopenharmony_ci				break;
92462306a36Sopenharmony_ci			case TOMOYO_MODE_OTHERS_EXECUTE:
92562306a36Sopenharmony_ci				value = 0001;
92662306a36Sopenharmony_ci				break;
92762306a36Sopenharmony_ci			case TOMOYO_EXEC_ARGC:
92862306a36Sopenharmony_ci				if (!bprm)
92962306a36Sopenharmony_ci					goto out;
93062306a36Sopenharmony_ci				value = bprm->argc;
93162306a36Sopenharmony_ci				break;
93262306a36Sopenharmony_ci			case TOMOYO_EXEC_ENVC:
93362306a36Sopenharmony_ci				if (!bprm)
93462306a36Sopenharmony_ci					goto out;
93562306a36Sopenharmony_ci				value = bprm->envc;
93662306a36Sopenharmony_ci				break;
93762306a36Sopenharmony_ci			case TOMOYO_NUMBER_UNION:
93862306a36Sopenharmony_ci				/* Fetch values later. */
93962306a36Sopenharmony_ci				break;
94062306a36Sopenharmony_ci			default:
94162306a36Sopenharmony_ci				if (!obj)
94262306a36Sopenharmony_ci					goto out;
94362306a36Sopenharmony_ci				if (!obj->validate_done) {
94462306a36Sopenharmony_ci					tomoyo_get_attributes(obj);
94562306a36Sopenharmony_ci					obj->validate_done = true;
94662306a36Sopenharmony_ci				}
94762306a36Sopenharmony_ci				{
94862306a36Sopenharmony_ci					u8 stat_index;
94962306a36Sopenharmony_ci					struct tomoyo_mini_stat *stat;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci					switch (index) {
95262306a36Sopenharmony_ci					case TOMOYO_PATH1_UID:
95362306a36Sopenharmony_ci					case TOMOYO_PATH1_GID:
95462306a36Sopenharmony_ci					case TOMOYO_PATH1_INO:
95562306a36Sopenharmony_ci					case TOMOYO_PATH1_MAJOR:
95662306a36Sopenharmony_ci					case TOMOYO_PATH1_MINOR:
95762306a36Sopenharmony_ci					case TOMOYO_PATH1_TYPE:
95862306a36Sopenharmony_ci					case TOMOYO_PATH1_DEV_MAJOR:
95962306a36Sopenharmony_ci					case TOMOYO_PATH1_DEV_MINOR:
96062306a36Sopenharmony_ci					case TOMOYO_PATH1_PERM:
96162306a36Sopenharmony_ci						stat_index = TOMOYO_PATH1;
96262306a36Sopenharmony_ci						break;
96362306a36Sopenharmony_ci					case TOMOYO_PATH2_UID:
96462306a36Sopenharmony_ci					case TOMOYO_PATH2_GID:
96562306a36Sopenharmony_ci					case TOMOYO_PATH2_INO:
96662306a36Sopenharmony_ci					case TOMOYO_PATH2_MAJOR:
96762306a36Sopenharmony_ci					case TOMOYO_PATH2_MINOR:
96862306a36Sopenharmony_ci					case TOMOYO_PATH2_TYPE:
96962306a36Sopenharmony_ci					case TOMOYO_PATH2_DEV_MAJOR:
97062306a36Sopenharmony_ci					case TOMOYO_PATH2_DEV_MINOR:
97162306a36Sopenharmony_ci					case TOMOYO_PATH2_PERM:
97262306a36Sopenharmony_ci						stat_index = TOMOYO_PATH2;
97362306a36Sopenharmony_ci						break;
97462306a36Sopenharmony_ci					case TOMOYO_PATH1_PARENT_UID:
97562306a36Sopenharmony_ci					case TOMOYO_PATH1_PARENT_GID:
97662306a36Sopenharmony_ci					case TOMOYO_PATH1_PARENT_INO:
97762306a36Sopenharmony_ci					case TOMOYO_PATH1_PARENT_PERM:
97862306a36Sopenharmony_ci						stat_index =
97962306a36Sopenharmony_ci							TOMOYO_PATH1_PARENT;
98062306a36Sopenharmony_ci						break;
98162306a36Sopenharmony_ci					case TOMOYO_PATH2_PARENT_UID:
98262306a36Sopenharmony_ci					case TOMOYO_PATH2_PARENT_GID:
98362306a36Sopenharmony_ci					case TOMOYO_PATH2_PARENT_INO:
98462306a36Sopenharmony_ci					case TOMOYO_PATH2_PARENT_PERM:
98562306a36Sopenharmony_ci						stat_index =
98662306a36Sopenharmony_ci							TOMOYO_PATH2_PARENT;
98762306a36Sopenharmony_ci						break;
98862306a36Sopenharmony_ci					default:
98962306a36Sopenharmony_ci						goto out;
99062306a36Sopenharmony_ci					}
99162306a36Sopenharmony_ci					if (!obj->stat_valid[stat_index])
99262306a36Sopenharmony_ci						goto out;
99362306a36Sopenharmony_ci					stat = &obj->stat[stat_index];
99462306a36Sopenharmony_ci					switch (index) {
99562306a36Sopenharmony_ci					case TOMOYO_PATH1_UID:
99662306a36Sopenharmony_ci					case TOMOYO_PATH2_UID:
99762306a36Sopenharmony_ci					case TOMOYO_PATH1_PARENT_UID:
99862306a36Sopenharmony_ci					case TOMOYO_PATH2_PARENT_UID:
99962306a36Sopenharmony_ci						value = from_kuid(&init_user_ns, stat->uid);
100062306a36Sopenharmony_ci						break;
100162306a36Sopenharmony_ci					case TOMOYO_PATH1_GID:
100262306a36Sopenharmony_ci					case TOMOYO_PATH2_GID:
100362306a36Sopenharmony_ci					case TOMOYO_PATH1_PARENT_GID:
100462306a36Sopenharmony_ci					case TOMOYO_PATH2_PARENT_GID:
100562306a36Sopenharmony_ci						value = from_kgid(&init_user_ns, stat->gid);
100662306a36Sopenharmony_ci						break;
100762306a36Sopenharmony_ci					case TOMOYO_PATH1_INO:
100862306a36Sopenharmony_ci					case TOMOYO_PATH2_INO:
100962306a36Sopenharmony_ci					case TOMOYO_PATH1_PARENT_INO:
101062306a36Sopenharmony_ci					case TOMOYO_PATH2_PARENT_INO:
101162306a36Sopenharmony_ci						value = stat->ino;
101262306a36Sopenharmony_ci						break;
101362306a36Sopenharmony_ci					case TOMOYO_PATH1_MAJOR:
101462306a36Sopenharmony_ci					case TOMOYO_PATH2_MAJOR:
101562306a36Sopenharmony_ci						value = MAJOR(stat->dev);
101662306a36Sopenharmony_ci						break;
101762306a36Sopenharmony_ci					case TOMOYO_PATH1_MINOR:
101862306a36Sopenharmony_ci					case TOMOYO_PATH2_MINOR:
101962306a36Sopenharmony_ci						value = MINOR(stat->dev);
102062306a36Sopenharmony_ci						break;
102162306a36Sopenharmony_ci					case TOMOYO_PATH1_TYPE:
102262306a36Sopenharmony_ci					case TOMOYO_PATH2_TYPE:
102362306a36Sopenharmony_ci						value = stat->mode & S_IFMT;
102462306a36Sopenharmony_ci						break;
102562306a36Sopenharmony_ci					case TOMOYO_PATH1_DEV_MAJOR:
102662306a36Sopenharmony_ci					case TOMOYO_PATH2_DEV_MAJOR:
102762306a36Sopenharmony_ci						value = MAJOR(stat->rdev);
102862306a36Sopenharmony_ci						break;
102962306a36Sopenharmony_ci					case TOMOYO_PATH1_DEV_MINOR:
103062306a36Sopenharmony_ci					case TOMOYO_PATH2_DEV_MINOR:
103162306a36Sopenharmony_ci						value = MINOR(stat->rdev);
103262306a36Sopenharmony_ci						break;
103362306a36Sopenharmony_ci					case TOMOYO_PATH1_PERM:
103462306a36Sopenharmony_ci					case TOMOYO_PATH2_PERM:
103562306a36Sopenharmony_ci					case TOMOYO_PATH1_PARENT_PERM:
103662306a36Sopenharmony_ci					case TOMOYO_PATH2_PARENT_PERM:
103762306a36Sopenharmony_ci						value = stat->mode & S_IALLUGO;
103862306a36Sopenharmony_ci						break;
103962306a36Sopenharmony_ci					}
104062306a36Sopenharmony_ci				}
104162306a36Sopenharmony_ci				break;
104262306a36Sopenharmony_ci			}
104362306a36Sopenharmony_ci			max_v[j] = value;
104462306a36Sopenharmony_ci			min_v[j] = value;
104562306a36Sopenharmony_ci			switch (index) {
104662306a36Sopenharmony_ci			case TOMOYO_MODE_SETUID:
104762306a36Sopenharmony_ci			case TOMOYO_MODE_SETGID:
104862306a36Sopenharmony_ci			case TOMOYO_MODE_STICKY:
104962306a36Sopenharmony_ci			case TOMOYO_MODE_OWNER_READ:
105062306a36Sopenharmony_ci			case TOMOYO_MODE_OWNER_WRITE:
105162306a36Sopenharmony_ci			case TOMOYO_MODE_OWNER_EXECUTE:
105262306a36Sopenharmony_ci			case TOMOYO_MODE_GROUP_READ:
105362306a36Sopenharmony_ci			case TOMOYO_MODE_GROUP_WRITE:
105462306a36Sopenharmony_ci			case TOMOYO_MODE_GROUP_EXECUTE:
105562306a36Sopenharmony_ci			case TOMOYO_MODE_OTHERS_READ:
105662306a36Sopenharmony_ci			case TOMOYO_MODE_OTHERS_WRITE:
105762306a36Sopenharmony_ci			case TOMOYO_MODE_OTHERS_EXECUTE:
105862306a36Sopenharmony_ci				is_bitop[j] = true;
105962306a36Sopenharmony_ci			}
106062306a36Sopenharmony_ci		}
106162306a36Sopenharmony_ci		if (left == TOMOYO_NUMBER_UNION) {
106262306a36Sopenharmony_ci			/* Fetch values now. */
106362306a36Sopenharmony_ci			const struct tomoyo_number_union *ptr = numbers_p++;
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci			min_v[0] = ptr->values[0];
106662306a36Sopenharmony_ci			max_v[0] = ptr->values[1];
106762306a36Sopenharmony_ci		}
106862306a36Sopenharmony_ci		if (right == TOMOYO_NUMBER_UNION) {
106962306a36Sopenharmony_ci			/* Fetch values now. */
107062306a36Sopenharmony_ci			const struct tomoyo_number_union *ptr = numbers_p++;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci			if (ptr->group) {
107362306a36Sopenharmony_ci				if (tomoyo_number_matches_group(min_v[0],
107462306a36Sopenharmony_ci								max_v[0],
107562306a36Sopenharmony_ci								ptr->group)
107662306a36Sopenharmony_ci				    == match)
107762306a36Sopenharmony_ci					continue;
107862306a36Sopenharmony_ci			} else {
107962306a36Sopenharmony_ci				if ((min_v[0] <= ptr->values[1] &&
108062306a36Sopenharmony_ci				     max_v[0] >= ptr->values[0]) == match)
108162306a36Sopenharmony_ci					continue;
108262306a36Sopenharmony_ci			}
108362306a36Sopenharmony_ci			goto out;
108462306a36Sopenharmony_ci		}
108562306a36Sopenharmony_ci		/*
108662306a36Sopenharmony_ci		 * Bit operation is valid only when counterpart value
108762306a36Sopenharmony_ci		 * represents permission.
108862306a36Sopenharmony_ci		 */
108962306a36Sopenharmony_ci		if (is_bitop[0] && is_bitop[1]) {
109062306a36Sopenharmony_ci			goto out;
109162306a36Sopenharmony_ci		} else if (is_bitop[0]) {
109262306a36Sopenharmony_ci			switch (right) {
109362306a36Sopenharmony_ci			case TOMOYO_PATH1_PERM:
109462306a36Sopenharmony_ci			case TOMOYO_PATH1_PARENT_PERM:
109562306a36Sopenharmony_ci			case TOMOYO_PATH2_PERM:
109662306a36Sopenharmony_ci			case TOMOYO_PATH2_PARENT_PERM:
109762306a36Sopenharmony_ci				if (!(max_v[0] & max_v[1]) == !match)
109862306a36Sopenharmony_ci					continue;
109962306a36Sopenharmony_ci			}
110062306a36Sopenharmony_ci			goto out;
110162306a36Sopenharmony_ci		} else if (is_bitop[1]) {
110262306a36Sopenharmony_ci			switch (left) {
110362306a36Sopenharmony_ci			case TOMOYO_PATH1_PERM:
110462306a36Sopenharmony_ci			case TOMOYO_PATH1_PARENT_PERM:
110562306a36Sopenharmony_ci			case TOMOYO_PATH2_PERM:
110662306a36Sopenharmony_ci			case TOMOYO_PATH2_PARENT_PERM:
110762306a36Sopenharmony_ci				if (!(max_v[0] & max_v[1]) == !match)
110862306a36Sopenharmony_ci					continue;
110962306a36Sopenharmony_ci			}
111062306a36Sopenharmony_ci			goto out;
111162306a36Sopenharmony_ci		}
111262306a36Sopenharmony_ci		/* Normal value range comparison. */
111362306a36Sopenharmony_ci		if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match)
111462306a36Sopenharmony_ci			continue;
111562306a36Sopenharmony_ciout:
111662306a36Sopenharmony_ci		return false;
111762306a36Sopenharmony_ci	}
111862306a36Sopenharmony_ci	/* Check argv[] and envp[] now. */
111962306a36Sopenharmony_ci	if (r->ee && (argc || envc))
112062306a36Sopenharmony_ci		return tomoyo_scan_bprm(r->ee, argc, argv, envc, envp);
112162306a36Sopenharmony_ci	return true;
112262306a36Sopenharmony_ci}
1123