X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=security%2Ftomoyo%2Ffile.c;h=1b24304edb7de3135a2febcd0b15f35d66582dd9;hb=170800088666963de1111d62fb503889c8c82eda;hp=9a6c58881c0a37562090a345f91b86afab76248a;hpb=004b35063296b6772fa72404a35b498f1e71e87e;p=pandora-kernel.git diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 9a6c58881c0a..1b24304edb7d 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -10,108 +10,64 @@ */ #include "common.h" -#include "tomoyo.h" -#include "realpath.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. - */ -struct tomoyo_globally_readable_file_entry { - struct list_head list; - const struct tomoyo_path_info *filename; - bool is_deleted; -}; - -/* - * 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. - */ -struct tomoyo_pattern_entry { - struct list_head list; - const struct tomoyo_path_info *pattern; - bool is_deleted; -}; - -/* - * 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. - */ -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", +static const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { + [TOMOYO_TYPE_READ_WRITE] = "read/write", + [TOMOYO_TYPE_EXECUTE] = "execute", + [TOMOYO_TYPE_READ] = "read", + [TOMOYO_TYPE_WRITE] = "write", + [TOMOYO_TYPE_CREATE] = "create", + [TOMOYO_TYPE_UNLINK] = "unlink", + [TOMOYO_TYPE_MKDIR] = "mkdir", + [TOMOYO_TYPE_RMDIR] = "rmdir", + [TOMOYO_TYPE_MKFIFO] = "mkfifo", + [TOMOYO_TYPE_MKSOCK] = "mksock", + [TOMOYO_TYPE_MKBLOCK] = "mkblock", + [TOMOYO_TYPE_MKCHAR] = "mkchar", + [TOMOYO_TYPE_TRUNCATE] = "truncate", + [TOMOYO_TYPE_SYMLINK] = "symlink", + [TOMOYO_TYPE_REWRITE] = "rewrite", + [TOMOYO_TYPE_IOCTL] = "ioctl", + [TOMOYO_TYPE_CHMOD] = "chmod", + [TOMOYO_TYPE_CHOWN] = "chown", + [TOMOYO_TYPE_CHGRP] = "chgrp", + [TOMOYO_TYPE_CHROOT] = "chroot", + [TOMOYO_TYPE_MOUNT] = "mount", + [TOMOYO_TYPE_UMOUNT] = "unmount", }; /* 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", +static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = { + [TOMOYO_TYPE_LINK] = "link", + [TOMOYO_TYPE_RENAME] = "rename", + [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root", }; /** - * tomoyo_sp2keyword - Get the name of single path operation. + * tomoyo_path2keyword - Get the name of single path operation. * * @operation: Type of operation. * * Returns the name of single path operation. */ -const char *tomoyo_sp2keyword(const u8 operation) +const char *tomoyo_path2keyword(const u8 operation) { - return (operation < TOMOYO_MAX_SINGLE_PATH_OPERATION) - ? tomoyo_sp_keyword[operation] : NULL; + return (operation < TOMOYO_MAX_PATH_OPERATION) + ? tomoyo_path_keyword[operation] : NULL; } /** - * tomoyo_dp2keyword - Get the name of double path operation. + * tomoyo_path22keyword - Get the name of double path operation. * * @operation: Type of operation. * * Returns the name of double path operation. */ -const char *tomoyo_dp2keyword(const u8 operation) +const char *tomoyo_path22keyword(const u8 operation) { - return (operation < TOMOYO_MAX_DOUBLE_PATH_OPERATION) - ? tomoyo_dp_keyword[operation] : NULL; + return (operation < TOMOYO_MAX_PATH2_OPERATION) + ? tomoyo_path2_keyword[operation] : NULL; } /** @@ -142,7 +98,8 @@ static bool tomoyo_strendswith(const char *name, const char *tail) static struct tomoyo_path_info *tomoyo_get_path(struct path *path) { int error; - struct tomoyo_path_info_with_data *buf = tomoyo_alloc(sizeof(*buf)); + struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf), + GFP_KERNEL); if (!buf) return NULL; @@ -154,20 +111,17 @@ static struct tomoyo_path_info *tomoyo_get_path(struct path *path) tomoyo_fill_path_info(&buf->head); return &buf->head; } - tomoyo_free(buf); + kfree(buf); return NULL; } -/* 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); +static int tomoyo_update_path2_acl(const u8 type, const char *filename1, + const char *filename2, + struct tomoyo_domain_info *const domain, + const bool is_delete); +static int tomoyo_update_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 @@ -194,8 +148,7 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, * given "allow_read /lib/libc-2.5.so" to the domain which current process * belongs to. */ -static LIST_HEAD(tomoyo_globally_readable_list); -static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); +LIST_HEAD(tomoyo_globally_readable_list); /** * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. @@ -204,40 +157,42 @@ static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_update_globally_readable_entry(const char *filename, const bool is_delete) { - struct tomoyo_globally_readable_file_entry *new_entry; + struct tomoyo_globally_readable_file_entry *entry = NULL; struct tomoyo_globally_readable_file_entry *ptr; const struct tomoyo_path_info *saved_filename; - int error = -ENOMEM; + int error = is_delete ? -ENOENT : -ENOMEM; - if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__)) + if (!tomoyo_is_correct_path(filename, 1, 0, -1)) return -EINVAL; - saved_filename = tomoyo_save_name(filename); + saved_filename = tomoyo_get_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 (!is_delete) + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + mutex_lock(&tomoyo_policy_lock); + list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { if (ptr->filename != saved_filename) continue; ptr->is_deleted = is_delete; error = 0; - goto out; + break; } - if (is_delete) { - error = -ENOENT; - goto out; + if (!is_delete && error && tomoyo_memory_ok(entry)) { + entry->filename = saved_filename; + saved_filename = NULL; + list_add_tail_rcu(&entry->list, &tomoyo_globally_readable_list); + entry = NULL; + error = 0; } - 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); + mutex_unlock(&tomoyo_policy_lock); + tomoyo_put_name(saved_filename); + kfree(entry); return error; } @@ -247,21 +202,22 @@ static int tomoyo_update_globally_readable_entry(const char *filename, * @filename: The filename to check. * * Returns true if any domain can open @filename for reading, false otherwise. + * + * Caller holds tomoyo_read_lock(). */ static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * filename) { 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) { + + list_for_each_entry_rcu(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; } @@ -272,6 +228,8 @@ static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) { @@ -284,13 +242,14 @@ int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) * @head: Pointer to "struct tomoyo_io_buffer". * * Returns true on success, false otherwise. + * + * Caller holds tomoyo_read_lock(). */ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) { 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; @@ -304,7 +263,6 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) if (!done) break; } - up_read(&tomoyo_globally_readable_list_lock); return done; } @@ -337,8 +295,7 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) * 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); +LIST_HEAD(tomoyo_pattern_list); /** * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. @@ -347,40 +304,43 @@ static DECLARE_RWSEM(tomoyo_pattern_list_lock); * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_update_file_pattern_entry(const char *pattern, const bool is_delete) { - struct tomoyo_pattern_entry *new_entry; + struct tomoyo_pattern_entry *entry = NULL; struct tomoyo_pattern_entry *ptr; const struct tomoyo_path_info *saved_pattern; - int error = -ENOMEM; + int error = is_delete ? -ENOENT : -ENOMEM; - if (!tomoyo_is_correct_path(pattern, 0, 1, 0, __func__)) - return -EINVAL; - saved_pattern = tomoyo_save_name(pattern); + saved_pattern = tomoyo_get_name(pattern); if (!saved_pattern) - return -ENOMEM; - down_write(&tomoyo_pattern_list_lock); - list_for_each_entry(ptr, &tomoyo_pattern_list, list) { + return error; + if (!saved_pattern->is_patterned) + goto out; + if (!is_delete) + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + mutex_lock(&tomoyo_policy_lock); + list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { if (saved_pattern != ptr->pattern) continue; ptr->is_deleted = is_delete; error = 0; - goto out; + break; } - if (is_delete) { - error = -ENOENT; - goto out; + if (!is_delete && error && tomoyo_memory_ok(entry)) { + entry->pattern = saved_pattern; + saved_pattern = NULL; + list_add_tail_rcu(&entry->list, &tomoyo_pattern_list); + entry = NULL; + error = 0; } - 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; + mutex_unlock(&tomoyo_policy_lock); out: - up_write(&tomoyo_pattern_list_lock); + kfree(entry); + tomoyo_put_name(saved_pattern); return error; } @@ -390,6 +350,8 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, * @filename: The filename to find patterned pathname. * * Returns pointer to pathname pattern if matched, @filename otherwise. + * + * Caller holds tomoyo_read_lock(). */ static const struct tomoyo_path_info * tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) @@ -397,8 +359,7 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) 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) { + list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { if (ptr->is_deleted) continue; if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) @@ -411,7 +372,6 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) break; } } - up_read(&tomoyo_pattern_list_lock); if (pattern) filename = pattern; return filename; @@ -424,6 +384,8 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ int tomoyo_write_pattern_policy(char *data, const bool is_delete) { @@ -436,13 +398,14 @@ int tomoyo_write_pattern_policy(char *data, const bool is_delete) * @head: Pointer to "struct tomoyo_io_buffer". * * Returns true on success, false otherwise. + * + * Caller holds tomoyo_read_lock(). */ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) { 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); @@ -453,7 +416,6 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) if (!done) break; } - up_read(&tomoyo_pattern_list_lock); return done; } @@ -486,8 +448,7 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) * " (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. */ -static LIST_HEAD(tomoyo_no_rewrite_list); -static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); +LIST_HEAD(tomoyo_no_rewrite_list); /** * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. @@ -496,39 +457,42 @@ static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_update_no_rewrite_entry(const char *pattern, const bool is_delete) { - struct tomoyo_no_rewrite_entry *new_entry, *ptr; + struct tomoyo_no_rewrite_entry *entry = NULL; + struct tomoyo_no_rewrite_entry *ptr; const struct tomoyo_path_info *saved_pattern; - int error = -ENOMEM; + int error = is_delete ? -ENOENT : -ENOMEM; - if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__)) + if (!tomoyo_is_correct_path(pattern, 0, 0, 0)) return -EINVAL; - saved_pattern = tomoyo_save_name(pattern); + saved_pattern = tomoyo_get_name(pattern); if (!saved_pattern) - return -ENOMEM; - down_write(&tomoyo_no_rewrite_list_lock); - list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { + return error; + if (!is_delete) + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + mutex_lock(&tomoyo_policy_lock); + list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { if (ptr->pattern != saved_pattern) continue; ptr->is_deleted = is_delete; error = 0; - goto out; + break; } - if (is_delete) { - error = -ENOENT; - goto out; + if (!is_delete && error && tomoyo_memory_ok(entry)) { + entry->pattern = saved_pattern; + saved_pattern = NULL; + list_add_tail_rcu(&entry->list, &tomoyo_no_rewrite_list); + entry = NULL; + error = 0; } - 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); + mutex_unlock(&tomoyo_policy_lock); + tomoyo_put_name(saved_pattern); + kfree(entry); return error; } @@ -539,14 +503,15 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, * * Returns true if @filename is specified by "deny_rewrite" directive, * false otherwise. + * + * Caller holds tomoyo_read_lock(). */ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) { 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) { + list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { if (ptr->is_deleted) continue; if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) @@ -554,7 +519,6 @@ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) found = true; break; } - up_read(&tomoyo_no_rewrite_list_lock); return found; } @@ -565,6 +529,8 @@ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) { @@ -577,13 +543,14 @@ int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) * @head: Pointer to "struct tomoyo_io_buffer". * * Returns true on success, false otherwise. + * + * Caller holds tomoyo_read_lock(). */ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) { 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); @@ -594,7 +561,6 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) if (!done) break; } - up_read(&tomoyo_no_rewrite_list_lock); return done; } @@ -612,6 +578,8 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) * 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". + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_update_file_acl(const char *filename, u8 perm, struct tomoyo_domain_info * const domain, @@ -629,19 +597,19 @@ static int tomoyo_update_file_acl(const char *filename, u8 perm, */ return 0; if (perm & 4) - tomoyo_update_single_path_acl(TOMOYO_TYPE_READ_ACL, filename, - domain, is_delete); + tomoyo_update_path_acl(TOMOYO_TYPE_READ, filename, domain, + is_delete); if (perm & 2) - tomoyo_update_single_path_acl(TOMOYO_TYPE_WRITE_ACL, filename, - domain, is_delete); + tomoyo_update_path_acl(TOMOYO_TYPE_WRITE, filename, domain, + is_delete); if (perm & 1) - tomoyo_update_single_path_acl(TOMOYO_TYPE_EXECUTE_ACL, - filename, domain, is_delete); + tomoyo_update_path_acl(TOMOYO_TYPE_EXECUTE, filename, domain, + is_delete); return 0; } /** - * tomoyo_check_single_path_acl2 - Check permission for single path operation. + * tomoyo_path_acl2 - Check permission for single path operation. * * @domain: Pointer to "struct tomoyo_domain_info". * @filename: Filename to check. @@ -649,26 +617,28 @@ static int tomoyo_update_file_acl(const char *filename, u8 perm, * @may_use_pattern: True if patterned ACL is permitted. * * Returns 0 on success, -EPERM 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_path_acl2(const struct tomoyo_domain_info *domain, + const struct tomoyo_path_info *filename, + const u32 perm, const bool may_use_pattern) { 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)) + list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { + struct tomoyo_path_acl *acl; + if (ptr->type != TOMOYO_TYPE_PATH_ACL) continue; + acl = container_of(ptr, struct tomoyo_path_acl, head); + if (perm <= 0xFFFF) { + if (!(acl->perm & perm)) + continue; + } else { + if (!(acl->perm_high & (perm >> 16))) + continue; + } if (may_use_pattern || !acl->filename->is_patterned) { if (!tomoyo_path_matches_pattern(filename, acl->filename)) @@ -679,7 +649,6 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * error = 0; break; } - up_read(&tomoyo_domain_acl_info_list_lock); return error; } @@ -691,27 +660,28 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * * @operation: Mode ("read" or "write" or "read/write" or "execute"). * * Returns 0 on success, -EPERM otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, const struct tomoyo_path_info *filename, const u8 operation) { - u16 perm = 0; + u32 perm = 0; if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) return 0; if (operation == 6) - perm = 1 << TOMOYO_TYPE_READ_WRITE_ACL; + perm = 1 << TOMOYO_TYPE_READ_WRITE; else if (operation == 4) - perm = 1 << TOMOYO_TYPE_READ_ACL; + perm = 1 << TOMOYO_TYPE_READ; else if (operation == 2) - perm = 1 << TOMOYO_TYPE_WRITE_ACL; + perm = 1 << TOMOYO_TYPE_WRITE; else if (operation == 1) - perm = 1 << TOMOYO_TYPE_EXECUTE_ACL; + perm = 1 << TOMOYO_TYPE_EXECUTE; else BUG(); - return tomoyo_check_single_path_acl2(domain, filename, perm, - operation != 1); + return tomoyo_path_acl2(domain, filename, perm, operation != 1); } /** @@ -724,6 +694,8 @@ static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, * @mode: Access control mode. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, const struct tomoyo_path_info *filename, @@ -737,18 +709,17 @@ static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, 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 + if (error && perm == 4 && !domain->ignore_global_allow_read && tomoyo_is_globally_readable_file(filename)) error = 0; if (perm == 6) - msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_WRITE_ACL); + msg = tomoyo_path2keyword(TOMOYO_TYPE_READ_WRITE); else if (perm == 4) - msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_ACL); + msg = tomoyo_path2keyword(TOMOYO_TYPE_READ); else if (perm == 2) - msg = tomoyo_sp2keyword(TOMOYO_TYPE_WRITE_ACL); + msg = tomoyo_path2keyword(TOMOYO_TYPE_WRITE); else if (perm == 1) - msg = tomoyo_sp2keyword(TOMOYO_TYPE_EXECUTE_ACL); + msg = tomoyo_path2keyword(TOMOYO_TYPE_EXECUTE); else BUG(); if (!error) @@ -777,6 +748,8 @@ static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, * @is_delete: True if it is a delete request. * * 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) @@ -795,28 +768,28 @@ int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, 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])) + for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { + if (strcmp(data, tomoyo_path_keyword[type])) continue; - return tomoyo_update_single_path_acl(type, filename, - domain, is_delete); + return tomoyo_update_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])) + for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { + if (strcmp(data, tomoyo_path2_keyword[type])) continue; - return tomoyo_update_double_path_acl(type, filename, filename2, - domain, is_delete); + return tomoyo_update_path2_acl(type, filename, filename2, + domain, is_delete); } out: return -EINVAL; } /** - * tomoyo_update_single_path_acl - Update "struct tomoyo_single_path_acl_record" list. + * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. * * @type: Type of operation. * @filename: Filename. @@ -824,85 +797,82 @@ int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, * @is_delete: True if it is a delete request. * * 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_update_path_acl(const u8 type, const char *filename, + struct tomoyo_domain_info *const domain, + const bool is_delete) { - static const u16 rw_mask = - (1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL); + static const u32 rw_mask = + (1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE); 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; + struct tomoyo_path_acl *entry = NULL; + int error = is_delete ? -ENOENT : -ENOMEM; + const u32 perm = 1 << type; if (!domain) return -EINVAL; - if (!tomoyo_is_correct_path(filename, 0, 0, 0, __func__)) + if (!tomoyo_is_correct_path(filename, 0, 0, 0)) return -EINVAL; - saved_filename = tomoyo_save_name(filename); + saved_filename = tomoyo_get_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) + if (!is_delete) + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + mutex_lock(&tomoyo_policy_lock); + list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { + struct tomoyo_path_acl *acl = + container_of(ptr, struct tomoyo_path_acl, head); + if (ptr->type != TOMOYO_TYPE_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; + if (is_delete) { + if (perm <= 0xFFFF) + acl->perm &= ~perm; + else + acl->perm_high &= ~(perm >> 16); + if ((acl->perm & rw_mask) != rw_mask) + acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE); + else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))) + acl->perm &= ~rw_mask; + } else { + if (perm <= 0xFFFF) + acl->perm |= perm; + else + acl->perm_high |= (perm >> 16); + if ((acl->perm & rw_mask) == rw_mask) + acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE; + else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)) + acl->perm |= rw_mask; + } error = 0; - goto out; + break; } - /* 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; + if (!is_delete && error && tomoyo_memory_ok(entry)) { + entry->head.type = TOMOYO_TYPE_PATH_ACL; + if (perm <= 0xFFFF) + entry->perm = perm; + else + entry->perm_high = (perm >> 16); + if (perm == (1 << TOMOYO_TYPE_READ_WRITE)) + entry->perm |= rw_mask; + entry->filename = saved_filename; + saved_filename = NULL; + list_add_tail_rcu(&entry->head.list, &domain->acl_info_list); + entry = NULL; error = 0; - break; } - out: - up_write(&tomoyo_domain_acl_info_list_lock); + mutex_unlock(&tomoyo_policy_lock); + kfree(entry); + tomoyo_put_name(saved_filename); return error; } /** - * tomoyo_update_double_path_acl - Update "struct tomoyo_double_path_acl_record" list. + * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. * * @type: Type of operation. * @filename1: First filename. @@ -911,98 +881,88 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, * @is_delete: True if it is a delete request. * * 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) +static int tomoyo_update_path2_acl(const u8 type, const char *filename1, + const char *filename2, + struct tomoyo_domain_info *const domain, + const bool is_delete) { 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; + struct tomoyo_path2_acl *entry = NULL; + int error = is_delete ? -ENOENT : -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__)) + if (!tomoyo_is_correct_path(filename1, 0, 0, 0) || + !tomoyo_is_correct_path(filename2, 0, 0, 0)) return -EINVAL; - saved_filename1 = tomoyo_save_name(filename1); - saved_filename2 = tomoyo_save_name(filename2); + saved_filename1 = tomoyo_get_name(filename1); + saved_filename2 = tomoyo_get_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) + if (!is_delete) + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + mutex_lock(&tomoyo_policy_lock); + list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { + struct tomoyo_path2_acl *acl = + container_of(ptr, struct tomoyo_path2_acl, head); + if (ptr->type != TOMOYO_TYPE_PATH2_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; + if (is_delete) + acl->perm &= ~perm; + else + acl->perm |= perm; error = 0; break; } + if (!is_delete && error && tomoyo_memory_ok(entry)) { + entry->head.type = TOMOYO_TYPE_PATH2_ACL; + entry->perm = perm; + entry->filename1 = saved_filename1; + saved_filename1 = NULL; + entry->filename2 = saved_filename2; + saved_filename2 = NULL; + list_add_tail_rcu(&entry->head.list, &domain->acl_info_list); + entry = NULL; + error = 0; + } + mutex_unlock(&tomoyo_policy_lock); out: - up_write(&tomoyo_domain_acl_info_list_lock); + tomoyo_put_name(saved_filename1); + tomoyo_put_name(saved_filename2); + kfree(entry); return error; } /** - * tomoyo_check_single_path_acl - Check permission for single path operation. + * tomoyo_path_acl - Check permission for single path operation. * * @domain: Pointer to "struct tomoyo_domain_info". * @type: Type of operation. * @filename: Filename to check. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ -static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain, - const u8 type, - const struct tomoyo_path_info *filename) +static int tomoyo_path_acl(struct tomoyo_domain_info *domain, const u8 type, + const struct tomoyo_path_info *filename) { if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) return 0; - return tomoyo_check_single_path_acl2(domain, filename, 1 << type, 1); + return tomoyo_path_acl2(domain, filename, 1 << type, 1); } /** - * tomoyo_check_double_path_acl - Check permission for double path operation. + * tomoyo_path2_acl - Check permission for double path operation. * * @domain: Pointer to "struct tomoyo_domain_info". * @type: Type of operation. @@ -1010,13 +970,13 @@ static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain, * @filename2: Second filename to check. * * Returns 0 on success, -EPERM otherwise. + * + * Caller holds tomoyo_read_lock(). */ -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 int tomoyo_path2_acl(const struct tomoyo_domain_info *domain, + const u8 type, + const struct tomoyo_path_info *filename1, + const struct tomoyo_path_info *filename2) { struct tomoyo_acl_info *ptr; const u8 perm = 1 << type; @@ -1024,13 +984,11 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, 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) + list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { + struct tomoyo_path2_acl *acl; + if (ptr->type != TOMOYO_TYPE_PATH2_ACL) continue; - acl = container_of(ptr, struct tomoyo_double_path_acl_record, - head); + acl = container_of(ptr, struct tomoyo_path2_acl, head); if (!(acl->perm & perm)) continue; if (!tomoyo_path_matches_pattern(filename1, acl->filename1)) @@ -1040,12 +998,11 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, error = 0; break; } - up_read(&tomoyo_domain_acl_info_list_lock); return error; } /** - * tomoyo_check_single_path_permission2 - Check permission for single path operation. + * tomoyo_path_permission2 - Check permission for single path operation. * * @domain: Pointer to "struct tomoyo_domain_info". * @operation: Type of operation. @@ -1053,11 +1010,13 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, * @mode: Access control mode. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ -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_path_permission2(struct tomoyo_domain_info *const domain, + u8 operation, + const struct tomoyo_path_info *filename, + const u8 mode) { const char *msg; int error; @@ -1066,8 +1025,8 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * if (!mode) return 0; next: - error = tomoyo_check_single_path_acl(domain, operation, filename); - msg = tomoyo_sp2keyword(operation); + error = tomoyo_path_acl(domain, operation, filename); + msg = tomoyo_path2keyword(operation); if (!error) goto ok; if (tomoyo_verbose_mode(domain)) @@ -1076,7 +1035,7 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * 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); + tomoyo_update_path_acl(operation, name, domain, false); } if (!is_enforce) error = 0; @@ -1086,9 +1045,9 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * * we need to check "allow_rewrite" permission if the filename is * specified by "deny_rewrite" keyword. */ - if (!error && operation == TOMOYO_TYPE_TRUNCATE_ACL && + if (!error && operation == TOMOYO_TYPE_TRUNCATE && tomoyo_is_no_rewrite_file(filename)) { - operation = TOMOYO_TYPE_REWRITE_ACL; + operation = TOMOYO_TYPE_REWRITE; goto next; } return error; @@ -1101,6 +1060,8 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * * @filename: Check permission for "execute". * * Returns 0 on success, negativevalue otherwise. + * + * Caller holds tomoyo_read_lock(). */ int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, const struct tomoyo_path_info *filename) @@ -1129,6 +1090,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, struct tomoyo_path_info *buf; const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); const bool is_enforce = (mode == 3); + int idx; if (!mode || !path->mnt) return 0; @@ -1140,6 +1102,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, * don't call me. */ return 0; + idx = tomoyo_read_lock(); buf = tomoyo_get_path(path); if (!buf) goto out; @@ -1152,49 +1115,50 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, 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); + error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE, + buf, mode); } 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); + error = tomoyo_path_permission2(domain, TOMOYO_TYPE_TRUNCATE, + buf, mode); out: - tomoyo_free(buf); + kfree(buf); + tomoyo_read_unlock(idx); if (!is_enforce) 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 "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate", "symlink", "ioctl", "chmod", "chown", "chgrp", "chroot", "mount" and "unmount". * - * @domain: Pointer to "struct tomoyo_domain_info". * @operation: Type of operation. * @path: Pointer to "struct path". * * 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) { int error = -ENOMEM; struct tomoyo_path_info *buf; + struct tomoyo_domain_info *domain = tomoyo_domain(); const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); const bool is_enforce = (mode == 3); + int idx; if (!mode || !path->mnt) return 0; + idx = tomoyo_read_lock(); buf = tomoyo_get_path(path); if (!buf) goto out; switch (operation) { - case TOMOYO_TYPE_MKDIR_ACL: - case TOMOYO_TYPE_RMDIR_ACL: + case TOMOYO_TYPE_MKDIR: + case TOMOYO_TYPE_RMDIR: + case TOMOYO_TYPE_CHROOT: if (!buf->is_dir) { /* * tomoyo_get_path() reserves space for appending "/." @@ -1203,10 +1167,10 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, tomoyo_fill_path_info(buf); } } - error = tomoyo_check_single_path_permission2(domain, operation, buf, - mode); + error = tomoyo_path_permission2(domain, operation, buf, mode); out: - tomoyo_free(buf); + kfree(buf); + tomoyo_read_unlock(idx); if (!is_enforce) error = 0; return error; @@ -1215,21 +1179,23 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, /** * tomoyo_check_rewrite_permission - Check permission for "rewrite". * - * @domain: Pointer to "struct tomoyo_domain_info". * @filp: Pointer to "struct file". * * Returns 0 on success, negative value otherwise. */ -int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, - struct file *filp) +int tomoyo_check_rewrite_permission(struct file *filp) { int error = -ENOMEM; + struct tomoyo_domain_info *domain = tomoyo_domain(); const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); const bool is_enforce = (mode == 3); struct tomoyo_path_info *buf; + int idx; if (!mode || !filp->f_path.mnt) return 0; + + idx = tomoyo_read_lock(); buf = tomoyo_get_path(&filp->f_path); if (!buf) goto out; @@ -1237,38 +1203,38 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, error = 0; goto out; } - error = tomoyo_check_single_path_permission2(domain, - TOMOYO_TYPE_REWRITE_ACL, - buf, mode); + error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE, buf, mode); out: - tomoyo_free(buf); + kfree(buf); + tomoyo_read_unlock(idx); if (!is_enforce) 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; + struct tomoyo_domain_info *domain = tomoyo_domain(); const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); const bool is_enforce = (mode == 3); const char *msg; + int idx; if (!mode || !path1->mnt || !path2->mnt) return 0; + idx = tomoyo_read_lock(); buf1 = tomoyo_get_path(path1); buf2 = tomoyo_get_path(path2); if (!buf1 || !buf2) @@ -1289,8 +1255,8 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, } } } - error = tomoyo_check_double_path_acl(domain, operation, buf1, buf2); - msg = tomoyo_dp2keyword(operation); + error = tomoyo_path2_acl(domain, operation, buf1, buf2); + msg = tomoyo_path22keyword(operation); if (!error) goto out; if (tomoyo_verbose_mode(domain)) @@ -1301,12 +1267,13 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info * const 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); + tomoyo_update_path2_acl(operation, name1, name2, domain, + false); } out: - tomoyo_free(buf1); - tomoyo_free(buf2); + kfree(buf1); + kfree(buf2); + tomoyo_read_unlock(idx); if (!is_enforce) error = 0; return error;