1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
22066a361STetsuo Handa /*
32066a361STetsuo Handa * security/tomoyo/condition.c
42066a361STetsuo Handa *
52066a361STetsuo Handa * Copyright (C) 2005-2011 NTT DATA CORPORATION
62066a361STetsuo Handa */
72066a361STetsuo Handa
82066a361STetsuo Handa #include "common.h"
92066a361STetsuo Handa #include <linux/slab.h>
102066a361STetsuo Handa
112066a361STetsuo Handa /* List of "struct tomoyo_condition". */
122066a361STetsuo Handa LIST_HEAD(tomoyo_condition_list);
132066a361STetsuo Handa
142066a361STetsuo Handa /**
155b636857STetsuo Handa * tomoyo_argv - Check argv[] in "struct linux_binbrm".
165b636857STetsuo Handa *
175b636857STetsuo Handa * @index: Index number of @arg_ptr.
185b636857STetsuo Handa * @arg_ptr: Contents of argv[@index].
195b636857STetsuo Handa * @argc: Length of @argv.
205b636857STetsuo Handa * @argv: Pointer to "struct tomoyo_argv".
215b636857STetsuo Handa * @checked: Set to true if @argv[@index] was found.
225b636857STetsuo Handa *
235b636857STetsuo Handa * Returns true on success, false otherwise.
245b636857STetsuo Handa */
tomoyo_argv(const unsigned int index,const char * arg_ptr,const int argc,const struct tomoyo_argv * argv,u8 * checked)255b636857STetsuo Handa static bool tomoyo_argv(const unsigned int index, const char *arg_ptr,
265b636857STetsuo Handa const int argc, const struct tomoyo_argv *argv,
275b636857STetsuo Handa u8 *checked)
285b636857STetsuo Handa {
295b636857STetsuo Handa int i;
305b636857STetsuo Handa struct tomoyo_path_info arg;
31cdcf6723STetsuo Handa
325b636857STetsuo Handa arg.name = arg_ptr;
335b636857STetsuo Handa for (i = 0; i < argc; argv++, checked++, i++) {
345b636857STetsuo Handa bool result;
35cdcf6723STetsuo Handa
365b636857STetsuo Handa if (index != argv->index)
375b636857STetsuo Handa continue;
385b636857STetsuo Handa *checked = 1;
395b636857STetsuo Handa tomoyo_fill_path_info(&arg);
405b636857STetsuo Handa result = tomoyo_path_matches_pattern(&arg, argv->value);
415b636857STetsuo Handa if (argv->is_not)
425b636857STetsuo Handa result = !result;
435b636857STetsuo Handa if (!result)
445b636857STetsuo Handa return false;
455b636857STetsuo Handa }
465b636857STetsuo Handa return true;
475b636857STetsuo Handa }
485b636857STetsuo Handa
495b636857STetsuo Handa /**
505b636857STetsuo Handa * tomoyo_envp - Check envp[] in "struct linux_binbrm".
515b636857STetsuo Handa *
525b636857STetsuo Handa * @env_name: The name of environment variable.
535b636857STetsuo Handa * @env_value: The value of environment variable.
545b636857STetsuo Handa * @envc: Length of @envp.
555b636857STetsuo Handa * @envp: Pointer to "struct tomoyo_envp".
565b636857STetsuo Handa * @checked: Set to true if @envp[@env_name] was found.
575b636857STetsuo Handa *
585b636857STetsuo Handa * Returns true on success, false otherwise.
595b636857STetsuo Handa */
tomoyo_envp(const char * env_name,const char * env_value,const int envc,const struct tomoyo_envp * envp,u8 * checked)605b636857STetsuo Handa static bool tomoyo_envp(const char *env_name, const char *env_value,
615b636857STetsuo Handa const int envc, const struct tomoyo_envp *envp,
625b636857STetsuo Handa u8 *checked)
635b636857STetsuo Handa {
645b636857STetsuo Handa int i;
655b636857STetsuo Handa struct tomoyo_path_info name;
665b636857STetsuo Handa struct tomoyo_path_info value;
67cdcf6723STetsuo Handa
685b636857STetsuo Handa name.name = env_name;
695b636857STetsuo Handa tomoyo_fill_path_info(&name);
705b636857STetsuo Handa value.name = env_value;
715b636857STetsuo Handa tomoyo_fill_path_info(&value);
725b636857STetsuo Handa for (i = 0; i < envc; envp++, checked++, i++) {
735b636857STetsuo Handa bool result;
74cdcf6723STetsuo Handa
755b636857STetsuo Handa if (!tomoyo_path_matches_pattern(&name, envp->name))
765b636857STetsuo Handa continue;
775b636857STetsuo Handa *checked = 1;
785b636857STetsuo Handa if (envp->value) {
795b636857STetsuo Handa result = tomoyo_path_matches_pattern(&value,
805b636857STetsuo Handa envp->value);
815b636857STetsuo Handa if (envp->is_not)
825b636857STetsuo Handa result = !result;
835b636857STetsuo Handa } else {
845b636857STetsuo Handa result = true;
855b636857STetsuo Handa if (!envp->is_not)
865b636857STetsuo Handa result = !result;
875b636857STetsuo Handa }
885b636857STetsuo Handa if (!result)
895b636857STetsuo Handa return false;
905b636857STetsuo Handa }
915b636857STetsuo Handa return true;
925b636857STetsuo Handa }
935b636857STetsuo Handa
945b636857STetsuo Handa /**
955b636857STetsuo Handa * tomoyo_scan_bprm - Scan "struct linux_binprm".
965b636857STetsuo Handa *
975b636857STetsuo Handa * @ee: Pointer to "struct tomoyo_execve".
985b636857STetsuo Handa * @argc: Length of @argc.
995b636857STetsuo Handa * @argv: Pointer to "struct tomoyo_argv".
1005b636857STetsuo Handa * @envc: Length of @envp.
101*15269fb1STetsuo Handa * @envp: Pointer to "struct tomoyo_envp".
1025b636857STetsuo Handa *
1035b636857STetsuo Handa * Returns true on success, false otherwise.
1045b636857STetsuo Handa */
tomoyo_scan_bprm(struct tomoyo_execve * ee,const u16 argc,const struct tomoyo_argv * argv,const u16 envc,const struct tomoyo_envp * envp)1055b636857STetsuo Handa static bool tomoyo_scan_bprm(struct tomoyo_execve *ee,
1065b636857STetsuo Handa const u16 argc, const struct tomoyo_argv *argv,
1075b636857STetsuo Handa const u16 envc, const struct tomoyo_envp *envp)
1085b636857STetsuo Handa {
1095b636857STetsuo Handa struct linux_binprm *bprm = ee->bprm;
1105b636857STetsuo Handa struct tomoyo_page_dump *dump = &ee->dump;
1115b636857STetsuo Handa char *arg_ptr = ee->tmp;
1125b636857STetsuo Handa int arg_len = 0;
1135b636857STetsuo Handa unsigned long pos = bprm->p;
1145b636857STetsuo Handa int offset = pos % PAGE_SIZE;
1155b636857STetsuo Handa int argv_count = bprm->argc;
1165b636857STetsuo Handa int envp_count = bprm->envc;
1175b636857STetsuo Handa bool result = true;
1185b636857STetsuo Handa u8 local_checked[32];
1195b636857STetsuo Handa u8 *checked;
120cdcf6723STetsuo Handa
1215b636857STetsuo Handa if (argc + envc <= sizeof(local_checked)) {
1225b636857STetsuo Handa checked = local_checked;
1235b636857STetsuo Handa memset(local_checked, 0, sizeof(local_checked));
1245b636857STetsuo Handa } else {
1255b636857STetsuo Handa checked = kzalloc(argc + envc, GFP_NOFS);
1265b636857STetsuo Handa if (!checked)
1275b636857STetsuo Handa return false;
1285b636857STetsuo Handa }
1295b636857STetsuo Handa while (argv_count || envp_count) {
1305b636857STetsuo Handa if (!tomoyo_dump_page(bprm, pos, dump)) {
1315b636857STetsuo Handa result = false;
1325b636857STetsuo Handa goto out;
1335b636857STetsuo Handa }
1345b636857STetsuo Handa pos += PAGE_SIZE - offset;
1355b636857STetsuo Handa while (offset < PAGE_SIZE) {
1365b636857STetsuo Handa /* Read. */
1375b636857STetsuo Handa const char *kaddr = dump->data;
1385b636857STetsuo Handa const unsigned char c = kaddr[offset++];
139cdcf6723STetsuo Handa
1405b636857STetsuo Handa if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) {
1415b636857STetsuo Handa if (c == '\\') {
1425b636857STetsuo Handa arg_ptr[arg_len++] = '\\';
1435b636857STetsuo Handa arg_ptr[arg_len++] = '\\';
1445b636857STetsuo Handa } else if (c > ' ' && c < 127) {
1455b636857STetsuo Handa arg_ptr[arg_len++] = c;
1465b636857STetsuo Handa } else {
1475b636857STetsuo Handa arg_ptr[arg_len++] = '\\';
1485b636857STetsuo Handa arg_ptr[arg_len++] = (c >> 6) + '0';
1495b636857STetsuo Handa arg_ptr[arg_len++] =
1505b636857STetsuo Handa ((c >> 3) & 7) + '0';
1515b636857STetsuo Handa arg_ptr[arg_len++] = (c & 7) + '0';
1525b636857STetsuo Handa }
1535b636857STetsuo Handa } else {
1545b636857STetsuo Handa arg_ptr[arg_len] = '\0';
1555b636857STetsuo Handa }
1565b636857STetsuo Handa if (c)
1575b636857STetsuo Handa continue;
1585b636857STetsuo Handa /* Check. */
1595b636857STetsuo Handa if (argv_count) {
1605b636857STetsuo Handa if (!tomoyo_argv(bprm->argc - argv_count,
1615b636857STetsuo Handa arg_ptr, argc, argv,
1625b636857STetsuo Handa checked)) {
1635b636857STetsuo Handa result = false;
1645b636857STetsuo Handa break;
1655b636857STetsuo Handa }
1665b636857STetsuo Handa argv_count--;
1675b636857STetsuo Handa } else if (envp_count) {
1685b636857STetsuo Handa char *cp = strchr(arg_ptr, '=');
169cdcf6723STetsuo Handa
1705b636857STetsuo Handa if (cp) {
1715b636857STetsuo Handa *cp = '\0';
1725b636857STetsuo Handa if (!tomoyo_envp(arg_ptr, cp + 1,
1735b636857STetsuo Handa envc, envp,
1745b636857STetsuo Handa checked + argc)) {
1755b636857STetsuo Handa result = false;
1765b636857STetsuo Handa break;
1775b636857STetsuo Handa }
1785b636857STetsuo Handa }
1795b636857STetsuo Handa envp_count--;
1805b636857STetsuo Handa } else {
1815b636857STetsuo Handa break;
1825b636857STetsuo Handa }
1835b636857STetsuo Handa arg_len = 0;
1845b636857STetsuo Handa }
1855b636857STetsuo Handa offset = 0;
1865b636857STetsuo Handa if (!result)
1875b636857STetsuo Handa break;
1885b636857STetsuo Handa }
1895b636857STetsuo Handa out:
1905b636857STetsuo Handa if (result) {
1915b636857STetsuo Handa int i;
192cdcf6723STetsuo Handa
1935b636857STetsuo Handa /* Check not-yet-checked entries. */
1945b636857STetsuo Handa for (i = 0; i < argc; i++) {
1955b636857STetsuo Handa if (checked[i])
1965b636857STetsuo Handa continue;
1975b636857STetsuo Handa /*
1985b636857STetsuo Handa * Return true only if all unchecked indexes in
1995b636857STetsuo Handa * bprm->argv[] are not matched.
2005b636857STetsuo Handa */
2015b636857STetsuo Handa if (argv[i].is_not)
2025b636857STetsuo Handa continue;
2035b636857STetsuo Handa result = false;
2045b636857STetsuo Handa break;
2055b636857STetsuo Handa }
2065b636857STetsuo Handa for (i = 0; i < envc; envp++, i++) {
2075b636857STetsuo Handa if (checked[argc + i])
2085b636857STetsuo Handa continue;
2095b636857STetsuo Handa /*
2105b636857STetsuo Handa * Return true only if all unchecked environ variables
2115b636857STetsuo Handa * in bprm->envp[] are either undefined or not matched.
2125b636857STetsuo Handa */
2135b636857STetsuo Handa if ((!envp->value && !envp->is_not) ||
2145b636857STetsuo Handa (envp->value && envp->is_not))
2155b636857STetsuo Handa continue;
2165b636857STetsuo Handa result = false;
2175b636857STetsuo Handa break;
2185b636857STetsuo Handa }
2195b636857STetsuo Handa }
2205b636857STetsuo Handa if (checked != local_checked)
2215b636857STetsuo Handa kfree(checked);
2225b636857STetsuo Handa return result;
2235b636857STetsuo Handa }
2245b636857STetsuo Handa
2255b636857STetsuo Handa /**
2262ca9bf45STetsuo Handa * tomoyo_scan_exec_realpath - Check "exec.realpath" parameter of "struct tomoyo_condition".
2272ca9bf45STetsuo Handa *
2282ca9bf45STetsuo Handa * @file: Pointer to "struct file".
2292ca9bf45STetsuo Handa * @ptr: Pointer to "struct tomoyo_name_union".
2302ca9bf45STetsuo Handa * @match: True if "exec.realpath=", false if "exec.realpath!=".
2312ca9bf45STetsuo Handa *
2322ca9bf45STetsuo Handa * Returns true on success, false otherwise.
2332ca9bf45STetsuo Handa */
tomoyo_scan_exec_realpath(struct file * file,const struct tomoyo_name_union * ptr,const bool match)2342ca9bf45STetsuo Handa static bool tomoyo_scan_exec_realpath(struct file *file,
2352ca9bf45STetsuo Handa const struct tomoyo_name_union *ptr,
2362ca9bf45STetsuo Handa const bool match)
2372ca9bf45STetsuo Handa {
2382ca9bf45STetsuo Handa bool result;
2392ca9bf45STetsuo Handa struct tomoyo_path_info exe;
240cdcf6723STetsuo Handa
2412ca9bf45STetsuo Handa if (!file)
2422ca9bf45STetsuo Handa return false;
2432ca9bf45STetsuo Handa exe.name = tomoyo_realpath_from_path(&file->f_path);
2442ca9bf45STetsuo Handa if (!exe.name)
2452ca9bf45STetsuo Handa return false;
2462ca9bf45STetsuo Handa tomoyo_fill_path_info(&exe);
2472ca9bf45STetsuo Handa result = tomoyo_compare_name_union(&exe, ptr);
2482ca9bf45STetsuo Handa kfree(exe.name);
2492ca9bf45STetsuo Handa return result == match;
2502ca9bf45STetsuo Handa }
2512ca9bf45STetsuo Handa
2522ca9bf45STetsuo Handa /**
2532ca9bf45STetsuo Handa * tomoyo_get_dqword - tomoyo_get_name() for a quoted string.
2542ca9bf45STetsuo Handa *
2552ca9bf45STetsuo Handa * @start: String to save.
2562ca9bf45STetsuo Handa *
2572ca9bf45STetsuo Handa * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
2582ca9bf45STetsuo Handa */
tomoyo_get_dqword(char * start)2592ca9bf45STetsuo Handa static const struct tomoyo_path_info *tomoyo_get_dqword(char *start)
2602ca9bf45STetsuo Handa {
2612ca9bf45STetsuo Handa char *cp = start + strlen(start) - 1;
262cdcf6723STetsuo Handa
2632ca9bf45STetsuo Handa if (cp == start || *start++ != '"' || *cp != '"')
2642ca9bf45STetsuo Handa return NULL;
2652ca9bf45STetsuo Handa *cp = '\0';
2662ca9bf45STetsuo Handa if (*start && !tomoyo_correct_word(start))
2672ca9bf45STetsuo Handa return NULL;
2682ca9bf45STetsuo Handa return tomoyo_get_name(start);
2692ca9bf45STetsuo Handa }
2702ca9bf45STetsuo Handa
2712ca9bf45STetsuo Handa /**
2722ca9bf45STetsuo Handa * tomoyo_parse_name_union_quoted - Parse a quoted word.
2732ca9bf45STetsuo Handa *
2742ca9bf45STetsuo Handa * @param: Pointer to "struct tomoyo_acl_param".
2752ca9bf45STetsuo Handa * @ptr: Pointer to "struct tomoyo_name_union".
2762ca9bf45STetsuo Handa *
2772ca9bf45STetsuo Handa * Returns true on success, false otherwise.
2782ca9bf45STetsuo Handa */
tomoyo_parse_name_union_quoted(struct tomoyo_acl_param * param,struct tomoyo_name_union * ptr)2792ca9bf45STetsuo Handa static bool tomoyo_parse_name_union_quoted(struct tomoyo_acl_param *param,
2802ca9bf45STetsuo Handa struct tomoyo_name_union *ptr)
2812ca9bf45STetsuo Handa {
2822ca9bf45STetsuo Handa char *filename = param->data;
283cdcf6723STetsuo Handa
2842ca9bf45STetsuo Handa if (*filename == '@')
2852ca9bf45STetsuo Handa return tomoyo_parse_name_union(param, ptr);
2862ca9bf45STetsuo Handa ptr->filename = tomoyo_get_dqword(filename);
2872ca9bf45STetsuo Handa return ptr->filename != NULL;
2882ca9bf45STetsuo Handa }
2892ca9bf45STetsuo Handa
2902ca9bf45STetsuo Handa /**
2915b636857STetsuo Handa * tomoyo_parse_argv - Parse an argv[] condition part.
2925b636857STetsuo Handa *
2935b636857STetsuo Handa * @left: Lefthand value.
2945b636857STetsuo Handa * @right: Righthand value.
2955b636857STetsuo Handa * @argv: Pointer to "struct tomoyo_argv".
2965b636857STetsuo Handa *
2975b636857STetsuo Handa * Returns true on success, false otherwise.
2985b636857STetsuo Handa */
tomoyo_parse_argv(char * left,char * right,struct tomoyo_argv * argv)2995b636857STetsuo Handa static bool tomoyo_parse_argv(char *left, char *right,
3005b636857STetsuo Handa struct tomoyo_argv *argv)
3015b636857STetsuo Handa {
3025b636857STetsuo Handa if (tomoyo_parse_ulong(&argv->index, &left) !=
3035b636857STetsuo Handa TOMOYO_VALUE_TYPE_DECIMAL || *left++ != ']' || *left)
3045b636857STetsuo Handa return false;
3055b636857STetsuo Handa argv->value = tomoyo_get_dqword(right);
3065b636857STetsuo Handa return argv->value != NULL;
3075b636857STetsuo Handa }
3085b636857STetsuo Handa
3095b636857STetsuo Handa /**
3105b636857STetsuo Handa * tomoyo_parse_envp - Parse an envp[] condition part.
3115b636857STetsuo Handa *
3125b636857STetsuo Handa * @left: Lefthand value.
3135b636857STetsuo Handa * @right: Righthand value.
3145b636857STetsuo Handa * @envp: Pointer to "struct tomoyo_envp".
3155b636857STetsuo Handa *
3165b636857STetsuo Handa * Returns true on success, false otherwise.
3175b636857STetsuo Handa */
tomoyo_parse_envp(char * left,char * right,struct tomoyo_envp * envp)3185b636857STetsuo Handa static bool tomoyo_parse_envp(char *left, char *right,
3195b636857STetsuo Handa struct tomoyo_envp *envp)
3205b636857STetsuo Handa {
3215b636857STetsuo Handa const struct tomoyo_path_info *name;
3225b636857STetsuo Handa const struct tomoyo_path_info *value;
3235b636857STetsuo Handa char *cp = left + strlen(left) - 1;
324cdcf6723STetsuo Handa
3255b636857STetsuo Handa if (*cp-- != ']' || *cp != '"')
3265b636857STetsuo Handa goto out;
3275b636857STetsuo Handa *cp = '\0';
3285b636857STetsuo Handa if (!tomoyo_correct_word(left))
3295b636857STetsuo Handa goto out;
3305b636857STetsuo Handa name = tomoyo_get_name(left);
3315b636857STetsuo Handa if (!name)
3325b636857STetsuo Handa goto out;
3335b636857STetsuo Handa if (!strcmp(right, "NULL")) {
3345b636857STetsuo Handa value = NULL;
3355b636857STetsuo Handa } else {
3365b636857STetsuo Handa value = tomoyo_get_dqword(right);
3375b636857STetsuo Handa if (!value) {
3385b636857STetsuo Handa tomoyo_put_name(name);
3395b636857STetsuo Handa goto out;
3405b636857STetsuo Handa }
3415b636857STetsuo Handa }
3425b636857STetsuo Handa envp->name = name;
3435b636857STetsuo Handa envp->value = value;
3445b636857STetsuo Handa return true;
3455b636857STetsuo Handa out:
3465b636857STetsuo Handa return false;
3475b636857STetsuo Handa }
3485b636857STetsuo Handa
3495b636857STetsuo Handa /**
3502066a361STetsuo Handa * tomoyo_same_condition - Check for duplicated "struct tomoyo_condition" entry.
3512066a361STetsuo Handa *
3522066a361STetsuo Handa * @a: Pointer to "struct tomoyo_condition".
3532066a361STetsuo Handa * @b: Pointer to "struct tomoyo_condition".
3542066a361STetsuo Handa *
3552066a361STetsuo Handa * Returns true if @a == @b, false otherwise.
3562066a361STetsuo Handa */
tomoyo_same_condition(const struct tomoyo_condition * a,const struct tomoyo_condition * b)3572066a361STetsuo Handa static inline bool tomoyo_same_condition(const struct tomoyo_condition *a,
3582066a361STetsuo Handa const struct tomoyo_condition *b)
3592066a361STetsuo Handa {
3602066a361STetsuo Handa return a->size == b->size && a->condc == b->condc &&
3612066a361STetsuo Handa a->numbers_count == b->numbers_count &&
3622ca9bf45STetsuo Handa a->names_count == b->names_count &&
3635b636857STetsuo Handa a->argc == b->argc && a->envc == b->envc &&
3646bce98edSTetsuo Handa a->grant_log == b->grant_log && a->transit == b->transit &&
3652066a361STetsuo Handa !memcmp(a + 1, b + 1, a->size - sizeof(*a));
3662066a361STetsuo Handa }
3672066a361STetsuo Handa
3682066a361STetsuo Handa /**
3692066a361STetsuo Handa * tomoyo_condition_type - Get condition type.
3702066a361STetsuo Handa *
3712066a361STetsuo Handa * @word: Keyword string.
3722066a361STetsuo Handa *
3732066a361STetsuo Handa * Returns one of values in "enum tomoyo_conditions_index" on success,
3742066a361STetsuo Handa * TOMOYO_MAX_CONDITION_KEYWORD otherwise.
3752066a361STetsuo Handa */
tomoyo_condition_type(const char * word)3762066a361STetsuo Handa static u8 tomoyo_condition_type(const char *word)
3772066a361STetsuo Handa {
3782066a361STetsuo Handa u8 i;
379cdcf6723STetsuo Handa
3802066a361STetsuo Handa for (i = 0; i < TOMOYO_MAX_CONDITION_KEYWORD; i++) {
3812066a361STetsuo Handa if (!strcmp(word, tomoyo_condition_keyword[i]))
3822066a361STetsuo Handa break;
3832066a361STetsuo Handa }
3842066a361STetsuo Handa return i;
3852066a361STetsuo Handa }
3862066a361STetsuo Handa
3872066a361STetsuo Handa /* Define this to enable debug mode. */
3882066a361STetsuo Handa /* #define DEBUG_CONDITION */
3892066a361STetsuo Handa
3902066a361STetsuo Handa #ifdef DEBUG_CONDITION
3912066a361STetsuo Handa #define dprintk printk
3922066a361STetsuo Handa #else
3932066a361STetsuo Handa #define dprintk(...) do { } while (0)
3942066a361STetsuo Handa #endif
3952066a361STetsuo Handa
3962066a361STetsuo Handa /**
3972066a361STetsuo Handa * tomoyo_commit_condition - Commit "struct tomoyo_condition".
3982066a361STetsuo Handa *
3992066a361STetsuo Handa * @entry: Pointer to "struct tomoyo_condition".
4002066a361STetsuo Handa *
4012066a361STetsuo Handa * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
4022066a361STetsuo Handa *
4032066a361STetsuo Handa * This function merges duplicated entries. This function returns NULL if
4042066a361STetsuo Handa * @entry is not duplicated but memory quota for policy has exceeded.
4052066a361STetsuo Handa */
tomoyo_commit_condition(struct tomoyo_condition * entry)4062066a361STetsuo Handa static struct tomoyo_condition *tomoyo_commit_condition
4072066a361STetsuo Handa (struct tomoyo_condition *entry)
4082066a361STetsuo Handa {
4092066a361STetsuo Handa struct tomoyo_condition *ptr;
4102066a361STetsuo Handa bool found = false;
411cdcf6723STetsuo Handa
4122066a361STetsuo Handa if (mutex_lock_interruptible(&tomoyo_policy_lock)) {
4132066a361STetsuo Handa dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
4142066a361STetsuo Handa ptr = NULL;
4152066a361STetsuo Handa found = true;
4162066a361STetsuo Handa goto out;
4172066a361STetsuo Handa }
418f9732ea1STetsuo Handa list_for_each_entry(ptr, &tomoyo_condition_list, head.list) {
419f9732ea1STetsuo Handa if (!tomoyo_same_condition(ptr, entry) ||
420f9732ea1STetsuo Handa atomic_read(&ptr->head.users) == TOMOYO_GC_IN_PROGRESS)
4212066a361STetsuo Handa continue;
4222066a361STetsuo Handa /* Same entry found. Share this entry. */
4232066a361STetsuo Handa atomic_inc(&ptr->head.users);
4242066a361STetsuo Handa found = true;
4252066a361STetsuo Handa break;
4262066a361STetsuo Handa }
4272066a361STetsuo Handa if (!found) {
4282066a361STetsuo Handa if (tomoyo_memory_ok(entry)) {
4292066a361STetsuo Handa atomic_set(&entry->head.users, 1);
430f9732ea1STetsuo Handa list_add(&entry->head.list, &tomoyo_condition_list);
4312066a361STetsuo Handa } else {
4322066a361STetsuo Handa found = true;
4332066a361STetsuo Handa ptr = NULL;
4342066a361STetsuo Handa }
4352066a361STetsuo Handa }
4362066a361STetsuo Handa mutex_unlock(&tomoyo_policy_lock);
4372066a361STetsuo Handa out:
4382066a361STetsuo Handa if (found) {
4392066a361STetsuo Handa tomoyo_del_condition(&entry->head.list);
4402066a361STetsuo Handa kfree(entry);
4412066a361STetsuo Handa entry = ptr;
4422066a361STetsuo Handa }
4432066a361STetsuo Handa return entry;
4442066a361STetsuo Handa }
4452066a361STetsuo Handa
4462066a361STetsuo Handa /**
4476bce98edSTetsuo Handa * tomoyo_get_transit_preference - Parse domain transition preference for execve().
4486bce98edSTetsuo Handa *
4496bce98edSTetsuo Handa * @param: Pointer to "struct tomoyo_acl_param".
4506bce98edSTetsuo Handa * @e: Pointer to "struct tomoyo_condition".
4516bce98edSTetsuo Handa *
4526bce98edSTetsuo Handa * Returns the condition string part.
4536bce98edSTetsuo Handa */
tomoyo_get_transit_preference(struct tomoyo_acl_param * param,struct tomoyo_condition * e)4546bce98edSTetsuo Handa static char *tomoyo_get_transit_preference(struct tomoyo_acl_param *param,
4556bce98edSTetsuo Handa struct tomoyo_condition *e)
4566bce98edSTetsuo Handa {
4576bce98edSTetsuo Handa char * const pos = param->data;
4586bce98edSTetsuo Handa bool flag;
459cdcf6723STetsuo Handa
4606bce98edSTetsuo Handa if (*pos == '<') {
4616bce98edSTetsuo Handa e->transit = tomoyo_get_domainname(param);
4626bce98edSTetsuo Handa goto done;
4636bce98edSTetsuo Handa }
4646bce98edSTetsuo Handa {
4656bce98edSTetsuo Handa char *cp = strchr(pos, ' ');
466cdcf6723STetsuo Handa
4676bce98edSTetsuo Handa if (cp)
4686bce98edSTetsuo Handa *cp = '\0';
4696bce98edSTetsuo Handa flag = tomoyo_correct_path(pos) || !strcmp(pos, "keep") ||
4706bce98edSTetsuo Handa !strcmp(pos, "initialize") || !strcmp(pos, "reset") ||
4716bce98edSTetsuo Handa !strcmp(pos, "child") || !strcmp(pos, "parent");
4726bce98edSTetsuo Handa if (cp)
4736bce98edSTetsuo Handa *cp = ' ';
4746bce98edSTetsuo Handa }
4756bce98edSTetsuo Handa if (!flag)
4766bce98edSTetsuo Handa return pos;
4776bce98edSTetsuo Handa e->transit = tomoyo_get_name(tomoyo_read_token(param));
4786bce98edSTetsuo Handa done:
4796bce98edSTetsuo Handa if (e->transit)
4806bce98edSTetsuo Handa return param->data;
4816bce98edSTetsuo Handa /*
4826bce98edSTetsuo Handa * Return a bad read-only condition string that will let
4836bce98edSTetsuo Handa * tomoyo_get_condition() return NULL.
4846bce98edSTetsuo Handa */
4856bce98edSTetsuo Handa return "/";
4866bce98edSTetsuo Handa }
4876bce98edSTetsuo Handa
4886bce98edSTetsuo Handa /**
4892066a361STetsuo Handa * tomoyo_get_condition - Parse condition part.
4902066a361STetsuo Handa *
4912066a361STetsuo Handa * @param: Pointer to "struct tomoyo_acl_param".
4922066a361STetsuo Handa *
4932066a361STetsuo Handa * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
4942066a361STetsuo Handa */
tomoyo_get_condition(struct tomoyo_acl_param * param)4952066a361STetsuo Handa struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param)
4962066a361STetsuo Handa {
4972066a361STetsuo Handa struct tomoyo_condition *entry = NULL;
4982066a361STetsuo Handa struct tomoyo_condition_element *condp = NULL;
4992066a361STetsuo Handa struct tomoyo_number_union *numbers_p = NULL;
5002ca9bf45STetsuo Handa struct tomoyo_name_union *names_p = NULL;
5015b636857STetsuo Handa struct tomoyo_argv *argv = NULL;
5025b636857STetsuo Handa struct tomoyo_envp *envp = NULL;
5032066a361STetsuo Handa struct tomoyo_condition e = { };
5046bce98edSTetsuo Handa char * const start_of_string =
5056bce98edSTetsuo Handa tomoyo_get_transit_preference(param, &e);
5062066a361STetsuo Handa char * const end_of_string = start_of_string + strlen(start_of_string);
5072066a361STetsuo Handa char *pos;
508cdcf6723STetsuo Handa
5092066a361STetsuo Handa rerun:
5102066a361STetsuo Handa pos = start_of_string;
5112066a361STetsuo Handa while (1) {
5122066a361STetsuo Handa u8 left = -1;
5132066a361STetsuo Handa u8 right = -1;
5142066a361STetsuo Handa char *left_word = pos;
5152066a361STetsuo Handa char *cp;
5162066a361STetsuo Handa char *right_word;
5172066a361STetsuo Handa bool is_not;
518cdcf6723STetsuo Handa
5192066a361STetsuo Handa if (!*left_word)
5202066a361STetsuo Handa break;
5212066a361STetsuo Handa /*
5222066a361STetsuo Handa * Since left-hand condition does not allow use of "path_group"
5232066a361STetsuo Handa * or "number_group" and environment variable's names do not
5242066a361STetsuo Handa * accept '=', it is guaranteed that the original line consists
5252066a361STetsuo Handa * of one or more repetition of $left$operator$right blocks
5262066a361STetsuo Handa * where "$left is free from '=' and ' '" and "$operator is
5272066a361STetsuo Handa * either '=' or '!='" and "$right is free from ' '".
5282066a361STetsuo Handa * Therefore, we can reconstruct the original line at the end
5292066a361STetsuo Handa * of dry run even if we overwrite $operator with '\0'.
5302066a361STetsuo Handa */
5312066a361STetsuo Handa cp = strchr(pos, ' ');
5322066a361STetsuo Handa if (cp) {
5332066a361STetsuo Handa *cp = '\0'; /* Will restore later. */
5342066a361STetsuo Handa pos = cp + 1;
5352066a361STetsuo Handa } else {
5362066a361STetsuo Handa pos = "";
5372066a361STetsuo Handa }
5382066a361STetsuo Handa right_word = strchr(left_word, '=');
5392066a361STetsuo Handa if (!right_word || right_word == left_word)
5402066a361STetsuo Handa goto out;
5412066a361STetsuo Handa is_not = *(right_word - 1) == '!';
5422066a361STetsuo Handa if (is_not)
5432066a361STetsuo Handa *(right_word++ - 1) = '\0'; /* Will restore later. */
5442066a361STetsuo Handa else if (*(right_word + 1) != '=')
5452066a361STetsuo Handa *right_word++ = '\0'; /* Will restore later. */
5462066a361STetsuo Handa else
5472066a361STetsuo Handa goto out;
5482066a361STetsuo Handa dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word,
5492066a361STetsuo Handa is_not ? "!" : "", right_word);
5501f067a68STetsuo Handa if (!strcmp(left_word, "grant_log")) {
5511f067a68STetsuo Handa if (entry) {
5521f067a68STetsuo Handa if (is_not ||
5531f067a68STetsuo Handa entry->grant_log != TOMOYO_GRANTLOG_AUTO)
5541f067a68STetsuo Handa goto out;
5551f067a68STetsuo Handa else if (!strcmp(right_word, "yes"))
5561f067a68STetsuo Handa entry->grant_log = TOMOYO_GRANTLOG_YES;
5571f067a68STetsuo Handa else if (!strcmp(right_word, "no"))
5581f067a68STetsuo Handa entry->grant_log = TOMOYO_GRANTLOG_NO;
5591f067a68STetsuo Handa else
5601f067a68STetsuo Handa goto out;
5611f067a68STetsuo Handa }
5621f067a68STetsuo Handa continue;
5631f067a68STetsuo Handa }
5645b636857STetsuo Handa if (!strncmp(left_word, "exec.argv[", 10)) {
5655b636857STetsuo Handa if (!argv) {
5665b636857STetsuo Handa e.argc++;
5675b636857STetsuo Handa e.condc++;
5685b636857STetsuo Handa } else {
5695b636857STetsuo Handa e.argc--;
5705b636857STetsuo Handa e.condc--;
5715b636857STetsuo Handa left = TOMOYO_ARGV_ENTRY;
5725b636857STetsuo Handa argv->is_not = is_not;
5735b636857STetsuo Handa if (!tomoyo_parse_argv(left_word + 10,
5745b636857STetsuo Handa right_word, argv++))
5755b636857STetsuo Handa goto out;
5765b636857STetsuo Handa }
5775b636857STetsuo Handa goto store_value;
5785b636857STetsuo Handa }
5795b636857STetsuo Handa if (!strncmp(left_word, "exec.envp[\"", 11)) {
5805b636857STetsuo Handa if (!envp) {
5815b636857STetsuo Handa e.envc++;
5825b636857STetsuo Handa e.condc++;
5835b636857STetsuo Handa } else {
5845b636857STetsuo Handa e.envc--;
5855b636857STetsuo Handa e.condc--;
5865b636857STetsuo Handa left = TOMOYO_ENVP_ENTRY;
5875b636857STetsuo Handa envp->is_not = is_not;
5885b636857STetsuo Handa if (!tomoyo_parse_envp(left_word + 11,
5895b636857STetsuo Handa right_word, envp++))
5905b636857STetsuo Handa goto out;
5915b636857STetsuo Handa }
5925b636857STetsuo Handa goto store_value;
5935b636857STetsuo Handa }
5942066a361STetsuo Handa left = tomoyo_condition_type(left_word);
5952066a361STetsuo Handa dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, left_word,
5962066a361STetsuo Handa left);
5972066a361STetsuo Handa if (left == TOMOYO_MAX_CONDITION_KEYWORD) {
5982066a361STetsuo Handa if (!numbers_p) {
5992066a361STetsuo Handa e.numbers_count++;
6002066a361STetsuo Handa } else {
6012066a361STetsuo Handa e.numbers_count--;
6022066a361STetsuo Handa left = TOMOYO_NUMBER_UNION;
6032066a361STetsuo Handa param->data = left_word;
6042066a361STetsuo Handa if (*left_word == '@' ||
6052066a361STetsuo Handa !tomoyo_parse_number_union(param,
6062066a361STetsuo Handa numbers_p++))
6072066a361STetsuo Handa goto out;
6082066a361STetsuo Handa }
6092066a361STetsuo Handa }
6102066a361STetsuo Handa if (!condp)
6112066a361STetsuo Handa e.condc++;
6122066a361STetsuo Handa else
6132066a361STetsuo Handa e.condc--;
6142ca9bf45STetsuo Handa if (left == TOMOYO_EXEC_REALPATH ||
6152ca9bf45STetsuo Handa left == TOMOYO_SYMLINK_TARGET) {
6162ca9bf45STetsuo Handa if (!names_p) {
6172ca9bf45STetsuo Handa e.names_count++;
6182ca9bf45STetsuo Handa } else {
6192ca9bf45STetsuo Handa e.names_count--;
6202ca9bf45STetsuo Handa right = TOMOYO_NAME_UNION;
6212ca9bf45STetsuo Handa param->data = right_word;
6222ca9bf45STetsuo Handa if (!tomoyo_parse_name_union_quoted(param,
6232ca9bf45STetsuo Handa names_p++))
6242ca9bf45STetsuo Handa goto out;
6252ca9bf45STetsuo Handa }
6262ca9bf45STetsuo Handa goto store_value;
6272ca9bf45STetsuo Handa }
6282066a361STetsuo Handa right = tomoyo_condition_type(right_word);
6292066a361STetsuo Handa if (right == TOMOYO_MAX_CONDITION_KEYWORD) {
6302066a361STetsuo Handa if (!numbers_p) {
6312066a361STetsuo Handa e.numbers_count++;
6322066a361STetsuo Handa } else {
6332066a361STetsuo Handa e.numbers_count--;
6342066a361STetsuo Handa right = TOMOYO_NUMBER_UNION;
6352066a361STetsuo Handa param->data = right_word;
6362066a361STetsuo Handa if (!tomoyo_parse_number_union(param,
6372066a361STetsuo Handa numbers_p++))
6382066a361STetsuo Handa goto out;
6392066a361STetsuo Handa }
6402066a361STetsuo Handa }
6412ca9bf45STetsuo Handa store_value:
6422066a361STetsuo Handa if (!condp) {
643cdcf6723STetsuo Handa dprintk(KERN_WARNING "%u: dry_run left=%u right=%u match=%u\n",
644cdcf6723STetsuo Handa __LINE__, left, right, !is_not);
6452066a361STetsuo Handa continue;
6462066a361STetsuo Handa }
6472066a361STetsuo Handa condp->left = left;
6482066a361STetsuo Handa condp->right = right;
6492066a361STetsuo Handa condp->equals = !is_not;
6502066a361STetsuo Handa dprintk(KERN_WARNING "%u: left=%u right=%u match=%u\n",
6512066a361STetsuo Handa __LINE__, condp->left, condp->right,
6522066a361STetsuo Handa condp->equals);
6532066a361STetsuo Handa condp++;
6542066a361STetsuo Handa }
6555b636857STetsuo Handa dprintk(KERN_INFO "%u: cond=%u numbers=%u names=%u ac=%u ec=%u\n",
6565b636857STetsuo Handa __LINE__, e.condc, e.numbers_count, e.names_count, e.argc,
6575b636857STetsuo Handa e.envc);
6582066a361STetsuo Handa if (entry) {
6595b636857STetsuo Handa BUG_ON(e.names_count | e.numbers_count | e.argc | e.envc |
6605b636857STetsuo Handa e.condc);
6612066a361STetsuo Handa return tomoyo_commit_condition(entry);
6622066a361STetsuo Handa }
6632066a361STetsuo Handa e.size = sizeof(*entry)
6642066a361STetsuo Handa + e.condc * sizeof(struct tomoyo_condition_element)
6652ca9bf45STetsuo Handa + e.numbers_count * sizeof(struct tomoyo_number_union)
6665b636857STetsuo Handa + e.names_count * sizeof(struct tomoyo_name_union)
6675b636857STetsuo Handa + e.argc * sizeof(struct tomoyo_argv)
6685b636857STetsuo Handa + e.envc * sizeof(struct tomoyo_envp);
6692066a361STetsuo Handa entry = kzalloc(e.size, GFP_NOFS);
6702066a361STetsuo Handa if (!entry)
6716bce98edSTetsuo Handa goto out2;
6722066a361STetsuo Handa *entry = e;
6736bce98edSTetsuo Handa e.transit = NULL;
6742066a361STetsuo Handa condp = (struct tomoyo_condition_element *) (entry + 1);
6752066a361STetsuo Handa numbers_p = (struct tomoyo_number_union *) (condp + e.condc);
6762ca9bf45STetsuo Handa names_p = (struct tomoyo_name_union *) (numbers_p + e.numbers_count);
6775b636857STetsuo Handa argv = (struct tomoyo_argv *) (names_p + e.names_count);
6785b636857STetsuo Handa envp = (struct tomoyo_envp *) (argv + e.argc);
6792066a361STetsuo Handa {
6802066a361STetsuo Handa bool flag = false;
681cdcf6723STetsuo Handa
6822066a361STetsuo Handa for (pos = start_of_string; pos < end_of_string; pos++) {
6832066a361STetsuo Handa if (*pos)
6842066a361STetsuo Handa continue;
6852066a361STetsuo Handa if (flag) /* Restore " ". */
6862066a361STetsuo Handa *pos = ' ';
6872066a361STetsuo Handa else if (*(pos + 1) == '=') /* Restore "!=". */
6882066a361STetsuo Handa *pos = '!';
6892066a361STetsuo Handa else /* Restore "=". */
6902066a361STetsuo Handa *pos = '=';
6912066a361STetsuo Handa flag = !flag;
6922066a361STetsuo Handa }
6932066a361STetsuo Handa }
6942066a361STetsuo Handa goto rerun;
6952066a361STetsuo Handa out:
6962066a361STetsuo Handa dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
6972066a361STetsuo Handa if (entry) {
6982066a361STetsuo Handa tomoyo_del_condition(&entry->head.list);
6992066a361STetsuo Handa kfree(entry);
7002066a361STetsuo Handa }
7016bce98edSTetsuo Handa out2:
7026bce98edSTetsuo Handa tomoyo_put_name(e.transit);
7032066a361STetsuo Handa return NULL;
7042066a361STetsuo Handa }
7052066a361STetsuo Handa
7062066a361STetsuo Handa /**
7078761afd4STetsuo Handa * tomoyo_get_attributes - Revalidate "struct inode".
7088761afd4STetsuo Handa *
7098761afd4STetsuo Handa * @obj: Pointer to "struct tomoyo_obj_info".
7108761afd4STetsuo Handa *
7118761afd4STetsuo Handa * Returns nothing.
7128761afd4STetsuo Handa */
tomoyo_get_attributes(struct tomoyo_obj_info * obj)7138761afd4STetsuo Handa void tomoyo_get_attributes(struct tomoyo_obj_info *obj)
7148761afd4STetsuo Handa {
7158761afd4STetsuo Handa u8 i;
7168761afd4STetsuo Handa struct dentry *dentry = NULL;
7178761afd4STetsuo Handa
7188761afd4STetsuo Handa for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) {
7198761afd4STetsuo Handa struct inode *inode;
720cdcf6723STetsuo Handa
7218761afd4STetsuo Handa switch (i) {
7228761afd4STetsuo Handa case TOMOYO_PATH1:
7238761afd4STetsuo Handa dentry = obj->path1.dentry;
7248761afd4STetsuo Handa if (!dentry)
7258761afd4STetsuo Handa continue;
7268761afd4STetsuo Handa break;
7278761afd4STetsuo Handa case TOMOYO_PATH2:
7288761afd4STetsuo Handa dentry = obj->path2.dentry;
7298761afd4STetsuo Handa if (!dentry)
7308761afd4STetsuo Handa continue;
7318761afd4STetsuo Handa break;
7328761afd4STetsuo Handa default:
7338761afd4STetsuo Handa if (!dentry)
7348761afd4STetsuo Handa continue;
7358761afd4STetsuo Handa dentry = dget_parent(dentry);
7368761afd4STetsuo Handa break;
7378761afd4STetsuo Handa }
738c6f493d6SDavid Howells inode = d_backing_inode(dentry);
7398761afd4STetsuo Handa if (inode) {
7408761afd4STetsuo Handa struct tomoyo_mini_stat *stat = &obj->stat[i];
741cdcf6723STetsuo Handa
7428761afd4STetsuo Handa stat->uid = inode->i_uid;
7438761afd4STetsuo Handa stat->gid = inode->i_gid;
7448761afd4STetsuo Handa stat->ino = inode->i_ino;
7458761afd4STetsuo Handa stat->mode = inode->i_mode;
7468761afd4STetsuo Handa stat->dev = inode->i_sb->s_dev;
7478761afd4STetsuo Handa stat->rdev = inode->i_rdev;
7488761afd4STetsuo Handa obj->stat_valid[i] = true;
7498761afd4STetsuo Handa }
750cdcf6723STetsuo Handa if (i & 1) /* TOMOYO_PATH1_PARENT or TOMOYO_PATH2_PARENT */
7518761afd4STetsuo Handa dput(dentry);
7528761afd4STetsuo Handa }
7538761afd4STetsuo Handa }
7548761afd4STetsuo Handa
7558761afd4STetsuo Handa /**
7562066a361STetsuo Handa * tomoyo_condition - Check condition part.
7572066a361STetsuo Handa *
7582066a361STetsuo Handa * @r: Pointer to "struct tomoyo_request_info".
7592066a361STetsuo Handa * @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
7602066a361STetsuo Handa *
7612066a361STetsuo Handa * Returns true on success, false otherwise.
7622066a361STetsuo Handa *
7632066a361STetsuo Handa * Caller holds tomoyo_read_lock().
7642066a361STetsuo Handa */
tomoyo_condition(struct tomoyo_request_info * r,const struct tomoyo_condition * cond)7652066a361STetsuo Handa bool tomoyo_condition(struct tomoyo_request_info *r,
7662066a361STetsuo Handa const struct tomoyo_condition *cond)
7672066a361STetsuo Handa {
7682066a361STetsuo Handa u32 i;
7692066a361STetsuo Handa unsigned long min_v[2] = { 0, 0 };
7702066a361STetsuo Handa unsigned long max_v[2] = { 0, 0 };
7712066a361STetsuo Handa const struct tomoyo_condition_element *condp;
7722066a361STetsuo Handa const struct tomoyo_number_union *numbers_p;
7732ca9bf45STetsuo Handa const struct tomoyo_name_union *names_p;
7745b636857STetsuo Handa const struct tomoyo_argv *argv;
7755b636857STetsuo Handa const struct tomoyo_envp *envp;
7768761afd4STetsuo Handa struct tomoyo_obj_info *obj;
7772066a361STetsuo Handa u16 condc;
7785b636857STetsuo Handa u16 argc;
7795b636857STetsuo Handa u16 envc;
7805b636857STetsuo Handa struct linux_binprm *bprm = NULL;
781cdcf6723STetsuo Handa
7822066a361STetsuo Handa if (!cond)
7832066a361STetsuo Handa return true;
7842066a361STetsuo Handa condc = cond->condc;
7855b636857STetsuo Handa argc = cond->argc;
7865b636857STetsuo Handa envc = cond->envc;
7878761afd4STetsuo Handa obj = r->obj;
7885b636857STetsuo Handa if (r->ee)
7895b636857STetsuo Handa bprm = r->ee->bprm;
7905b636857STetsuo Handa if (!bprm && (argc || envc))
7915b636857STetsuo Handa return false;
7922066a361STetsuo Handa condp = (struct tomoyo_condition_element *) (cond + 1);
7932066a361STetsuo Handa numbers_p = (const struct tomoyo_number_union *) (condp + condc);
7942ca9bf45STetsuo Handa names_p = (const struct tomoyo_name_union *)
7952ca9bf45STetsuo Handa (numbers_p + cond->numbers_count);
7965b636857STetsuo Handa argv = (const struct tomoyo_argv *) (names_p + cond->names_count);
7975b636857STetsuo Handa envp = (const struct tomoyo_envp *) (argv + argc);
7982066a361STetsuo Handa for (i = 0; i < condc; i++) {
7992066a361STetsuo Handa const bool match = condp->equals;
8002066a361STetsuo Handa const u8 left = condp->left;
8012066a361STetsuo Handa const u8 right = condp->right;
8028761afd4STetsuo Handa bool is_bitop[2] = { false, false };
8032066a361STetsuo Handa u8 j;
804cdcf6723STetsuo Handa
8052066a361STetsuo Handa condp++;
8065b636857STetsuo Handa /* Check argv[] and envp[] later. */
8075b636857STetsuo Handa if (left == TOMOYO_ARGV_ENTRY || left == TOMOYO_ENVP_ENTRY)
8085b636857STetsuo Handa continue;
8092ca9bf45STetsuo Handa /* Check string expressions. */
8102ca9bf45STetsuo Handa if (right == TOMOYO_NAME_UNION) {
8112ca9bf45STetsuo Handa const struct tomoyo_name_union *ptr = names_p++;
8122ca9bf45STetsuo Handa struct tomoyo_path_info *symlink;
8132ca9bf45STetsuo Handa struct tomoyo_execve *ee;
8142ca9bf45STetsuo Handa struct file *file;
815cdcf6723STetsuo Handa
816cdcf6723STetsuo Handa switch (left) {
8172ca9bf45STetsuo Handa case TOMOYO_SYMLINK_TARGET:
8182ca9bf45STetsuo Handa symlink = obj ? obj->symlink_target : NULL;
8192ca9bf45STetsuo Handa if (!symlink ||
8202ca9bf45STetsuo Handa !tomoyo_compare_name_union(symlink, ptr)
8212ca9bf45STetsuo Handa == match)
8222ca9bf45STetsuo Handa goto out;
8232ca9bf45STetsuo Handa break;
8242ca9bf45STetsuo Handa case TOMOYO_EXEC_REALPATH:
8252ca9bf45STetsuo Handa ee = r->ee;
8262ca9bf45STetsuo Handa file = ee ? ee->bprm->file : NULL;
8272ca9bf45STetsuo Handa if (!tomoyo_scan_exec_realpath(file, ptr,
8282ca9bf45STetsuo Handa match))
8292ca9bf45STetsuo Handa goto out;
8302ca9bf45STetsuo Handa break;
8312ca9bf45STetsuo Handa }
8322ca9bf45STetsuo Handa continue;
8332ca9bf45STetsuo Handa }
8342066a361STetsuo Handa /* Check numeric or bit-op expressions. */
8352066a361STetsuo Handa for (j = 0; j < 2; j++) {
8362066a361STetsuo Handa const u8 index = j ? right : left;
8372066a361STetsuo Handa unsigned long value = 0;
838cdcf6723STetsuo Handa
8392066a361STetsuo Handa switch (index) {
8402066a361STetsuo Handa case TOMOYO_TASK_UID:
841609fcd1bSEric W. Biederman value = from_kuid(&init_user_ns, current_uid());
8422066a361STetsuo Handa break;
8432066a361STetsuo Handa case TOMOYO_TASK_EUID:
844609fcd1bSEric W. Biederman value = from_kuid(&init_user_ns, current_euid());
8452066a361STetsuo Handa break;
8462066a361STetsuo Handa case TOMOYO_TASK_SUID:
847609fcd1bSEric W. Biederman value = from_kuid(&init_user_ns, current_suid());
8482066a361STetsuo Handa break;
8492066a361STetsuo Handa case TOMOYO_TASK_FSUID:
850609fcd1bSEric W. Biederman value = from_kuid(&init_user_ns, current_fsuid());
8512066a361STetsuo Handa break;
8522066a361STetsuo Handa case TOMOYO_TASK_GID:
853609fcd1bSEric W. Biederman value = from_kgid(&init_user_ns, current_gid());
8542066a361STetsuo Handa break;
8552066a361STetsuo Handa case TOMOYO_TASK_EGID:
856609fcd1bSEric W. Biederman value = from_kgid(&init_user_ns, current_egid());
8572066a361STetsuo Handa break;
8582066a361STetsuo Handa case TOMOYO_TASK_SGID:
859609fcd1bSEric W. Biederman value = from_kgid(&init_user_ns, current_sgid());
8602066a361STetsuo Handa break;
8612066a361STetsuo Handa case TOMOYO_TASK_FSGID:
862609fcd1bSEric W. Biederman value = from_kgid(&init_user_ns, current_fsgid());
8632066a361STetsuo Handa break;
8642066a361STetsuo Handa case TOMOYO_TASK_PID:
8652066a361STetsuo Handa value = tomoyo_sys_getpid();
8662066a361STetsuo Handa break;
8672066a361STetsuo Handa case TOMOYO_TASK_PPID:
8682066a361STetsuo Handa value = tomoyo_sys_getppid();
8692066a361STetsuo Handa break;
8708761afd4STetsuo Handa case TOMOYO_TYPE_IS_SOCKET:
8718761afd4STetsuo Handa value = S_IFSOCK;
8728761afd4STetsuo Handa break;
8738761afd4STetsuo Handa case TOMOYO_TYPE_IS_SYMLINK:
8748761afd4STetsuo Handa value = S_IFLNK;
8758761afd4STetsuo Handa break;
8768761afd4STetsuo Handa case TOMOYO_TYPE_IS_FILE:
8778761afd4STetsuo Handa value = S_IFREG;
8788761afd4STetsuo Handa break;
8798761afd4STetsuo Handa case TOMOYO_TYPE_IS_BLOCK_DEV:
8808761afd4STetsuo Handa value = S_IFBLK;
8818761afd4STetsuo Handa break;
8828761afd4STetsuo Handa case TOMOYO_TYPE_IS_DIRECTORY:
8838761afd4STetsuo Handa value = S_IFDIR;
8848761afd4STetsuo Handa break;
8858761afd4STetsuo Handa case TOMOYO_TYPE_IS_CHAR_DEV:
8868761afd4STetsuo Handa value = S_IFCHR;
8878761afd4STetsuo Handa break;
8888761afd4STetsuo Handa case TOMOYO_TYPE_IS_FIFO:
8898761afd4STetsuo Handa value = S_IFIFO;
8908761afd4STetsuo Handa break;
8918761afd4STetsuo Handa case TOMOYO_MODE_SETUID:
8928761afd4STetsuo Handa value = S_ISUID;
8938761afd4STetsuo Handa break;
8948761afd4STetsuo Handa case TOMOYO_MODE_SETGID:
8958761afd4STetsuo Handa value = S_ISGID;
8968761afd4STetsuo Handa break;
8978761afd4STetsuo Handa case TOMOYO_MODE_STICKY:
8988761afd4STetsuo Handa value = S_ISVTX;
8998761afd4STetsuo Handa break;
9008761afd4STetsuo Handa case TOMOYO_MODE_OWNER_READ:
901cdcf6723STetsuo Handa value = 0400;
9028761afd4STetsuo Handa break;
9038761afd4STetsuo Handa case TOMOYO_MODE_OWNER_WRITE:
904cdcf6723STetsuo Handa value = 0200;
9058761afd4STetsuo Handa break;
9068761afd4STetsuo Handa case TOMOYO_MODE_OWNER_EXECUTE:
907cdcf6723STetsuo Handa value = 0100;
9088761afd4STetsuo Handa break;
9098761afd4STetsuo Handa case TOMOYO_MODE_GROUP_READ:
910cdcf6723STetsuo Handa value = 0040;
9118761afd4STetsuo Handa break;
9128761afd4STetsuo Handa case TOMOYO_MODE_GROUP_WRITE:
913cdcf6723STetsuo Handa value = 0020;
9148761afd4STetsuo Handa break;
9158761afd4STetsuo Handa case TOMOYO_MODE_GROUP_EXECUTE:
916cdcf6723STetsuo Handa value = 0010;
9178761afd4STetsuo Handa break;
9188761afd4STetsuo Handa case TOMOYO_MODE_OTHERS_READ:
919cdcf6723STetsuo Handa value = 0004;
9208761afd4STetsuo Handa break;
9218761afd4STetsuo Handa case TOMOYO_MODE_OTHERS_WRITE:
922cdcf6723STetsuo Handa value = 0002;
9238761afd4STetsuo Handa break;
9248761afd4STetsuo Handa case TOMOYO_MODE_OTHERS_EXECUTE:
925cdcf6723STetsuo Handa value = 0001;
9268761afd4STetsuo Handa break;
9275b636857STetsuo Handa case TOMOYO_EXEC_ARGC:
9285b636857STetsuo Handa if (!bprm)
9295b636857STetsuo Handa goto out;
9305b636857STetsuo Handa value = bprm->argc;
9315b636857STetsuo Handa break;
9325b636857STetsuo Handa case TOMOYO_EXEC_ENVC:
9335b636857STetsuo Handa if (!bprm)
9345b636857STetsuo Handa goto out;
9355b636857STetsuo Handa value = bprm->envc;
9365b636857STetsuo Handa break;
9372066a361STetsuo Handa case TOMOYO_NUMBER_UNION:
9382066a361STetsuo Handa /* Fetch values later. */
9392066a361STetsuo Handa break;
9402066a361STetsuo Handa default:
9418761afd4STetsuo Handa if (!obj)
9428761afd4STetsuo Handa goto out;
9438761afd4STetsuo Handa if (!obj->validate_done) {
9448761afd4STetsuo Handa tomoyo_get_attributes(obj);
9458761afd4STetsuo Handa obj->validate_done = true;
9468761afd4STetsuo Handa }
9478761afd4STetsuo Handa {
9488761afd4STetsuo Handa u8 stat_index;
9498761afd4STetsuo Handa struct tomoyo_mini_stat *stat;
950cdcf6723STetsuo Handa
9518761afd4STetsuo Handa switch (index) {
9528761afd4STetsuo Handa case TOMOYO_PATH1_UID:
9538761afd4STetsuo Handa case TOMOYO_PATH1_GID:
9548761afd4STetsuo Handa case TOMOYO_PATH1_INO:
9558761afd4STetsuo Handa case TOMOYO_PATH1_MAJOR:
9568761afd4STetsuo Handa case TOMOYO_PATH1_MINOR:
9578761afd4STetsuo Handa case TOMOYO_PATH1_TYPE:
9588761afd4STetsuo Handa case TOMOYO_PATH1_DEV_MAJOR:
9598761afd4STetsuo Handa case TOMOYO_PATH1_DEV_MINOR:
9608761afd4STetsuo Handa case TOMOYO_PATH1_PERM:
9618761afd4STetsuo Handa stat_index = TOMOYO_PATH1;
9628761afd4STetsuo Handa break;
9638761afd4STetsuo Handa case TOMOYO_PATH2_UID:
9648761afd4STetsuo Handa case TOMOYO_PATH2_GID:
9658761afd4STetsuo Handa case TOMOYO_PATH2_INO:
9668761afd4STetsuo Handa case TOMOYO_PATH2_MAJOR:
9678761afd4STetsuo Handa case TOMOYO_PATH2_MINOR:
9688761afd4STetsuo Handa case TOMOYO_PATH2_TYPE:
9698761afd4STetsuo Handa case TOMOYO_PATH2_DEV_MAJOR:
9708761afd4STetsuo Handa case TOMOYO_PATH2_DEV_MINOR:
9718761afd4STetsuo Handa case TOMOYO_PATH2_PERM:
9728761afd4STetsuo Handa stat_index = TOMOYO_PATH2;
9738761afd4STetsuo Handa break;
9748761afd4STetsuo Handa case TOMOYO_PATH1_PARENT_UID:
9758761afd4STetsuo Handa case TOMOYO_PATH1_PARENT_GID:
9768761afd4STetsuo Handa case TOMOYO_PATH1_PARENT_INO:
9778761afd4STetsuo Handa case TOMOYO_PATH1_PARENT_PERM:
9788761afd4STetsuo Handa stat_index =
9798761afd4STetsuo Handa TOMOYO_PATH1_PARENT;
9808761afd4STetsuo Handa break;
9818761afd4STetsuo Handa case TOMOYO_PATH2_PARENT_UID:
9828761afd4STetsuo Handa case TOMOYO_PATH2_PARENT_GID:
9838761afd4STetsuo Handa case TOMOYO_PATH2_PARENT_INO:
9848761afd4STetsuo Handa case TOMOYO_PATH2_PARENT_PERM:
9858761afd4STetsuo Handa stat_index =
9868761afd4STetsuo Handa TOMOYO_PATH2_PARENT;
9878761afd4STetsuo Handa break;
9888761afd4STetsuo Handa default:
9898761afd4STetsuo Handa goto out;
9908761afd4STetsuo Handa }
9918761afd4STetsuo Handa if (!obj->stat_valid[stat_index])
9928761afd4STetsuo Handa goto out;
9938761afd4STetsuo Handa stat = &obj->stat[stat_index];
9948761afd4STetsuo Handa switch (index) {
9958761afd4STetsuo Handa case TOMOYO_PATH1_UID:
9968761afd4STetsuo Handa case TOMOYO_PATH2_UID:
9978761afd4STetsuo Handa case TOMOYO_PATH1_PARENT_UID:
9988761afd4STetsuo Handa case TOMOYO_PATH2_PARENT_UID:
999609fcd1bSEric W. Biederman value = from_kuid(&init_user_ns, stat->uid);
10008761afd4STetsuo Handa break;
10018761afd4STetsuo Handa case TOMOYO_PATH1_GID:
10028761afd4STetsuo Handa case TOMOYO_PATH2_GID:
10038761afd4STetsuo Handa case TOMOYO_PATH1_PARENT_GID:
10048761afd4STetsuo Handa case TOMOYO_PATH2_PARENT_GID:
1005609fcd1bSEric W. Biederman value = from_kgid(&init_user_ns, stat->gid);
10068761afd4STetsuo Handa break;
10078761afd4STetsuo Handa case TOMOYO_PATH1_INO:
10088761afd4STetsuo Handa case TOMOYO_PATH2_INO:
10098761afd4STetsuo Handa case TOMOYO_PATH1_PARENT_INO:
10108761afd4STetsuo Handa case TOMOYO_PATH2_PARENT_INO:
10118761afd4STetsuo Handa value = stat->ino;
10128761afd4STetsuo Handa break;
10138761afd4STetsuo Handa case TOMOYO_PATH1_MAJOR:
10148761afd4STetsuo Handa case TOMOYO_PATH2_MAJOR:
10158761afd4STetsuo Handa value = MAJOR(stat->dev);
10168761afd4STetsuo Handa break;
10178761afd4STetsuo Handa case TOMOYO_PATH1_MINOR:
10188761afd4STetsuo Handa case TOMOYO_PATH2_MINOR:
10198761afd4STetsuo Handa value = MINOR(stat->dev);
10208761afd4STetsuo Handa break;
10218761afd4STetsuo Handa case TOMOYO_PATH1_TYPE:
10228761afd4STetsuo Handa case TOMOYO_PATH2_TYPE:
10238761afd4STetsuo Handa value = stat->mode & S_IFMT;
10248761afd4STetsuo Handa break;
10258761afd4STetsuo Handa case TOMOYO_PATH1_DEV_MAJOR:
10268761afd4STetsuo Handa case TOMOYO_PATH2_DEV_MAJOR:
10278761afd4STetsuo Handa value = MAJOR(stat->rdev);
10288761afd4STetsuo Handa break;
10298761afd4STetsuo Handa case TOMOYO_PATH1_DEV_MINOR:
10308761afd4STetsuo Handa case TOMOYO_PATH2_DEV_MINOR:
10318761afd4STetsuo Handa value = MINOR(stat->rdev);
10328761afd4STetsuo Handa break;
10338761afd4STetsuo Handa case TOMOYO_PATH1_PERM:
10348761afd4STetsuo Handa case TOMOYO_PATH2_PERM:
10358761afd4STetsuo Handa case TOMOYO_PATH1_PARENT_PERM:
10368761afd4STetsuo Handa case TOMOYO_PATH2_PARENT_PERM:
10378761afd4STetsuo Handa value = stat->mode & S_IALLUGO;
10388761afd4STetsuo Handa break;
10398761afd4STetsuo Handa }
10408761afd4STetsuo Handa }
10412066a361STetsuo Handa break;
10422066a361STetsuo Handa }
10432066a361STetsuo Handa max_v[j] = value;
10442066a361STetsuo Handa min_v[j] = value;
10458761afd4STetsuo Handa switch (index) {
10468761afd4STetsuo Handa case TOMOYO_MODE_SETUID:
10478761afd4STetsuo Handa case TOMOYO_MODE_SETGID:
10488761afd4STetsuo Handa case TOMOYO_MODE_STICKY:
10498761afd4STetsuo Handa case TOMOYO_MODE_OWNER_READ:
10508761afd4STetsuo Handa case TOMOYO_MODE_OWNER_WRITE:
10518761afd4STetsuo Handa case TOMOYO_MODE_OWNER_EXECUTE:
10528761afd4STetsuo Handa case TOMOYO_MODE_GROUP_READ:
10538761afd4STetsuo Handa case TOMOYO_MODE_GROUP_WRITE:
10548761afd4STetsuo Handa case TOMOYO_MODE_GROUP_EXECUTE:
10558761afd4STetsuo Handa case TOMOYO_MODE_OTHERS_READ:
10568761afd4STetsuo Handa case TOMOYO_MODE_OTHERS_WRITE:
10578761afd4STetsuo Handa case TOMOYO_MODE_OTHERS_EXECUTE:
10588761afd4STetsuo Handa is_bitop[j] = true;
10598761afd4STetsuo Handa }
10602066a361STetsuo Handa }
10612066a361STetsuo Handa if (left == TOMOYO_NUMBER_UNION) {
10622066a361STetsuo Handa /* Fetch values now. */
10632066a361STetsuo Handa const struct tomoyo_number_union *ptr = numbers_p++;
1064cdcf6723STetsuo Handa
10652066a361STetsuo Handa min_v[0] = ptr->values[0];
10662066a361STetsuo Handa max_v[0] = ptr->values[1];
10672066a361STetsuo Handa }
10682066a361STetsuo Handa if (right == TOMOYO_NUMBER_UNION) {
10692066a361STetsuo Handa /* Fetch values now. */
10702066a361STetsuo Handa const struct tomoyo_number_union *ptr = numbers_p++;
1071cdcf6723STetsuo Handa
10722066a361STetsuo Handa if (ptr->group) {
10732066a361STetsuo Handa if (tomoyo_number_matches_group(min_v[0],
10742066a361STetsuo Handa max_v[0],
10752066a361STetsuo Handa ptr->group)
10762066a361STetsuo Handa == match)
10772066a361STetsuo Handa continue;
10782066a361STetsuo Handa } else {
10792066a361STetsuo Handa if ((min_v[0] <= ptr->values[1] &&
10802066a361STetsuo Handa max_v[0] >= ptr->values[0]) == match)
10812066a361STetsuo Handa continue;
10822066a361STetsuo Handa }
10832066a361STetsuo Handa goto out;
10842066a361STetsuo Handa }
10858761afd4STetsuo Handa /*
10868761afd4STetsuo Handa * Bit operation is valid only when counterpart value
10878761afd4STetsuo Handa * represents permission.
10888761afd4STetsuo Handa */
10898761afd4STetsuo Handa if (is_bitop[0] && is_bitop[1]) {
10908761afd4STetsuo Handa goto out;
10918761afd4STetsuo Handa } else if (is_bitop[0]) {
10928761afd4STetsuo Handa switch (right) {
10938761afd4STetsuo Handa case TOMOYO_PATH1_PERM:
10948761afd4STetsuo Handa case TOMOYO_PATH1_PARENT_PERM:
10958761afd4STetsuo Handa case TOMOYO_PATH2_PERM:
10968761afd4STetsuo Handa case TOMOYO_PATH2_PARENT_PERM:
10978761afd4STetsuo Handa if (!(max_v[0] & max_v[1]) == !match)
10988761afd4STetsuo Handa continue;
10998761afd4STetsuo Handa }
11008761afd4STetsuo Handa goto out;
11018761afd4STetsuo Handa } else if (is_bitop[1]) {
11028761afd4STetsuo Handa switch (left) {
11038761afd4STetsuo Handa case TOMOYO_PATH1_PERM:
11048761afd4STetsuo Handa case TOMOYO_PATH1_PARENT_PERM:
11058761afd4STetsuo Handa case TOMOYO_PATH2_PERM:
11068761afd4STetsuo Handa case TOMOYO_PATH2_PARENT_PERM:
11078761afd4STetsuo Handa if (!(max_v[0] & max_v[1]) == !match)
11088761afd4STetsuo Handa continue;
11098761afd4STetsuo Handa }
11108761afd4STetsuo Handa goto out;
11118761afd4STetsuo Handa }
11122066a361STetsuo Handa /* Normal value range comparison. */
11132066a361STetsuo Handa if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match)
11142066a361STetsuo Handa continue;
11152066a361STetsuo Handa out:
11162066a361STetsuo Handa return false;
11172066a361STetsuo Handa }
11185b636857STetsuo Handa /* Check argv[] and envp[] now. */
11195b636857STetsuo Handa if (r->ee && (argc || envc))
11205b636857STetsuo Handa return tomoyo_scan_bprm(r->ee, argc, argv, envc, envp);
11212066a361STetsuo Handa return true;
11222066a361STetsuo Handa }
1123