bool tomoyo_condition()

in security/tomoyo/condition.c [744:1094]


bool tomoyo_condition(struct tomoyo_request_info *r,
		      const struct tomoyo_condition *cond)
{
	u32 i;
	unsigned long min_v[2] = { 0, 0 };
	unsigned long max_v[2] = { 0, 0 };
	const struct tomoyo_condition_element *condp;
	const struct tomoyo_number_union *numbers_p;
	const struct tomoyo_name_union *names_p;
	const struct tomoyo_argv *argv;
	const struct tomoyo_envp *envp;
	struct tomoyo_obj_info *obj;
	u16 condc;
	u16 argc;
	u16 envc;
	struct linux_binprm *bprm = NULL;
	if (!cond)
		return true;
	condc = cond->condc;
	argc = cond->argc;
	envc = cond->envc;
	obj = r->obj;
	if (r->ee)
		bprm = r->ee->bprm;
	if (!bprm && (argc || envc))
		return false;
	condp = (struct tomoyo_condition_element *) (cond + 1);
	numbers_p = (const struct tomoyo_number_union *) (condp + condc);
	names_p = (const struct tomoyo_name_union *)
		(numbers_p + cond->numbers_count);
	argv = (const struct tomoyo_argv *) (names_p + cond->names_count);
	envp = (const struct tomoyo_envp *) (argv + argc);
	for (i = 0; i < condc; i++) {
		const bool match = condp->equals;
		const u8 left = condp->left;
		const u8 right = condp->right;
		bool is_bitop[2] = { false, false };
		u8 j;
		condp++;
		/* Check argv[] and envp[] later. */
		if (left == TOMOYO_ARGV_ENTRY || left == TOMOYO_ENVP_ENTRY)
			continue;
		/* Check string expressions. */
		if (right == TOMOYO_NAME_UNION) {
			const struct tomoyo_name_union *ptr = names_p++;
			switch (left) {
				struct tomoyo_path_info *symlink;
				struct tomoyo_execve *ee;
				struct file *file;
			case TOMOYO_SYMLINK_TARGET:
				symlink = obj ? obj->symlink_target : NULL;
				if (!symlink ||
				    !tomoyo_compare_name_union(symlink, ptr)
				    == match)
					goto out;
				break;
			case TOMOYO_EXEC_REALPATH:
				ee = r->ee;
				file = ee ? ee->bprm->file : NULL;
				if (!tomoyo_scan_exec_realpath(file, ptr,
							       match))
					goto out;
				break;
			}
			continue;
		}
		/* Check numeric or bit-op expressions. */
		for (j = 0; j < 2; j++) {
			const u8 index = j ? right : left;
			unsigned long value = 0;
			switch (index) {
			case TOMOYO_TASK_UID:
				value = from_kuid(&init_user_ns, current_uid());
				break;
			case TOMOYO_TASK_EUID:
				value = from_kuid(&init_user_ns, current_euid());
				break;
			case TOMOYO_TASK_SUID:
				value = from_kuid(&init_user_ns, current_suid());
				break;
			case TOMOYO_TASK_FSUID:
				value = from_kuid(&init_user_ns, current_fsuid());
				break;
			case TOMOYO_TASK_GID:
				value = from_kgid(&init_user_ns, current_gid());
				break;
			case TOMOYO_TASK_EGID:
				value = from_kgid(&init_user_ns, current_egid());
				break;
			case TOMOYO_TASK_SGID:
				value = from_kgid(&init_user_ns, current_sgid());
				break;
			case TOMOYO_TASK_FSGID:
				value = from_kgid(&init_user_ns, current_fsgid());
				break;
			case TOMOYO_TASK_PID:
				value = tomoyo_sys_getpid();
				break;
			case TOMOYO_TASK_PPID:
				value = tomoyo_sys_getppid();
				break;
			case TOMOYO_TYPE_IS_SOCKET:
				value = S_IFSOCK;
				break;
			case TOMOYO_TYPE_IS_SYMLINK:
				value = S_IFLNK;
				break;
			case TOMOYO_TYPE_IS_FILE:
				value = S_IFREG;
				break;
			case TOMOYO_TYPE_IS_BLOCK_DEV:
				value = S_IFBLK;
				break;
			case TOMOYO_TYPE_IS_DIRECTORY:
				value = S_IFDIR;
				break;
			case TOMOYO_TYPE_IS_CHAR_DEV:
				value = S_IFCHR;
				break;
			case TOMOYO_TYPE_IS_FIFO:
				value = S_IFIFO;
				break;
			case TOMOYO_MODE_SETUID:
				value = S_ISUID;
				break;
			case TOMOYO_MODE_SETGID:
				value = S_ISGID;
				break;
			case TOMOYO_MODE_STICKY:
				value = S_ISVTX;
				break;
			case TOMOYO_MODE_OWNER_READ:
				value = S_IRUSR;
				break;
			case TOMOYO_MODE_OWNER_WRITE:
				value = S_IWUSR;
				break;
			case TOMOYO_MODE_OWNER_EXECUTE:
				value = S_IXUSR;
				break;
			case TOMOYO_MODE_GROUP_READ:
				value = S_IRGRP;
				break;
			case TOMOYO_MODE_GROUP_WRITE:
				value = S_IWGRP;
				break;
			case TOMOYO_MODE_GROUP_EXECUTE:
				value = S_IXGRP;
				break;
			case TOMOYO_MODE_OTHERS_READ:
				value = S_IROTH;
				break;
			case TOMOYO_MODE_OTHERS_WRITE:
				value = S_IWOTH;
				break;
			case TOMOYO_MODE_OTHERS_EXECUTE:
				value = S_IXOTH;
				break;
			case TOMOYO_EXEC_ARGC:
				if (!bprm)
					goto out;
				value = bprm->argc;
				break;
			case TOMOYO_EXEC_ENVC:
				if (!bprm)
					goto out;
				value = bprm->envc;
				break;
			case TOMOYO_NUMBER_UNION:
				/* Fetch values later. */
				break;
			default:
				if (!obj)
					goto out;
				if (!obj->validate_done) {
					tomoyo_get_attributes(obj);
					obj->validate_done = true;
				}
				{
					u8 stat_index;
					struct tomoyo_mini_stat *stat;
					switch (index) {
					case TOMOYO_PATH1_UID:
					case TOMOYO_PATH1_GID:
					case TOMOYO_PATH1_INO:
					case TOMOYO_PATH1_MAJOR:
					case TOMOYO_PATH1_MINOR:
					case TOMOYO_PATH1_TYPE:
					case TOMOYO_PATH1_DEV_MAJOR:
					case TOMOYO_PATH1_DEV_MINOR:
					case TOMOYO_PATH1_PERM:
						stat_index = TOMOYO_PATH1;
						break;
					case TOMOYO_PATH2_UID:
					case TOMOYO_PATH2_GID:
					case TOMOYO_PATH2_INO:
					case TOMOYO_PATH2_MAJOR:
					case TOMOYO_PATH2_MINOR:
					case TOMOYO_PATH2_TYPE:
					case TOMOYO_PATH2_DEV_MAJOR:
					case TOMOYO_PATH2_DEV_MINOR:
					case TOMOYO_PATH2_PERM:
						stat_index = TOMOYO_PATH2;
						break;
					case TOMOYO_PATH1_PARENT_UID:
					case TOMOYO_PATH1_PARENT_GID:
					case TOMOYO_PATH1_PARENT_INO:
					case TOMOYO_PATH1_PARENT_PERM:
						stat_index =
							TOMOYO_PATH1_PARENT;
						break;
					case TOMOYO_PATH2_PARENT_UID:
					case TOMOYO_PATH2_PARENT_GID:
					case TOMOYO_PATH2_PARENT_INO:
					case TOMOYO_PATH2_PARENT_PERM:
						stat_index =
							TOMOYO_PATH2_PARENT;
						break;
					default:
						goto out;
					}
					if (!obj->stat_valid[stat_index])
						goto out;
					stat = &obj->stat[stat_index];
					switch (index) {
					case TOMOYO_PATH1_UID:
					case TOMOYO_PATH2_UID:
					case TOMOYO_PATH1_PARENT_UID:
					case TOMOYO_PATH2_PARENT_UID:
						value = from_kuid(&init_user_ns, stat->uid);
						break;
					case TOMOYO_PATH1_GID:
					case TOMOYO_PATH2_GID:
					case TOMOYO_PATH1_PARENT_GID:
					case TOMOYO_PATH2_PARENT_GID:
						value = from_kgid(&init_user_ns, stat->gid);
						break;
					case TOMOYO_PATH1_INO:
					case TOMOYO_PATH2_INO:
					case TOMOYO_PATH1_PARENT_INO:
					case TOMOYO_PATH2_PARENT_INO:
						value = stat->ino;
						break;
					case TOMOYO_PATH1_MAJOR:
					case TOMOYO_PATH2_MAJOR:
						value = MAJOR(stat->dev);
						break;
					case TOMOYO_PATH1_MINOR:
					case TOMOYO_PATH2_MINOR:
						value = MINOR(stat->dev);
						break;
					case TOMOYO_PATH1_TYPE:
					case TOMOYO_PATH2_TYPE:
						value = stat->mode & S_IFMT;
						break;
					case TOMOYO_PATH1_DEV_MAJOR:
					case TOMOYO_PATH2_DEV_MAJOR:
						value = MAJOR(stat->rdev);
						break;
					case TOMOYO_PATH1_DEV_MINOR:
					case TOMOYO_PATH2_DEV_MINOR:
						value = MINOR(stat->rdev);
						break;
					case TOMOYO_PATH1_PERM:
					case TOMOYO_PATH2_PERM:
					case TOMOYO_PATH1_PARENT_PERM:
					case TOMOYO_PATH2_PARENT_PERM:
						value = stat->mode & S_IALLUGO;
						break;
					}
				}
				break;
			}
			max_v[j] = value;
			min_v[j] = value;
			switch (index) {
			case TOMOYO_MODE_SETUID:
			case TOMOYO_MODE_SETGID:
			case TOMOYO_MODE_STICKY:
			case TOMOYO_MODE_OWNER_READ:
			case TOMOYO_MODE_OWNER_WRITE:
			case TOMOYO_MODE_OWNER_EXECUTE:
			case TOMOYO_MODE_GROUP_READ:
			case TOMOYO_MODE_GROUP_WRITE:
			case TOMOYO_MODE_GROUP_EXECUTE:
			case TOMOYO_MODE_OTHERS_READ:
			case TOMOYO_MODE_OTHERS_WRITE:
			case TOMOYO_MODE_OTHERS_EXECUTE:
				is_bitop[j] = true;
			}
		}
		if (left == TOMOYO_NUMBER_UNION) {
			/* Fetch values now. */
			const struct tomoyo_number_union *ptr = numbers_p++;
			min_v[0] = ptr->values[0];
			max_v[0] = ptr->values[1];
		}
		if (right == TOMOYO_NUMBER_UNION) {
			/* Fetch values now. */
			const struct tomoyo_number_union *ptr = numbers_p++;
			if (ptr->group) {
				if (tomoyo_number_matches_group(min_v[0],
								max_v[0],
								ptr->group)
				    == match)
					continue;
			} else {
				if ((min_v[0] <= ptr->values[1] &&
				     max_v[0] >= ptr->values[0]) == match)
					continue;
			}
			goto out;
		}
		/*
		 * Bit operation is valid only when counterpart value
		 * represents permission.
		 */
		if (is_bitop[0] && is_bitop[1]) {
			goto out;
		} else if (is_bitop[0]) {
			switch (right) {
			case TOMOYO_PATH1_PERM:
			case TOMOYO_PATH1_PARENT_PERM:
			case TOMOYO_PATH2_PERM:
			case TOMOYO_PATH2_PARENT_PERM:
				if (!(max_v[0] & max_v[1]) == !match)
					continue;
			}
			goto out;
		} else if (is_bitop[1]) {
			switch (left) {
			case TOMOYO_PATH1_PERM:
			case TOMOYO_PATH1_PARENT_PERM:
			case TOMOYO_PATH2_PERM:
			case TOMOYO_PATH2_PARENT_PERM:
				if (!(max_v[0] & max_v[1]) == !match)
					continue;
			}
			goto out;
		}
		/* Normal value range comparison. */
		if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match)
			continue;
out:
		return false;
	}
	/* Check argv[] and envp[] now. */
	if (r->ee && (argc || envc))
		return tomoyo_scan_bprm(r->ee, argc, argv, envc, envp);
	return true;
}