diff options
Diffstat (limited to 'security/selinux/selinuxfs.c')
-rw-r--r-- | security/selinux/selinuxfs.c | 97 |
1 files changed, 41 insertions, 56 deletions
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 8eb140dd2e4..0e1352a555c 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -105,7 +105,7 @@ static ssize_t sel_write_enforce(struct file * file, const char __user * buf, ssize_t length; int new_value; - if (count < 0 || count >= PAGE_SIZE) + if (count >= PAGE_SIZE) return -ENOMEM; if (*ppos != 0) { /* No partial writes. */ @@ -155,7 +155,7 @@ static ssize_t sel_write_disable(struct file * file, const char __user * buf, int new_value; extern int selinux_disable(void); - if (count < 0 || count >= PAGE_SIZE) + if (count >= PAGE_SIZE) return -ENOMEM; if (*ppos != 0) { /* No partial writes. */ @@ -242,7 +242,7 @@ static ssize_t sel_write_load(struct file * file, const char __user * buf, goto out; } - if ((count < 0) || (count > 64 * 1024 * 1024) + if ((count > 64 * 1024 * 1024) || (data = vmalloc(count)) == NULL) { length = -ENOMEM; goto out; @@ -271,46 +271,38 @@ static struct file_operations sel_load_ops = { .write = sel_write_load, }; - -static ssize_t sel_write_context(struct file * file, const char __user * buf, - size_t count, loff_t *ppos) - +static ssize_t sel_write_context(struct file * file, char *buf, size_t size) { - char *page; - u32 sid; + char *canon; + u32 sid, len; ssize_t length; length = task_has_security(current, SECURITY__CHECK_CONTEXT); if (length) return length; - if (count < 0 || count >= PAGE_SIZE) - return -ENOMEM; - if (*ppos != 0) { - /* No partial writes. */ - return -EINVAL; - } - page = (char*)get_zeroed_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - length = -EFAULT; - if (copy_from_user(page, buf, count)) - goto out; + length = security_context_to_sid(buf, size, &sid); + if (length < 0) + return length; - length = security_context_to_sid(page, count, &sid); + length = security_sid_to_context(sid, &canon, &len); if (length < 0) + return length; + + if (len > SIMPLE_TRANSACTION_LIMIT) { + printk(KERN_ERR "%s: context size (%u) exceeds payload " + "max\n", __FUNCTION__, len); + length = -ERANGE; goto out; + } - length = count; + memcpy(buf, canon, len); + length = len; out: - free_page((unsigned long) page); + kfree(canon); return length; } -static struct file_operations sel_context_ops = { - .write = sel_write_context, -}; - static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { @@ -332,7 +324,7 @@ static ssize_t sel_write_checkreqprot(struct file * file, const char __user * bu if (length) return length; - if (count < 0 || count >= PAGE_SIZE) + if (count >= PAGE_SIZE) return -ENOMEM; if (*ppos != 0) { /* No partial writes. */ @@ -375,6 +367,7 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = { [SEL_RELABEL] = sel_write_relabel, [SEL_USER] = sel_write_user, [SEL_MEMBER] = sel_write_member, + [SEL_CONTEXT] = sel_write_context, }; static ssize_t selinux_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) @@ -424,15 +417,13 @@ static ssize_t sel_write_access(struct file * file, char *buf, size_t size) return length; length = -ENOMEM; - scon = kmalloc(size+1, GFP_KERNEL); + scon = kzalloc(size+1, GFP_KERNEL); if (!scon) return length; - memset(scon, 0, size+1); - tcon = kmalloc(size+1, GFP_KERNEL); + tcon = kzalloc(size+1, GFP_KERNEL); if (!tcon) goto out; - memset(tcon, 0, size+1); length = -EINVAL; if (sscanf(buf, "%s %s %hu %x", scon, tcon, &tclass, &req) != 4) @@ -475,15 +466,13 @@ static ssize_t sel_write_create(struct file * file, char *buf, size_t size) return length; length = -ENOMEM; - scon = kmalloc(size+1, GFP_KERNEL); + scon = kzalloc(size+1, GFP_KERNEL); if (!scon) return length; - memset(scon, 0, size+1); - tcon = kmalloc(size+1, GFP_KERNEL); + tcon = kzalloc(size+1, GFP_KERNEL); if (!tcon) goto out; - memset(tcon, 0, size+1); length = -EINVAL; if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) @@ -536,15 +525,13 @@ static ssize_t sel_write_relabel(struct file * file, char *buf, size_t size) return length; length = -ENOMEM; - scon = kmalloc(size+1, GFP_KERNEL); + scon = kzalloc(size+1, GFP_KERNEL); if (!scon) return length; - memset(scon, 0, size+1); - tcon = kmalloc(size+1, GFP_KERNEL); + tcon = kzalloc(size+1, GFP_KERNEL); if (!tcon) goto out; - memset(tcon, 0, size+1); length = -EINVAL; if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) @@ -595,15 +582,13 @@ static ssize_t sel_write_user(struct file * file, char *buf, size_t size) return length; length = -ENOMEM; - con = kmalloc(size+1, GFP_KERNEL); + con = kzalloc(size+1, GFP_KERNEL); if (!con) return length; - memset(con, 0, size+1); - user = kmalloc(size+1, GFP_KERNEL); + user = kzalloc(size+1, GFP_KERNEL); if (!user) goto out; - memset(user, 0, size+1); length = -EINVAL; if (sscanf(buf, "%s %s", con, user) != 2) @@ -658,15 +643,13 @@ static ssize_t sel_write_member(struct file * file, char *buf, size_t size) return length; length = -ENOMEM; - scon = kmalloc(size+1, GFP_KERNEL); + scon = kzalloc(size+1, GFP_KERNEL); if (!scon) return length; - memset(scon, 0, size+1); - tcon = kmalloc(size+1, GFP_KERNEL); + tcon = kzalloc(size+1, GFP_KERNEL); if (!tcon) goto out; - memset(tcon, 0, size+1); length = -EINVAL; if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) @@ -739,7 +722,7 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, if (!filep->f_op) goto out; - if (count < 0 || count > PAGE_SIZE) { + if (count > PAGE_SIZE) { ret = -EINVAL; goto out; } @@ -800,7 +783,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, if (!filep->f_op) goto out; - if (count < 0 || count >= PAGE_SIZE) { + if (count >= PAGE_SIZE) { length = -ENOMEM; goto out; } @@ -858,7 +841,7 @@ static ssize_t sel_commit_bools_write(struct file *filep, if (!filep->f_op) goto out; - if (count < 0 || count >= PAGE_SIZE) { + if (count >= PAGE_SIZE) { length = -ENOMEM; goto out; } @@ -879,7 +862,7 @@ static ssize_t sel_commit_bools_write(struct file *filep, if (sscanf(page, "%d", &new_value) != 1) goto out; - if (new_value) { + if (new_value && bool_pending_values) { security_set_bools(bool_num, bool_pending_values); } @@ -924,7 +907,7 @@ static void sel_remove_bools(struct dentry *de) file_list_lock(); list_for_each(p, &sb->s_files) { - struct file * filp = list_entry(p, struct file, f_list); + struct file * filp = list_entry(p, struct file, f_u.fu_list); struct dentry * dentry = filp->f_dentry; if (dentry->d_parent != de) { @@ -952,6 +935,7 @@ static int sel_make_bools(void) /* remove any existing files */ kfree(bool_pending_values); + bool_pending_values = NULL; sel_remove_bools(dir); @@ -1002,6 +986,7 @@ out: } return ret; err: + kfree(values); d_genocide(dir); ret = -ENOMEM; goto out; @@ -1030,7 +1015,7 @@ static ssize_t sel_write_avc_cache_threshold(struct file * file, ssize_t ret; int new_value; - if (count < 0 || count >= PAGE_SIZE) { + if (count >= PAGE_SIZE) { ret = -ENOMEM; goto out; } @@ -1228,7 +1213,7 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent) static struct tree_descr selinux_files[] = { [SEL_LOAD] = {"load", &sel_load_ops, S_IRUSR|S_IWUSR}, [SEL_ENFORCE] = {"enforce", &sel_enforce_ops, S_IRUGO|S_IWUSR}, - [SEL_CONTEXT] = {"context", &sel_context_ops, S_IRUGO|S_IWUGO}, + [SEL_CONTEXT] = {"context", &transaction_ops, S_IRUGO|S_IWUGO}, [SEL_ACCESS] = {"access", &transaction_ops, S_IRUGO|S_IWUGO}, [SEL_CREATE] = {"create", &transaction_ops, S_IRUGO|S_IWUGO}, [SEL_RELABEL] = {"relabel", &transaction_ops, S_IRUGO|S_IWUGO}, |