diff options
Diffstat (limited to 'security/tomoyo/file.c')
| -rw-r--r-- | security/tomoyo/file.c | 1727 |
1 files changed, 720 insertions, 1007 deletions
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 9a6c58881c0..40039079074 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -1,1115 +1,726 @@ /* * security/tomoyo/file.c * - * Implementation of the Domain-Based Mandatory Access Control. - * - * Copyright (C) 2005-2009 NTT DATA CORPORATION - * - * Version: 2.2.0 2009/04/01 - * + * Copyright (C) 2005-2011 NTT DATA CORPORATION */ #include "common.h" -#include "tomoyo.h" -#include "realpath.h" +#include <linux/slab.h> /* - * tomoyo_globally_readable_file_entry is a structure which is used for holding - * "allow_read" entries. - * It has following fields. - * - * (1) "list" which is linked to tomoyo_globally_readable_list . - * (2) "filename" is a pathname which is allowed to open(O_RDONLY). - * (3) "is_deleted" is a bool which is true if marked as deleted, false - * otherwise. + * Mapping table from "enum tomoyo_path_acl_index" to "enum tomoyo_mac_index". */ -struct tomoyo_globally_readable_file_entry { - struct list_head list; - const struct tomoyo_path_info *filename; - bool is_deleted; +static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = { + [TOMOYO_TYPE_EXECUTE] = TOMOYO_MAC_FILE_EXECUTE, + [TOMOYO_TYPE_READ] = TOMOYO_MAC_FILE_OPEN, + [TOMOYO_TYPE_WRITE] = TOMOYO_MAC_FILE_OPEN, + [TOMOYO_TYPE_APPEND] = TOMOYO_MAC_FILE_OPEN, + [TOMOYO_TYPE_UNLINK] = TOMOYO_MAC_FILE_UNLINK, + [TOMOYO_TYPE_GETATTR] = TOMOYO_MAC_FILE_GETATTR, + [TOMOYO_TYPE_RMDIR] = TOMOYO_MAC_FILE_RMDIR, + [TOMOYO_TYPE_TRUNCATE] = TOMOYO_MAC_FILE_TRUNCATE, + [TOMOYO_TYPE_SYMLINK] = TOMOYO_MAC_FILE_SYMLINK, + [TOMOYO_TYPE_CHROOT] = TOMOYO_MAC_FILE_CHROOT, + [TOMOYO_TYPE_UMOUNT] = TOMOYO_MAC_FILE_UMOUNT, }; /* - * tomoyo_pattern_entry is a structure which is used for holding - * "tomoyo_pattern_list" entries. - * It has following fields. - * - * (1) "list" which is linked to tomoyo_pattern_list . - * (2) "pattern" is a pathname pattern which is used for converting pathnames - * to pathname patterns during learning mode. - * (3) "is_deleted" is a bool which is true if marked as deleted, false - * otherwise. + * Mapping table from "enum tomoyo_mkdev_acl_index" to "enum tomoyo_mac_index". */ -struct tomoyo_pattern_entry { - struct list_head list; - const struct tomoyo_path_info *pattern; - bool is_deleted; +const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = { + [TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK, + [TOMOYO_TYPE_MKCHAR] = TOMOYO_MAC_FILE_MKCHAR, }; /* - * tomoyo_no_rewrite_entry is a structure which is used for holding - * "deny_rewrite" entries. - * It has following fields. - * - * (1) "list" which is linked to tomoyo_no_rewrite_list . - * (2) "pattern" is a pathname which is by default not permitted to modify - * already existing content. - * (3) "is_deleted" is a bool which is true if marked as deleted, false - * otherwise. + * Mapping table from "enum tomoyo_path2_acl_index" to "enum tomoyo_mac_index". */ -struct tomoyo_no_rewrite_entry { - struct list_head list; - const struct tomoyo_path_info *pattern; - bool is_deleted; -}; - -/* Keyword array for single path operations. */ -static const char *tomoyo_sp_keyword[TOMOYO_MAX_SINGLE_PATH_OPERATION] = { - [TOMOYO_TYPE_READ_WRITE_ACL] = "read/write", - [TOMOYO_TYPE_EXECUTE_ACL] = "execute", - [TOMOYO_TYPE_READ_ACL] = "read", - [TOMOYO_TYPE_WRITE_ACL] = "write", - [TOMOYO_TYPE_CREATE_ACL] = "create", - [TOMOYO_TYPE_UNLINK_ACL] = "unlink", - [TOMOYO_TYPE_MKDIR_ACL] = "mkdir", - [TOMOYO_TYPE_RMDIR_ACL] = "rmdir", - [TOMOYO_TYPE_MKFIFO_ACL] = "mkfifo", - [TOMOYO_TYPE_MKSOCK_ACL] = "mksock", - [TOMOYO_TYPE_MKBLOCK_ACL] = "mkblock", - [TOMOYO_TYPE_MKCHAR_ACL] = "mkchar", - [TOMOYO_TYPE_TRUNCATE_ACL] = "truncate", - [TOMOYO_TYPE_SYMLINK_ACL] = "symlink", - [TOMOYO_TYPE_REWRITE_ACL] = "rewrite", +const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = { + [TOMOYO_TYPE_LINK] = TOMOYO_MAC_FILE_LINK, + [TOMOYO_TYPE_RENAME] = TOMOYO_MAC_FILE_RENAME, + [TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT, }; -/* Keyword array for double path operations. */ -static const char *tomoyo_dp_keyword[TOMOYO_MAX_DOUBLE_PATH_OPERATION] = { - [TOMOYO_TYPE_LINK_ACL] = "link", - [TOMOYO_TYPE_RENAME_ACL] = "rename", +/* + * Mapping table from "enum tomoyo_path_number_acl_index" to + * "enum tomoyo_mac_index". + */ +const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = { + [TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE, + [TOMOYO_TYPE_MKDIR] = TOMOYO_MAC_FILE_MKDIR, + [TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO, + [TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK, + [TOMOYO_TYPE_IOCTL] = TOMOYO_MAC_FILE_IOCTL, + [TOMOYO_TYPE_CHMOD] = TOMOYO_MAC_FILE_CHMOD, + [TOMOYO_TYPE_CHOWN] = TOMOYO_MAC_FILE_CHOWN, + [TOMOYO_TYPE_CHGRP] = TOMOYO_MAC_FILE_CHGRP, }; /** - * tomoyo_sp2keyword - Get the name of single path operation. + * tomoyo_put_name_union - Drop reference on "struct tomoyo_name_union". * - * @operation: Type of operation. + * @ptr: Pointer to "struct tomoyo_name_union". * - * Returns the name of single path operation. + * Returns nothing. */ -const char *tomoyo_sp2keyword(const u8 operation) +void tomoyo_put_name_union(struct tomoyo_name_union *ptr) { - return (operation < TOMOYO_MAX_SINGLE_PATH_OPERATION) - ? tomoyo_sp_keyword[operation] : NULL; + tomoyo_put_group(ptr->group); + tomoyo_put_name(ptr->filename); } /** - * tomoyo_dp2keyword - Get the name of double path operation. + * tomoyo_compare_name_union - Check whether a name matches "struct tomoyo_name_union" or not. * - * @operation: Type of operation. + * @name: Pointer to "struct tomoyo_path_info". + * @ptr: Pointer to "struct tomoyo_name_union". * - * Returns the name of double path operation. + * Returns "struct tomoyo_path_info" if @name matches @ptr, NULL otherwise. */ -const char *tomoyo_dp2keyword(const u8 operation) +const struct tomoyo_path_info * +tomoyo_compare_name_union(const struct tomoyo_path_info *name, + const struct tomoyo_name_union *ptr) { - return (operation < TOMOYO_MAX_DOUBLE_PATH_OPERATION) - ? tomoyo_dp_keyword[operation] : NULL; + if (ptr->group) + return tomoyo_path_matches_group(name, ptr->group); + if (tomoyo_path_matches_pattern(name, ptr->filename)) + return ptr->filename; + return NULL; } /** - * tomoyo_strendswith - Check whether the token ends with the given token. + * tomoyo_put_number_union - Drop reference on "struct tomoyo_number_union". * - * @name: The token to check. - * @tail: The token to find. + * @ptr: Pointer to "struct tomoyo_number_union". * - * Returns true if @name ends with @tail, false otherwise. + * Returns nothing. */ -static bool tomoyo_strendswith(const char *name, const char *tail) +void tomoyo_put_number_union(struct tomoyo_number_union *ptr) { - int len; - - if (!name || !tail) - return false; - len = strlen(name) - strlen(tail); - return len >= 0 && !strcmp(name + len, tail); + tomoyo_put_group(ptr->group); } /** - * tomoyo_get_path - Get realpath. + * tomoyo_compare_number_union - Check whether a value matches "struct tomoyo_number_union" or not. * - * @path: Pointer to "struct path". + * @value: Number to check. + * @ptr: Pointer to "struct tomoyo_number_union". * - * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. + * Returns true if @value matches @ptr, false otherwise. */ -static struct tomoyo_path_info *tomoyo_get_path(struct path *path) +bool tomoyo_compare_number_union(const unsigned long value, + const struct tomoyo_number_union *ptr) { - int error; - struct tomoyo_path_info_with_data *buf = tomoyo_alloc(sizeof(*buf)); - - if (!buf) - return NULL; - /* Reserve one byte for appending "/". */ - error = tomoyo_realpath_from_path2(path, buf->body, - sizeof(buf->body) - 2); - if (!error) { - buf->head.name = buf->body; - tomoyo_fill_path_info(&buf->head); - return &buf->head; - } - tomoyo_free(buf); - return NULL; + if (ptr->group) + return tomoyo_number_matches_group(value, value, ptr->group); + return value >= ptr->values[0] && value <= ptr->values[1]; } -/* Lock for domain->acl_info_list. */ -DECLARE_RWSEM(tomoyo_domain_acl_info_list_lock); - -static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, - const char *filename2, - struct tomoyo_domain_info * - const domain, const bool is_delete); -static int tomoyo_update_single_path_acl(const u8 type, const char *filename, - struct tomoyo_domain_info * - const domain, const bool is_delete); - -/* - * tomoyo_globally_readable_list is used for holding list of pathnames which - * are by default allowed to be open()ed for reading by any process. - * - * An entry is added by - * - * # echo 'allow_read /lib/libc-2.5.so' > \ - * /sys/kernel/security/tomoyo/exception_policy - * - * and is deleted by - * - * # echo 'delete allow_read /lib/libc-2.5.so' > \ - * /sys/kernel/security/tomoyo/exception_policy +/** + * tomoyo_add_slash - Add trailing '/' if needed. * - * and all entries are retrieved by + * @buf: Pointer to "struct tomoyo_path_info". * - * # grep ^allow_read /sys/kernel/security/tomoyo/exception_policy + * Returns nothing. * - * In the example above, any process is allowed to - * open("/lib/libc-2.5.so", O_RDONLY). - * One exception is, if the domain which current process belongs to is marked - * as "ignore_global_allow_read", current process can't do so unless explicitly - * given "allow_read /lib/libc-2.5.so" to the domain which current process - * belongs to. + * @buf must be generated by tomoyo_encode() because this function does not + * allocate memory for adding '/'. */ -static LIST_HEAD(tomoyo_globally_readable_list); -static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); +static void tomoyo_add_slash(struct tomoyo_path_info *buf) +{ + if (buf->is_dir) + return; + /* + * This is OK because tomoyo_encode() reserves space for appending "/". + */ + strcat((char *) buf->name, "/"); + tomoyo_fill_path_info(buf); +} /** - * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. + * tomoyo_get_realpath - Get realpath. * - * @filename: Filename unconditionally permitted to open() for reading. - * @is_delete: True if it is a delete request. + * @buf: Pointer to "struct tomoyo_path_info". + * @path: Pointer to "struct path". * - * Returns 0 on success, negative value otherwise. + * Returns true on success, false otherwise. */ -static int tomoyo_update_globally_readable_entry(const char *filename, - const bool is_delete) +static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path) { - struct tomoyo_globally_readable_file_entry *new_entry; - struct tomoyo_globally_readable_file_entry *ptr; - const struct tomoyo_path_info *saved_filename; - int error = -ENOMEM; - - if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__)) - return -EINVAL; - saved_filename = tomoyo_save_name(filename); - if (!saved_filename) - return -ENOMEM; - down_write(&tomoyo_globally_readable_list_lock); - list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { - if (ptr->filename != saved_filename) - continue; - ptr->is_deleted = is_delete; - error = 0; - goto out; + buf->name = tomoyo_realpath_from_path(path); + if (buf->name) { + tomoyo_fill_path_info(buf); + return true; } - if (is_delete) { - error = -ENOENT; - goto out; - } - new_entry = tomoyo_alloc_element(sizeof(*new_entry)); - if (!new_entry) - goto out; - new_entry->filename = saved_filename; - list_add_tail(&new_entry->list, &tomoyo_globally_readable_list); - error = 0; - out: - up_write(&tomoyo_globally_readable_list_lock); - return error; + return false; } /** - * tomoyo_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading. + * tomoyo_audit_path_log - Audit path request log. * - * @filename: The filename to check. + * @r: Pointer to "struct tomoyo_request_info". * - * Returns true if any domain can open @filename for reading, false otherwise. + * Returns 0 on success, negative value otherwise. */ -static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * - filename) +static int tomoyo_audit_path_log(struct tomoyo_request_info *r) { - struct tomoyo_globally_readable_file_entry *ptr; - bool found = false; - down_read(&tomoyo_globally_readable_list_lock); - list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { - if (!ptr->is_deleted && - tomoyo_path_matches_pattern(filename, ptr->filename)) { - found = true; - break; - } - } - up_read(&tomoyo_globally_readable_list_lock); - return found; + return tomoyo_supervisor(r, "file %s %s\n", tomoyo_path_keyword + [r->param.path.operation], + r->param.path.filename->name); } /** - * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list. + * tomoyo_audit_path2_log - Audit path/path request log. * - * @data: String to parse. - * @is_delete: True if it is a delete request. + * @r: Pointer to "struct tomoyo_request_info". * * Returns 0 on success, negative value otherwise. */ -int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) +static int tomoyo_audit_path2_log(struct tomoyo_request_info *r) { - return tomoyo_update_globally_readable_entry(data, is_delete); + return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords + [tomoyo_pp2mac[r->param.path2.operation]], + r->param.path2.filename1->name, + r->param.path2.filename2->name); } /** - * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list. + * tomoyo_audit_mkdev_log - Audit path/number/number/number request log. * - * @head: Pointer to "struct tomoyo_io_buffer". + * @r: Pointer to "struct tomoyo_request_info". * - * Returns true on success, false otherwise. + * Returns 0 on success, negative value otherwise. */ -bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) +static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r) { - struct list_head *pos; - bool done = true; - - down_read(&tomoyo_globally_readable_list_lock); - list_for_each_cookie(pos, head->read_var2, - &tomoyo_globally_readable_list) { - struct tomoyo_globally_readable_file_entry *ptr; - ptr = list_entry(pos, - struct tomoyo_globally_readable_file_entry, - list); - if (ptr->is_deleted) - continue; - done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n", - ptr->filename->name); - if (!done) - break; - } - up_read(&tomoyo_globally_readable_list_lock); - return done; + return tomoyo_supervisor(r, "file %s %s 0%o %u %u\n", + tomoyo_mac_keywords + [tomoyo_pnnn2mac[r->param.mkdev.operation]], + r->param.mkdev.filename->name, + r->param.mkdev.mode, r->param.mkdev.major, + r->param.mkdev.minor); } -/* tomoyo_pattern_list is used for holding list of pathnames which are used for - * converting pathnames to pathname patterns during learning mode. - * - * An entry is added by - * - * # echo 'file_pattern /proc/\$/mounts' > \ - * /sys/kernel/security/tomoyo/exception_policy - * - * and is deleted by - * - * # echo 'delete file_pattern /proc/\$/mounts' > \ - * /sys/kernel/security/tomoyo/exception_policy - * - * and all entries are retrieved by - * - * # grep ^file_pattern /sys/kernel/security/tomoyo/exception_policy - * - * In the example above, if a process which belongs to a domain which is in - * learning mode requested open("/proc/1/mounts", O_RDONLY), - * "allow_read /proc/\$/mounts" is automatically added to the domain which that - * process belongs to. - * - * It is not a desirable behavior that we have to use /proc/\$/ instead of - * /proc/self/ when current process needs to access only current process's - * information. As of now, LSM version of TOMOYO is using __d_path() for - * calculating pathname. Non LSM version of TOMOYO is using its own function - * which pretends as if /proc/self/ is not a symlink; so that we can forbid - * current process from accessing other process's information. - */ -static LIST_HEAD(tomoyo_pattern_list); -static DECLARE_RWSEM(tomoyo_pattern_list_lock); - /** - * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. + * tomoyo_audit_path_number_log - Audit path/number request log. * - * @pattern: Pathname pattern. - * @is_delete: True if it is a delete request. + * @r: Pointer to "struct tomoyo_request_info". * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_update_file_pattern_entry(const char *pattern, - const bool is_delete) +static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r) { - struct tomoyo_pattern_entry *new_entry; - struct tomoyo_pattern_entry *ptr; - const struct tomoyo_path_info *saved_pattern; - int error = -ENOMEM; - - if (!tomoyo_is_correct_path(pattern, 0, 1, 0, __func__)) - return -EINVAL; - saved_pattern = tomoyo_save_name(pattern); - if (!saved_pattern) - return -ENOMEM; - down_write(&tomoyo_pattern_list_lock); - list_for_each_entry(ptr, &tomoyo_pattern_list, list) { - if (saved_pattern != ptr->pattern) - continue; - ptr->is_deleted = is_delete; - error = 0; - goto out; - } - if (is_delete) { - error = -ENOENT; - goto out; + const u8 type = r->param.path_number.operation; + u8 radix; + char buffer[64]; + switch (type) { + case TOMOYO_TYPE_CREATE: + case TOMOYO_TYPE_MKDIR: + case TOMOYO_TYPE_MKFIFO: + case TOMOYO_TYPE_MKSOCK: + case TOMOYO_TYPE_CHMOD: + radix = TOMOYO_VALUE_TYPE_OCTAL; + break; + case TOMOYO_TYPE_IOCTL: + radix = TOMOYO_VALUE_TYPE_HEXADECIMAL; + break; + default: + radix = TOMOYO_VALUE_TYPE_DECIMAL; + break; } - new_entry = tomoyo_alloc_element(sizeof(*new_entry)); - if (!new_entry) - goto out; - new_entry->pattern = saved_pattern; - list_add_tail(&new_entry->list, &tomoyo_pattern_list); - error = 0; - out: - up_write(&tomoyo_pattern_list_lock); - return error; + tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number, + radix); + return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords + [tomoyo_pn2mac[type]], + r->param.path_number.filename->name, buffer); } /** - * tomoyo_get_file_pattern - Get patterned pathname. + * tomoyo_check_path_acl - Check permission for path operation. * - * @filename: The filename to find patterned pathname. + * @r: Pointer to "struct tomoyo_request_info". + * @ptr: Pointer to "struct tomoyo_acl_info". * - * Returns pointer to pathname pattern if matched, @filename otherwise. + * Returns true if granted, false otherwise. + * + * To be able to use wildcard for domain transition, this function sets + * matching entry on success. Since the caller holds tomoyo_read_lock(), + * it is safe to set matching entry. */ -static const struct tomoyo_path_info * -tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) +static bool tomoyo_check_path_acl(struct tomoyo_request_info *r, + const struct tomoyo_acl_info *ptr) { - struct tomoyo_pattern_entry *ptr; - const struct tomoyo_path_info *pattern = NULL; - - down_read(&tomoyo_pattern_list_lock); - list_for_each_entry(ptr, &tomoyo_pattern_list, list) { - if (ptr->is_deleted) - continue; - if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) - continue; - pattern = ptr->pattern; - if (tomoyo_strendswith(pattern->name, "/\\*")) { - /* Do nothing. Try to find the better match. */ - } else { - /* This would be the better match. Use this. */ - break; - } + const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl), + head); + if (acl->perm & (1 << r->param.path.operation)) { + r->param.path.matched_path = + tomoyo_compare_name_union(r->param.path.filename, + &acl->name); + return r->param.path.matched_path != NULL; } - up_read(&tomoyo_pattern_list_lock); - if (pattern) - filename = pattern; - return filename; + return false; } /** - * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list. + * tomoyo_check_path_number_acl - Check permission for path number operation. * - * @data: String to parse. - * @is_delete: True if it is a delete request. + * @r: Pointer to "struct tomoyo_request_info". + * @ptr: Pointer to "struct tomoyo_acl_info". * - * Returns 0 on success, negative value otherwise. + * Returns true if granted, false otherwise. */ -int tomoyo_write_pattern_policy(char *data, const bool is_delete) +static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r, + const struct tomoyo_acl_info *ptr) { - return tomoyo_update_file_pattern_entry(data, is_delete); + const struct tomoyo_path_number_acl *acl = + container_of(ptr, typeof(*acl), head); + return (acl->perm & (1 << r->param.path_number.operation)) && + tomoyo_compare_number_union(r->param.path_number.number, + &acl->number) && + tomoyo_compare_name_union(r->param.path_number.filename, + &acl->name); } /** - * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list. + * tomoyo_check_path2_acl - Check permission for path path operation. * - * @head: Pointer to "struct tomoyo_io_buffer". + * @r: Pointer to "struct tomoyo_request_info". + * @ptr: Pointer to "struct tomoyo_acl_info". * - * Returns true on success, false otherwise. + * Returns true if granted, false otherwise. */ -bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) +static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r, + const struct tomoyo_acl_info *ptr) { - struct list_head *pos; - bool done = true; - - down_read(&tomoyo_pattern_list_lock); - list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { - struct tomoyo_pattern_entry *ptr; - ptr = list_entry(pos, struct tomoyo_pattern_entry, list); - if (ptr->is_deleted) - continue; - done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN - "%s\n", ptr->pattern->name); - if (!done) - break; - } - up_read(&tomoyo_pattern_list_lock); - return done; + const struct tomoyo_path2_acl *acl = + container_of(ptr, typeof(*acl), head); + return (acl->perm & (1 << r->param.path2.operation)) && + tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1) + && tomoyo_compare_name_union(r->param.path2.filename2, + &acl->name2); } -/* - * tomoyo_no_rewrite_list is used for holding list of pathnames which are by - * default forbidden to modify already written content of a file. - * - * An entry is added by - * - * # echo 'deny_rewrite /var/log/messages' > \ - * /sys/kernel/security/tomoyo/exception_policy - * - * and is deleted by - * - * # echo 'delete deny_rewrite /var/log/messages' > \ - * /sys/kernel/security/tomoyo/exception_policy - * - * and all entries are retrieved by - * - * # grep ^deny_rewrite /sys/kernel/security/tomoyo/exception_policy +/** + * tomoyo_check_mkdev_acl - Check permission for path number number number operation. * - * In the example above, if a process requested to rewrite /var/log/messages , - * the process can't rewrite unless the domain which that process belongs to - * has "allow_rewrite /var/log/messages" entry. + * @r: Pointer to "struct tomoyo_request_info". + * @ptr: Pointer to "struct tomoyo_acl_info". * - * It is not a desirable behavior that we have to add "\040(deleted)" suffix - * when we want to allow rewriting already unlink()ed file. As of now, - * LSM version of TOMOYO is using __d_path() for calculating pathname. - * Non LSM version of TOMOYO is using its own function which doesn't append - * " (deleted)" suffix if the file is already unlink()ed; so that we don't - * need to worry whether the file is already unlink()ed or not. + * Returns true if granted, false otherwise. */ -static LIST_HEAD(tomoyo_no_rewrite_list); -static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); +static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r, + const struct tomoyo_acl_info *ptr) +{ + const struct tomoyo_mkdev_acl *acl = + container_of(ptr, typeof(*acl), head); + return (acl->perm & (1 << r->param.mkdev.operation)) && + tomoyo_compare_number_union(r->param.mkdev.mode, + &acl->mode) && + tomoyo_compare_number_union(r->param.mkdev.major, + &acl->major) && + tomoyo_compare_number_union(r->param.mkdev.minor, + &acl->minor) && + tomoyo_compare_name_union(r->param.mkdev.filename, + &acl->name); +} /** - * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. + * tomoyo_same_path_acl - Check for duplicated "struct tomoyo_path_acl" entry. * - * @pattern: Pathname pattern that are not rewritable by default. - * @is_delete: True if it is a delete request. + * @a: Pointer to "struct tomoyo_acl_info". + * @b: Pointer to "struct tomoyo_acl_info". * - * Returns 0 on success, negative value otherwise. + * Returns true if @a == @b except permission bits, false otherwise. */ -static int tomoyo_update_no_rewrite_entry(const char *pattern, - const bool is_delete) +static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a, + const struct tomoyo_acl_info *b) { - struct tomoyo_no_rewrite_entry *new_entry, *ptr; - const struct tomoyo_path_info *saved_pattern; - int error = -ENOMEM; - - if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__)) - return -EINVAL; - saved_pattern = tomoyo_save_name(pattern); - if (!saved_pattern) - return -ENOMEM; - down_write(&tomoyo_no_rewrite_list_lock); - list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { - if (ptr->pattern != saved_pattern) - continue; - ptr->is_deleted = is_delete; - error = 0; - goto out; - } - if (is_delete) { - error = -ENOENT; - goto out; - } - new_entry = tomoyo_alloc_element(sizeof(*new_entry)); - if (!new_entry) - goto out; - new_entry->pattern = saved_pattern; - list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list); - error = 0; - out: - up_write(&tomoyo_no_rewrite_list_lock); - return error; + const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head); + const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head); + return tomoyo_same_name_union(&p1->name, &p2->name); } /** - * tomoyo_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited. + * tomoyo_merge_path_acl - Merge duplicated "struct tomoyo_path_acl" entry. * - * @filename: Filename to check. + * @a: Pointer to "struct tomoyo_acl_info". + * @b: Pointer to "struct tomoyo_acl_info". + * @is_delete: True for @a &= ~@b, false for @a |= @b. * - * Returns true if @filename is specified by "deny_rewrite" directive, - * false otherwise. + * Returns true if @a is empty, false otherwise. */ -static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) +static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a, + struct tomoyo_acl_info *b, + const bool is_delete) { - struct tomoyo_no_rewrite_entry *ptr; - bool found = false; - - down_read(&tomoyo_no_rewrite_list_lock); - list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { - if (ptr->is_deleted) - continue; - if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) - continue; - found = true; - break; - } - up_read(&tomoyo_no_rewrite_list_lock); - return found; + u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head) + ->perm; + u16 perm = *a_perm; + const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm; + if (is_delete) + perm &= ~b_perm; + else + perm |= b_perm; + *a_perm = perm; + return !perm; } /** - * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list. + * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. * - * @data: String to parse. - * @is_delete: True if it is a delete request. + * @perm: Permission. + * @param: Pointer to "struct tomoyo_acl_param". * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ -int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) +static int tomoyo_update_path_acl(const u16 perm, + struct tomoyo_acl_param *param) { - return tomoyo_update_no_rewrite_entry(data, is_delete); + struct tomoyo_path_acl e = { + .head.type = TOMOYO_TYPE_PATH_ACL, + .perm = perm + }; + int error; + if (!tomoyo_parse_name_union(param, &e.name)) + error = -EINVAL; + else + error = tomoyo_update_domain(&e.head, sizeof(e), param, + tomoyo_same_path_acl, + tomoyo_merge_path_acl); + tomoyo_put_name_union(&e.name); + return error; } /** - * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list. + * tomoyo_same_mkdev_acl - Check for duplicated "struct tomoyo_mkdev_acl" entry. * - * @head: Pointer to "struct tomoyo_io_buffer". + * @a: Pointer to "struct tomoyo_acl_info". + * @b: Pointer to "struct tomoyo_acl_info". * - * Returns true on success, false otherwise. + * Returns true if @a == @b except permission bits, false otherwise. */ -bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) +static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a, + const struct tomoyo_acl_info *b) { - struct list_head *pos; - bool done = true; - - down_read(&tomoyo_no_rewrite_list_lock); - list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { - struct tomoyo_no_rewrite_entry *ptr; - ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); - if (ptr->is_deleted) - continue; - done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE - "%s\n", ptr->pattern->name); - if (!done) - break; - } - up_read(&tomoyo_no_rewrite_list_lock); - return done; + const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), head); + const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), head); + return tomoyo_same_name_union(&p1->name, &p2->name) && + tomoyo_same_number_union(&p1->mode, &p2->mode) && + tomoyo_same_number_union(&p1->major, &p2->major) && + tomoyo_same_number_union(&p1->minor, &p2->minor); } /** - * tomoyo_update_file_acl - Update file's read/write/execute ACL. + * tomoyo_merge_mkdev_acl - Merge duplicated "struct tomoyo_mkdev_acl" entry. * - * @filename: Filename. - * @perm: Permission (between 1 to 7). - * @domain: Pointer to "struct tomoyo_domain_info". - * @is_delete: True if it is a delete request. + * @a: Pointer to "struct tomoyo_acl_info". + * @b: Pointer to "struct tomoyo_acl_info". + * @is_delete: True for @a &= ~@b, false for @a |= @b. * - * Returns 0 on success, negative value otherwise. - * - * This is legacy support interface for older policy syntax. - * Current policy syntax uses "allow_read/write" instead of "6", - * "allow_read" instead of "4", "allow_write" instead of "2", - * "allow_execute" instead of "1". + * Returns true if @a is empty, false otherwise. */ -static int tomoyo_update_file_acl(const char *filename, u8 perm, - struct tomoyo_domain_info * const domain, - const bool is_delete) +static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a, + struct tomoyo_acl_info *b, + const bool is_delete) { - if (perm > 7 || !perm) { - printk(KERN_DEBUG "%s: Invalid permission '%d %s'\n", - __func__, perm, filename); - return -EINVAL; - } - if (filename[0] != '@' && tomoyo_strendswith(filename, "/")) - /* - * Only 'allow_mkdir' and 'allow_rmdir' are valid for - * directory permissions. - */ - return 0; - if (perm & 4) - tomoyo_update_single_path_acl(TOMOYO_TYPE_READ_ACL, filename, - domain, is_delete); - if (perm & 2) - tomoyo_update_single_path_acl(TOMOYO_TYPE_WRITE_ACL, filename, - domain, is_delete); - if (perm & 1) - tomoyo_update_single_path_acl(TOMOYO_TYPE_EXECUTE_ACL, - filename, domain, is_delete); - return 0; + u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl, + head)->perm; + u8 perm = *a_perm; + const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head) + ->perm; + if (is_delete) + perm &= ~b_perm; + else + perm |= b_perm; + *a_perm = perm; + return !perm; } /** - * tomoyo_check_single_path_acl2 - Check permission for single path operation. + * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list. * - * @domain: Pointer to "struct tomoyo_domain_info". - * @filename: Filename to check. - * @perm: Permission. - * @may_use_pattern: True if patterned ACL is permitted. + * @perm: Permission. + * @param: Pointer to "struct tomoyo_acl_param". * - * Returns 0 on success, -EPERM otherwise. + * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ -static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * - domain, - const struct tomoyo_path_info * - filename, - const u16 perm, - const bool may_use_pattern) +static int tomoyo_update_mkdev_acl(const u8 perm, + struct tomoyo_acl_param *param) { - struct tomoyo_acl_info *ptr; - int error = -EPERM; - - down_read(&tomoyo_domain_acl_info_list_lock); - list_for_each_entry(ptr, &domain->acl_info_list, list) { - struct tomoyo_single_path_acl_record *acl; - if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) - continue; - acl = container_of(ptr, struct tomoyo_single_path_acl_record, - head); - if (!(acl->perm & perm)) - continue; - if (may_use_pattern || !acl->filename->is_patterned) { - if (!tomoyo_path_matches_pattern(filename, - acl->filename)) - continue; - } else { - continue; - } - error = 0; - break; - } - up_read(&tomoyo_domain_acl_info_list_lock); + struct tomoyo_mkdev_acl e = { + .head.type = TOMOYO_TYPE_MKDEV_ACL, + .perm = perm + }; + int error; + if (!tomoyo_parse_name_union(param, &e.name) || + !tomoyo_parse_number_union(param, &e.mode) || + !tomoyo_parse_number_union(param, &e.major) || + !tomoyo_parse_number_union(param, &e.minor)) + error = -EINVAL; + else + error = tomoyo_update_domain(&e.head, sizeof(e), param, + tomoyo_same_mkdev_acl, + tomoyo_merge_mkdev_acl); + tomoyo_put_name_union(&e.name); + tomoyo_put_number_union(&e.mode); + tomoyo_put_number_union(&e.major); + tomoyo_put_number_union(&e.minor); return error; } /** - * tomoyo_check_file_acl - Check permission for opening files. + * tomoyo_same_path2_acl - Check for duplicated "struct tomoyo_path2_acl" entry. * - * @domain: Pointer to "struct tomoyo_domain_info". - * @filename: Filename to check. - * @operation: Mode ("read" or "write" or "read/write" or "execute"). + * @a: Pointer to "struct tomoyo_acl_info". + * @b: Pointer to "struct tomoyo_acl_info". * - * Returns 0 on success, -EPERM otherwise. + * Returns true if @a == @b except permission bits, false otherwise. */ -static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, - const struct tomoyo_path_info *filename, - const u8 operation) +static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a, + const struct tomoyo_acl_info *b) { - u16 perm = 0; - - if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) - return 0; - if (operation == 6) - perm = 1 << TOMOYO_TYPE_READ_WRITE_ACL; - else if (operation == 4) - perm = 1 << TOMOYO_TYPE_READ_ACL; - else if (operation == 2) - perm = 1 << TOMOYO_TYPE_WRITE_ACL; - else if (operation == 1) - perm = 1 << TOMOYO_TYPE_EXECUTE_ACL; - else - BUG(); - return tomoyo_check_single_path_acl2(domain, filename, perm, - operation != 1); + const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head); + const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head); + return tomoyo_same_name_union(&p1->name1, &p2->name1) && + tomoyo_same_name_union(&p1->name2, &p2->name2); } /** - * tomoyo_check_file_perm2 - Check permission for opening files. + * tomoyo_merge_path2_acl - Merge duplicated "struct tomoyo_path2_acl" entry. * - * @domain: Pointer to "struct tomoyo_domain_info". - * @filename: Filename to check. - * @perm: Mode ("read" or "write" or "read/write" or "execute"). - * @operation: Operation name passed used for verbose mode. - * @mode: Access control mode. + * @a: Pointer to "struct tomoyo_acl_info". + * @b: Pointer to "struct tomoyo_acl_info". + * @is_delete: True for @a &= ~@b, false for @a |= @b. * - * Returns 0 on success, negative value otherwise. + * Returns true if @a is empty, false otherwise. */ -static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, - const struct tomoyo_path_info *filename, - const u8 perm, const char *operation, - const u8 mode) +static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a, + struct tomoyo_acl_info *b, + const bool is_delete) { - const bool is_enforce = (mode == 3); - const char *msg = "<unknown>"; - int error = 0; - - if (!filename) - return 0; - error = tomoyo_check_file_acl(domain, filename, perm); - if (error && perm == 4 && - (domain->flags & TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) == 0 - && tomoyo_is_globally_readable_file(filename)) - error = 0; - if (perm == 6) - msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_WRITE_ACL); - else if (perm == 4) - msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_ACL); - else if (perm == 2) - msg = tomoyo_sp2keyword(TOMOYO_TYPE_WRITE_ACL); - else if (perm == 1) - msg = tomoyo_sp2keyword(TOMOYO_TYPE_EXECUTE_ACL); + u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head) + ->perm; + u8 perm = *a_perm; + const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm; + if (is_delete) + perm &= ~b_perm; else - BUG(); - if (!error) - return 0; - if (tomoyo_verbose_mode(domain)) - printk(KERN_WARNING "TOMOYO-%s: Access '%s(%s) %s' denied " - "for %s\n", tomoyo_get_msg(is_enforce), msg, operation, - filename->name, tomoyo_get_last_name(domain)); - if (is_enforce) - return error; - if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { - /* Don't use patterns for execute permission. */ - const struct tomoyo_path_info *patterned_file = (perm != 1) ? - tomoyo_get_file_pattern(filename) : filename; - tomoyo_update_file_acl(patterned_file->name, perm, - domain, false); - } - return 0; + perm |= b_perm; + *a_perm = perm; + return !perm; } /** - * tomoyo_write_file_policy - Update file related list. + * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. * - * @data: String to parse. - * @domain: Pointer to "struct tomoyo_domain_info". - * @is_delete: True if it is a delete request. + * @perm: Permission. + * @param: Pointer to "struct tomoyo_acl_param". * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ -int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, - const bool is_delete) +static int tomoyo_update_path2_acl(const u8 perm, + struct tomoyo_acl_param *param) { - char *filename = strchr(data, ' '); - char *filename2; - unsigned int perm; - u8 type; - - if (!filename) - return -EINVAL; - *filename++ = '\0'; - if (sscanf(data, "%u", &perm) == 1) - return tomoyo_update_file_acl(filename, (u8) perm, domain, - is_delete); - if (strncmp(data, "allow_", 6)) - goto out; - data += 6; - for (type = 0; type < TOMOYO_MAX_SINGLE_PATH_OPERATION; type++) { - if (strcmp(data, tomoyo_sp_keyword[type])) - continue; - return tomoyo_update_single_path_acl(type, filename, - domain, is_delete); - } - filename2 = strchr(filename, ' '); - if (!filename2) - goto out; - *filename2++ = '\0'; - for (type = 0; type < TOMOYO_MAX_DOUBLE_PATH_OPERATION; type++) { - if (strcmp(data, tomoyo_dp_keyword[type])) - continue; - return tomoyo_update_double_path_acl(type, filename, filename2, - domain, is_delete); - } - out: - return -EINVAL; + struct tomoyo_path2_acl e = { + .head.type = TOMOYO_TYPE_PATH2_ACL, + .perm = perm + }; + int error; + if (!tomoyo_parse_name_union(param, &e.name1) || + !tomoyo_parse_name_union(param, &e.name2)) + error = -EINVAL; + else + error = tomoyo_update_domain(&e.head, sizeof(e), param, + tomoyo_same_path2_acl, + tomoyo_merge_path2_acl); + tomoyo_put_name_union(&e.name1); + tomoyo_put_name_union(&e.name2); + return error; } /** - * tomoyo_update_single_path_acl - Update "struct tomoyo_single_path_acl_record" list. + * tomoyo_path_permission - Check permission for single path operation. * - * @type: Type of operation. - * @filename: Filename. - * @domain: Pointer to "struct tomoyo_domain_info". - * @is_delete: True if it is a delete request. + * @r: Pointer to "struct tomoyo_request_info". + * @operation: Type of operation. + * @filename: Filename to check. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ -static int tomoyo_update_single_path_acl(const u8 type, const char *filename, - struct tomoyo_domain_info * - const domain, const bool is_delete) +static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, + const struct tomoyo_path_info *filename) { - static const u16 rw_mask = - (1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL); - const struct tomoyo_path_info *saved_filename; - struct tomoyo_acl_info *ptr; - struct tomoyo_single_path_acl_record *acl; - int error = -ENOMEM; - const u16 perm = 1 << type; + int error; - if (!domain) - return -EINVAL; - if (!tomoyo_is_correct_path(filename, 0, 0, 0, __func__)) - return -EINVAL; - saved_filename = tomoyo_save_name(filename); - if (!saved_filename) - return -ENOMEM; - down_write(&tomoyo_domain_acl_info_list_lock); - if (is_delete) - goto delete; - list_for_each_entry(ptr, &domain->acl_info_list, list) { - if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) - continue; - acl = container_of(ptr, struct tomoyo_single_path_acl_record, - head); - if (acl->filename != saved_filename) - continue; - /* Special case. Clear all bits if marked as deleted. */ - if (ptr->type & TOMOYO_ACL_DELETED) - acl->perm = 0; - acl->perm |= perm; - if ((acl->perm & rw_mask) == rw_mask) - acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE_ACL; - else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)) - acl->perm |= rw_mask; - ptr->type &= ~TOMOYO_ACL_DELETED; - error = 0; - goto out; - } - /* Not found. Append it to the tail. */ - acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_SINGLE_PATH_ACL); - if (!acl) - goto out; - acl->perm = perm; - if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL)) - acl->perm |= rw_mask; - acl->filename = saved_filename; - list_add_tail(&acl->head.list, &domain->acl_info_list); - error = 0; - goto out; - delete: - error = -ENOENT; - list_for_each_entry(ptr, &domain->acl_info_list, list) { - if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) - continue; - acl = container_of(ptr, struct tomoyo_single_path_acl_record, - head); - if (acl->filename != saved_filename) - continue; - acl->perm &= ~perm; - if ((acl->perm & rw_mask) != rw_mask) - acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE_ACL); - else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))) - acl->perm &= ~rw_mask; - if (!acl->perm) - ptr->type |= TOMOYO_ACL_DELETED; - error = 0; - break; - } - out: - up_write(&tomoyo_domain_acl_info_list_lock); + r->type = tomoyo_p2mac[operation]; + r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type); + if (r->mode == TOMOYO_CONFIG_DISABLED) + return 0; + r->param_type = TOMOYO_TYPE_PATH_ACL; + r->param.path.filename = filename; + r->param.path.operation = operation; + do { + tomoyo_check_acl(r, tomoyo_check_path_acl); + error = tomoyo_audit_path_log(r); + } while (error == TOMOYO_RETRY_REQUEST); return error; } /** - * tomoyo_update_double_path_acl - Update "struct tomoyo_double_path_acl_record" list. + * tomoyo_execute_permission - Check permission for execute operation. * - * @type: Type of operation. - * @filename1: First filename. - * @filename2: Second filename. - * @domain: Pointer to "struct tomoyo_domain_info". - * @is_delete: True if it is a delete request. + * @r: Pointer to "struct tomoyo_request_info". + * @filename: Filename to check. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ -static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, - const char *filename2, - struct tomoyo_domain_info * - const domain, const bool is_delete) +int tomoyo_execute_permission(struct tomoyo_request_info *r, + const struct tomoyo_path_info *filename) { - const struct tomoyo_path_info *saved_filename1; - const struct tomoyo_path_info *saved_filename2; - struct tomoyo_acl_info *ptr; - struct tomoyo_double_path_acl_record *acl; - int error = -ENOMEM; - const u8 perm = 1 << type; - - if (!domain) - return -EINVAL; - if (!tomoyo_is_correct_path(filename1, 0, 0, 0, __func__) || - !tomoyo_is_correct_path(filename2, 0, 0, 0, __func__)) - return -EINVAL; - saved_filename1 = tomoyo_save_name(filename1); - saved_filename2 = tomoyo_save_name(filename2); - if (!saved_filename1 || !saved_filename2) - return -ENOMEM; - down_write(&tomoyo_domain_acl_info_list_lock); - if (is_delete) - goto delete; - list_for_each_entry(ptr, &domain->acl_info_list, list) { - if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) - continue; - acl = container_of(ptr, struct tomoyo_double_path_acl_record, - head); - if (acl->filename1 != saved_filename1 || - acl->filename2 != saved_filename2) - continue; - /* Special case. Clear all bits if marked as deleted. */ - if (ptr->type & TOMOYO_ACL_DELETED) - acl->perm = 0; - acl->perm |= perm; - ptr->type &= ~TOMOYO_ACL_DELETED; - error = 0; - goto out; - } - /* Not found. Append it to the tail. */ - acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_DOUBLE_PATH_ACL); - if (!acl) - goto out; - acl->perm = perm; - acl->filename1 = saved_filename1; - acl->filename2 = saved_filename2; - list_add_tail(&acl->head.list, &domain->acl_info_list); - error = 0; - goto out; - delete: - error = -ENOENT; - list_for_each_entry(ptr, &domain->acl_info_list, list) { - if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) - continue; - acl = container_of(ptr, struct tomoyo_double_path_acl_record, - head); - if (acl->filename1 != saved_filename1 || - acl->filename2 != saved_filename2) - continue; - acl->perm &= ~perm; - if (!acl->perm) - ptr->type |= TOMOYO_ACL_DELETED; - error = 0; - break; - } - out: - up_write(&tomoyo_domain_acl_info_list_lock); - return error; + /* + * Unlike other permission checks, this check is done regardless of + * profile mode settings in order to check for domain transition + * preference. + */ + r->type = TOMOYO_MAC_FILE_EXECUTE; + r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type); + r->param_type = TOMOYO_TYPE_PATH_ACL; + r->param.path.filename = filename; + r->param.path.operation = TOMOYO_TYPE_EXECUTE; + tomoyo_check_acl(r, tomoyo_check_path_acl); + r->ee->transition = r->matched_acl && r->matched_acl->cond ? + r->matched_acl->cond->transit : NULL; + if (r->mode != TOMOYO_CONFIG_DISABLED) + return tomoyo_audit_path_log(r); + return 0; } /** - * tomoyo_check_single_path_acl - Check permission for single path operation. + * tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry. * - * @domain: Pointer to "struct tomoyo_domain_info". - * @type: Type of operation. - * @filename: Filename to check. + * @a: Pointer to "struct tomoyo_acl_info". + * @b: Pointer to "struct tomoyo_acl_info". * - * Returns 0 on success, negative value otherwise. + * Returns true if @a == @b except permission bits, false otherwise. */ -static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain, - const u8 type, - const struct tomoyo_path_info *filename) +static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a, + const struct tomoyo_acl_info *b) { - if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) - return 0; - return tomoyo_check_single_path_acl2(domain, filename, 1 << type, 1); + const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1), + head); + const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2), + head); + return tomoyo_same_name_union(&p1->name, &p2->name) && + tomoyo_same_number_union(&p1->number, &p2->number); } /** - * tomoyo_check_double_path_acl - Check permission for double path operation. + * tomoyo_merge_path_number_acl - Merge duplicated "struct tomoyo_path_number_acl" entry. * - * @domain: Pointer to "struct tomoyo_domain_info". - * @type: Type of operation. - * @filename1: First filename to check. - * @filename2: Second filename to check. + * @a: Pointer to "struct tomoyo_acl_info". + * @b: Pointer to "struct tomoyo_acl_info". + * @is_delete: True for @a &= ~@b, false for @a |= @b. * - * Returns 0 on success, -EPERM otherwise. + * Returns true if @a is empty, false otherwise. */ -static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, - const u8 type, - const struct tomoyo_path_info * - filename1, - const struct tomoyo_path_info * - filename2) +static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a, + struct tomoyo_acl_info *b, + const bool is_delete) { - struct tomoyo_acl_info *ptr; - const u8 perm = 1 << type; - int error = -EPERM; - - if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) - return 0; - down_read(&tomoyo_domain_acl_info_list_lock); - list_for_each_entry(ptr, &domain->acl_info_list, list) { - struct tomoyo_double_path_acl_record *acl; - if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) - continue; - acl = container_of(ptr, struct tomoyo_double_path_acl_record, - head); - if (!(acl->perm & perm)) - continue; - if (!tomoyo_path_matches_pattern(filename1, acl->filename1)) - continue; - if (!tomoyo_path_matches_pattern(filename2, acl->filename2)) - continue; - error = 0; - break; - } - up_read(&tomoyo_domain_acl_info_list_lock); - return error; + u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl, + head)->perm; + u8 perm = *a_perm; + const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head) + ->perm; + if (is_delete) + perm &= ~b_perm; + else + perm |= b_perm; + *a_perm = perm; + return !perm; } /** - * tomoyo_check_single_path_permission2 - Check permission for single path operation. + * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL. * - * @domain: Pointer to "struct tomoyo_domain_info". - * @operation: Type of operation. - * @filename: Filename to check. - * @mode: Access control mode. + * @perm: Permission. + * @param: Pointer to "struct tomoyo_acl_param". * * Returns 0 on success, negative value otherwise. */ -static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * - const domain, u8 operation, - const struct tomoyo_path_info * - filename, const u8 mode) +static int tomoyo_update_path_number_acl(const u8 perm, + struct tomoyo_acl_param *param) { - const char *msg; + struct tomoyo_path_number_acl e = { + .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL, + .perm = perm + }; int error; - const bool is_enforce = (mode == 3); - - if (!mode) - return 0; - next: - error = tomoyo_check_single_path_acl(domain, operation, filename); - msg = tomoyo_sp2keyword(operation); - if (!error) - goto ok; - if (tomoyo_verbose_mode(domain)) - printk(KERN_WARNING "TOMOYO-%s: Access '%s %s' denied for %s\n", - tomoyo_get_msg(is_enforce), msg, filename->name, - tomoyo_get_last_name(domain)); - if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { - const char *name = tomoyo_get_file_pattern(filename)->name; - tomoyo_update_single_path_acl(operation, name, domain, false); - } - if (!is_enforce) - error = 0; - ok: - /* - * Since "allow_truncate" doesn't imply "allow_rewrite" permission, - * we need to check "allow_rewrite" permission if the filename is - * specified by "deny_rewrite" keyword. - */ - if (!error && operation == TOMOYO_TYPE_TRUNCATE_ACL && - tomoyo_is_no_rewrite_file(filename)) { - operation = TOMOYO_TYPE_REWRITE_ACL; - goto next; - } + if (!tomoyo_parse_name_union(param, &e.name) || + !tomoyo_parse_number_union(param, &e.number)) + error = -EINVAL; + else + error = tomoyo_update_domain(&e.head, sizeof(e), param, + tomoyo_same_path_number_acl, + tomoyo_merge_path_number_acl); + tomoyo_put_name_union(&e.name); + tomoyo_put_number_union(&e.number); return error; } /** - * tomoyo_check_exec_perm - Check permission for "execute". + * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp". * - * @domain: Pointer to "struct tomoyo_domain_info". - * @filename: Check permission for "execute". + * @type: Type of operation. + * @path: Pointer to "struct path". + * @number: Number. * - * Returns 0 on success, negativevalue otherwise. + * Returns 0 on success, negative value otherwise. */ -int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, - const struct tomoyo_path_info *filename) +int tomoyo_path_number_perm(const u8 type, struct path *path, + unsigned long number) { - const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); + struct tomoyo_request_info r; + struct tomoyo_obj_info obj = { + .path1 = *path, + }; + int error = -ENOMEM; + struct tomoyo_path_info buf; + int idx; - if (!mode) + if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type]) + == TOMOYO_CONFIG_DISABLED || !path->dentry) return 0; - return tomoyo_check_file_perm2(domain, filename, 1, "do_execve", mode); + idx = tomoyo_read_lock(); + if (!tomoyo_get_realpath(&buf, path)) + goto out; + r.obj = &obj; + if (type == TOMOYO_TYPE_MKDIR) + tomoyo_add_slash(&buf); + r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL; + r.param.path_number.operation = type; + r.param.path_number.filename = &buf; + r.param.path_number.number = number; + do { + tomoyo_check_acl(&r, tomoyo_check_path_number_acl); + error = tomoyo_audit_path_number_log(&r); + } while (error == TOMOYO_RETRY_REQUEST); + kfree(buf.name); + out: + tomoyo_read_unlock(idx); + if (r.mode != TOMOYO_CONFIG_ENFORCING) + error = 0; + return error; } /** @@ -1125,189 +736,291 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, struct path *path, const int flag) { const u8 acc_mode = ACC_MODE(flag); - int error = -ENOMEM; - struct tomoyo_path_info *buf; - const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); - const bool is_enforce = (mode == 3); - - if (!mode || !path->mnt) - return 0; - if (acc_mode == 0) - return 0; - if (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode)) - /* - * I don't check directories here because mkdir() and rmdir() - * don't call me. - */ - return 0; - buf = tomoyo_get_path(path); - if (!buf) - goto out; - error = 0; - /* - * If the filename is specified by "deny_rewrite" keyword, - * we need to check "allow_rewrite" permission when the filename is not - * opened for append mode or the filename is truncated at open time. - */ - if ((acc_mode & MAY_WRITE) && - ((flag & O_TRUNC) || !(flag & O_APPEND)) && - (tomoyo_is_no_rewrite_file(buf))) { - error = tomoyo_check_single_path_permission2(domain, - TOMOYO_TYPE_REWRITE_ACL, - buf, mode); + int error = 0; + struct tomoyo_path_info buf; + struct tomoyo_request_info r; + struct tomoyo_obj_info obj = { + .path1 = *path, + }; + int idx; + + buf.name = NULL; + r.mode = TOMOYO_CONFIG_DISABLED; + idx = tomoyo_read_lock(); + if (acc_mode && + tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN) + != TOMOYO_CONFIG_DISABLED) { + if (!tomoyo_get_realpath(&buf, path)) { + error = -ENOMEM; + goto out; + } + r.obj = &obj; + if (acc_mode & MAY_READ) + error = tomoyo_path_permission(&r, TOMOYO_TYPE_READ, + &buf); + if (!error && (acc_mode & MAY_WRITE)) + error = tomoyo_path_permission(&r, (flag & O_APPEND) ? + TOMOYO_TYPE_APPEND : + TOMOYO_TYPE_WRITE, + &buf); } - if (!error) - error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open", - mode); - if (!error && (flag & O_TRUNC)) - error = tomoyo_check_single_path_permission2(domain, - TOMOYO_TYPE_TRUNCATE_ACL, - buf, mode); out: - tomoyo_free(buf); - if (!is_enforce) + kfree(buf.name); + tomoyo_read_unlock(idx); + if (r.mode != TOMOYO_CONFIG_ENFORCING) error = 0; return error; } /** - * tomoyo_check_1path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate" and "symlink". + * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "append", "chroot" and "unmount". * - * @domain: Pointer to "struct tomoyo_domain_info". * @operation: Type of operation. * @path: Pointer to "struct path". + * @target: Symlink's target if @operation is TOMOYO_TYPE_SYMLINK, + * NULL otherwise. * * Returns 0 on success, negative value otherwise. */ -int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, - const u8 operation, struct path *path) +int tomoyo_path_perm(const u8 operation, struct path *path, const char *target) { - int error = -ENOMEM; - struct tomoyo_path_info *buf; - const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); - const bool is_enforce = (mode == 3); + struct tomoyo_request_info r; + struct tomoyo_obj_info obj = { + .path1 = *path, + }; + int error; + struct tomoyo_path_info buf; + bool is_enforce; + struct tomoyo_path_info symlink_target; + int idx; - if (!mode || !path->mnt) + if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation]) + == TOMOYO_CONFIG_DISABLED) return 0; - buf = tomoyo_get_path(path); - if (!buf) + is_enforce = (r.mode == TOMOYO_CONFIG_ENFORCING); + error = -ENOMEM; + buf.name = NULL; + idx = tomoyo_read_lock(); + if (!tomoyo_get_realpath(&buf, path)) goto out; + r.obj = &obj; switch (operation) { - case TOMOYO_TYPE_MKDIR_ACL: - case TOMOYO_TYPE_RMDIR_ACL: - if (!buf->is_dir) { - /* - * tomoyo_get_path() reserves space for appending "/." - */ - strcat((char *) buf->name, "/"); - tomoyo_fill_path_info(buf); - } + case TOMOYO_TYPE_RMDIR: + case TOMOYO_TYPE_CHROOT: + tomoyo_add_slash(&buf); + break; + case TOMOYO_TYPE_SYMLINK: + symlink_target.name = tomoyo_encode(target); + if (!symlink_target.name) + goto out; + tomoyo_fill_path_info(&symlink_target); + obj.symlink_target = &symlink_target; + break; } - error = tomoyo_check_single_path_permission2(domain, operation, buf, - mode); + error = tomoyo_path_permission(&r, operation, &buf); + if (operation == TOMOYO_TYPE_SYMLINK) + kfree(symlink_target.name); out: - tomoyo_free(buf); + kfree(buf.name); + tomoyo_read_unlock(idx); if (!is_enforce) error = 0; return error; } /** - * tomoyo_check_rewrite_permission - Check permission for "rewrite". + * tomoyo_mkdev_perm - Check permission for "mkblock" and "mkchar". * - * @domain: Pointer to "struct tomoyo_domain_info". - * @filp: Pointer to "struct file". + * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK) + * @path: Pointer to "struct path". + * @mode: Create mode. + * @dev: Device number. * * Returns 0 on success, negative value otherwise. */ -int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, - struct file *filp) +int tomoyo_mkdev_perm(const u8 operation, struct path *path, + const unsigned int mode, unsigned int dev) { + struct tomoyo_request_info r; + struct tomoyo_obj_info obj = { + .path1 = *path, + }; int error = -ENOMEM; - const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); - const bool is_enforce = (mode == 3); - struct tomoyo_path_info *buf; + struct tomoyo_path_info buf; + int idx; - if (!mode || !filp->f_path.mnt) + if (tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation]) + == TOMOYO_CONFIG_DISABLED) return 0; - buf = tomoyo_get_path(&filp->f_path); - if (!buf) - goto out; - if (!tomoyo_is_no_rewrite_file(buf)) { - error = 0; - goto out; + idx = tomoyo_read_lock(); + error = -ENOMEM; + if (tomoyo_get_realpath(&buf, path)) { + r.obj = &obj; + dev = new_decode_dev(dev); + r.param_type = TOMOYO_TYPE_MKDEV_ACL; + r.param.mkdev.filename = &buf; + r.param.mkdev.operation = operation; + r.param.mkdev.mode = mode; + r.param.mkdev.major = MAJOR(dev); + r.param.mkdev.minor = MINOR(dev); + tomoyo_check_acl(&r, tomoyo_check_mkdev_acl); + error = tomoyo_audit_mkdev_log(&r); + kfree(buf.name); } - error = tomoyo_check_single_path_permission2(domain, - TOMOYO_TYPE_REWRITE_ACL, - buf, mode); - out: - tomoyo_free(buf); - if (!is_enforce) + tomoyo_read_unlock(idx); + if (r.mode != TOMOYO_CONFIG_ENFORCING) error = 0; return error; } /** - * tomoyo_check_2path_perm - Check permission for "rename" and "link". + * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root". * - * @domain: Pointer to "struct tomoyo_domain_info". * @operation: Type of operation. * @path1: Pointer to "struct path". * @path2: Pointer to "struct path". * * Returns 0 on success, negative value otherwise. */ -int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, - const u8 operation, struct path *path1, - struct path *path2) +int tomoyo_path2_perm(const u8 operation, struct path *path1, + struct path *path2) { int error = -ENOMEM; - struct tomoyo_path_info *buf1, *buf2; - const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); - const bool is_enforce = (mode == 3); - const char *msg; - - if (!mode || !path1->mnt || !path2->mnt) + struct tomoyo_path_info buf1; + struct tomoyo_path_info buf2; + struct tomoyo_request_info r; + struct tomoyo_obj_info obj = { + .path1 = *path1, + .path2 = *path2, + }; + int idx; + + if (tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation]) + == TOMOYO_CONFIG_DISABLED) return 0; - buf1 = tomoyo_get_path(path1); - buf2 = tomoyo_get_path(path2); - if (!buf1 || !buf2) - goto out; - { - struct dentry *dentry = path1->dentry; - if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { - /* - * tomoyo_get_path() reserves space for appending "/." - */ - if (!buf1->is_dir) { - strcat((char *) buf1->name, "/"); - tomoyo_fill_path_info(buf1); - } - if (!buf2->is_dir) { - strcat((char *) buf2->name, "/"); - tomoyo_fill_path_info(buf2); - } - } - } - error = tomoyo_check_double_path_acl(domain, operation, buf1, buf2); - msg = tomoyo_dp2keyword(operation); - if (!error) + buf1.name = NULL; + buf2.name = NULL; + idx = tomoyo_read_lock(); + if (!tomoyo_get_realpath(&buf1, path1) || + !tomoyo_get_realpath(&buf2, path2)) goto out; - if (tomoyo_verbose_mode(domain)) - printk(KERN_WARNING "TOMOYO-%s: Access '%s %s %s' " - "denied for %s\n", tomoyo_get_msg(is_enforce), - msg, buf1->name, buf2->name, - tomoyo_get_last_name(domain)); - if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { - const char *name1 = tomoyo_get_file_pattern(buf1)->name; - const char *name2 = tomoyo_get_file_pattern(buf2)->name; - tomoyo_update_double_path_acl(operation, name1, name2, domain, - false); + switch (operation) { + struct dentry *dentry; + case TOMOYO_TYPE_RENAME: + case TOMOYO_TYPE_LINK: + dentry = path1->dentry; + if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode)) + break; + /* fall through */ + case TOMOYO_TYPE_PIVOT_ROOT: + tomoyo_add_slash(&buf1); + tomoyo_add_slash(&buf2); + break; } + r.obj = &obj; + r.param_type = TOMOYO_TYPE_PATH2_ACL; + r.param.path2.operation = operation; + r.param.path2.filename1 = &buf1; + r.param.path2.filename2 = &buf2; + do { + tomoyo_check_acl(&r, tomoyo_check_path2_acl); + error = tomoyo_audit_path2_log(&r); + } while (error == TOMOYO_RETRY_REQUEST); out: - tomoyo_free(buf1); - tomoyo_free(buf2); - if (!is_enforce) + kfree(buf1.name); + kfree(buf2.name); + tomoyo_read_unlock(idx); + if (r.mode != TOMOYO_CONFIG_ENFORCING) error = 0; return error; } + +/** + * tomoyo_same_mount_acl - Check for duplicated "struct tomoyo_mount_acl" entry. + * + * @a: Pointer to "struct tomoyo_acl_info". + * @b: Pointer to "struct tomoyo_acl_info". + * + * Returns true if @a == @b, false otherwise. + */ +static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a, + const struct tomoyo_acl_info *b) +{ + const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head); + const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head); + return tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) && + tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) && + tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) && + tomoyo_same_number_union(&p1->flags, &p2->flags); +} + +/** + * tomoyo_update_mount_acl - Write "struct tomoyo_mount_acl" list. + * + * @param: Pointer to "struct tomoyo_acl_param". + * + * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). + */ +static int tomoyo_update_mount_acl(struct tomoyo_acl_param *param) +{ + struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL }; + int error; + if (!tomoyo_parse_name_union(param, &e.dev_name) || + !tomoyo_parse_name_union(param, &e.dir_name) || + !tomoyo_parse_name_union(param, &e.fs_type) || + !tomoyo_parse_number_union(param, &e.flags)) + error = -EINVAL; + else + error = tomoyo_update_domain(&e.head, sizeof(e), param, + tomoyo_same_mount_acl, NULL); + tomoyo_put_name_union(&e.dev_name); + tomoyo_put_name_union(&e.dir_name); + tomoyo_put_name_union(&e.fs_type); + tomoyo_put_number_union(&e.flags); + return error; +} + +/** + * tomoyo_write_file - Update file related list. + * + * @param: Pointer to "struct tomoyo_acl_param". + * + * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). + */ +int tomoyo_write_file(struct tomoyo_acl_param *param) +{ + u16 perm = 0; + u8 type; + const char *operation = tomoyo_read_token(param); + for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) + if (tomoyo_permstr(operation, tomoyo_path_keyword[type])) + perm |= 1 << type; + if (perm) + return tomoyo_update_path_acl(perm, param); + for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) + if (tomoyo_permstr(operation, + tomoyo_mac_keywords[tomoyo_pp2mac[type]])) + perm |= 1 << type; + if (perm) + return tomoyo_update_path2_acl(perm, param); + for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) + if (tomoyo_permstr(operation, + tomoyo_mac_keywords[tomoyo_pn2mac[type]])) + perm |= 1 << type; + if (perm) + return tomoyo_update_path_number_acl(perm, param); + for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) + if (tomoyo_permstr(operation, + tomoyo_mac_keywords[tomoyo_pnnn2mac[type]])) + perm |= 1 << type; + if (perm) + return tomoyo_update_mkdev_acl(perm, param); + if (tomoyo_permstr(operation, + tomoyo_mac_keywords[TOMOYO_MAC_FILE_MOUNT])) + return tomoyo_update_mount_acl(param); + return -EINVAL; +} |
