aboutsummaryrefslogtreecommitdiff
path: root/security/tomoyo
diff options
context:
space:
mode:
authorJames Morris <jmorris@namei.org>2010-05-18 08:57:00 +1000
committerJames Morris <jmorris@namei.org>2010-05-18 08:57:00 +1000
commit539c99fd7fc28f8db257c713c10fb4aceadf8887 (patch)
treee603e48ac816cde56e4872e0f7bcdfe7bd33f3b3 /security/tomoyo
parentba2e1c5f25a99dec3873745031ad23ce3fd79bff (diff)
parent4d09ec0f705cf88a12add029c058b53f288cfaa2 (diff)
Merge branch 'next' into for-linus
Diffstat (limited to 'security/tomoyo')
-rw-r--r--security/tomoyo/Makefile2
-rw-r--r--security/tomoyo/common.c157
-rw-r--r--security/tomoyo/common.h121
-rw-r--r--security/tomoyo/domain.c143
-rw-r--r--security/tomoyo/file.c250
-rw-r--r--security/tomoyo/gc.c55
-rw-r--r--security/tomoyo/path_group.c172
-rw-r--r--security/tomoyo/realpath.c30
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