lkml.org 
[lkml]   [2009]   [Oct]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[TOMOYO #16 10/25] TOMOYO: Add conditional ACL support.
    This patch contains code for handling "if" clause of a permission.
    TOMOYO is a pathname based access control system, but also deals some of non
    pathname attributes.

    TOMOYO supports conditional permissions based on process's UID/GID etc. and/or
    requested pathname's UID/GID.

    Regarding symlink(), you can check symlink's contents.

    Regarding execve(), you can check argv[]/envp[] conditions.
    If you need to examine argv[]/envp[] more deeply, you can use execute handler.

    Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
    ---
    security/tomoyo/condition.c | 1332 ++++++++++++++++++++++++++++++++++++++++++++
    1 file changed, 1332 insertions(+)

    --- /dev/null
    +++ security-testing-2.6/security/tomoyo/condition.c
    @@ -0,0 +1,1332 @@
    +/*
    + * security/tomoyo/condition.c
    + *
    + * Copyright (C) 2005-2009 NTT DATA CORPORATION
    + */
    +#include "internal.h"
    +
    +/**
    + * tomoyo_argv - Check argv[] in "struct linux_binbrm".
    + *
    + * @index: Index number of @arg_ptr.
    + * @arg_ptr: Contents of argv[@index].
    + * @argc: Length of @argv.
    + * @argv: Pointer to "struct tomoyo_argv_entry".
    + * @checked: Set to true if @argv[@index] was found.
    + *
    + * Returns true on success, false otherwise.
    + */
    +static bool tomoyo_argv(const unsigned int index, const char *arg_ptr,
    + const int argc, const struct tomoyo_argv_entry *argv,
    + u8 *checked)
    +{
    + int i;
    + struct tomoyo_path_info arg;
    + arg.name = arg_ptr;
    + for (i = 0; i < argc; argv++, checked++, i++) {
    + bool result;
    + if (index != argv->index)
    + continue;
    + *checked = 1;
    + tomoyo_fill_path_info(&arg);
    + result = tomoyo_path_matches_pattern(&arg, argv->value);
    + if (argv->is_not)
    + result = !result;
    + if (!result)
    + return false;
    + }
    + return true;
    +}
    +
    +/**
    + * tomoyo_envp - Check envp[] in "struct linux_binbrm".
    + *
    + * @env_name: The name of environment variable.
    + * @env_value: The value of environment variable.
    + * @envc: Length of @envp.
    + * @envp: Pointer to "struct tomoyo_envp_entry".
    + * @checked: Set to true if @envp[@env_name] was found.
    + *
    + * Returns true on success, false otherwise.
    + */
    +static bool tomoyo_envp(const char *env_name, const char *env_value,
    + const int envc, const struct tomoyo_envp_entry *envp,
    + u8 *checked)
    +{
    + int i;
    + struct tomoyo_path_info name;
    + struct tomoyo_path_info value;
    + name.name = env_name;
    + tomoyo_fill_path_info(&name);
    + value.name = env_value;
    + tomoyo_fill_path_info(&value);
    + for (i = 0; i < envc; envp++, checked++, i++) {
    + bool result;
    + if (!tomoyo_path_matches_pattern(&name, envp->name))
    + continue;
    + *checked = 1;
    + if (envp->value) {
    + result = tomoyo_path_matches_pattern(&value,
    + envp->value);
    + if (envp->is_not)
    + result = !result;
    + } else {
    + result = true;
    + if (!envp->is_not)
    + result = !result;
    + }
    + if (!result)
    + return false;
    + }
    + return true;
    +}
    +
    +/**
    + * tomoyo_scan_bprm - Scan "struct linux_binprm".
    + *
    + * @ee: Pointer to "struct tomoyo_execve_entry".
    + * @argc: Length of @argc.
    + * @argv: Pointer to "struct tomoyo_argv_entry".
    + * @envc: Length of @envp.
    + * @envp: Poiner to "struct tomoyo_envp_entry".
    + *
    + * Returns true on success, false otherwise.
    + */
    +static bool tomoyo_scan_bprm(struct tomoyo_execve_entry *ee, const u16 argc,
    + const struct tomoyo_argv_entry *argv,
    + const u16 envc,
    + const struct tomoyo_envp_entry *envp)
    +{
    + /*
    + if exec.argc=3
    + if (argc == 3)
    + if exec.argv[1]="-c"
    + if (argc >= 2 && !strcmp(argv[1], "-c"))
    + if exec.argv[1]!="-c"
    + if (argc < 2 || strcmp(argv[1], "-c"))
    + if exec.envc=10-20
    + if (envc >= 10 && envc <= 20)
    + if exec.envc!=10-20
    + if (envc < 10 || envc > 20)
    + if exec.envp["HOME"]!=NULL
    + if (getenv("HOME"))
    + if exec.envp["HOME"]=NULL
    + if (!getenv("HOME"))
    + if exec.envp["HOME"]="/"
    + if (getenv("HOME") && !strcmp(getenv("HOME"), "/"))
    + if exec.envp["HOME"]!="/"
    + if (!getenv("HOME") || strcmp(getenv("HOME", "/"))
    + */
    + struct linux_binprm *bprm = ee->bprm;
    + struct tomoyo_page_dump *dump = &ee->dump;
    + char *arg_ptr = ee->tmp;
    + int arg_len = 0;
    + unsigned long pos = bprm->p;
    + int offset = pos % PAGE_SIZE;
    + int argv_count = bprm->argc;
    + int envp_count = bprm->envc;
    + bool result = true;
    + u8 local_checked[32];
    + u8 *checked;
    + if (argc + envc <= sizeof(local_checked)) {
    + checked = local_checked;
    + memset(local_checked, 0, sizeof(local_checked));
    + } else {
    + checked = kzalloc(argc + envc, GFP_KERNEL);
    + if (!checked)
    + return false;
    + }
    + while (argv_count || envp_count) {
    + if (!tomoyo_dump_page(bprm, pos, dump)) {
    + result = false;
    + goto out;
    + }
    + pos += PAGE_SIZE - offset;
    + while (offset < PAGE_SIZE) {
    + /* Read. */
    + struct tomoyo_path_info arg;
    + const char *kaddr = dump->data;
    + const unsigned char c = kaddr[offset++];
    + arg.name = arg_ptr;
    + if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) {
    + if (c == '\\') {
    + arg_ptr[arg_len++] = '\\';
    + arg_ptr[arg_len++] = '\\';
    + } else if (c > ' ' && c < 127) {
    + arg_ptr[arg_len++] = c;
    + } else {
    + arg_ptr[arg_len++] = '\\';
    + arg_ptr[arg_len++] = (c >> 6) + '0';
    + arg_ptr[arg_len++] =
    + ((c >> 3) & 7) + '0';
    + arg_ptr[arg_len++] = (c & 7) + '0';
    + }
    + } else {
    + arg_ptr[arg_len] = '\0';
    + }
    + if (c)
    + continue;
    + /* Check. */
    + if (argv_count) {
    + if (!tomoyo_argv(bprm->argc - argv_count,
    + arg_ptr, argc, argv,
    + checked)) {
    + result = false;
    + break;
    + }
    + argv_count--;
    + } else if (envp_count) {
    + char *cp = strchr(arg_ptr, '=');
    + if (cp) {
    + *cp = '\0';
    + if (!tomoyo_envp(arg_ptr, cp + 1,
    + envc, envp,
    + checked + argc)) {
    + result = false;
    + break;
    + }
    + }
    + envp_count--;
    + } else {
    + break;
    + }
    + arg_len = 0;
    + }
    + offset = 0;
    + if (!result)
    + break;
    + }
    + out:
    + if (result) {
    + int i;
    + /* Check not-yet-checked entries. */
    + for (i = 0; i < argc; i++) {
    + if (checked[i])
    + continue;
    + /*
    + * Return true only if all unchecked indexes in
    + * bprm->argv[] are not matched.
    + */
    + if (argv[i].is_not)
    + continue;
    + result = false;
    + break;
    + }
    + for (i = 0; i < envc; envp++, i++) {
    + if (checked[argc + i])
    + continue;
    + /*
    + * Return true only if all unchecked environ variables
    + * in bprm->envp[] are either undefined or not matched.
    + */
    + if ((!envp->value && !envp->is_not) ||
    + (envp->value && envp->is_not))
    + continue;
    + result = false;
    + break;
    + }
    + }
    + if (checked != local_checked)
    + kfree(checked);
    + return result;
    +}
    +
    +static bool tomoyo_scan_exec_realpath(struct file *file,
    + const struct tomoyo_name_union *ptr,
    + const bool match)
    +{
    + bool result;
    + struct tomoyo_path_info exe;
    + if (!file)
    + return false;
    + exe.name = tomoyo_realpath_from_path(&file->f_path);
    + if (!exe.name)
    + return false;
    + tomoyo_fill_path_info(&exe);
    + result = tomoyo_compare_name_union(&exe, ptr);
    + kfree(exe.name);
    + return result == match;
    +}
    +
    +static bool tomoyo_parse_name_union_quoted(char *filename,
    + struct tomoyo_name_union *ptr)
    +{
    + bool result;
    + char *cp = NULL;
    + if (*filename == '"') {
    + cp = filename + strlen(filename) - 1;
    + if (*cp != '"')
    + return false;
    + *cp = '\0';
    + filename++;
    + }
    + result = tomoyo_parse_name_union(filename, ptr);
    + if (cp)
    + *cp = '"';
    + return result;
    +}
    +
    +/**
    + * tomoyo_get_dqword - tomoyo_get_name() for a quoted string.
    + *
    + * @start: String to save.
    + *
    + * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
    + */
    +static const struct tomoyo_path_info *tomoyo_get_dqword(char *start)
    +{
    + char *cp;
    + if (*start++ != '"')
    + return NULL;
    + cp = start;
    + while (1) {
    + const char c = *cp++;
    + if (!c)
    + return NULL;
    + if (c != '"' || *cp)
    + continue;
    + *(cp - 1) = '\0';
    + break;
    + }
    + if (!tomoyo_is_correct_path(start, 0, 0, 0))
    + return NULL;
    + return tomoyo_get_name(start);
    +}
    +
    +/**
    + * tomoyo_parse_argv - Parse an argv[] condition part.
    + *
    + * @start: String to parse.
    + * @argv: Pointer to "struct tomoyo_argv_entry".
    + *
    + * Returns true on success, false otherwise.
    + */
    +static bool tomoyo_parse_argv(char *start, struct tomoyo_argv_entry *argv)
    +{
    + unsigned long index;
    + const struct tomoyo_path_info *value;
    + bool is_not;
    + char c;
    + if (tomoyo_parse_ulong(&index, &start) != TOMOYO_VALUE_TYPE_DECIMAL)
    + goto out;
    + if (*start++ != ']')
    + goto out;
    + c = *start++;
    + if (c == '=')
    + is_not = false;
    + else if (c == '!' && *start++ == '=')
    + is_not = true;
    + else
    + goto out;
    + value = tomoyo_get_dqword(start);
    + if (!value)
    + goto out;
    + argv->index = index;
    + argv->is_not = is_not;
    + argv->value = value;
    + return true;
    + out:
    + return false;
    +}
    +
    +/**
    + * tomoyo_parse_envp - Parse an envp[] condition part.
    + *
    + * @start: String to parse.
    + * @envp: Pointer to "struct tomoyo_envp_entry".
    + *
    + * Returns true on success, false otherwise.
    + */
    +static bool tomoyo_parse_envp(char *start, struct tomoyo_envp_entry *envp)
    +{
    + const struct tomoyo_path_info *name;
    + const struct tomoyo_path_info *value;
    + bool is_not;
    + char *cp = start;
    + /*
    + * Since environment variable names don't
    + * contain '=', I can treat '"]=' and '"]!='
    + * sequences as delimiters.
    + */
    + while (1) {
    + if (!strncmp(start, "\"]=", 3)) {
    + is_not = false;
    + *start = '\0';
    + start += 3;
    + break;
    + } else if (!strncmp(start, "\"]!=", 4)) {
    + is_not = true;
    + *start = '\0';
    + start += 4;
    + break;
    + } else if (!*start++) {
    + goto out;
    + }
    + }
    + if (!*cp || !tomoyo_is_correct_path(cp, 0, 0, 0))
    + goto out;
    + name = tomoyo_get_name(cp);
    + if (!name)
    + goto out;
    + if (!strcmp(start, "NULL")) {
    + value = NULL;
    + } else {
    + value = tomoyo_get_dqword(start);
    + if (!value)
    + goto out;
    + }
    + envp->name = name;
    + envp->is_not = is_not;
    + envp->value = value;
    + return true;
    + out:
    + return false;
    +}
    +
    +/* The list for "struct tomoyo_condition". */
    +static LIST_HEAD(tomoyo_condition_list);
    +
    +const char *tomoyo_condition_keyword[TOMOYO_MAX_CONDITION_KEYWORD] = {
    + [TOMOYO_TASK_UID] = "task.uid",
    + [TOMOYO_TASK_EUID] = "task.euid",
    + [TOMOYO_TASK_SUID] = "task.suid",
    + [TOMOYO_TASK_FSUID] = "task.fsuid",
    + [TOMOYO_TASK_GID] = "task.gid",
    + [TOMOYO_TASK_EGID] = "task.egid",
    + [TOMOYO_TASK_SGID] = "task.sgid",
    + [TOMOYO_TASK_FSGID] = "task.fsgid",
    + [TOMOYO_TASK_PID] = "task.pid",
    + [TOMOYO_TASK_PPID] = "task.ppid",
    + [TOMOYO_EXEC_ARGC] = "exec.argc",
    + [TOMOYO_EXEC_ENVC] = "exec.envc",
    + [TOMOYO_TASK_STATE_0] = "task.state[0]",
    + [TOMOYO_TASK_STATE_1] = "task.state[1]",
    + [TOMOYO_TASK_STATE_2] = "task.state[2]",
    + [TOMOYO_TYPE_IS_SOCKET] = "socket",
    + [TOMOYO_TYPE_IS_SYMLINK] = "symlink",
    + [TOMOYO_TYPE_IS_FILE] = "file",
    + [TOMOYO_TYPE_IS_BLOCK_DEV] = "block",
    + [TOMOYO_TYPE_IS_DIRECTORY] = "directory",
    + [TOMOYO_TYPE_IS_CHAR_DEV] = "char",
    + [TOMOYO_TYPE_IS_FIFO] = "fifo",
    + [TOMOYO_MODE_SETUID] = "setuid",
    + [TOMOYO_MODE_SETGID] = "setgid",
    + [TOMOYO_MODE_STICKY] = "sticky",
    + [TOMOYO_MODE_OWNER_READ] = "owner_read",
    + [TOMOYO_MODE_OWNER_WRITE] = "owner_write",
    + [TOMOYO_MODE_OWNER_EXECUTE] = "owner_execute",
    + [TOMOYO_MODE_GROUP_READ] = "group_read",
    + [TOMOYO_MODE_GROUP_WRITE] = "group_write",
    + [TOMOYO_MODE_GROUP_EXECUTE] = "group_execute",
    + [TOMOYO_MODE_OTHERS_READ] = "others_read",
    + [TOMOYO_MODE_OTHERS_WRITE] = "others_write",
    + [TOMOYO_MODE_OTHERS_EXECUTE] = "others_execute",
    + [TOMOYO_TASK_TYPE] = "task.type",
    + [TOMOYO_TASK_EXECUTE_HANDLER] = "execute_handler",
    + [TOMOYO_EXEC_REALPATH] = "exec.realpath",
    + [TOMOYO_SYMLINK_TARGET] = "symlink.target",
    + [TOMOYO_PATH1_UID] = "path1.uid",
    + [TOMOYO_PATH1_GID] = "path1.gid",
    + [TOMOYO_PATH1_INO] = "path1.ino",
    + [TOMOYO_PATH1_MAJOR] = "path1.major",
    + [TOMOYO_PATH1_MINOR] = "path1.minor",
    + [TOMOYO_PATH1_PERM] = "path1.perm",
    + [TOMOYO_PATH1_TYPE] = "path1.type",
    + [TOMOYO_PATH1_DEV_MAJOR] = "path1.dev_major",
    + [TOMOYO_PATH1_DEV_MINOR] = "path1.dev_minor",
    + [TOMOYO_PATH2_UID] = "path2.uid",
    + [TOMOYO_PATH2_GID] = "path2.gid",
    + [TOMOYO_PATH2_INO] = "path2.ino",
    + [TOMOYO_PATH2_MAJOR] = "path2.major",
    + [TOMOYO_PATH2_MINOR] = "path2.minor",
    + [TOMOYO_PATH2_PERM] = "path2.perm",
    + [TOMOYO_PATH2_TYPE] = "path2.type",
    + [TOMOYO_PATH2_DEV_MAJOR] = "path2.dev_major",
    + [TOMOYO_PATH2_DEV_MINOR] = "path2.dev_minor",
    + [TOMOYO_PATH1_PARENT_UID] = "path1.parent.uid",
    + [TOMOYO_PATH1_PARENT_GID] = "path1.parent.gid",
    + [TOMOYO_PATH1_PARENT_INO] = "path1.parent.ino",
    + [TOMOYO_PATH1_PARENT_PERM] = "path1.parent.perm",
    + [TOMOYO_PATH2_PARENT_UID] = "path2.parent.uid",
    + [TOMOYO_PATH2_PARENT_GID] = "path2.parent.gid",
    + [TOMOYO_PATH2_PARENT_INO] = "path2.parent.ino",
    + [TOMOYO_PATH2_PARENT_PERM] = "path2.parent.perm",
    +};
    +
    +/**
    + * tomoyo_parse_post_condition - Parse post-condition part.
    + *
    + * @condition: String to parse.
    + * @post_state: Buffer to store post-condition part.
    + *
    + * Returns true on success, false otherwise.
    + */
    +static bool tomoyo_parse_post_condition(char * const condition,
    + u8 post_state[4])
    +{
    + char *start = strstr(condition, "; set ");
    + if (!start)
    + return true;
    + *start = '\0';
    + start += 6;
    + while (1) {
    + int i;
    + unsigned long value;
    + while (*start == ' ')
    + start++;
    + if (!*start)
    + break;
    + if (!strncmp(start, "task.state[0]=", 14))
    + i = 0;
    + else if (!strncmp(start, "task.state[1]=", 14))
    + i = 1;
    + else if (!strncmp(start, "task.state[2]=", 14))
    + i = 2;
    + else
    + goto out;
    + start += 14;
    + if (post_state[3] & (1 << i))
    + goto out;
    + post_state[3] |= 1 << i;
    + if (!tomoyo_parse_ulong(&value, &start) || value > 255)
    + goto out;
    + post_state[i] = (u8) value;
    + }
    + return true;
    + out:
    + return false;
    +}
    +
    +/**
    + * tomoyo_get_condition - Parse condition part.
    + *
    + * @condition: Pointer to string to parse.
    + *
    + * Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
    + */
    +struct tomoyo_condition *tomoyo_get_condition(char * const condition)
    +{
    + static const bool debug;
    + char *start = condition;
    + struct tomoyo_condition *entry = NULL;
    + struct tomoyo_condition *ptr;
    + struct tomoyo_condition_element *condp;
    + struct tomoyo_number_union *numbers_p;
    + struct tomoyo_name_union *names_p;
    + struct tomoyo_argv_entry *argv;
    + struct tomoyo_envp_entry *envp;
    + u32 size;
    + u8 i;
    + bool found = false;
    + u16 condc = 0;
    + u16 numbers_count = 0;
    + u16 names_count = 0;
    + u16 argc = 0;
    + u16 envc = 0;
    + u8 post_state[4] = { 0, 0, 0, 0 };
    + char *end_of_string;
    + if (!tomoyo_parse_post_condition(start, post_state))
    + goto out;
    + start = condition;
    + if (!strncmp(start, "if ", 3))
    + start += 3;
    + else if (*start)
    + return NULL;
    + end_of_string = start + strlen(start);
    + while (1) {
    + u8 left;
    + u8 right;
    + char *word = start;
    + char *cp;
    + char *eq;
    + bool is_not = false;
    + if (!*word)
    + break;
    + cp = strchr(start, ' ');
    + if (cp) {
    + *cp = '\0';
    + start = cp + 1;
    + } else {
    + start = "";
    + }
    + if (debug)
    + printk(KERN_WARNING "%u: <%s>\n", __LINE__, word);
    + if (!strncmp(word, "exec.argv[", 10)) {
    + argc++;
    + condc++;
    + continue;
    + } else if (!strncmp(word, "exec.envp[\"", 11)) {
    + envc++;
    + condc++;
    + continue;
    + }
    + eq = strchr(word, '=');
    + if (!eq)
    + goto out;
    + if (eq > word && *(eq - 1) == '!') {
    + is_not = true;
    + eq--;
    + }
    + *eq = '\0';
    + for (left = 0; left < TOMOYO_MAX_CONDITION_KEYWORD; left++) {
    + if (strcmp(word, tomoyo_condition_keyword[left]))
    + continue;
    + break;
    + }
    + if (debug)
    + printk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__,
    + word, left);
    + if (left == TOMOYO_MAX_CONDITION_KEYWORD)
    + numbers_count++;
    + *eq = is_not ? '!' : '=';
    + word = eq + 1;
    + if (is_not)
    + word++;
    + condc++;
    + if (debug)
    + printk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__,
    + word, left);
    + if (left == TOMOYO_EXEC_REALPATH ||
    + left == TOMOYO_SYMLINK_TARGET) {
    + names_count++;
    + continue;
    + }
    + for (right = 0; right < TOMOYO_MAX_CONDITION_KEYWORD;
    + right++) {
    + if (strcmp(word, tomoyo_condition_keyword[right]))
    + continue;
    + break;
    + }
    + if (debug)
    + printk(KERN_WARNING "%u: <%s> right=%u\n", __LINE__,
    + word, right);
    + if (right == TOMOYO_MAX_CONDITION_KEYWORD)
    + numbers_count++;
    + }
    + if (debug)
    + printk(KERN_DEBUG "%u: cond=%u numbers=%u names=%u ac=%u "
    + "ec=%u\n", __LINE__, condc, numbers_count, names_count,
    + argc, envc);
    + size = sizeof(*entry)
    + + condc * sizeof(struct tomoyo_condition_element)
    + + numbers_count * sizeof(struct tomoyo_number_union)
    + + names_count * sizeof(struct tomoyo_name_union)
    + + argc * sizeof(struct tomoyo_argv_entry)
    + + envc * sizeof(struct tomoyo_envp_entry);
    + entry = kzalloc(size, GFP_KERNEL);
    + if (!entry)
    + return NULL;
    + atomic_set(&entry->users, 1);
    + INIT_LIST_HEAD(&entry->list);
    + for (i = 0; i < 4; i++)
    + entry->post_state[i] = post_state[i];
    + entry->condc = condc;
    + entry->numbers_count = numbers_count;
    + entry->names_count = names_count;
    + entry->argc = argc;
    + entry->envc = envc;
    + condp = (struct tomoyo_condition_element *) (entry + 1);
    + numbers_p = (struct tomoyo_number_union *) (condp + condc);
    + names_p = (struct tomoyo_name_union *) (numbers_p + numbers_count);
    + argv = (struct tomoyo_argv_entry *) (names_p + names_count);
    + envp = (struct tomoyo_envp_entry *) (argv + argc);
    + for (start = condition; start < end_of_string; start++)
    + if (!*start)
    + *start = ' ';
    + start = condition;
    + if (!strncmp(start, "if ", 3))
    + start += 3;
    + else if (*start)
    + goto out;
    + while (1) {
    + u8 left;
    + u8 right;
    + char *word = start;
    + char *cp;
    + char *eq;
    + bool is_not = false;
    + if (!*word)
    + break;
    + cp = strchr(start, ' ');
    + if (cp) {
    + *cp = '\0';
    + start = cp + 1;
    + } else {
    + start = "";
    + }
    + if (debug)
    + printk(KERN_WARNING "%u: <%s>\n", __LINE__, word);
    + if (!strncmp(word, "exec.argv[", 10)) {
    + if (!tomoyo_parse_argv(word + 10, argv))
    + goto out;
    + argv++;
    + argc--;
    + condc--;
    + left = TOMOYO_ARGV_ENTRY;
    + right = -1;
    + goto store_value;
    + } else if (!strncmp(word, "exec.envp[\"", 11)) {
    + if (!tomoyo_parse_envp(word + 11, envp))
    + goto out;
    + envp++;
    + envc--;
    + condc--;
    + left = TOMOYO_ENVP_ENTRY;
    + right = -1;
    + goto store_value;
    + }
    + eq = strchr(word, '=');
    + if (!eq) {
    + if (debug)
    + printk(KERN_WARNING "%u: No operator.\n",
    + __LINE__);
    + goto out;
    + }
    + if (eq > word && *(eq - 1) == '!') {
    + is_not = true;
    + eq--;
    + }
    + *eq = '\0';
    + for (left = 0; left < TOMOYO_MAX_CONDITION_KEYWORD; left++) {
    + if (strcmp(word, tomoyo_condition_keyword[left]))
    + continue;
    + break;
    + }
    + if (debug)
    + printk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__,
    + word, left);
    + if (left == TOMOYO_MAX_CONDITION_KEYWORD) {
    + left = TOMOYO_NUMBER_UNION;
    + if (!tomoyo_parse_number_union(word, numbers_p))
    + goto out;
    + if (numbers_p->is_group)
    + goto out;
    + numbers_p++;
    + numbers_count--;
    + }
    + *eq = is_not ? '!' : '=';
    + word = eq + 1;
    + if (is_not)
    + word++;
    + condc--;
    + if (debug)
    + printk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__,
    + word, left);
    + if (left == TOMOYO_EXEC_REALPATH ||
    + left == TOMOYO_SYMLINK_TARGET) {
    + right = TOMOYO_NAME_UNION;
    + if (!tomoyo_parse_name_union_quoted(word, names_p++))
    + goto out;
    + names_count--;
    + goto store_value;
    + }
    + for (right = 0; right < TOMOYO_MAX_CONDITION_KEYWORD;
    + right++) {
    + if (strcmp(word, tomoyo_condition_keyword[right]))
    + continue;
    + break;
    + }
    + if (right == TOMOYO_MAX_CONDITION_KEYWORD) {
    + right = TOMOYO_NUMBER_UNION;
    + if (!tomoyo_parse_number_union(word, numbers_p++))
    + goto out;
    + numbers_count--;
    + }
    + store_value:
    + condp->left = left;
    + condp->right = right;
    + condp->equals = !is_not;
    + if (debug)
    + printk(KERN_WARNING "%u: left=%u right=%u match=%u\n",
    + __LINE__, condp->left, condp->right,
    + condp->equals);
    + condp++;
    + }
    + if (debug) {
    + for (start = condition; start < end_of_string; start++)
    + if (!*start)
    + *start = ' ';
    + printk(KERN_DEBUG "%u: <%s> cond=%u numbers=%u names=%u ac=%u "
    + "ec=%u\n", __LINE__, condition, condc, numbers_count,
    + names_count, argc, envc);
    + }
    + BUG_ON(names_count);
    + BUG_ON(numbers_count);
    + BUG_ON(argc);
    + BUG_ON(envc);
    + BUG_ON(condc);
    + entry->size = size;
    + mutex_lock(&tomoyo_policy_lock);
    + list_for_each_entry_rcu(ptr, &tomoyo_condition_list, list) {
    + if (tomoyo_memcmp(ptr, entry, offsetof(typeof(*entry), size),
    + size))
    + continue;
    + /* Same entry found. Share this entry. */
    + atomic_inc(&ptr->users);
    + found = true;
    + break;
    + }
    + if (!found) {
    + if (tomoyo_memory_ok(entry, size)) {
    + list_add_rcu(&entry->list, &tomoyo_condition_list);
    + } else {
    + found = true;
    + ptr = NULL;
    + }
    + }
    + mutex_unlock(&tomoyo_policy_lock);
    + if (found) {
    + entry->size = 0;
    + tomoyo_put_condition(entry);
    + entry = ptr;
    + }
    + return entry;
    + out:
    + if (debug)
    + printk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
    + tomoyo_put_condition(entry);
    + return NULL;
    +}
    +
    +/**
    + * tomoyo_get_attributes - Revalidate "struct inode".
    + *
    + * @obj: Pointer to "struct tomoyo_obj_info".
    + *
    + * Returns nothing.
    + */
    +void tomoyo_get_attributes(struct tomoyo_obj_info *obj)
    +{
    + struct vfsmount *mnt;
    + struct dentry *dentry;
    + struct inode *inode;
    + struct kstat stat;
    +
    + if (!obj->path1.mnt)
    + goto no_path1;
    +
    + /* Get information on "path1". */
    + mnt = obj->path1.mnt;
    + dentry = obj->path1.dentry;
    + inode = dentry->d_inode;
    + if (inode) {
    + if (!inode->i_op || vfs_getattr(mnt, dentry, &stat)) {
    + /* Nothing to do. */
    + } else {
    + obj->path1_stat.uid = stat.uid;
    + obj->path1_stat.gid = stat.gid;
    + obj->path1_stat.ino = stat.ino;
    + obj->path1_stat.mode = stat.mode;
    + obj->path1_stat.dev = stat.dev;
    + obj->path1_stat.rdev = stat.rdev;
    + obj->path1_valid = true;
    + }
    + }
    +
    + /* Get information on "path1.parent". */
    + dentry = dget_parent(obj->path1.dentry);
    + inode = dentry->d_inode;
    + if (inode) {
    + if (!inode->i_op || vfs_getattr(mnt, dentry, &stat)) {
    + /* Nothing to do. */
    + } else {
    + obj->path1_parent_stat.uid = stat.uid;
    + obj->path1_parent_stat.gid = stat.gid;
    + obj->path1_parent_stat.ino = stat.ino;
    + obj->path1_parent_stat.mode = stat.mode;
    + obj->path1_parent_stat.dev = stat.dev;
    + obj->path1_parent_stat.rdev = stat.rdev;
    + obj->path1_parent_valid = true;
    + }
    + }
    + dput(dentry);
    +
    + no_path1:
    + mnt = obj->path2.mnt;
    + if (!mnt)
    + return;
    +
    + /* Get information on "path2". */
    + dentry = obj->path2.dentry;
    + inode = dentry->d_inode;
    + if (inode) {
    + if (!inode->i_op || vfs_getattr(mnt, dentry, &stat)) {
    + /* Nothing to do. */
    + } else {
    + obj->path2_stat.uid = stat.uid;
    + obj->path2_stat.gid = stat.gid;
    + obj->path2_stat.ino = stat.ino;
    + obj->path2_stat.mode = stat.mode;
    + obj->path2_stat.dev = stat.dev;
    + obj->path2_stat.rdev = stat.rdev;
    + obj->path2_valid = true;
    + }
    + }
    +
    + /* Get information on "path2.parent". */
    + dentry = dget_parent(obj->path2.dentry);
    + inode = dentry->d_inode;
    + if (inode) {
    + if (!inode->i_op || vfs_getattr(mnt, dentry, &stat)) {
    + /* Nothing to do. */
    + } else {
    + obj->path2_parent_stat.uid = stat.uid;
    + obj->path2_parent_stat.gid = stat.gid;
    + obj->path2_parent_stat.ino = stat.ino;
    + obj->path2_parent_stat.mode = stat.mode;
    + obj->path2_parent_stat.dev = stat.dev;
    + obj->path2_parent_stat.rdev = stat.rdev;
    + obj->path2_parent_valid = true;
    + }
    + }
    + dput(dentry);
    +}
    +
    +/**
    + * tomoyo_condition - Check condition part.
    + *
    + * @r: Pointer to "struct tomoyo_request_info".
    + * @acl: Pointer to "struct tomoyo_acl_info".
    + *
    + * Returns true on success, false otherwise.
    + *
    + * Caller holds tomoyo_read_lock().
    + */
    +bool tomoyo_condition(struct tomoyo_request_info *r,
    + const struct tomoyo_acl_info *acl)
    +{
    + const struct task_struct *task = current;
    + u32 i;
    + unsigned long left_min = 0;
    + unsigned long left_max = 0;
    + unsigned long right_min = 0;
    + unsigned long right_max = 0;
    + const struct tomoyo_condition_element *condp;
    + const struct tomoyo_number_union *numbers_p;
    + const struct tomoyo_name_union *names_p;
    + const struct tomoyo_argv_entry *argv;
    + const struct tomoyo_envp_entry *envp;
    + struct tomoyo_obj_info *obj;
    + u16 condc;
    + u16 argc;
    + u16 envc;
    + struct linux_binprm *bprm = NULL;
    + const struct tomoyo_condition *cond = acl->cond;
    + if (!cond)
    + return true;
    + condc = cond->condc;
    + argc = cond->argc;
    + envc = cond->envc;
    + obj = r->obj;
    + if (r->ee)
    + bprm = r->ee->bprm;
    + if (!bprm && (argc || envc))
    + return false;
    + condp = (struct tomoyo_condition_element *) (cond + 1);
    + numbers_p = (const struct tomoyo_number_union *) (condp + condc);
    + names_p = (const struct tomoyo_name_union *)
    + (numbers_p + cond->numbers_count);
    + argv = (const struct tomoyo_argv_entry *) (names_p +
    + cond->names_count);
    + envp = (const struct tomoyo_envp_entry *) (argv + argc);
    + for (i = 0; i < condc; i++) {
    + const bool match = condp->equals;
    + const u8 left = condp->left;
    + const u8 right = condp->right;
    + bool left_is_bitop = false;
    + bool right_is_bitop = false;
    + u8 j;
    + condp++;
    + /* Check argv[] and envp[] later. */
    + if (left == TOMOYO_ARGV_ENTRY || left == TOMOYO_ENVP_ENTRY)
    + continue;
    + /* Check string expressions. */
    + if (right == TOMOYO_NAME_UNION) {
    + const struct tomoyo_name_union *ptr = names_p++;
    + switch (left) {
    + struct tomoyo_path_info *symlink;
    + struct tomoyo_execve_entry *ee;
    + struct file *file;
    + case TOMOYO_SYMLINK_TARGET:
    + symlink = obj->symlink_target;
    + if (!symlink ||
    + tomoyo_compare_name_union(symlink, ptr)
    + != match)
    + goto out;
    + break;
    + case TOMOYO_EXEC_REALPATH:
    + ee = r->ee;
    + file = ee ? ee->bprm->file : NULL;
    + if (!tomoyo_scan_exec_realpath(file, ptr,
    + match))
    + goto out;
    + break;
    + }
    + continue;
    + }
    + /* Check numeric or bit-op expressions. */
    + for (j = 0; j < 2; j++) {
    + const u8 index = j ? right : left;
    + unsigned long value = 0;
    + bool is_bitop = false;
    + switch (index) {
    + case TOMOYO_TASK_UID:
    + value = current_uid();
    + break;
    + case TOMOYO_TASK_EUID:
    + value = current_euid();
    + break;
    + case TOMOYO_TASK_SUID:
    + value = current_suid();
    + break;
    + case TOMOYO_TASK_FSUID:
    + value = current_fsuid();
    + break;
    + case TOMOYO_TASK_GID:
    + value = current_gid();
    + break;
    + case TOMOYO_TASK_EGID:
    + value = current_egid();
    + break;
    + case TOMOYO_TASK_SGID:
    + value = current_sgid();
    + break;
    + case TOMOYO_TASK_FSGID:
    + value = current_fsgid();
    + break;
    + case TOMOYO_TASK_PID:
    + value = sys_getpid();
    + break;
    + case TOMOYO_TASK_PPID:
    + value = sys_getppid();
    + break;
    + case TOMOYO_TYPE_IS_SOCKET:
    + value = S_IFSOCK;
    + break;
    + case TOMOYO_TYPE_IS_SYMLINK:
    + value = S_IFLNK;
    + break;
    + case TOMOYO_TYPE_IS_FILE:
    + value = S_IFREG;
    + break;
    + case TOMOYO_TYPE_IS_BLOCK_DEV:
    + value = S_IFBLK;
    + break;
    + case TOMOYO_TYPE_IS_DIRECTORY:
    + value = S_IFDIR;
    + break;
    + case TOMOYO_TYPE_IS_CHAR_DEV:
    + value = S_IFCHR;
    + break;
    + case TOMOYO_TYPE_IS_FIFO:
    + value = S_IFIFO;
    + break;
    + case TOMOYO_MODE_SETUID:
    + value = S_ISUID;
    + is_bitop = true;
    + break;
    + case TOMOYO_MODE_SETGID:
    + value = S_ISGID;
    + is_bitop = true;
    + break;
    + case TOMOYO_MODE_STICKY:
    + value = S_ISVTX;
    + is_bitop = true;
    + break;
    + case TOMOYO_MODE_OWNER_READ:
    + value = S_IRUSR;
    + is_bitop = true;
    + break;
    + case TOMOYO_MODE_OWNER_WRITE:
    + value = S_IWUSR;
    + is_bitop = true;
    + break;
    + case TOMOYO_MODE_OWNER_EXECUTE:
    + value = S_IXUSR;
    + is_bitop = true;
    + break;
    + case TOMOYO_MODE_GROUP_READ:
    + value = S_IRGRP;
    + is_bitop = true;
    + break;
    + case TOMOYO_MODE_GROUP_WRITE:
    + value = S_IWGRP;
    + is_bitop = true;
    + break;
    + case TOMOYO_MODE_GROUP_EXECUTE:
    + value = S_IXGRP;
    + is_bitop = true;
    + break;
    + case TOMOYO_MODE_OTHERS_READ:
    + value = S_IROTH;
    + is_bitop = true;
    + break;
    + case TOMOYO_MODE_OTHERS_WRITE:
    + value = S_IWOTH;
    + is_bitop = true;
    + break;
    + case TOMOYO_MODE_OTHERS_EXECUTE:
    + value = S_IXOTH;
    + is_bitop = true;
    + break;
    + case TOMOYO_EXEC_ARGC:
    + if (!bprm)
    + goto out;
    + value = bprm->argc;
    + break;
    + case TOMOYO_EXEC_ENVC:
    + if (!bprm)
    + goto out;
    + value = bprm->envc;
    + break;
    + case TOMOYO_TASK_STATE_0:
    + value = (u8) (task->tomoyo_flags >> 24);
    + break;
    + case TOMOYO_TASK_STATE_1:
    + value = (u8) (task->tomoyo_flags >> 16);
    + break;
    + case TOMOYO_TASK_STATE_2:
    + value = (u8) (task->tomoyo_flags >> 8);
    + break;
    + case TOMOYO_TASK_TYPE:
    + value = ((u8) task->tomoyo_flags)
    + & TOMOYO_TASK_IS_EXECUTE_HANDLER;
    + break;
    + case TOMOYO_TASK_EXECUTE_HANDLER:
    + value = TOMOYO_TASK_IS_EXECUTE_HANDLER;
    + break;
    + case TOMOYO_NUMBER_UNION:
    + /* Fetch values later. */
    + break;
    + default:
    + if (!obj)
    + goto out;
    + if (!obj->validate_done) {
    + tomoyo_get_attributes(obj);
    + obj->validate_done = true;
    + }
    + switch (index) {
    + case TOMOYO_PATH1_UID:
    + if (!obj->path1_valid)
    + goto out;
    + value = obj->path1_stat.uid;
    + break;
    + case TOMOYO_PATH1_GID:
    + if (!obj->path1_valid)
    + goto out;
    + value = obj->path1_stat.gid;
    + break;
    + case TOMOYO_PATH1_INO:
    + if (!obj->path1_valid)
    + goto out;
    + value = obj->path1_stat.ino;
    + break;
    + case TOMOYO_PATH1_MAJOR:
    + if (!obj->path1_valid)
    + goto out;
    + value = MAJOR(obj->path1_stat.dev);
    + break;
    + case TOMOYO_PATH1_MINOR:
    + if (!obj->path1_valid)
    + goto out;
    + value = MINOR(obj->path1_stat.dev);
    + break;
    + case TOMOYO_PATH1_TYPE:
    + if (!obj->path1_valid)
    + goto out;
    + value = obj->path1_stat.mode & S_IFMT;
    + break;
    + case TOMOYO_PATH1_DEV_MAJOR:
    + if (!obj->path1_valid)
    + goto out;
    + value = MAJOR(obj->path1_stat.rdev);
    + break;
    + case TOMOYO_PATH1_DEV_MINOR:
    + if (!obj->path1_valid)
    + goto out;
    + value = MINOR(obj->path1_stat.rdev);
    + break;
    + case TOMOYO_PATH1_PERM:
    + if (!obj->path1_valid)
    + goto out;
    + value = obj->path1_stat.mode
    + & S_IALLUGO;
    + break;
    + case TOMOYO_PATH2_UID:
    + if (!obj->path2_valid)
    + goto out;
    + value = obj->path2_stat.uid;
    + break;
    + case TOMOYO_PATH2_GID:
    + if (!obj->path2_valid)
    + goto out;
    + value = obj->path2_stat.gid;
    + break;
    + case TOMOYO_PATH2_INO:
    + if (!obj->path2_valid)
    + goto out;
    + value = obj->path2_stat.ino;
    + break;
    + case TOMOYO_PATH2_MAJOR:
    + if (!obj->path2_valid)
    + goto out;
    + value = MAJOR(obj->path2_stat.dev);
    + break;
    + case TOMOYO_PATH2_MINOR:
    + if (!obj->path2_valid)
    + goto out;
    + value = MINOR(obj->path2_stat.dev);
    + break;
    + case TOMOYO_PATH2_TYPE:
    + if (!obj->path2_valid)
    + goto out;
    + value = obj->path2_stat.mode & S_IFMT;
    + break;
    + case TOMOYO_PATH2_DEV_MAJOR:
    + if (!obj->path2_valid)
    + goto out;
    + value = MAJOR(obj->path2_stat.rdev);
    + break;
    + case TOMOYO_PATH2_DEV_MINOR:
    + if (!obj->path2_valid)
    + goto out;
    + value = MINOR(obj->path2_stat.rdev);
    + break;
    + case TOMOYO_PATH2_PERM:
    + if (!obj->path2_valid)
    + goto out;
    + value = obj->path2_stat.mode
    + & S_IALLUGO;
    + break;
    + case TOMOYO_PATH1_PARENT_UID:
    + if (!obj->path1_parent_valid)
    + goto out;
    + value = obj->path1_parent_stat.uid;
    + break;
    + case TOMOYO_PATH1_PARENT_GID:
    + if (!obj->path1_parent_valid)
    + goto out;
    + value = obj->path1_parent_stat.gid;
    + break;
    + case TOMOYO_PATH1_PARENT_INO:
    + if (!obj->path1_parent_valid)
    + goto out;
    + value = obj->path1_parent_stat.ino;
    + break;
    + case TOMOYO_PATH1_PARENT_PERM:
    + if (!obj->path1_parent_valid)
    + goto out;
    + value = obj->path1_parent_stat.mode
    + & S_IALLUGO;
    + break;
    + case TOMOYO_PATH2_PARENT_UID:
    + if (!obj->path2_parent_valid)
    + goto out;
    + value = obj->path2_parent_stat.uid;
    + break;
    + case TOMOYO_PATH2_PARENT_GID:
    + if (!obj->path2_parent_valid)
    + goto out;
    + value = obj->path2_parent_stat.gid;
    + break;
    + case TOMOYO_PATH2_PARENT_INO:
    + if (!obj->path2_parent_valid)
    + goto out;
    + value = obj->path2_parent_stat.ino;
    + break;
    + case TOMOYO_PATH2_PARENT_PERM:
    + if (!obj->path2_parent_valid)
    + goto out;
    + value = obj->path2_parent_stat.mode
    + & S_IALLUGO;
    + break;
    + }
    + break;
    + }
    + value = value;
    + if (j) {
    + right_max = value;
    + right_min = value;
    + right_is_bitop = is_bitop;
    + } else {
    + left_max = value;
    + left_min = value;
    + left_is_bitop = is_bitop;
    + }
    + }
    + if (left == TOMOYO_NUMBER_UNION) {
    + /* Fetch values now. */
    + const struct tomoyo_number_union *ptr = numbers_p++;
    + left_min = ptr->values[0];
    + left_max = ptr->values[1];
    + }
    + if (right == TOMOYO_NUMBER_UNION) {
    + /* Fetch values now. */
    + const struct tomoyo_number_union *ptr = numbers_p++;
    + if (ptr->is_group) {
    + if (tomoyo_number_matches_group(left_min,
    + left_max,
    + ptr->group)
    + == match)
    + continue;
    + } else {
    + if ((left_min <= ptr->values[1] &&
    + left_max >= ptr->values[0]) == match)
    + continue;
    + }
    + goto out;
    + }
    + /*
    + * Bit operation is valid only when counterpart value
    + * represents permission.
    + */
    + if (left_is_bitop && right_is_bitop)
    + goto out;
    + if (left_is_bitop) {
    + switch (right) {
    + case TOMOYO_PATH1_PERM:
    + case TOMOYO_PATH1_PARENT_PERM:
    + case TOMOYO_PATH2_PERM:
    + case TOMOYO_PATH2_PARENT_PERM:
    + if (match) {
    + if ((right_max & left_max))
    + continue;
    + } else {
    + if (!(right_max & left_max))
    + continue;
    + }
    + }
    + goto out;
    + }
    + if (right_is_bitop) {
    + switch (left) {
    + case TOMOYO_PATH1_PERM:
    + case TOMOYO_PATH1_PARENT_PERM:
    + case TOMOYO_PATH2_PERM:
    + case TOMOYO_PATH2_PARENT_PERM:
    + if (match) {
    + if ((left_max & right_max))
    + continue;
    + } else {
    + if (!(left_max & right_max))
    + continue;
    + }
    + }
    + goto out;
    + }
    + /* Normal value range comparison. */
    + if (match) {
    + if (left_min <= right_max && left_max >= right_min)
    + continue;
    + } else {
    + if (left_min > right_max || left_max < right_min)
    + continue;
    + }
    + out:
    + return false;
    + }
    + /* Check argv[] and envp[] now. */
    + if (r->ee && (argc || envc))
    + return tomoyo_scan_bprm(r->ee, argc, argv, envc, envp);
    + return true;
    +}
    --


    \
     
     \ /
      Last update: 2009-10-04 15:01    [W:0.121 / U:89.424 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site