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