diff options
author | James Morris <jmorris@namei.org> | 2010-05-18 08:57:00 +1000 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2010-05-18 08:57:00 +1000 |
commit | 539c99fd7fc28f8db257c713c10fb4aceadf8887 (patch) | |
tree | e603e48ac816cde56e4872e0f7bcdfe7bd33f3b3 /security/tomoyo | |
parent | ba2e1c5f25a99dec3873745031ad23ce3fd79bff (diff) | |
parent | 4d09ec0f705cf88a12add029c058b53f288cfaa2 (diff) |
Merge branch 'next' into for-linus
Diffstat (limited to 'security/tomoyo')
-rw-r--r-- | security/tomoyo/Makefile | 2 | ||||
-rw-r--r-- | security/tomoyo/common.c | 157 | ||||
-rw-r--r-- | security/tomoyo/common.h | 121 | ||||
-rw-r--r-- | security/tomoyo/domain.c | 143 | ||||
-rw-r--r-- | security/tomoyo/file.c | 250 | ||||
-rw-r--r-- | security/tomoyo/gc.c | 55 | ||||
-rw-r--r-- | security/tomoyo/path_group.c | 172 | ||||
-rw-r--r-- | security/tomoyo/realpath.c | 30 |
8 files changed, 658 insertions, 272 deletions
diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile index 60a9e2002da..4fb39030f6b 100644 --- a/security/tomoyo/Makefile +++ b/security/tomoyo/Makefile @@ -1 +1 @@ -obj-y = common.o realpath.o tomoyo.o domain.o file.o gc.o +obj-y = common.o realpath.o tomoyo.o domain.o file.o gc.o path_group.o diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 975c45d88ba..b5dbdc9ff73 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -76,6 +76,49 @@ static int tomoyo_write_control(struct file *file, const char __user *buffer, const int buffer_len); /** + * tomoyo_parse_name_union - Parse a tomoyo_name_union. + * + * @filename: Name or name group. + * @ptr: Pointer to "struct tomoyo_name_union". + * + * Returns true on success, false otherwise. + */ +bool tomoyo_parse_name_union(const char *filename, + struct tomoyo_name_union *ptr) +{ + if (!tomoyo_is_correct_path(filename, 0, 0, 0)) + return false; + if (filename[0] == '@') { + ptr->group = tomoyo_get_path_group(filename + 1); + ptr->is_group = true; + return ptr->group != NULL; + } + ptr->filename = tomoyo_get_name(filename); + ptr->is_group = false; + return ptr->filename != NULL; +} + +/** + * tomoyo_print_name_union - Print a tomoyo_name_union. + * + * @head: Pointer to "struct tomoyo_io_buffer". + * @ptr: Pointer to "struct tomoyo_name_union". + * + * Returns true on success, false otherwise. + */ +static bool tomoyo_print_name_union(struct tomoyo_io_buffer *head, + const struct tomoyo_name_union *ptr) +{ + int pos = head->read_avail; + if (pos && head->read_buf[pos - 1] == ' ') + head->read_avail--; + if (ptr->is_group) + return tomoyo_io_printf(head, " @%s", + ptr->group->group_name->name); + return tomoyo_io_printf(head, " %s", ptr->filename->name); +} + +/** * tomoyo_is_byte_range - Check whether the string isa \ooo style octal value. * * @str: Pointer to the string. @@ -172,6 +215,33 @@ static void tomoyo_normalize_line(unsigned char *buffer) } /** + * tomoyo_tokenize - Tokenize string. + * + * @buffer: The line to tokenize. + * @w: Pointer to "char *". + * @size: Sizeof @w . + * + * Returns true on success, false otherwise. + */ +bool tomoyo_tokenize(char *buffer, char *w[], size_t size) +{ + int count = size / sizeof(char *); + int i; + for (i = 0; i < count; i++) + w[i] = ""; + for (i = 0; i < count; i++) { + char *cp = strchr(buffer, ' '); + if (cp) + *cp = '\0'; + w[i] = buffer; + if (!cp) + break; + buffer = cp + 1; + } + return i < count || !*buffer; +} + +/** * tomoyo_is_correct_path - Validate a pathname. * @filename: The pathname to check. * @start_type: Should the pathname start with '/'? @@ -874,17 +944,17 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain) static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned int profile) { - static DEFINE_MUTEX(lock); struct tomoyo_profile *ptr = NULL; int i; if (profile >= TOMOYO_MAX_PROFILES) return NULL; - mutex_lock(&lock); + if (mutex_lock_interruptible(&tomoyo_policy_lock)) + return NULL; ptr = tomoyo_profile_ptr[profile]; if (ptr) goto ok; - ptr = kmalloc(sizeof(*ptr), GFP_KERNEL); + ptr = kmalloc(sizeof(*ptr), GFP_NOFS); if (!tomoyo_memory_ok(ptr)) { kfree(ptr); ptr = NULL; @@ -895,7 +965,7 @@ static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned mb(); /* Avoid out-of-order execution. */ tomoyo_profile_ptr[profile] = ptr; ok: - mutex_unlock(&lock); + mutex_unlock(&tomoyo_policy_lock); return ptr; } @@ -1071,44 +1141,42 @@ LIST_HEAD(tomoyo_policy_manager_list); static int tomoyo_update_manager_entry(const char *manager, const bool is_delete) { - struct tomoyo_policy_manager_entry *entry = NULL; struct tomoyo_policy_manager_entry *ptr; - const struct tomoyo_path_info *saved_manager; + struct tomoyo_policy_manager_entry e = { }; int error = is_delete ? -ENOENT : -ENOMEM; - bool is_domain = false; if (tomoyo_is_domain_def(manager)) { if (!tomoyo_is_correct_domain(manager)) return -EINVAL; - is_domain = true; + e.is_domain = true; } else { if (!tomoyo_is_correct_path(manager, 1, -1, -1)) return -EINVAL; } - saved_manager = tomoyo_get_name(manager); - if (!saved_manager) + e.manager = tomoyo_get_name(manager); + if (!e.manager) return -ENOMEM; - if (!is_delete) - entry = kmalloc(sizeof(*entry), GFP_KERNEL); - mutex_lock(&tomoyo_policy_lock); + if (mutex_lock_interruptible(&tomoyo_policy_lock)) + goto out; list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) { - if (ptr->manager != saved_manager) + if (ptr->manager != e.manager) continue; ptr->is_deleted = is_delete; error = 0; break; } - if (!is_delete && error && tomoyo_memory_ok(entry)) { - entry->manager = saved_manager; - saved_manager = NULL; - entry->is_domain = is_domain; - list_add_tail_rcu(&entry->list, &tomoyo_policy_manager_list); - entry = NULL; - error = 0; + if (!is_delete && error) { + struct tomoyo_policy_manager_entry *entry = + tomoyo_commit_ok(&e, sizeof(e)); + if (entry) { + list_add_tail_rcu(&entry->list, + &tomoyo_policy_manager_list); + error = 0; + } } mutex_unlock(&tomoyo_policy_lock); - tomoyo_put_name(saved_manager); - kfree(entry); + out: + tomoyo_put_name(e.manager); return error; } @@ -1287,7 +1355,8 @@ static int tomoyo_delete_domain(char *domainname) name.name = domainname; tomoyo_fill_path_info(&name); - mutex_lock(&tomoyo_policy_lock); + if (mutex_lock_interruptible(&tomoyo_policy_lock)) + return 0; /* Is there an active domain? */ list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { /* Never delete tomoyo_kernel_domain */ @@ -1369,23 +1438,20 @@ static bool tomoyo_print_path_acl(struct tomoyo_io_buffer *head, { int pos; u8 bit; - const char *atmark = ""; - const char *filename; const u32 perm = ptr->perm | (((u32) ptr->perm_high) << 16); - filename = ptr->filename->name; for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { - const char *msg; if (!(perm & (1 << bit))) continue; /* Print "read/write" instead of "read" and "write". */ if ((bit == TOMOYO_TYPE_READ || bit == TOMOYO_TYPE_WRITE) && (perm & (1 << TOMOYO_TYPE_READ_WRITE))) continue; - msg = tomoyo_path2keyword(bit); pos = head->read_avail; - if (!tomoyo_io_printf(head, "allow_%s %s%s\n", msg, - atmark, filename)) + if (!tomoyo_io_printf(head, "allow_%s ", + tomoyo_path2keyword(bit)) || + !tomoyo_print_name_union(head, &ptr->name) || + !tomoyo_io_printf(head, "\n")) goto out; } head->read_bit = 0; @@ -1408,23 +1474,18 @@ static bool tomoyo_print_path2_acl(struct tomoyo_io_buffer *head, struct tomoyo_path2_acl *ptr) { int pos; - const char *atmark1 = ""; - const char *atmark2 = ""; - const char *filename1; - const char *filename2; const u8 perm = ptr->perm; u8 bit; - filename1 = ptr->filename1->name; - filename2 = ptr->filename2->name; for (bit = head->read_bit; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) { - const char *msg; if (!(perm & (1 << bit))) continue; - msg = tomoyo_path22keyword(bit); pos = head->read_avail; - if (!tomoyo_io_printf(head, "allow_%s %s%s %s%s\n", msg, - atmark1, filename1, atmark2, filename2)) + if (!tomoyo_io_printf(head, "allow_%s ", + tomoyo_path22keyword(bit)) || + !tomoyo_print_name_union(head, &ptr->name1) || + !tomoyo_print_name_union(head, &ptr->name2) || + !tomoyo_io_printf(head, "\n")) goto out; } head->read_bit = 0; @@ -1687,6 +1748,8 @@ static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head) return tomoyo_write_pattern_policy(data, is_delete); if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DENY_REWRITE)) return tomoyo_write_no_rewrite_policy(data, is_delete); + if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_PATH_GROUP)) + return tomoyo_write_path_group_policy(data, is_delete); return -EINVAL; } @@ -1743,6 +1806,12 @@ static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head) head->read_var2 = NULL; head->read_step = 9; case 9: + if (!tomoyo_read_path_group_policy(head)) + break; + head->read_var1 = NULL; + head->read_var2 = NULL; + head->read_step = 10; + case 10: head->read_eof = true; break; default: @@ -1886,7 +1955,7 @@ static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head) */ static int tomoyo_open_control(const u8 type, struct file *file) { - struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_KERNEL); + struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS); if (!head) return -ENOMEM; @@ -1947,7 +2016,7 @@ static int tomoyo_open_control(const u8 type, struct file *file) } else { if (!head->readbuf_size) head->readbuf_size = 4096 * 2; - head->read_buf = kzalloc(head->readbuf_size, GFP_KERNEL); + head->read_buf = kzalloc(head->readbuf_size, GFP_NOFS); if (!head->read_buf) { kfree(head); return -ENOMEM; @@ -1961,7 +2030,7 @@ static int tomoyo_open_control(const u8 type, struct file *file) head->write = NULL; } else if (head->write) { head->writebuf_size = 4096 * 2; - head->write_buf = kzalloc(head->writebuf_size, GFP_KERNEL); + head->write_buf = kzalloc(head->writebuf_size, GFP_NOFS); if (!head->write_buf) { kfree(head->read_buf); kfree(head); diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 67bd22dd3e6..9f1ae5e3ba5 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -54,6 +54,7 @@ struct linux_binprm; #define TOMOYO_KEYWORD_KEEP_DOMAIN "keep_domain " #define TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN "no_initialize_domain " #define TOMOYO_KEYWORD_NO_KEEP_DOMAIN "no_keep_domain " +#define TOMOYO_KEYWORD_PATH_GROUP "path_group " #define TOMOYO_KEYWORD_SELECT "select " #define TOMOYO_KEYWORD_USE_PROFILE "use_profile " #define TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "ignore_global_allow_read" @@ -204,6 +205,27 @@ struct tomoyo_path_info_with_data { char barrier2[16]; /* Safeguard for overrun. */ }; +struct tomoyo_name_union { + const struct tomoyo_path_info *filename; + struct tomoyo_path_group *group; + u8 is_group; +}; + +/* Structure for "path_group" directive. */ +struct tomoyo_path_group { + struct list_head list; + const struct tomoyo_path_info *group_name; + struct list_head member_list; + atomic_t users; +}; + +/* Structure for "path_group" directive. */ +struct tomoyo_path_group_member { + struct list_head list; + bool is_deleted; + const struct tomoyo_path_info *member_name; +}; + /* * tomoyo_acl_info is a structure which is used for holding * @@ -274,7 +296,7 @@ struct tomoyo_domain_info { * * (1) "head" which is a "struct tomoyo_acl_info". * (2) "perm" which is a bitmask of permitted operations. - * (3) "filename" is the pathname. + * (3) "name" is the pathname. * * Directives held by this structure are "allow_read/write", "allow_execute", * "allow_read", "allow_write", "allow_create", "allow_unlink", "allow_mkdir", @@ -287,8 +309,7 @@ struct tomoyo_path_acl { struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_ACL */ u8 perm_high; u16 perm; - /* Pointer to single pathname. */ - const struct tomoyo_path_info *filename; + struct tomoyo_name_union name; }; /* @@ -298,8 +319,8 @@ struct tomoyo_path_acl { * * (1) "head" which is a "struct tomoyo_acl_info". * (2) "perm" which is a bitmask of permitted operations. - * (3) "filename1" is the source/old pathname. - * (4) "filename2" is the destination/new pathname. + * (3) "name1" is the source/old pathname. + * (4) "name2" is the destination/new pathname. * * Directives held by this structure are "allow_rename", "allow_link" and * "allow_pivot_root". @@ -307,10 +328,8 @@ struct tomoyo_path_acl { struct tomoyo_path2_acl { struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH2_ACL */ u8 perm; - /* Pointer to single pathname. */ - const struct tomoyo_path_info *filename1; - /* Pointer to single pathname. */ - const struct tomoyo_path_info *filename2; + struct tomoyo_name_union name1; + struct tomoyo_name_union name2; }; /* @@ -514,6 +533,9 @@ struct tomoyo_policy_manager_entry { /********** Function prototypes. **********/ +/* Check whether the given name matches the given name_union. */ +bool tomoyo_compare_name_union(const struct tomoyo_path_info *name, + const struct tomoyo_name_union *ptr); /* Check whether the domain has too many ACL entries to hold. */ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain); /* Transactional sprintf() for policy dump. */ @@ -526,6 +548,12 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, const s8 pattern_type, const s8 end_type); /* Check whether the token can be a domainname. */ bool tomoyo_is_domain_def(const unsigned char *buffer); +bool tomoyo_parse_name_union(const char *filename, + struct tomoyo_name_union *ptr); +/* Check whether the given filename matches the given path_group. */ +bool tomoyo_path_matches_group(const struct tomoyo_path_info *pathname, + const struct tomoyo_path_group *group, + const bool may_use_pattern); /* Check whether the given filename matches the given pattern. */ bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename, const struct tomoyo_path_info *pattern); @@ -540,10 +568,14 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head); bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head); /* Read "file_pattern" entry in exception policy. */ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head); +/* Read "path_group" entry in exception policy. */ +bool tomoyo_read_path_group_policy(struct tomoyo_io_buffer *head); /* Read "allow_read" entry in exception policy. */ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head); /* Read "deny_rewrite" entry in exception policy. */ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head); +/* Tokenize a line. */ +bool tomoyo_tokenize(char *buffer, char *w[], size_t size); /* Write domain policy violation warning message to console? */ bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain); /* Convert double path operation to operation name. */ @@ -580,12 +612,18 @@ int tomoyo_write_globally_readable_policy(char *data, const bool is_delete); int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete); /* Create "file_pattern" entry in exception policy. */ int tomoyo_write_pattern_policy(char *data, const bool is_delete); +/* Create "path_group" entry in exception policy. */ +int tomoyo_write_path_group_policy(char *data, const bool is_delete); /* Find a domain by the given name. */ struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname); /* Find or create a domain by the given name. */ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * domainname, const u8 profile); + +/* Allocate memory for "struct tomoyo_path_group". */ +struct tomoyo_path_group *tomoyo_get_path_group(const char *group_name); + /* Check mode for specified functionality. */ unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain, const u8 index); @@ -616,6 +654,7 @@ char *tomoyo_realpath_from_path(struct path *path); /* Check memory quota. */ bool tomoyo_memory_ok(void *ptr); +void *tomoyo_commit_ok(void *data, const unsigned int size); /* * Keep the given name on the RAM. @@ -641,6 +680,9 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1, int tomoyo_check_rewrite_permission(struct file *filp); int tomoyo_find_next_domain(struct linux_binprm *bprm); +/* Drop refcount on tomoyo_name_union. */ +void tomoyo_put_name_union(struct tomoyo_name_union *ptr); + /* Run garbage collector. */ void tomoyo_run_gc(void); @@ -654,6 +696,7 @@ extern struct srcu_struct tomoyo_ss; /* The list for "struct tomoyo_domain_info". */ extern struct list_head tomoyo_domain_list; +extern struct list_head tomoyo_path_group_list; extern struct list_head tomoyo_domain_initializer_list; extern struct list_head tomoyo_domain_keeper_list; extern struct list_head tomoyo_alias_list; @@ -662,7 +705,6 @@ extern struct list_head tomoyo_pattern_list; extern struct list_head tomoyo_no_rewrite_list; extern struct list_head tomoyo_policy_manager_list; extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; -extern struct mutex tomoyo_name_list_lock; /* Lock for protecting policy. */ extern struct mutex tomoyo_policy_lock; @@ -725,6 +767,12 @@ static inline void tomoyo_put_name(const struct tomoyo_path_info *name) } } +static inline void tomoyo_put_path_group(struct tomoyo_path_group *group) +{ + if (group) + atomic_dec(&group->users); +} + static inline struct tomoyo_domain_info *tomoyo_domain(void) { return current_cred()->security; @@ -736,6 +784,59 @@ static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct return task_cred_xxx(task, security); } +static inline bool tomoyo_is_same_acl_head(const struct tomoyo_acl_info *p1, + const struct tomoyo_acl_info *p2) +{ + return p1->type == p2->type; +} + +static inline bool tomoyo_is_same_name_union +(const struct tomoyo_name_union *p1, const struct tomoyo_name_union *p2) +{ + return p1->filename == p2->filename && p1->group == p2->group && + p1->is_group == p2->is_group; +} + +static inline bool tomoyo_is_same_path_acl(const struct tomoyo_path_acl *p1, + const struct tomoyo_path_acl *p2) +{ + return tomoyo_is_same_acl_head(&p1->head, &p2->head) && + tomoyo_is_same_name_union(&p1->name, &p2->name); +} + +static inline bool tomoyo_is_same_path2_acl(const struct tomoyo_path2_acl *p1, + const struct tomoyo_path2_acl *p2) +{ + return tomoyo_is_same_acl_head(&p1->head, &p2->head) && + tomoyo_is_same_name_union(&p1->name1, &p2->name1) && + tomoyo_is_same_name_union(&p1->name2, &p2->name2); +} + +static inline bool tomoyo_is_same_domain_initializer_entry +(const struct tomoyo_domain_initializer_entry *p1, + const struct tomoyo_domain_initializer_entry *p2) +{ + return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name + && p1->domainname == p2->domainname + && p1->program == p2->program; +} + +static inline bool tomoyo_is_same_domain_keeper_entry +(const struct tomoyo_domain_keeper_entry *p1, + const struct tomoyo_domain_keeper_entry *p2) +{ + return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name + && p1->domainname == p2->domainname + && p1->program == p2->program; +} + +static inline bool tomoyo_is_same_alias_entry +(const struct tomoyo_alias_entry *p1, const struct tomoyo_alias_entry *p2) +{ + return p1->original_name == p2->original_name && + p1->aliased_name == p2->aliased_name; +} + /** * list_for_each_cookie - iterate over a list with cookie. * @pos: the &struct list_head to use as a loop cursor. diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index acb8c397d5c..cd8ba444676 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -130,57 +130,47 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, const bool is_not, const bool is_delete) { - struct tomoyo_domain_initializer_entry *entry = NULL; struct tomoyo_domain_initializer_entry *ptr; - const struct tomoyo_path_info *saved_program = NULL; - const struct tomoyo_path_info *saved_domainname = NULL; + struct tomoyo_domain_initializer_entry e = { .is_not = is_not }; int error = is_delete ? -ENOENT : -ENOMEM; - bool is_last_name = false; if (!tomoyo_is_correct_path(program, 1, -1, -1)) return -EINVAL; /* No patterns allowed. */ if (domainname) { if (!tomoyo_is_domain_def(domainname) && tomoyo_is_correct_path(domainname, 1, -1, -1)) - is_last_name = true; + e.is_last_name = true; else if (!tomoyo_is_correct_domain(domainname)) return -EINVAL; - saved_domainname = tomoyo_get_name(domainname); - if (!saved_domainname) + e.domainname = tomoyo_get_name(domainname); + if (!e.domainname) goto out; } - saved_program = tomoyo_get_name(program); - if (!saved_program) + e.program = tomoyo_get_name(program); + if (!e.program) + goto out; + if (mutex_lock_interruptible(&tomoyo_policy_lock)) goto out; - if (!is_delete) - entry = kmalloc(sizeof(*entry), GFP_KERNEL); - mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) { - if (ptr->is_not != is_not || - ptr->domainname != saved_domainname || - ptr->program != saved_program) + if (!tomoyo_is_same_domain_initializer_entry(ptr, &e)) continue; ptr->is_deleted = is_delete; error = 0; break; } - if (!is_delete && error && tomoyo_memory_ok(entry)) { - entry->domainname = saved_domainname; - saved_domainname = NULL; - entry->program = saved_program; - saved_program = NULL; - entry->is_not = is_not; - entry->is_last_name = is_last_name; - list_add_tail_rcu(&entry->list, - &tomoyo_domain_initializer_list); - entry = NULL; - error = 0; + if (!is_delete && error) { + struct tomoyo_domain_initializer_entry *entry = + tomoyo_commit_ok(&e, sizeof(e)); + if (entry) { + list_add_tail_rcu(&entry->list, + &tomoyo_domain_initializer_list); + error = 0; + } } mutex_unlock(&tomoyo_policy_lock); out: - tomoyo_put_name(saved_domainname); - tomoyo_put_name(saved_program); - kfree(entry); + tomoyo_put_name(e.domainname); + tomoyo_put_name(e.program); return error; } @@ -350,56 +340,47 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, const bool is_not, const bool is_delete) { - struct tomoyo_domain_keeper_entry *entry = NULL; struct tomoyo_domain_keeper_entry *ptr; - const struct tomoyo_path_info *saved_domainname = NULL; - const struct tomoyo_path_info *saved_program = NULL; + struct tomoyo_domain_keeper_entry e = { .is_not = is_not }; int error = is_delete ? -ENOENT : -ENOMEM; - bool is_last_name = false; if (!tomoyo_is_domain_def(domainname) && tomoyo_is_correct_path(domainname, 1, -1, -1)) - is_last_name = true; + e.is_last_name = true; else if (!tomoyo_is_correct_domain(domainname)) return -EINVAL; if (program) { if (!tomoyo_is_correct_path(program, 1, -1, -1)) return -EINVAL; - saved_program = tomoyo_get_name(program); - if (!saved_program) + e.program = tomoyo_get_name(program); + if (!e.program) goto out; } - saved_domainname = tomoyo_get_name(domainname); - if (!saved_domainname) + e.domainname = tomoyo_get_name(domainname); + if (!e.domainname) + goto out; + if (mutex_lock_interruptible(&tomoyo_policy_lock)) goto out; - if (!is_delete) - entry = kmalloc(sizeof(*entry), GFP_KERNEL); - mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { - if (ptr->is_not != is_not || - ptr->domainname != saved_domainname || - ptr->program != saved_program) + if (!tomoyo_is_same_domain_keeper_entry(ptr, &e)) continue; ptr->is_deleted = is_delete; error = 0; break; } - if (!is_delete && error && tomoyo_memory_ok(entry)) { - entry->domainname = saved_domainname; - saved_domainname = NULL; - entry->program = saved_program; - saved_program = NULL; - entry->is_not = is_not; - entry->is_last_name = is_last_name; - list_add_tail_rcu(&entry->list, &tomoyo_domain_keeper_list); - entry = NULL; - error = 0; + if (!is_delete && error) { + struct tomoyo_domain_keeper_entry *entry = + tomoyo_commit_ok(&e, sizeof(e)); + if (entry) { + list_add_tail_rcu(&entry->list, + &tomoyo_domain_keeper_list); + error = 0; + } } mutex_unlock(&tomoyo_policy_lock); out: - tomoyo_put_name(saved_domainname); - tomoyo_put_name(saved_program); - kfree(entry); + tomoyo_put_name(e.domainname); + tomoyo_put_name(e.program); return error; } @@ -551,44 +532,38 @@ static int tomoyo_update_alias_entry(const char *original_name, const char *aliased_name, const bool is_delete) { - struct tomoyo_alias_entry *entry = NULL; struct tomoyo_alias_entry *ptr; - const struct tomoyo_path_info *saved_original_name; - const struct tomoyo_path_info *saved_aliased_name; + struct tomoyo_alias_entry e = { }; int error = is_delete ? -ENOENT : -ENOMEM; if (!tomoyo_is_correct_path(original_name, 1, -1, -1) || !tomoyo_is_correct_path(aliased_name, 1, -1, -1)) return -EINVAL; /* No patterns allowed. */ - saved_original_name = tomoyo_get_name(original_name); - saved_aliased_name = tomoyo_get_name(aliased_name); - if (!saved_original_name || !saved_aliased_name) + e.original_name = tomoyo_get_name(original_name); + e.aliased_name = tomoyo_get_name(aliased_name); + if (!e.original_name || !e.aliased_name) + goto out; + if (mutex_lock_interruptible(&tomoyo_policy_lock)) goto out; - if (!is_delete) - entry = kmalloc(sizeof(*entry), GFP_KERNEL); - mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { - if (ptr->original_name != saved_original_name || - ptr->aliased_name != saved_aliased_name) + if (!tomoyo_is_same_alias_entry(ptr, &e)) continue; ptr->is_deleted = is_delete; error = 0; break; } - if (!is_delete && error && tomoyo_memory_ok(entry)) { - entry->original_name = saved_original_name; - saved_original_name = NULL; - entry->aliased_name = saved_aliased_name; - saved_aliased_name = NULL; - list_add_tail_rcu(&entry->list, &tomoyo_alias_list); - entry = NULL; - error = 0; + if (!is_delete && error) { + struct tomoyo_alias_entry *entry = + tomoyo_commit_ok(&e, sizeof(e)); + if (entry) { + list_add_tail_rcu(&entry->list, &tomoyo_alias_list); + error = 0; + } } mutex_unlock(&tomoyo_policy_lock); out: - tomoyo_put_name(saved_original_name); - tomoyo_put_name(saved_aliased_name); - kfree(entry); + tomoyo_put_name(e.original_name); + tomoyo_put_name(e.aliased_name); return error; } @@ -656,7 +631,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * const u8 profile) { struct tomoyo_domain_info *entry; - struct tomoyo_domain_info *domain; + struct tomoyo_domain_info *domain = NULL; const struct tomoyo_path_info *saved_domainname; bool found = false; @@ -665,8 +640,9 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * saved_domainname = tomoyo_get_name(domainname); if (!saved_domainname) return NULL; - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - mutex_lock(&tomoyo_policy_lock); + entry = kzalloc(sizeof(*entry), GFP_NOFS); + if (mutex_lock_interruptible(&tomoyo_policy_lock)) + goto out; list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { if (domain->is_deleted || tomoyo_pathcmp(saved_domainname, domain->domainname)) @@ -685,6 +661,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * found = true; } mutex_unlock(&tomoyo_policy_lock); + out: tomoyo_put_name(saved_domainname); kfree(entry); return found ? domain : NULL; @@ -705,7 +682,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) * This function assumes that the size of buffer returned by * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN. */ - struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); + struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_NOFS); struct tomoyo_domain_info *old_domain = tomoyo_domain(); struct tomoyo_domain_info *domain = NULL; const char *old_domain_name = old_domain->domainname->name; diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 6f3fe76a1fd..1c6f8238ec4 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -45,6 +45,37 @@ static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = { [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root", }; +void tomoyo_put_name_union(struct tomoyo_name_union *ptr) +{ + if (!ptr) + return; + if (ptr->is_group) + tomoyo_put_path_group(ptr->group); + else + tomoyo_put_name(ptr->filename); +} + +bool tomoyo_compare_name_union(const struct tomoyo_path_info *name, + const struct tomoyo_name_union *ptr) +{ + if (ptr->is_group) + return tomoyo_path_matches_group(name, ptr->group, 1); + return tomoyo_path_matches_pattern(name, ptr->filename); +} + +static bool tomoyo_compare_name_union_pattern(const struct tomoyo_path_info + *name, + const struct tomoyo_name_union + *ptr, const bool may_use_pattern) +{ + if (ptr->is_group) + return tomoyo_path_matches_group(name, ptr->group, + may_use_pattern); + if (may_use_pattern || !ptr->filename->is_patterned) + return tomoyo_path_matches_pattern(name, ptr->filename); + return false; +} + /** * tomoyo_path2keyword - Get the name of single path operation. * @@ -100,7 +131,7 @@ static struct tomoyo_path_info *tomoyo_get_path(struct path *path) { int error; struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf), - GFP_KERNEL); + GFP_NOFS); if (!buf) return NULL; @@ -164,36 +195,36 @@ LIST_HEAD(tomoyo_globally_readable_list); static int tomoyo_update_globally_readable_entry(const char *filename, const bool is_delete) { - struct tomoyo_globally_readable_file_entry *entry = NULL; struct tomoyo_globally_readable_file_entry *ptr; - const struct tomoyo_path_info *saved_filename; + struct tomoyo_globally_readable_file_entry e = { }; int error = is_delete ? -ENOENT : -ENOMEM; if (!tomoyo_is_correct_path(filename, 1, 0, -1)) return -EINVAL; - saved_filename = tomoyo_get_name(filename); - if (!saved_filename) + e.filename = tomoyo_get_name(filename); + if (!e.filename) return -ENOMEM; - if (!is_delete) - entry = kmalloc(sizeof(*entry), GFP_KERNEL); - mutex_lock(&tomoyo_policy_lock); + if (mutex_lock_interruptible(&tomoyo_policy_lock)) + goto out; list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { - if (ptr->filename != saved_filename) + if (ptr->filename != e.filename) continue; ptr->is_deleted = is_delete; error = 0; break; } - 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; + if (!is_delete && error) { + struct tomoyo_globally_readable_file_entry *entry = + tomoyo_commit_ok(&e, sizeof(e)); + if (entry) { + list_add_tail_rcu(&entry->list, + &tomoyo_globally_readable_list); + error = 0; + } } mutex_unlock(&tomoyo_policy_lock); - tomoyo_put_name(saved_filename); - kfree(entry); + out: + tomoyo_put_name(e.filename); return error; } @@ -311,37 +342,34 @@ LIST_HEAD(tomoyo_pattern_list); static int tomoyo_update_file_pattern_entry(const char *pattern, const bool is_delete) { - struct tomoyo_pattern_entry *entry = NULL; struct tomoyo_pattern_entry *ptr; - const struct tomoyo_path_info *saved_pattern; + struct tomoyo_pattern_entry e = { .pattern = tomoyo_get_name(pattern) }; int error = is_delete ? -ENOENT : -ENOMEM; - saved_pattern = tomoyo_get_name(pattern); - if (!saved_pattern) + if (!e.pattern) return error; - if (!saved_pattern->is_patterned) + if (!e.pattern->is_patterned) + goto out; + if (mutex_lock_interruptible(&tomoyo_policy_lock)) 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) + if (e.pattern != ptr->pattern) continue; ptr->is_deleted = is_delete; error = 0; break; } - 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; + if (!is_delete && error) { + struct tomoyo_pattern_entry *entry = + tomoyo_commit_ok(&e, sizeof(e)); + if (entry) { + list_add_tail_rcu(&entry->list, &tomoyo_pattern_list); + error = 0; + } } mutex_unlock(&tomoyo_policy_lock); out: - kfree(entry); - tomoyo_put_name(saved_pattern); + tomoyo_put_name(e.pattern); return error; } @@ -464,36 +492,36 @@ LIST_HEAD(tomoyo_no_rewrite_list); static int tomoyo_update_no_rewrite_entry(const char *pa |