Linux Audio

Check our new training course

Loading...
v6.2
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * security/tomoyo/condition.c
   4 *
   5 * Copyright (C) 2005-2011  NTT DATA CORPORATION
   6 */
   7
   8#include "common.h"
   9#include <linux/slab.h>
  10
  11/* List of "struct tomoyo_condition". */
  12LIST_HEAD(tomoyo_condition_list);
  13
  14/**
  15 * tomoyo_argv - Check argv[] in "struct linux_binbrm".
  16 *
  17 * @index:   Index number of @arg_ptr.
  18 * @arg_ptr: Contents of argv[@index].
  19 * @argc:    Length of @argv.
  20 * @argv:    Pointer to "struct tomoyo_argv".
  21 * @checked: Set to true if @argv[@index] was found.
  22 *
  23 * Returns true on success, false otherwise.
  24 */
  25static bool tomoyo_argv(const unsigned int index, const char *arg_ptr,
  26			const int argc, const struct tomoyo_argv *argv,
  27			u8 *checked)
  28{
  29	int i;
  30	struct tomoyo_path_info arg;
  31
  32	arg.name = arg_ptr;
  33	for (i = 0; i < argc; argv++, checked++, i++) {
  34		bool result;
  35
  36		if (index != argv->index)
  37			continue;
  38		*checked = 1;
  39		tomoyo_fill_path_info(&arg);
  40		result = tomoyo_path_matches_pattern(&arg, argv->value);
  41		if (argv->is_not)
  42			result = !result;
  43		if (!result)
  44			return false;
  45	}
  46	return true;
  47}
  48
  49/**
  50 * tomoyo_envp - Check envp[] in "struct linux_binbrm".
  51 *
  52 * @env_name:  The name of environment variable.
  53 * @env_value: The value of environment variable.
  54 * @envc:      Length of @envp.
  55 * @envp:      Pointer to "struct tomoyo_envp".
  56 * @checked:   Set to true if @envp[@env_name] was found.
  57 *
  58 * Returns true on success, false otherwise.
  59 */
  60static bool tomoyo_envp(const char *env_name, const char *env_value,
  61			const int envc, const struct tomoyo_envp *envp,
  62			u8 *checked)
  63{
  64	int i;
  65	struct tomoyo_path_info name;
  66	struct tomoyo_path_info value;
  67
  68	name.name = env_name;
  69	tomoyo_fill_path_info(&name);
  70	value.name = env_value;
  71	tomoyo_fill_path_info(&value);
  72	for (i = 0; i < envc; envp++, checked++, i++) {
  73		bool result;
  74
  75		if (!tomoyo_path_matches_pattern(&name, envp->name))
  76			continue;
  77		*checked = 1;
  78		if (envp->value) {
  79			result = tomoyo_path_matches_pattern(&value,
  80							     envp->value);
  81			if (envp->is_not)
  82				result = !result;
  83		} else {
  84			result = true;
  85			if (!envp->is_not)
  86				result = !result;
  87		}
  88		if (!result)
  89			return false;
  90	}
  91	return true;
  92}
  93
  94/**
  95 * tomoyo_scan_bprm - Scan "struct linux_binprm".
  96 *
  97 * @ee:   Pointer to "struct tomoyo_execve".
  98 * @argc: Length of @argc.
  99 * @argv: Pointer to "struct tomoyo_argv".
 100 * @envc: Length of @envp.
 101 * @envp: Pointer to "struct tomoyo_envp".
 102 *
 103 * Returns true on success, false otherwise.
 104 */
 105static bool tomoyo_scan_bprm(struct tomoyo_execve *ee,
 106			     const u16 argc, const struct tomoyo_argv *argv,
 107			     const u16 envc, const struct tomoyo_envp *envp)
 108{
 109	struct linux_binprm *bprm = ee->bprm;
 110	struct tomoyo_page_dump *dump = &ee->dump;
 111	char *arg_ptr = ee->tmp;
 112	int arg_len = 0;
 113	unsigned long pos = bprm->p;
 114	int offset = pos % PAGE_SIZE;
 115	int argv_count = bprm->argc;
 116	int envp_count = bprm->envc;
 117	bool result = true;
 118	u8 local_checked[32];
 119	u8 *checked;
 120
 121	if (argc + envc <= sizeof(local_checked)) {
 122		checked = local_checked;
 123		memset(local_checked, 0, sizeof(local_checked));
 124	} else {
 125		checked = kzalloc(argc + envc, GFP_NOFS);
 126		if (!checked)
 127			return false;
 128	}
 129	while (argv_count || envp_count) {
 130		if (!tomoyo_dump_page(bprm, pos, dump)) {
 131			result = false;
 132			goto out;
 133		}
 134		pos += PAGE_SIZE - offset;
 135		while (offset < PAGE_SIZE) {
 136			/* Read. */
 137			const char *kaddr = dump->data;
 138			const unsigned char c = kaddr[offset++];
 139
 140			if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) {
 141				if (c == '\\') {
 142					arg_ptr[arg_len++] = '\\';
 143					arg_ptr[arg_len++] = '\\';
 144				} else if (c > ' ' && c < 127) {
 145					arg_ptr[arg_len++] = c;
 146				} else {
 147					arg_ptr[arg_len++] = '\\';
 148					arg_ptr[arg_len++] = (c >> 6) + '0';
 149					arg_ptr[arg_len++] =
 150						((c >> 3) & 7) + '0';
 151					arg_ptr[arg_len++] = (c & 7) + '0';
 152				}
 153			} else {
 154				arg_ptr[arg_len] = '\0';
 155			}
 156			if (c)
 157				continue;
 158			/* Check. */
 159			if (argv_count) {
 160				if (!tomoyo_argv(bprm->argc - argv_count,
 161						 arg_ptr, argc, argv,
 162						 checked)) {
 163					result = false;
 164					break;
 165				}
 166				argv_count--;
 167			} else if (envp_count) {
 168				char *cp = strchr(arg_ptr, '=');
 169
 170				if (cp) {
 171					*cp = '\0';
 172					if (!tomoyo_envp(arg_ptr, cp + 1,
 173							 envc, envp,
 174							 checked + argc)) {
 175						result = false;
 176						break;
 177					}
 178				}
 179				envp_count--;
 180			} else {
 181				break;
 182			}
 183			arg_len = 0;
 184		}
 185		offset = 0;
 186		if (!result)
 187			break;
 188	}
 189out:
 190	if (result) {
 191		int i;
 192
 193		/* Check not-yet-checked entries. */
 194		for (i = 0; i < argc; i++) {
 195			if (checked[i])
 196				continue;
 197			/*
 198			 * Return true only if all unchecked indexes in
 199			 * bprm->argv[] are not matched.
 200			 */
 201			if (argv[i].is_not)
 202				continue;
 203			result = false;
 204			break;
 205		}
 206		for (i = 0; i < envc; envp++, i++) {
 207			if (checked[argc + i])
 208				continue;
 209			/*
 210			 * Return true only if all unchecked environ variables
 211			 * in bprm->envp[] are either undefined or not matched.
 212			 */
 213			if ((!envp->value && !envp->is_not) ||
 214			    (envp->value && envp->is_not))
 215				continue;
 216			result = false;
 217			break;
 218		}
 219	}
 220	if (checked != local_checked)
 221		kfree(checked);
 222	return result;
 223}
 224
 225/**
 226 * tomoyo_scan_exec_realpath - Check "exec.realpath" parameter of "struct tomoyo_condition".
 227 *
 228 * @file:  Pointer to "struct file".
 229 * @ptr:   Pointer to "struct tomoyo_name_union".
 230 * @match: True if "exec.realpath=", false if "exec.realpath!=".
 231 *
 232 * Returns true on success, false otherwise.
 233 */
 234static bool tomoyo_scan_exec_realpath(struct file *file,
 235				      const struct tomoyo_name_union *ptr,
 236				      const bool match)
 237{
 238	bool result;
 239	struct tomoyo_path_info exe;
 240
 241	if (!file)
 242		return false;
 243	exe.name = tomoyo_realpath_from_path(&file->f_path);
 244	if (!exe.name)
 245		return false;
 246	tomoyo_fill_path_info(&exe);
 247	result = tomoyo_compare_name_union(&exe, ptr);
 248	kfree(exe.name);
 249	return result == match;
 250}
 251
 252/**
 253 * tomoyo_get_dqword - tomoyo_get_name() for a quoted string.
 254 *
 255 * @start: String to save.
 256 *
 257 * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
 258 */
 259static const struct tomoyo_path_info *tomoyo_get_dqword(char *start)
 260{
 261	char *cp = start + strlen(start) - 1;
 262
 263	if (cp == start || *start++ != '"' || *cp != '"')
 264		return NULL;
 265	*cp = '\0';
 266	if (*start && !tomoyo_correct_word(start))
 267		return NULL;
 268	return tomoyo_get_name(start);
 269}
 270
 271/**
 272 * tomoyo_parse_name_union_quoted - Parse a quoted word.
 273 *
 274 * @param: Pointer to "struct tomoyo_acl_param".
 275 * @ptr:   Pointer to "struct tomoyo_name_union".
 276 *
 277 * Returns true on success, false otherwise.
 278 */
 279static bool tomoyo_parse_name_union_quoted(struct tomoyo_acl_param *param,
 280					   struct tomoyo_name_union *ptr)
 281{
 282	char *filename = param->data;
 283
 284	if (*filename == '@')
 285		return tomoyo_parse_name_union(param, ptr);
 286	ptr->filename = tomoyo_get_dqword(filename);
 287	return ptr->filename != NULL;
 288}
 289
 290/**
 291 * tomoyo_parse_argv - Parse an argv[] condition part.
 292 *
 293 * @left:  Lefthand value.
 294 * @right: Righthand value.
 295 * @argv:  Pointer to "struct tomoyo_argv".
 296 *
 297 * Returns true on success, false otherwise.
 298 */
 299static bool tomoyo_parse_argv(char *left, char *right,
 300			      struct tomoyo_argv *argv)
 301{
 302	if (tomoyo_parse_ulong(&argv->index, &left) !=
 303	    TOMOYO_VALUE_TYPE_DECIMAL || *left++ != ']' || *left)
 304		return false;
 305	argv->value = tomoyo_get_dqword(right);
 306	return argv->value != NULL;
 307}
 308
 309/**
 310 * tomoyo_parse_envp - Parse an envp[] condition part.
 311 *
 312 * @left:  Lefthand value.
 313 * @right: Righthand value.
 314 * @envp:  Pointer to "struct tomoyo_envp".
 315 *
 316 * Returns true on success, false otherwise.
 317 */
 318static bool tomoyo_parse_envp(char *left, char *right,
 319			      struct tomoyo_envp *envp)
 320{
 321	const struct tomoyo_path_info *name;
 322	const struct tomoyo_path_info *value;
 323	char *cp = left + strlen(left) - 1;
 324
 325	if (*cp-- != ']' || *cp != '"')
 326		goto out;
 327	*cp = '\0';
 328	if (!tomoyo_correct_word(left))
 329		goto out;
 330	name = tomoyo_get_name(left);
 331	if (!name)
 332		goto out;
 333	if (!strcmp(right, "NULL")) {
 334		value = NULL;
 335	} else {
 336		value = tomoyo_get_dqword(right);
 337		if (!value) {
 338			tomoyo_put_name(name);
 339			goto out;
 340		}
 341	}
 342	envp->name = name;
 343	envp->value = value;
 344	return true;
 345out:
 346	return false;
 347}
 348
 349/**
 350 * tomoyo_same_condition - Check for duplicated "struct tomoyo_condition" entry.
 351 *
 352 * @a: Pointer to "struct tomoyo_condition".
 353 * @b: Pointer to "struct tomoyo_condition".
 354 *
 355 * Returns true if @a == @b, false otherwise.
 356 */
 357static inline bool tomoyo_same_condition(const struct tomoyo_condition *a,
 358					 const struct tomoyo_condition *b)
 359{
 360	return a->size == b->size && a->condc == b->condc &&
 361		a->numbers_count == b->numbers_count &&
 362		a->names_count == b->names_count &&
 363		a->argc == b->argc && a->envc == b->envc &&
 364		a->grant_log == b->grant_log && a->transit == b->transit &&
 365		!memcmp(a + 1, b + 1, a->size - sizeof(*a));
 366}
 367
 368/**
 369 * tomoyo_condition_type - Get condition type.
 370 *
 371 * @word: Keyword string.
 372 *
 373 * Returns one of values in "enum tomoyo_conditions_index" on success,
 374 * TOMOYO_MAX_CONDITION_KEYWORD otherwise.
 375 */
 376static u8 tomoyo_condition_type(const char *word)
 377{
 378	u8 i;
 379
 380	for (i = 0; i < TOMOYO_MAX_CONDITION_KEYWORD; i++) {
 381		if (!strcmp(word, tomoyo_condition_keyword[i]))
 382			break;
 383	}
 384	return i;
 385}
 386
 387/* Define this to enable debug mode. */
 388/* #define DEBUG_CONDITION */
 389
 390#ifdef DEBUG_CONDITION
 391#define dprintk printk
 392#else
 393#define dprintk(...) do { } while (0)
 394#endif
 395
 396/**
 397 * tomoyo_commit_condition - Commit "struct tomoyo_condition".
 398 *
 399 * @entry: Pointer to "struct tomoyo_condition".
 400 *
 401 * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
 402 *
 403 * This function merges duplicated entries. This function returns NULL if
 404 * @entry is not duplicated but memory quota for policy has exceeded.
 405 */
 406static struct tomoyo_condition *tomoyo_commit_condition
 407(struct tomoyo_condition *entry)
 408{
 409	struct tomoyo_condition *ptr;
 410	bool found = false;
 411
 412	if (mutex_lock_interruptible(&tomoyo_policy_lock)) {
 413		dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
 414		ptr = NULL;
 415		found = true;
 416		goto out;
 417	}
 418	list_for_each_entry(ptr, &tomoyo_condition_list, head.list) {
 419		if (!tomoyo_same_condition(ptr, entry) ||
 420		    atomic_read(&ptr->head.users) == TOMOYO_GC_IN_PROGRESS)
 421			continue;
 422		/* Same entry found. Share this entry. */
 423		atomic_inc(&ptr->head.users);
 424		found = true;
 425		break;
 426	}
 427	if (!found) {
 428		if (tomoyo_memory_ok(entry)) {
 429			atomic_set(&entry->head.users, 1);
 430			list_add(&entry->head.list, &tomoyo_condition_list);
 431		} else {
 432			found = true;
 433			ptr = NULL;
 434		}
 435	}
 436	mutex_unlock(&tomoyo_policy_lock);
 437out:
 438	if (found) {
 439		tomoyo_del_condition(&entry->head.list);
 440		kfree(entry);
 441		entry = ptr;
 442	}
 443	return entry;
 444}
 445
 446/**
 447 * tomoyo_get_transit_preference - Parse domain transition preference for execve().
 448 *
 449 * @param: Pointer to "struct tomoyo_acl_param".
 450 * @e:     Pointer to "struct tomoyo_condition".
 451 *
 452 * Returns the condition string part.
 453 */
 454static char *tomoyo_get_transit_preference(struct tomoyo_acl_param *param,
 455					   struct tomoyo_condition *e)
 456{
 457	char * const pos = param->data;
 458	bool flag;
 459
 460	if (*pos == '<') {
 461		e->transit = tomoyo_get_domainname(param);
 462		goto done;
 463	}
 464	{
 465		char *cp = strchr(pos, ' ');
 466
 467		if (cp)
 468			*cp = '\0';
 469		flag = tomoyo_correct_path(pos) || !strcmp(pos, "keep") ||
 470			!strcmp(pos, "initialize") || !strcmp(pos, "reset") ||
 471			!strcmp(pos, "child") || !strcmp(pos, "parent");
 472		if (cp)
 473			*cp = ' ';
 474	}
 475	if (!flag)
 476		return pos;
 477	e->transit = tomoyo_get_name(tomoyo_read_token(param));
 478done:
 479	if (e->transit)
 480		return param->data;
 481	/*
 482	 * Return a bad read-only condition string that will let
 483	 * tomoyo_get_condition() return NULL.
 484	 */
 485	return "/";
 486}
 487
 488/**
 489 * tomoyo_get_condition - Parse condition part.
 490 *
 491 * @param: Pointer to "struct tomoyo_acl_param".
 492 *
 493 * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
 494 */
 495struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param)
 496{
 497	struct tomoyo_condition *entry = NULL;
 498	struct tomoyo_condition_element *condp = NULL;
 499	struct tomoyo_number_union *numbers_p = NULL;
 500	struct tomoyo_name_union *names_p = NULL;
 501	struct tomoyo_argv *argv = NULL;
 502	struct tomoyo_envp *envp = NULL;
 503	struct tomoyo_condition e = { };
 504	char * const start_of_string =
 505		tomoyo_get_transit_preference(param, &e);
 506	char * const end_of_string = start_of_string + strlen(start_of_string);
 507	char *pos;
 508
 509rerun:
 510	pos = start_of_string;
 511	while (1) {
 512		u8 left = -1;
 513		u8 right = -1;
 514		char *left_word = pos;
 515		char *cp;
 516		char *right_word;
 517		bool is_not;
 518
 519		if (!*left_word)
 520			break;
 521		/*
 522		 * Since left-hand condition does not allow use of "path_group"
 523		 * or "number_group" and environment variable's names do not
 524		 * accept '=', it is guaranteed that the original line consists
 525		 * of one or more repetition of $left$operator$right blocks
 526		 * where "$left is free from '=' and ' '" and "$operator is
 527		 * either '=' or '!='" and "$right is free from ' '".
 528		 * Therefore, we can reconstruct the original line at the end
 529		 * of dry run even if we overwrite $operator with '\0'.
 530		 */
 531		cp = strchr(pos, ' ');
 532		if (cp) {
 533			*cp = '\0'; /* Will restore later. */
 534			pos = cp + 1;
 535		} else {
 536			pos = "";
 537		}
 538		right_word = strchr(left_word, '=');
 539		if (!right_word || right_word == left_word)
 540			goto out;
 541		is_not = *(right_word - 1) == '!';
 542		if (is_not)
 543			*(right_word++ - 1) = '\0'; /* Will restore later. */
 544		else if (*(right_word + 1) != '=')
 545			*right_word++ = '\0'; /* Will restore later. */
 546		else
 547			goto out;
 548		dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word,
 549			is_not ? "!" : "", right_word);
 550		if (!strcmp(left_word, "grant_log")) {
 551			if (entry) {
 552				if (is_not ||
 553				    entry->grant_log != TOMOYO_GRANTLOG_AUTO)
 554					goto out;
 555				else if (!strcmp(right_word, "yes"))
 556					entry->grant_log = TOMOYO_GRANTLOG_YES;
 557				else if (!strcmp(right_word, "no"))
 558					entry->grant_log = TOMOYO_GRANTLOG_NO;
 559				else
 560					goto out;
 561			}
 562			continue;
 563		}
 564		if (!strncmp(left_word, "exec.argv[", 10)) {
 565			if (!argv) {
 566				e.argc++;
 567				e.condc++;
 568			} else {
 569				e.argc--;
 570				e.condc--;
 571				left = TOMOYO_ARGV_ENTRY;
 572				argv->is_not = is_not;
 573				if (!tomoyo_parse_argv(left_word + 10,
 574						       right_word, argv++))
 575					goto out;
 576			}
 577			goto store_value;
 578		}
 579		if (!strncmp(left_word, "exec.envp[\"", 11)) {
 580			if (!envp) {
 581				e.envc++;
 582				e.condc++;
 583			} else {
 584				e.envc--;
 585				e.condc--;
 586				left = TOMOYO_ENVP_ENTRY;
 587				envp->is_not = is_not;
 588				if (!tomoyo_parse_envp(left_word + 11,
 589						       right_word, envp++))
 590					goto out;
 591			}
 592			goto store_value;
 593		}
 594		left = tomoyo_condition_type(left_word);
 595		dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, left_word,
 596			left);
 597		if (left == TOMOYO_MAX_CONDITION_KEYWORD) {
 598			if (!numbers_p) {
 599				e.numbers_count++;
 600			} else {
 601				e.numbers_count--;
 602				left = TOMOYO_NUMBER_UNION;
 603				param->data = left_word;
 604				if (*left_word == '@' ||
 605				    !tomoyo_parse_number_union(param,
 606							       numbers_p++))
 607					goto out;
 608			}
 609		}
 610		if (!condp)
 611			e.condc++;
 612		else
 613			e.condc--;
 614		if (left == TOMOYO_EXEC_REALPATH ||
 615		    left == TOMOYO_SYMLINK_TARGET) {
 616			if (!names_p) {
 617				e.names_count++;
 618			} else {
 619				e.names_count--;
 620				right = TOMOYO_NAME_UNION;
 621				param->data = right_word;
 622				if (!tomoyo_parse_name_union_quoted(param,
 623								    names_p++))
 624					goto out;
 625			}
 626			goto store_value;
 627		}
 628		right = tomoyo_condition_type(right_word);
 629		if (right == TOMOYO_MAX_CONDITION_KEYWORD) {
 630			if (!numbers_p) {
 631				e.numbers_count++;
 632			} else {
 633				e.numbers_count--;
 634				right = TOMOYO_NUMBER_UNION;
 635				param->data = right_word;
 636				if (!tomoyo_parse_number_union(param,
 637							       numbers_p++))
 638					goto out;
 639			}
 640		}
 641store_value:
 642		if (!condp) {
 643			dprintk(KERN_WARNING "%u: dry_run left=%u right=%u match=%u\n",
 644				__LINE__, left, right, !is_not);
 645			continue;
 646		}
 647		condp->left = left;
 648		condp->right = right;
 649		condp->equals = !is_not;
 650		dprintk(KERN_WARNING "%u: left=%u right=%u match=%u\n",
 651			__LINE__, condp->left, condp->right,
 652			condp->equals);
 653		condp++;
 654	}
 655	dprintk(KERN_INFO "%u: cond=%u numbers=%u names=%u ac=%u ec=%u\n",
 656		__LINE__, e.condc, e.numbers_count, e.names_count, e.argc,
 657		e.envc);
 658	if (entry) {
 659		BUG_ON(e.names_count | e.numbers_count | e.argc | e.envc |
 660		       e.condc);
 661		return tomoyo_commit_condition(entry);
 662	}
 663	e.size = sizeof(*entry)
 664		+ e.condc * sizeof(struct tomoyo_condition_element)
 665		+ e.numbers_count * sizeof(struct tomoyo_number_union)
 666		+ e.names_count * sizeof(struct tomoyo_name_union)
 667		+ e.argc * sizeof(struct tomoyo_argv)
 668		+ e.envc * sizeof(struct tomoyo_envp);
 669	entry = kzalloc(e.size, GFP_NOFS);
 670	if (!entry)
 671		goto out2;
 672	*entry = e;
 673	e.transit = NULL;
 674	condp = (struct tomoyo_condition_element *) (entry + 1);
 675	numbers_p = (struct tomoyo_number_union *) (condp + e.condc);
 676	names_p = (struct tomoyo_name_union *) (numbers_p + e.numbers_count);
 677	argv = (struct tomoyo_argv *) (names_p + e.names_count);
 678	envp = (struct tomoyo_envp *) (argv + e.argc);
 679	{
 680		bool flag = false;
 681
 682		for (pos = start_of_string; pos < end_of_string; pos++) {
 683			if (*pos)
 684				continue;
 685			if (flag) /* Restore " ". */
 686				*pos = ' ';
 687			else if (*(pos + 1) == '=') /* Restore "!=". */
 688				*pos = '!';
 689			else /* Restore "=". */
 690				*pos = '=';
 691			flag = !flag;
 692		}
 693	}
 694	goto rerun;
 695out:
 696	dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
 697	if (entry) {
 698		tomoyo_del_condition(&entry->head.list);
 699		kfree(entry);
 700	}
 701out2:
 702	tomoyo_put_name(e.transit);
 703	return NULL;
 704}
 705
 706/**
 707 * tomoyo_get_attributes - Revalidate "struct inode".
 708 *
 709 * @obj: Pointer to "struct tomoyo_obj_info".
 710 *
 711 * Returns nothing.
 712 */
 713void tomoyo_get_attributes(struct tomoyo_obj_info *obj)
 714{
 715	u8 i;
 716	struct dentry *dentry = NULL;
 717
 718	for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) {
 719		struct inode *inode;
 720
 721		switch (i) {
 722		case TOMOYO_PATH1:
 723			dentry = obj->path1.dentry;
 724			if (!dentry)
 725				continue;
 726			break;
 727		case TOMOYO_PATH2:
 728			dentry = obj->path2.dentry;
 729			if (!dentry)
 730				continue;
 731			break;
 732		default:
 733			if (!dentry)
 734				continue;
 735			dentry = dget_parent(dentry);
 736			break;
 737		}
 738		inode = d_backing_inode(dentry);
 739		if (inode) {
 740			struct tomoyo_mini_stat *stat = &obj->stat[i];
 741
 742			stat->uid  = inode->i_uid;
 743			stat->gid  = inode->i_gid;
 744			stat->ino  = inode->i_ino;
 745			stat->mode = inode->i_mode;
 746			stat->dev  = inode->i_sb->s_dev;
 747			stat->rdev = inode->i_rdev;
 748			obj->stat_valid[i] = true;
 749		}
 750		if (i & 1) /* TOMOYO_PATH1_PARENT or TOMOYO_PATH2_PARENT */
 751			dput(dentry);
 752	}
 753}
 754
 755/**
 756 * tomoyo_condition - Check condition part.
 757 *
 758 * @r:    Pointer to "struct tomoyo_request_info".
 759 * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
 760 *
 761 * Returns true on success, false otherwise.
 762 *
 763 * Caller holds tomoyo_read_lock().
 764 */
 765bool tomoyo_condition(struct tomoyo_request_info *r,
 766		      const struct tomoyo_condition *cond)
 767{
 768	u32 i;
 769	unsigned long min_v[2] = { 0, 0 };
 770	unsigned long max_v[2] = { 0, 0 };
 771	const struct tomoyo_condition_element *condp;
 772	const struct tomoyo_number_union *numbers_p;
 773	const struct tomoyo_name_union *names_p;
 774	const struct tomoyo_argv *argv;
 775	const struct tomoyo_envp *envp;
 776	struct tomoyo_obj_info *obj;
 777	u16 condc;
 778	u16 argc;
 779	u16 envc;
 780	struct linux_binprm *bprm = NULL;
 781
 782	if (!cond)
 783		return true;
 784	condc = cond->condc;
 785	argc = cond->argc;
 786	envc = cond->envc;
 787	obj = r->obj;
 788	if (r->ee)
 789		bprm = r->ee->bprm;
 790	if (!bprm && (argc || envc))
 791		return false;
 792	condp = (struct tomoyo_condition_element *) (cond + 1);
 793	numbers_p = (const struct tomoyo_number_union *) (condp + condc);
 794	names_p = (const struct tomoyo_name_union *)
 795		(numbers_p + cond->numbers_count);
 796	argv = (const struct tomoyo_argv *) (names_p + cond->names_count);
 797	envp = (const struct tomoyo_envp *) (argv + argc);
 798	for (i = 0; i < condc; i++) {
 799		const bool match = condp->equals;
 800		const u8 left = condp->left;
 801		const u8 right = condp->right;
 802		bool is_bitop[2] = { false, false };
 803		u8 j;
 804
 805		condp++;
 806		/* Check argv[] and envp[] later. */
 807		if (left == TOMOYO_ARGV_ENTRY || left == TOMOYO_ENVP_ENTRY)
 808			continue;
 809		/* Check string expressions. */
 810		if (right == TOMOYO_NAME_UNION) {
 811			const struct tomoyo_name_union *ptr = names_p++;
 812			struct tomoyo_path_info *symlink;
 813			struct tomoyo_execve *ee;
 814			struct file *file;
 815
 816			switch (left) {
 817			case TOMOYO_SYMLINK_TARGET:
 818				symlink = obj ? obj->symlink_target : NULL;
 819				if (!symlink ||
 820				    !tomoyo_compare_name_union(symlink, ptr)
 821				    == match)
 822					goto out;
 823				break;
 824			case TOMOYO_EXEC_REALPATH:
 825				ee = r->ee;
 826				file = ee ? ee->bprm->file : NULL;
 827				if (!tomoyo_scan_exec_realpath(file, ptr,
 828							       match))
 829					goto out;
 830				break;
 831			}
 832			continue;
 833		}
 834		/* Check numeric or bit-op expressions. */
 835		for (j = 0; j < 2; j++) {
 836			const u8 index = j ? right : left;
 837			unsigned long value = 0;
 838
 839			switch (index) {
 840			case TOMOYO_TASK_UID:
 841				value = from_kuid(&init_user_ns, current_uid());
 842				break;
 843			case TOMOYO_TASK_EUID:
 844				value = from_kuid(&init_user_ns, current_euid());
 845				break;
 846			case TOMOYO_TASK_SUID:
 847				value = from_kuid(&init_user_ns, current_suid());
 848				break;
 849			case TOMOYO_TASK_FSUID:
 850				value = from_kuid(&init_user_ns, current_fsuid());
 851				break;
 852			case TOMOYO_TASK_GID:
 853				value = from_kgid(&init_user_ns, current_gid());
 854				break;
 855			case TOMOYO_TASK_EGID:
 856				value = from_kgid(&init_user_ns, current_egid());
 857				break;
 858			case TOMOYO_TASK_SGID:
 859				value = from_kgid(&init_user_ns, current_sgid());
 860				break;
 861			case TOMOYO_TASK_FSGID:
 862				value = from_kgid(&init_user_ns, current_fsgid());
 863				break;
 864			case TOMOYO_TASK_PID:
 865				value = tomoyo_sys_getpid();
 866				break;
 867			case TOMOYO_TASK_PPID:
 868				value = tomoyo_sys_getppid();
 869				break;
 870			case TOMOYO_TYPE_IS_SOCKET:
 871				value = S_IFSOCK;
 872				break;
 873			case TOMOYO_TYPE_IS_SYMLINK:
 874				value = S_IFLNK;
 875				break;
 876			case TOMOYO_TYPE_IS_FILE:
 877				value = S_IFREG;
 878				break;
 879			case TOMOYO_TYPE_IS_BLOCK_DEV:
 880				value = S_IFBLK;
 881				break;
 882			case TOMOYO_TYPE_IS_DIRECTORY:
 883				value = S_IFDIR;
 884				break;
 885			case TOMOYO_TYPE_IS_CHAR_DEV:
 886				value = S_IFCHR;
 887				break;
 888			case TOMOYO_TYPE_IS_FIFO:
 889				value = S_IFIFO;
 890				break;
 891			case TOMOYO_MODE_SETUID:
 892				value = S_ISUID;
 893				break;
 894			case TOMOYO_MODE_SETGID:
 895				value = S_ISGID;
 896				break;
 897			case TOMOYO_MODE_STICKY:
 898				value = S_ISVTX;
 899				break;
 900			case TOMOYO_MODE_OWNER_READ:
 901				value = 0400;
 902				break;
 903			case TOMOYO_MODE_OWNER_WRITE:
 904				value = 0200;
 905				break;
 906			case TOMOYO_MODE_OWNER_EXECUTE:
 907				value = 0100;
 908				break;
 909			case TOMOYO_MODE_GROUP_READ:
 910				value = 0040;
 911				break;
 912			case TOMOYO_MODE_GROUP_WRITE:
 913				value = 0020;
 914				break;
 915			case TOMOYO_MODE_GROUP_EXECUTE:
 916				value = 0010;
 917				break;
 918			case TOMOYO_MODE_OTHERS_READ:
 919				value = 0004;
 920				break;
 921			case TOMOYO_MODE_OTHERS_WRITE:
 922				value = 0002;
 923				break;
 924			case TOMOYO_MODE_OTHERS_EXECUTE:
 925				value = 0001;
 926				break;
 927			case TOMOYO_EXEC_ARGC:
 928				if (!bprm)
 929					goto out;
 930				value = bprm->argc;
 931				break;
 932			case TOMOYO_EXEC_ENVC:
 933				if (!bprm)
 934					goto out;
 935				value = bprm->envc;
 936				break;
 937			case TOMOYO_NUMBER_UNION:
 938				/* Fetch values later. */
 939				break;
 940			default:
 941				if (!obj)
 942					goto out;
 943				if (!obj->validate_done) {
 944					tomoyo_get_attributes(obj);
 945					obj->validate_done = true;
 946				}
 947				{
 948					u8 stat_index;
 949					struct tomoyo_mini_stat *stat;
 950
 951					switch (index) {
 952					case TOMOYO_PATH1_UID:
 953					case TOMOYO_PATH1_GID:
 954					case TOMOYO_PATH1_INO:
 955					case TOMOYO_PATH1_MAJOR:
 956					case TOMOYO_PATH1_MINOR:
 957					case TOMOYO_PATH1_TYPE:
 958					case TOMOYO_PATH1_DEV_MAJOR:
 959					case TOMOYO_PATH1_DEV_MINOR:
 960					case TOMOYO_PATH1_PERM:
 961						stat_index = TOMOYO_PATH1;
 962						break;
 963					case TOMOYO_PATH2_UID:
 964					case TOMOYO_PATH2_GID:
 965					case TOMOYO_PATH2_INO:
 966					case TOMOYO_PATH2_MAJOR:
 967					case TOMOYO_PATH2_MINOR:
 968					case TOMOYO_PATH2_TYPE:
 969					case TOMOYO_PATH2_DEV_MAJOR:
 970					case TOMOYO_PATH2_DEV_MINOR:
 971					case TOMOYO_PATH2_PERM:
 972						stat_index = TOMOYO_PATH2;
 973						break;
 974					case TOMOYO_PATH1_PARENT_UID:
 975					case TOMOYO_PATH1_PARENT_GID:
 976					case TOMOYO_PATH1_PARENT_INO:
 977					case TOMOYO_PATH1_PARENT_PERM:
 978						stat_index =
 979							TOMOYO_PATH1_PARENT;
 980						break;
 981					case TOMOYO_PATH2_PARENT_UID:
 982					case TOMOYO_PATH2_PARENT_GID:
 983					case TOMOYO_PATH2_PARENT_INO:
 984					case TOMOYO_PATH2_PARENT_PERM:
 985						stat_index =
 986							TOMOYO_PATH2_PARENT;
 987						break;
 988					default:
 989						goto out;
 990					}
 991					if (!obj->stat_valid[stat_index])
 992						goto out;
 993					stat = &obj->stat[stat_index];
 994					switch (index) {
 995					case TOMOYO_PATH1_UID:
 996					case TOMOYO_PATH2_UID:
 997					case TOMOYO_PATH1_PARENT_UID:
 998					case TOMOYO_PATH2_PARENT_UID:
 999						value = from_kuid(&init_user_ns, stat->uid);
1000						break;
1001					case TOMOYO_PATH1_GID:
1002					case TOMOYO_PATH2_GID:
1003					case TOMOYO_PATH1_PARENT_GID:
1004					case TOMOYO_PATH2_PARENT_GID:
1005						value = from_kgid(&init_user_ns, stat->gid);
1006						break;
1007					case TOMOYO_PATH1_INO:
1008					case TOMOYO_PATH2_INO:
1009					case TOMOYO_PATH1_PARENT_INO:
1010					case TOMOYO_PATH2_PARENT_INO:
1011						value = stat->ino;
1012						break;
1013					case TOMOYO_PATH1_MAJOR:
1014					case TOMOYO_PATH2_MAJOR:
1015						value = MAJOR(stat->dev);
1016						break;
1017					case TOMOYO_PATH1_MINOR:
1018					case TOMOYO_PATH2_MINOR:
1019						value = MINOR(stat->dev);
1020						break;
1021					case TOMOYO_PATH1_TYPE:
1022					case TOMOYO_PATH2_TYPE:
1023						value = stat->mode & S_IFMT;
1024						break;
1025					case TOMOYO_PATH1_DEV_MAJOR:
1026					case TOMOYO_PATH2_DEV_MAJOR:
1027						value = MAJOR(stat->rdev);
1028						break;
1029					case TOMOYO_PATH1_DEV_MINOR:
1030					case TOMOYO_PATH2_DEV_MINOR:
1031						value = MINOR(stat->rdev);
1032						break;
1033					case TOMOYO_PATH1_PERM:
1034					case TOMOYO_PATH2_PERM:
1035					case TOMOYO_PATH1_PARENT_PERM:
1036					case TOMOYO_PATH2_PARENT_PERM:
1037						value = stat->mode & S_IALLUGO;
1038						break;
1039					}
1040				}
1041				break;
1042			}
1043			max_v[j] = value;
1044			min_v[j] = value;
1045			switch (index) {
1046			case TOMOYO_MODE_SETUID:
1047			case TOMOYO_MODE_SETGID:
1048			case TOMOYO_MODE_STICKY:
1049			case TOMOYO_MODE_OWNER_READ:
1050			case TOMOYO_MODE_OWNER_WRITE:
1051			case TOMOYO_MODE_OWNER_EXECUTE:
1052			case TOMOYO_MODE_GROUP_READ:
1053			case TOMOYO_MODE_GROUP_WRITE:
1054			case TOMOYO_MODE_GROUP_EXECUTE:
1055			case TOMOYO_MODE_OTHERS_READ:
1056			case TOMOYO_MODE_OTHERS_WRITE:
1057			case TOMOYO_MODE_OTHERS_EXECUTE:
1058				is_bitop[j] = true;
1059			}
1060		}
1061		if (left == TOMOYO_NUMBER_UNION) {
1062			/* Fetch values now. */
1063			const struct tomoyo_number_union *ptr = numbers_p++;
1064
1065			min_v[0] = ptr->values[0];
1066			max_v[0] = ptr->values[1];
1067		}
1068		if (right == TOMOYO_NUMBER_UNION) {
1069			/* Fetch values now. */
1070			const struct tomoyo_number_union *ptr = numbers_p++;
1071
1072			if (ptr->group) {
1073				if (tomoyo_number_matches_group(min_v[0],
1074								max_v[0],
1075								ptr->group)
1076				    == match)
1077					continue;
1078			} else {
1079				if ((min_v[0] <= ptr->values[1] &&
1080				     max_v[0] >= ptr->values[0]) == match)
1081					continue;
1082			}
1083			goto out;
1084		}
1085		/*
1086		 * Bit operation is valid only when counterpart value
1087		 * represents permission.
1088		 */
1089		if (is_bitop[0] && is_bitop[1]) {
1090			goto out;
1091		} else if (is_bitop[0]) {
1092			switch (right) {
1093			case TOMOYO_PATH1_PERM:
1094			case TOMOYO_PATH1_PARENT_PERM:
1095			case TOMOYO_PATH2_PERM:
1096			case TOMOYO_PATH2_PARENT_PERM:
1097				if (!(max_v[0] & max_v[1]) == !match)
1098					continue;
1099			}
1100			goto out;
1101		} else if (is_bitop[1]) {
1102			switch (left) {
1103			case TOMOYO_PATH1_PERM:
1104			case TOMOYO_PATH1_PARENT_PERM:
1105			case TOMOYO_PATH2_PERM:
1106			case TOMOYO_PATH2_PARENT_PERM:
1107				if (!(max_v[0] & max_v[1]) == !match)
1108					continue;
1109			}
1110			goto out;
1111		}
1112		/* Normal value range comparison. */
1113		if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match)
1114			continue;
1115out:
1116		return false;
1117	}
1118	/* Check argv[] and envp[] now. */
1119	if (r->ee && (argc || envc))
1120		return tomoyo_scan_bprm(r->ee, argc, argv, envc, envp);
1121	return true;
1122}
v5.9
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * security/tomoyo/condition.c
   4 *
   5 * Copyright (C) 2005-2011  NTT DATA CORPORATION
   6 */
   7
   8#include "common.h"
   9#include <linux/slab.h>
  10
  11/* List of "struct tomoyo_condition". */
  12LIST_HEAD(tomoyo_condition_list);
  13
  14/**
  15 * tomoyo_argv - Check argv[] in "struct linux_binbrm".
  16 *
  17 * @index:   Index number of @arg_ptr.
  18 * @arg_ptr: Contents of argv[@index].
  19 * @argc:    Length of @argv.
  20 * @argv:    Pointer to "struct tomoyo_argv".
  21 * @checked: Set to true if @argv[@index] was found.
  22 *
  23 * Returns true on success, false otherwise.
  24 */
  25static bool tomoyo_argv(const unsigned int index, const char *arg_ptr,
  26			const int argc, const struct tomoyo_argv *argv,
  27			u8 *checked)
  28{
  29	int i;
  30	struct tomoyo_path_info arg;
  31
  32	arg.name = arg_ptr;
  33	for (i = 0; i < argc; argv++, checked++, i++) {
  34		bool result;
  35
  36		if (index != argv->index)
  37			continue;
  38		*checked = 1;
  39		tomoyo_fill_path_info(&arg);
  40		result = tomoyo_path_matches_pattern(&arg, argv->value);
  41		if (argv->is_not)
  42			result = !result;
  43		if (!result)
  44			return false;
  45	}
  46	return true;
  47}
  48
  49/**
  50 * tomoyo_envp - Check envp[] in "struct linux_binbrm".
  51 *
  52 * @env_name:  The name of environment variable.
  53 * @env_value: The value of environment variable.
  54 * @envc:      Length of @envp.
  55 * @envp:      Pointer to "struct tomoyo_envp".
  56 * @checked:   Set to true if @envp[@env_name] was found.
  57 *
  58 * Returns true on success, false otherwise.
  59 */
  60static bool tomoyo_envp(const char *env_name, const char *env_value,
  61			const int envc, const struct tomoyo_envp *envp,
  62			u8 *checked)
  63{
  64	int i;
  65	struct tomoyo_path_info name;
  66	struct tomoyo_path_info value;
  67
  68	name.name = env_name;
  69	tomoyo_fill_path_info(&name);
  70	value.name = env_value;
  71	tomoyo_fill_path_info(&value);
  72	for (i = 0; i < envc; envp++, checked++, i++) {
  73		bool result;
  74
  75		if (!tomoyo_path_matches_pattern(&name, envp->name))
  76			continue;
  77		*checked = 1;
  78		if (envp->value) {
  79			result = tomoyo_path_matches_pattern(&value,
  80							     envp->value);
  81			if (envp->is_not)
  82				result = !result;
  83		} else {
  84			result = true;
  85			if (!envp->is_not)
  86				result = !result;
  87		}
  88		if (!result)
  89			return false;
  90	}
  91	return true;
  92}
  93
  94/**
  95 * tomoyo_scan_bprm - Scan "struct linux_binprm".
  96 *
  97 * @ee:   Pointer to "struct tomoyo_execve".
  98 * @argc: Length of @argc.
  99 * @argv: Pointer to "struct tomoyo_argv".
 100 * @envc: Length of @envp.
 101 * @envp: Poiner to "struct tomoyo_envp".
 102 *
 103 * Returns true on success, false otherwise.
 104 */
 105static bool tomoyo_scan_bprm(struct tomoyo_execve *ee,
 106			     const u16 argc, const struct tomoyo_argv *argv,
 107			     const u16 envc, const struct tomoyo_envp *envp)
 108{
 109	struct linux_binprm *bprm = ee->bprm;
 110	struct tomoyo_page_dump *dump = &ee->dump;
 111	char *arg_ptr = ee->tmp;
 112	int arg_len = 0;
 113	unsigned long pos = bprm->p;
 114	int offset = pos % PAGE_SIZE;
 115	int argv_count = bprm->argc;
 116	int envp_count = bprm->envc;
 117	bool result = true;
 118	u8 local_checked[32];
 119	u8 *checked;
 120
 121	if (argc + envc <= sizeof(local_checked)) {
 122		checked = local_checked;
 123		memset(local_checked, 0, sizeof(local_checked));
 124	} else {
 125		checked = kzalloc(argc + envc, GFP_NOFS);
 126		if (!checked)
 127			return false;
 128	}
 129	while (argv_count || envp_count) {
 130		if (!tomoyo_dump_page(bprm, pos, dump)) {
 131			result = false;
 132			goto out;
 133		}
 134		pos += PAGE_SIZE - offset;
 135		while (offset < PAGE_SIZE) {
 136			/* Read. */
 137			const char *kaddr = dump->data;
 138			const unsigned char c = kaddr[offset++];
 139
 140			if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) {
 141				if (c == '\\') {
 142					arg_ptr[arg_len++] = '\\';
 143					arg_ptr[arg_len++] = '\\';
 144				} else if (c > ' ' && c < 127) {
 145					arg_ptr[arg_len++] = c;
 146				} else {
 147					arg_ptr[arg_len++] = '\\';
 148					arg_ptr[arg_len++] = (c >> 6) + '0';
 149					arg_ptr[arg_len++] =
 150						((c >> 3) & 7) + '0';
 151					arg_ptr[arg_len++] = (c & 7) + '0';
 152				}
 153			} else {
 154				arg_ptr[arg_len] = '\0';
 155			}
 156			if (c)
 157				continue;
 158			/* Check. */
 159			if (argv_count) {
 160				if (!tomoyo_argv(bprm->argc - argv_count,
 161						 arg_ptr, argc, argv,
 162						 checked)) {
 163					result = false;
 164					break;
 165				}
 166				argv_count--;
 167			} else if (envp_count) {
 168				char *cp = strchr(arg_ptr, '=');
 169
 170				if (cp) {
 171					*cp = '\0';
 172					if (!tomoyo_envp(arg_ptr, cp + 1,
 173							 envc, envp,
 174							 checked + argc)) {
 175						result = false;
 176						break;
 177					}
 178				}
 179				envp_count--;
 180			} else {
 181				break;
 182			}
 183			arg_len = 0;
 184		}
 185		offset = 0;
 186		if (!result)
 187			break;
 188	}
 189out:
 190	if (result) {
 191		int i;
 192
 193		/* Check not-yet-checked entries. */
 194		for (i = 0; i < argc; i++) {
 195			if (checked[i])
 196				continue;
 197			/*
 198			 * Return true only if all unchecked indexes in
 199			 * bprm->argv[] are not matched.
 200			 */
 201			if (argv[i].is_not)
 202				continue;
 203			result = false;
 204			break;
 205		}
 206		for (i = 0; i < envc; envp++, i++) {
 207			if (checked[argc + i])
 208				continue;
 209			/*
 210			 * Return true only if all unchecked environ variables
 211			 * in bprm->envp[] are either undefined or not matched.
 212			 */
 213			if ((!envp->value && !envp->is_not) ||
 214			    (envp->value && envp->is_not))
 215				continue;
 216			result = false;
 217			break;
 218		}
 219	}
 220	if (checked != local_checked)
 221		kfree(checked);
 222	return result;
 223}
 224
 225/**
 226 * tomoyo_scan_exec_realpath - Check "exec.realpath" parameter of "struct tomoyo_condition".
 227 *
 228 * @file:  Pointer to "struct file".
 229 * @ptr:   Pointer to "struct tomoyo_name_union".
 230 * @match: True if "exec.realpath=", false if "exec.realpath!=".
 231 *
 232 * Returns true on success, false otherwise.
 233 */
 234static bool tomoyo_scan_exec_realpath(struct file *file,
 235				      const struct tomoyo_name_union *ptr,
 236				      const bool match)
 237{
 238	bool result;
 239	struct tomoyo_path_info exe;
 240
 241	if (!file)
 242		return false;
 243	exe.name = tomoyo_realpath_from_path(&file->f_path);
 244	if (!exe.name)
 245		return false;
 246	tomoyo_fill_path_info(&exe);
 247	result = tomoyo_compare_name_union(&exe, ptr);
 248	kfree(exe.name);
 249	return result == match;
 250}
 251
 252/**
 253 * tomoyo_get_dqword - tomoyo_get_name() for a quoted string.
 254 *
 255 * @start: String to save.
 256 *
 257 * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
 258 */
 259static const struct tomoyo_path_info *tomoyo_get_dqword(char *start)
 260{
 261	char *cp = start + strlen(start) - 1;
 262
 263	if (cp == start || *start++ != '"' || *cp != '"')
 264		return NULL;
 265	*cp = '\0';
 266	if (*start && !tomoyo_correct_word(start))
 267		return NULL;
 268	return tomoyo_get_name(start);
 269}
 270
 271/**
 272 * tomoyo_parse_name_union_quoted - Parse a quoted word.
 273 *
 274 * @param: Pointer to "struct tomoyo_acl_param".
 275 * @ptr:   Pointer to "struct tomoyo_name_union".
 276 *
 277 * Returns true on success, false otherwise.
 278 */
 279static bool tomoyo_parse_name_union_quoted(struct tomoyo_acl_param *param,
 280					   struct tomoyo_name_union *ptr)
 281{
 282	char *filename = param->data;
 283
 284	if (*filename == '@')
 285		return tomoyo_parse_name_union(param, ptr);
 286	ptr->filename = tomoyo_get_dqword(filename);
 287	return ptr->filename != NULL;
 288}
 289
 290/**
 291 * tomoyo_parse_argv - Parse an argv[] condition part.
 292 *
 293 * @left:  Lefthand value.
 294 * @right: Righthand value.
 295 * @argv:  Pointer to "struct tomoyo_argv".
 296 *
 297 * Returns true on success, false otherwise.
 298 */
 299static bool tomoyo_parse_argv(char *left, char *right,
 300			      struct tomoyo_argv *argv)
 301{
 302	if (tomoyo_parse_ulong(&argv->index, &left) !=
 303	    TOMOYO_VALUE_TYPE_DECIMAL || *left++ != ']' || *left)
 304		return false;
 305	argv->value = tomoyo_get_dqword(right);
 306	return argv->value != NULL;
 307}
 308
 309/**
 310 * tomoyo_parse_envp - Parse an envp[] condition part.
 311 *
 312 * @left:  Lefthand value.
 313 * @right: Righthand value.
 314 * @envp:  Pointer to "struct tomoyo_envp".
 315 *
 316 * Returns true on success, false otherwise.
 317 */
 318static bool tomoyo_parse_envp(char *left, char *right,
 319			      struct tomoyo_envp *envp)
 320{
 321	const struct tomoyo_path_info *name;
 322	const struct tomoyo_path_info *value;
 323	char *cp = left + strlen(left) - 1;
 324
 325	if (*cp-- != ']' || *cp != '"')
 326		goto out;
 327	*cp = '\0';
 328	if (!tomoyo_correct_word(left))
 329		goto out;
 330	name = tomoyo_get_name(left);
 331	if (!name)
 332		goto out;
 333	if (!strcmp(right, "NULL")) {
 334		value = NULL;
 335	} else {
 336		value = tomoyo_get_dqword(right);
 337		if (!value) {
 338			tomoyo_put_name(name);
 339			goto out;
 340		}
 341	}
 342	envp->name = name;
 343	envp->value = value;
 344	return true;
 345out:
 346	return false;
 347}
 348
 349/**
 350 * tomoyo_same_condition - Check for duplicated "struct tomoyo_condition" entry.
 351 *
 352 * @a: Pointer to "struct tomoyo_condition".
 353 * @b: Pointer to "struct tomoyo_condition".
 354 *
 355 * Returns true if @a == @b, false otherwise.
 356 */
 357static inline bool tomoyo_same_condition(const struct tomoyo_condition *a,
 358					 const struct tomoyo_condition *b)
 359{
 360	return a->size == b->size && a->condc == b->condc &&
 361		a->numbers_count == b->numbers_count &&
 362		a->names_count == b->names_count &&
 363		a->argc == b->argc && a->envc == b->envc &&
 364		a->grant_log == b->grant_log && a->transit == b->transit &&
 365		!memcmp(a + 1, b + 1, a->size - sizeof(*a));
 366}
 367
 368/**
 369 * tomoyo_condition_type - Get condition type.
 370 *
 371 * @word: Keyword string.
 372 *
 373 * Returns one of values in "enum tomoyo_conditions_index" on success,
 374 * TOMOYO_MAX_CONDITION_KEYWORD otherwise.
 375 */
 376static u8 tomoyo_condition_type(const char *word)
 377{
 378	u8 i;
 379
 380	for (i = 0; i < TOMOYO_MAX_CONDITION_KEYWORD; i++) {
 381		if (!strcmp(word, tomoyo_condition_keyword[i]))
 382			break;
 383	}
 384	return i;
 385}
 386
 387/* Define this to enable debug mode. */
 388/* #define DEBUG_CONDITION */
 389
 390#ifdef DEBUG_CONDITION
 391#define dprintk printk
 392#else
 393#define dprintk(...) do { } while (0)
 394#endif
 395
 396/**
 397 * tomoyo_commit_condition - Commit "struct tomoyo_condition".
 398 *
 399 * @entry: Pointer to "struct tomoyo_condition".
 400 *
 401 * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
 402 *
 403 * This function merges duplicated entries. This function returns NULL if
 404 * @entry is not duplicated but memory quota for policy has exceeded.
 405 */
 406static struct tomoyo_condition *tomoyo_commit_condition
 407(struct tomoyo_condition *entry)
 408{
 409	struct tomoyo_condition *ptr;
 410	bool found = false;
 411
 412	if (mutex_lock_interruptible(&tomoyo_policy_lock)) {
 413		dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
 414		ptr = NULL;
 415		found = true;
 416		goto out;
 417	}
 418	list_for_each_entry(ptr, &tomoyo_condition_list, head.list) {
 419		if (!tomoyo_same_condition(ptr, entry) ||
 420		    atomic_read(&ptr->head.users) == TOMOYO_GC_IN_PROGRESS)
 421			continue;
 422		/* Same entry found. Share this entry. */
 423		atomic_inc(&ptr->head.users);
 424		found = true;
 425		break;
 426	}
 427	if (!found) {
 428		if (tomoyo_memory_ok(entry)) {
 429			atomic_set(&entry->head.users, 1);
 430			list_add(&entry->head.list, &tomoyo_condition_list);
 431		} else {
 432			found = true;
 433			ptr = NULL;
 434		}
 435	}
 436	mutex_unlock(&tomoyo_policy_lock);
 437out:
 438	if (found) {
 439		tomoyo_del_condition(&entry->head.list);
 440		kfree(entry);
 441		entry = ptr;
 442	}
 443	return entry;
 444}
 445
 446/**
 447 * tomoyo_get_transit_preference - Parse domain transition preference for execve().
 448 *
 449 * @param: Pointer to "struct tomoyo_acl_param".
 450 * @e:     Pointer to "struct tomoyo_condition".
 451 *
 452 * Returns the condition string part.
 453 */
 454static char *tomoyo_get_transit_preference(struct tomoyo_acl_param *param,
 455					   struct tomoyo_condition *e)
 456{
 457	char * const pos = param->data;
 458	bool flag;
 459
 460	if (*pos == '<') {
 461		e->transit = tomoyo_get_domainname(param);
 462		goto done;
 463	}
 464	{
 465		char *cp = strchr(pos, ' ');
 466
 467		if (cp)
 468			*cp = '\0';
 469		flag = tomoyo_correct_path(pos) || !strcmp(pos, "keep") ||
 470			!strcmp(pos, "initialize") || !strcmp(pos, "reset") ||
 471			!strcmp(pos, "child") || !strcmp(pos, "parent");
 472		if (cp)
 473			*cp = ' ';
 474	}
 475	if (!flag)
 476		return pos;
 477	e->transit = tomoyo_get_name(tomoyo_read_token(param));
 478done:
 479	if (e->transit)
 480		return param->data;
 481	/*
 482	 * Return a bad read-only condition string that will let
 483	 * tomoyo_get_condition() return NULL.
 484	 */
 485	return "/";
 486}
 487
 488/**
 489 * tomoyo_get_condition - Parse condition part.
 490 *
 491 * @param: Pointer to "struct tomoyo_acl_param".
 492 *
 493 * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
 494 */
 495struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param)
 496{
 497	struct tomoyo_condition *entry = NULL;
 498	struct tomoyo_condition_element *condp = NULL;
 499	struct tomoyo_number_union *numbers_p = NULL;
 500	struct tomoyo_name_union *names_p = NULL;
 501	struct tomoyo_argv *argv = NULL;
 502	struct tomoyo_envp *envp = NULL;
 503	struct tomoyo_condition e = { };
 504	char * const start_of_string =
 505		tomoyo_get_transit_preference(param, &e);
 506	char * const end_of_string = start_of_string + strlen(start_of_string);
 507	char *pos;
 508
 509rerun:
 510	pos = start_of_string;
 511	while (1) {
 512		u8 left = -1;
 513		u8 right = -1;
 514		char *left_word = pos;
 515		char *cp;
 516		char *right_word;
 517		bool is_not;
 518
 519		if (!*left_word)
 520			break;
 521		/*
 522		 * Since left-hand condition does not allow use of "path_group"
 523		 * or "number_group" and environment variable's names do not
 524		 * accept '=', it is guaranteed that the original line consists
 525		 * of one or more repetition of $left$operator$right blocks
 526		 * where "$left is free from '=' and ' '" and "$operator is
 527		 * either '=' or '!='" and "$right is free from ' '".
 528		 * Therefore, we can reconstruct the original line at the end
 529		 * of dry run even if we overwrite $operator with '\0'.
 530		 */
 531		cp = strchr(pos, ' ');
 532		if (cp) {
 533			*cp = '\0'; /* Will restore later. */
 534			pos = cp + 1;
 535		} else {
 536			pos = "";
 537		}
 538		right_word = strchr(left_word, '=');
 539		if (!right_word || right_word == left_word)
 540			goto out;
 541		is_not = *(right_word - 1) == '!';
 542		if (is_not)
 543			*(right_word++ - 1) = '\0'; /* Will restore later. */
 544		else if (*(right_word + 1) != '=')
 545			*right_word++ = '\0'; /* Will restore later. */
 546		else
 547			goto out;
 548		dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word,
 549			is_not ? "!" : "", right_word);
 550		if (!strcmp(left_word, "grant_log")) {
 551			if (entry) {
 552				if (is_not ||
 553				    entry->grant_log != TOMOYO_GRANTLOG_AUTO)
 554					goto out;
 555				else if (!strcmp(right_word, "yes"))
 556					entry->grant_log = TOMOYO_GRANTLOG_YES;
 557				else if (!strcmp(right_word, "no"))
 558					entry->grant_log = TOMOYO_GRANTLOG_NO;
 559				else
 560					goto out;
 561			}
 562			continue;
 563		}
 564		if (!strncmp(left_word, "exec.argv[", 10)) {
 565			if (!argv) {
 566				e.argc++;
 567				e.condc++;
 568			} else {
 569				e.argc--;
 570				e.condc--;
 571				left = TOMOYO_ARGV_ENTRY;
 572				argv->is_not = is_not;
 573				if (!tomoyo_parse_argv(left_word + 10,
 574						       right_word, argv++))
 575					goto out;
 576			}
 577			goto store_value;
 578		}
 579		if (!strncmp(left_word, "exec.envp[\"", 11)) {
 580			if (!envp) {
 581				e.envc++;
 582				e.condc++;
 583			} else {
 584				e.envc--;
 585				e.condc--;
 586				left = TOMOYO_ENVP_ENTRY;
 587				envp->is_not = is_not;
 588				if (!tomoyo_parse_envp(left_word + 11,
 589						       right_word, envp++))
 590					goto out;
 591			}
 592			goto store_value;
 593		}
 594		left = tomoyo_condition_type(left_word);
 595		dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, left_word,
 596			left);
 597		if (left == TOMOYO_MAX_CONDITION_KEYWORD) {
 598			if (!numbers_p) {
 599				e.numbers_count++;
 600			} else {
 601				e.numbers_count--;
 602				left = TOMOYO_NUMBER_UNION;
 603				param->data = left_word;
 604				if (*left_word == '@' ||
 605				    !tomoyo_parse_number_union(param,
 606							       numbers_p++))
 607					goto out;
 608			}
 609		}
 610		if (!condp)
 611			e.condc++;
 612		else
 613			e.condc--;
 614		if (left == TOMOYO_EXEC_REALPATH ||
 615		    left == TOMOYO_SYMLINK_TARGET) {
 616			if (!names_p) {
 617				e.names_count++;
 618			} else {
 619				e.names_count--;
 620				right = TOMOYO_NAME_UNION;
 621				param->data = right_word;
 622				if (!tomoyo_parse_name_union_quoted(param,
 623								    names_p++))
 624					goto out;
 625			}
 626			goto store_value;
 627		}
 628		right = tomoyo_condition_type(right_word);
 629		if (right == TOMOYO_MAX_CONDITION_KEYWORD) {
 630			if (!numbers_p) {
 631				e.numbers_count++;
 632			} else {
 633				e.numbers_count--;
 634				right = TOMOYO_NUMBER_UNION;
 635				param->data = right_word;
 636				if (!tomoyo_parse_number_union(param,
 637							       numbers_p++))
 638					goto out;
 639			}
 640		}
 641store_value:
 642		if (!condp) {
 643			dprintk(KERN_WARNING "%u: dry_run left=%u right=%u match=%u\n",
 644				__LINE__, left, right, !is_not);
 645			continue;
 646		}
 647		condp->left = left;
 648		condp->right = right;
 649		condp->equals = !is_not;
 650		dprintk(KERN_WARNING "%u: left=%u right=%u match=%u\n",
 651			__LINE__, condp->left, condp->right,
 652			condp->equals);
 653		condp++;
 654	}
 655	dprintk(KERN_INFO "%u: cond=%u numbers=%u names=%u ac=%u ec=%u\n",
 656		__LINE__, e.condc, e.numbers_count, e.names_count, e.argc,
 657		e.envc);
 658	if (entry) {
 659		BUG_ON(e.names_count | e.numbers_count | e.argc | e.envc |
 660		       e.condc);
 661		return tomoyo_commit_condition(entry);
 662	}
 663	e.size = sizeof(*entry)
 664		+ e.condc * sizeof(struct tomoyo_condition_element)
 665		+ e.numbers_count * sizeof(struct tomoyo_number_union)
 666		+ e.names_count * sizeof(struct tomoyo_name_union)
 667		+ e.argc * sizeof(struct tomoyo_argv)
 668		+ e.envc * sizeof(struct tomoyo_envp);
 669	entry = kzalloc(e.size, GFP_NOFS);
 670	if (!entry)
 671		goto out2;
 672	*entry = e;
 673	e.transit = NULL;
 674	condp = (struct tomoyo_condition_element *) (entry + 1);
 675	numbers_p = (struct tomoyo_number_union *) (condp + e.condc);
 676	names_p = (struct tomoyo_name_union *) (numbers_p + e.numbers_count);
 677	argv = (struct tomoyo_argv *) (names_p + e.names_count);
 678	envp = (struct tomoyo_envp *) (argv + e.argc);
 679	{
 680		bool flag = false;
 681
 682		for (pos = start_of_string; pos < end_of_string; pos++) {
 683			if (*pos)
 684				continue;
 685			if (flag) /* Restore " ". */
 686				*pos = ' ';
 687			else if (*(pos + 1) == '=') /* Restore "!=". */
 688				*pos = '!';
 689			else /* Restore "=". */
 690				*pos = '=';
 691			flag = !flag;
 692		}
 693	}
 694	goto rerun;
 695out:
 696	dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
 697	if (entry) {
 698		tomoyo_del_condition(&entry->head.list);
 699		kfree(entry);
 700	}
 701out2:
 702	tomoyo_put_name(e.transit);
 703	return NULL;
 704}
 705
 706/**
 707 * tomoyo_get_attributes - Revalidate "struct inode".
 708 *
 709 * @obj: Pointer to "struct tomoyo_obj_info".
 710 *
 711 * Returns nothing.
 712 */
 713void tomoyo_get_attributes(struct tomoyo_obj_info *obj)
 714{
 715	u8 i;
 716	struct dentry *dentry = NULL;
 717
 718	for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) {
 719		struct inode *inode;
 720
 721		switch (i) {
 722		case TOMOYO_PATH1:
 723			dentry = obj->path1.dentry;
 724			if (!dentry)
 725				continue;
 726			break;
 727		case TOMOYO_PATH2:
 728			dentry = obj->path2.dentry;
 729			if (!dentry)
 730				continue;
 731			break;
 732		default:
 733			if (!dentry)
 734				continue;
 735			dentry = dget_parent(dentry);
 736			break;
 737		}
 738		inode = d_backing_inode(dentry);
 739		if (inode) {
 740			struct tomoyo_mini_stat *stat = &obj->stat[i];
 741
 742			stat->uid  = inode->i_uid;
 743			stat->gid  = inode->i_gid;
 744			stat->ino  = inode->i_ino;
 745			stat->mode = inode->i_mode;
 746			stat->dev  = inode->i_sb->s_dev;
 747			stat->rdev = inode->i_rdev;
 748			obj->stat_valid[i] = true;
 749		}
 750		if (i & 1) /* TOMOYO_PATH1_PARENT or TOMOYO_PATH2_PARENT */
 751			dput(dentry);
 752	}
 753}
 754
 755/**
 756 * tomoyo_condition - Check condition part.
 757 *
 758 * @r:    Pointer to "struct tomoyo_request_info".
 759 * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
 760 *
 761 * Returns true on success, false otherwise.
 762 *
 763 * Caller holds tomoyo_read_lock().
 764 */
 765bool tomoyo_condition(struct tomoyo_request_info *r,
 766		      const struct tomoyo_condition *cond)
 767{
 768	u32 i;
 769	unsigned long min_v[2] = { 0, 0 };
 770	unsigned long max_v[2] = { 0, 0 };
 771	const struct tomoyo_condition_element *condp;
 772	const struct tomoyo_number_union *numbers_p;
 773	const struct tomoyo_name_union *names_p;
 774	const struct tomoyo_argv *argv;
 775	const struct tomoyo_envp *envp;
 776	struct tomoyo_obj_info *obj;
 777	u16 condc;
 778	u16 argc;
 779	u16 envc;
 780	struct linux_binprm *bprm = NULL;
 781
 782	if (!cond)
 783		return true;
 784	condc = cond->condc;
 785	argc = cond->argc;
 786	envc = cond->envc;
 787	obj = r->obj;
 788	if (r->ee)
 789		bprm = r->ee->bprm;
 790	if (!bprm && (argc || envc))
 791		return false;
 792	condp = (struct tomoyo_condition_element *) (cond + 1);
 793	numbers_p = (const struct tomoyo_number_union *) (condp + condc);
 794	names_p = (const struct tomoyo_name_union *)
 795		(numbers_p + cond->numbers_count);
 796	argv = (const struct tomoyo_argv *) (names_p + cond->names_count);
 797	envp = (const struct tomoyo_envp *) (argv + argc);
 798	for (i = 0; i < condc; i++) {
 799		const bool match = condp->equals;
 800		const u8 left = condp->left;
 801		const u8 right = condp->right;
 802		bool is_bitop[2] = { false, false };
 803		u8 j;
 804
 805		condp++;
 806		/* Check argv[] and envp[] later. */
 807		if (left == TOMOYO_ARGV_ENTRY || left == TOMOYO_ENVP_ENTRY)
 808			continue;
 809		/* Check string expressions. */
 810		if (right == TOMOYO_NAME_UNION) {
 811			const struct tomoyo_name_union *ptr = names_p++;
 812			struct tomoyo_path_info *symlink;
 813			struct tomoyo_execve *ee;
 814			struct file *file;
 815
 816			switch (left) {
 817			case TOMOYO_SYMLINK_TARGET:
 818				symlink = obj ? obj->symlink_target : NULL;
 819				if (!symlink ||
 820				    !tomoyo_compare_name_union(symlink, ptr)
 821				    == match)
 822					goto out;
 823				break;
 824			case TOMOYO_EXEC_REALPATH:
 825				ee = r->ee;
 826				file = ee ? ee->bprm->file : NULL;
 827				if (!tomoyo_scan_exec_realpath(file, ptr,
 828							       match))
 829					goto out;
 830				break;
 831			}
 832			continue;
 833		}
 834		/* Check numeric or bit-op expressions. */
 835		for (j = 0; j < 2; j++) {
 836			const u8 index = j ? right : left;
 837			unsigned long value = 0;
 838
 839			switch (index) {
 840			case TOMOYO_TASK_UID:
 841				value = from_kuid(&init_user_ns, current_uid());
 842				break;
 843			case TOMOYO_TASK_EUID:
 844				value = from_kuid(&init_user_ns, current_euid());
 845				break;
 846			case TOMOYO_TASK_SUID:
 847				value = from_kuid(&init_user_ns, current_suid());
 848				break;
 849			case TOMOYO_TASK_FSUID:
 850				value = from_kuid(&init_user_ns, current_fsuid());
 851				break;
 852			case TOMOYO_TASK_GID:
 853				value = from_kgid(&init_user_ns, current_gid());
 854				break;
 855			case TOMOYO_TASK_EGID:
 856				value = from_kgid(&init_user_ns, current_egid());
 857				break;
 858			case TOMOYO_TASK_SGID:
 859				value = from_kgid(&init_user_ns, current_sgid());
 860				break;
 861			case TOMOYO_TASK_FSGID:
 862				value = from_kgid(&init_user_ns, current_fsgid());
 863				break;
 864			case TOMOYO_TASK_PID:
 865				value = tomoyo_sys_getpid();
 866				break;
 867			case TOMOYO_TASK_PPID:
 868				value = tomoyo_sys_getppid();
 869				break;
 870			case TOMOYO_TYPE_IS_SOCKET:
 871				value = S_IFSOCK;
 872				break;
 873			case TOMOYO_TYPE_IS_SYMLINK:
 874				value = S_IFLNK;
 875				break;
 876			case TOMOYO_TYPE_IS_FILE:
 877				value = S_IFREG;
 878				break;
 879			case TOMOYO_TYPE_IS_BLOCK_DEV:
 880				value = S_IFBLK;
 881				break;
 882			case TOMOYO_TYPE_IS_DIRECTORY:
 883				value = S_IFDIR;
 884				break;
 885			case TOMOYO_TYPE_IS_CHAR_DEV:
 886				value = S_IFCHR;
 887				break;
 888			case TOMOYO_TYPE_IS_FIFO:
 889				value = S_IFIFO;
 890				break;
 891			case TOMOYO_MODE_SETUID:
 892				value = S_ISUID;
 893				break;
 894			case TOMOYO_MODE_SETGID:
 895				value = S_ISGID;
 896				break;
 897			case TOMOYO_MODE_STICKY:
 898				value = S_ISVTX;
 899				break;
 900			case TOMOYO_MODE_OWNER_READ:
 901				value = 0400;
 902				break;
 903			case TOMOYO_MODE_OWNER_WRITE:
 904				value = 0200;
 905				break;
 906			case TOMOYO_MODE_OWNER_EXECUTE:
 907				value = 0100;
 908				break;
 909			case TOMOYO_MODE_GROUP_READ:
 910				value = 0040;
 911				break;
 912			case TOMOYO_MODE_GROUP_WRITE:
 913				value = 0020;
 914				break;
 915			case TOMOYO_MODE_GROUP_EXECUTE:
 916				value = 0010;
 917				break;
 918			case TOMOYO_MODE_OTHERS_READ:
 919				value = 0004;
 920				break;
 921			case TOMOYO_MODE_OTHERS_WRITE:
 922				value = 0002;
 923				break;
 924			case TOMOYO_MODE_OTHERS_EXECUTE:
 925				value = 0001;
 926				break;
 927			case TOMOYO_EXEC_ARGC:
 928				if (!bprm)
 929					goto out;
 930				value = bprm->argc;
 931				break;
 932			case TOMOYO_EXEC_ENVC:
 933				if (!bprm)
 934					goto out;
 935				value = bprm->envc;
 936				break;
 937			case TOMOYO_NUMBER_UNION:
 938				/* Fetch values later. */
 939				break;
 940			default:
 941				if (!obj)
 942					goto out;
 943				if (!obj->validate_done) {
 944					tomoyo_get_attributes(obj);
 945					obj->validate_done = true;
 946				}
 947				{
 948					u8 stat_index;
 949					struct tomoyo_mini_stat *stat;
 950
 951					switch (index) {
 952					case TOMOYO_PATH1_UID:
 953					case TOMOYO_PATH1_GID:
 954					case TOMOYO_PATH1_INO:
 955					case TOMOYO_PATH1_MAJOR:
 956					case TOMOYO_PATH1_MINOR:
 957					case TOMOYO_PATH1_TYPE:
 958					case TOMOYO_PATH1_DEV_MAJOR:
 959					case TOMOYO_PATH1_DEV_MINOR:
 960					case TOMOYO_PATH1_PERM:
 961						stat_index = TOMOYO_PATH1;
 962						break;
 963					case TOMOYO_PATH2_UID:
 964					case TOMOYO_PATH2_GID:
 965					case TOMOYO_PATH2_INO:
 966					case TOMOYO_PATH2_MAJOR:
 967					case TOMOYO_PATH2_MINOR:
 968					case TOMOYO_PATH2_TYPE:
 969					case TOMOYO_PATH2_DEV_MAJOR:
 970					case TOMOYO_PATH2_DEV_MINOR:
 971					case TOMOYO_PATH2_PERM:
 972						stat_index = TOMOYO_PATH2;
 973						break;
 974					case TOMOYO_PATH1_PARENT_UID:
 975					case TOMOYO_PATH1_PARENT_GID:
 976					case TOMOYO_PATH1_PARENT_INO:
 977					case TOMOYO_PATH1_PARENT_PERM:
 978						stat_index =
 979							TOMOYO_PATH1_PARENT;
 980						break;
 981					case TOMOYO_PATH2_PARENT_UID:
 982					case TOMOYO_PATH2_PARENT_GID:
 983					case TOMOYO_PATH2_PARENT_INO:
 984					case TOMOYO_PATH2_PARENT_PERM:
 985						stat_index =
 986							TOMOYO_PATH2_PARENT;
 987						break;
 988					default:
 989						goto out;
 990					}
 991					if (!obj->stat_valid[stat_index])
 992						goto out;
 993					stat = &obj->stat[stat_index];
 994					switch (index) {
 995					case TOMOYO_PATH1_UID:
 996					case TOMOYO_PATH2_UID:
 997					case TOMOYO_PATH1_PARENT_UID:
 998					case TOMOYO_PATH2_PARENT_UID:
 999						value = from_kuid(&init_user_ns, stat->uid);
1000						break;
1001					case TOMOYO_PATH1_GID:
1002					case TOMOYO_PATH2_GID:
1003					case TOMOYO_PATH1_PARENT_GID:
1004					case TOMOYO_PATH2_PARENT_GID:
1005						value = from_kgid(&init_user_ns, stat->gid);
1006						break;
1007					case TOMOYO_PATH1_INO:
1008					case TOMOYO_PATH2_INO:
1009					case TOMOYO_PATH1_PARENT_INO:
1010					case TOMOYO_PATH2_PARENT_INO:
1011						value = stat->ino;
1012						break;
1013					case TOMOYO_PATH1_MAJOR:
1014					case TOMOYO_PATH2_MAJOR:
1015						value = MAJOR(stat->dev);
1016						break;
1017					case TOMOYO_PATH1_MINOR:
1018					case TOMOYO_PATH2_MINOR:
1019						value = MINOR(stat->dev);
1020						break;
1021					case TOMOYO_PATH1_TYPE:
1022					case TOMOYO_PATH2_TYPE:
1023						value = stat->mode & S_IFMT;
1024						break;
1025					case TOMOYO_PATH1_DEV_MAJOR:
1026					case TOMOYO_PATH2_DEV_MAJOR:
1027						value = MAJOR(stat->rdev);
1028						break;
1029					case TOMOYO_PATH1_DEV_MINOR:
1030					case TOMOYO_PATH2_DEV_MINOR:
1031						value = MINOR(stat->rdev);
1032						break;
1033					case TOMOYO_PATH1_PERM:
1034					case TOMOYO_PATH2_PERM:
1035					case TOMOYO_PATH1_PARENT_PERM:
1036					case TOMOYO_PATH2_PARENT_PERM:
1037						value = stat->mode & S_IALLUGO;
1038						break;
1039					}
1040				}
1041				break;
1042			}
1043			max_v[j] = value;
1044			min_v[j] = value;
1045			switch (index) {
1046			case TOMOYO_MODE_SETUID:
1047			case TOMOYO_MODE_SETGID:
1048			case TOMOYO_MODE_STICKY:
1049			case TOMOYO_MODE_OWNER_READ:
1050			case TOMOYO_MODE_OWNER_WRITE:
1051			case TOMOYO_MODE_OWNER_EXECUTE:
1052			case TOMOYO_MODE_GROUP_READ:
1053			case TOMOYO_MODE_GROUP_WRITE:
1054			case TOMOYO_MODE_GROUP_EXECUTE:
1055			case TOMOYO_MODE_OTHERS_READ:
1056			case TOMOYO_MODE_OTHERS_WRITE:
1057			case TOMOYO_MODE_OTHERS_EXECUTE:
1058				is_bitop[j] = true;
1059			}
1060		}
1061		if (left == TOMOYO_NUMBER_UNION) {
1062			/* Fetch values now. */
1063			const struct tomoyo_number_union *ptr = numbers_p++;
1064
1065			min_v[0] = ptr->values[0];
1066			max_v[0] = ptr->values[1];
1067		}
1068		if (right == TOMOYO_NUMBER_UNION) {
1069			/* Fetch values now. */
1070			const struct tomoyo_number_union *ptr = numbers_p++;
1071
1072			if (ptr->group) {
1073				if (tomoyo_number_matches_group(min_v[0],
1074								max_v[0],
1075								ptr->group)
1076				    == match)
1077					continue;
1078			} else {
1079				if ((min_v[0] <= ptr->values[1] &&
1080				     max_v[0] >= ptr->values[0]) == match)
1081					continue;
1082			}
1083			goto out;
1084		}
1085		/*
1086		 * Bit operation is valid only when counterpart value
1087		 * represents permission.
1088		 */
1089		if (is_bitop[0] && is_bitop[1]) {
1090			goto out;
1091		} else if (is_bitop[0]) {
1092			switch (right) {
1093			case TOMOYO_PATH1_PERM:
1094			case TOMOYO_PATH1_PARENT_PERM:
1095			case TOMOYO_PATH2_PERM:
1096			case TOMOYO_PATH2_PARENT_PERM:
1097				if (!(max_v[0] & max_v[1]) == !match)
1098					continue;
1099			}
1100			goto out;
1101		} else if (is_bitop[1]) {
1102			switch (left) {
1103			case TOMOYO_PATH1_PERM:
1104			case TOMOYO_PATH1_PARENT_PERM:
1105			case TOMOYO_PATH2_PERM:
1106			case TOMOYO_PATH2_PARENT_PERM:
1107				if (!(max_v[0] & max_v[1]) == !match)
1108					continue;
1109			}
1110			goto out;
1111		}
1112		/* Normal value range comparison. */
1113		if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match)
1114			continue;
1115out:
1116		return false;
1117	}
1118	/* Check argv[] and envp[] now. */
1119	if (r->ee && (argc || envc))
1120		return tomoyo_scan_bprm(r->ee, argc, argv, envc, envp);
1121	return true;
1122}