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;
}