📄 selinuxfs.c
字号:
kfree(scon); return length;}static ssize_t sel_write_create(struct file * file, char *buf, size_t size){ char *scon, *tcon; u32 ssid, tsid, newsid; u16 tclass; ssize_t length; char *newcon; u32 len; length = task_has_security(current, SECURITY__COMPUTE_CREATE); if (length) return length; length = -ENOMEM; scon = kzalloc(size+1, GFP_KERNEL); if (!scon) return length; tcon = kzalloc(size+1, GFP_KERNEL); if (!tcon) goto out; length = -EINVAL; if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) goto out2; length = security_context_to_sid(scon, strlen(scon)+1, &ssid); if (length < 0) goto out2; length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid); if (length < 0) goto out2; length = security_transition_sid(ssid, tsid, tclass, &newsid); if (length < 0) goto out2; length = security_sid_to_context(newsid, &newcon, &len); if (length < 0) goto out2; if (len > SIMPLE_TRANSACTION_LIMIT) { printk(KERN_ERR "%s: context size (%u) exceeds payload " "max\n", __FUNCTION__, len); length = -ERANGE; goto out3; } memcpy(buf, newcon, len); length = len;out3: kfree(newcon);out2: kfree(tcon);out: kfree(scon); return length;}static ssize_t sel_write_relabel(struct file * file, char *buf, size_t size){ char *scon, *tcon; u32 ssid, tsid, newsid; u16 tclass; ssize_t length; char *newcon; u32 len; length = task_has_security(current, SECURITY__COMPUTE_RELABEL); if (length) return length; length = -ENOMEM; scon = kzalloc(size+1, GFP_KERNEL); if (!scon) return length; tcon = kzalloc(size+1, GFP_KERNEL); if (!tcon) goto out; length = -EINVAL; if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) goto out2; length = security_context_to_sid(scon, strlen(scon)+1, &ssid); if (length < 0) goto out2; length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid); if (length < 0) goto out2; length = security_change_sid(ssid, tsid, tclass, &newsid); if (length < 0) goto out2; length = security_sid_to_context(newsid, &newcon, &len); if (length < 0) goto out2; if (len > SIMPLE_TRANSACTION_LIMIT) { length = -ERANGE; goto out3; } memcpy(buf, newcon, len); length = len;out3: kfree(newcon);out2: kfree(tcon);out: kfree(scon); return length;}static ssize_t sel_write_user(struct file * file, char *buf, size_t size){ char *con, *user, *ptr; u32 sid, *sids; ssize_t length; char *newcon; int i, rc; u32 len, nsids; length = task_has_security(current, SECURITY__COMPUTE_USER); if (length) return length; length = -ENOMEM; con = kzalloc(size+1, GFP_KERNEL); if (!con) return length; user = kzalloc(size+1, GFP_KERNEL); if (!user) goto out; length = -EINVAL; if (sscanf(buf, "%s %s", con, user) != 2) goto out2; length = security_context_to_sid(con, strlen(con)+1, &sid); if (length < 0) goto out2; length = security_get_user_sids(sid, user, &sids, &nsids); if (length < 0) goto out2; length = sprintf(buf, "%u", nsids) + 1; ptr = buf + length; for (i = 0; i < nsids; i++) { rc = security_sid_to_context(sids[i], &newcon, &len); if (rc) { length = rc; goto out3; } if ((length + len) >= SIMPLE_TRANSACTION_LIMIT) { kfree(newcon); length = -ERANGE; goto out3; } memcpy(ptr, newcon, len); kfree(newcon); ptr += len; length += len; }out3: kfree(sids);out2: kfree(user);out: kfree(con); return length;}static ssize_t sel_write_member(struct file * file, char *buf, size_t size){ char *scon, *tcon; u32 ssid, tsid, newsid; u16 tclass; ssize_t length; char *newcon; u32 len; length = task_has_security(current, SECURITY__COMPUTE_MEMBER); if (length) return length; length = -ENOMEM; scon = kzalloc(size+1, GFP_KERNEL); if (!scon) return length; tcon = kzalloc(size+1, GFP_KERNEL); if (!tcon) goto out; length = -EINVAL; if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) goto out2; length = security_context_to_sid(scon, strlen(scon)+1, &ssid); if (length < 0) goto out2; length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid); if (length < 0) goto out2; length = security_member_sid(ssid, tsid, tclass, &newsid); if (length < 0) goto out2; length = security_sid_to_context(newsid, &newcon, &len); if (length < 0) goto out2; if (len > SIMPLE_TRANSACTION_LIMIT) { printk(KERN_ERR "%s: context size (%u) exceeds payload " "max\n", __FUNCTION__, len); length = -ERANGE; goto out3; } memcpy(buf, newcon, len); length = len;out3: kfree(newcon);out2: kfree(tcon);out: kfree(scon); return length;}static struct inode *sel_make_inode(struct super_block *sb, int mode){ struct inode *ret = new_inode(sb); if (ret) { ret->i_mode = mode; ret->i_uid = ret->i_gid = 0; ret->i_blocks = 0; ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME; } return ret;}static ssize_t sel_read_bool(struct file *filep, char __user *buf, size_t count, loff_t *ppos){ char *page = NULL; ssize_t length; ssize_t ret; int cur_enforcing; struct inode *inode = filep->f_path.dentry->d_inode; unsigned index = inode->i_ino & SEL_INO_MASK; const char *name = filep->f_path.dentry->d_name.name; mutex_lock(&sel_mutex); if (index >= bool_num || strcmp(name, bool_pending_names[index])) { ret = -EINVAL; goto out; } if (count > PAGE_SIZE) { ret = -EINVAL; goto out; } if (!(page = (char*)get_zeroed_page(GFP_KERNEL))) { ret = -ENOMEM; goto out; } cur_enforcing = security_get_bool_value(index); if (cur_enforcing < 0) { ret = cur_enforcing; goto out; } length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing, bool_pending_values[index]); ret = simple_read_from_buffer(buf, count, ppos, page, length);out: mutex_unlock(&sel_mutex); if (page) free_page((unsigned long)page); return ret;}static ssize_t sel_write_bool(struct file *filep, const char __user *buf, size_t count, loff_t *ppos){ char *page = NULL; ssize_t length; int new_value; struct inode *inode = filep->f_path.dentry->d_inode; unsigned index = inode->i_ino & SEL_INO_MASK; const char *name = filep->f_path.dentry->d_name.name; mutex_lock(&sel_mutex); length = task_has_security(current, SECURITY__SETBOOL); if (length) goto out; if (index >= bool_num || strcmp(name, bool_pending_names[index])) { length = -EINVAL; goto out; } if (count >= PAGE_SIZE) { length = -ENOMEM; goto out; } if (*ppos != 0) { /* No partial writes. */ length = -EINVAL; goto out; } page = (char*)get_zeroed_page(GFP_KERNEL); if (!page) { length = -ENOMEM; goto out; } length = -EFAULT; if (copy_from_user(page, buf, count)) goto out; length = -EINVAL; if (sscanf(page, "%d", &new_value) != 1) goto out; if (new_value) new_value = 1; bool_pending_values[index] = new_value; length = count;out: mutex_unlock(&sel_mutex); if (page) free_page((unsigned long) page); return length;}static const struct file_operations sel_bool_ops = { .read = sel_read_bool, .write = sel_write_bool,};static ssize_t sel_commit_bools_write(struct file *filep, const char __user *buf, size_t count, loff_t *ppos){ char *page = NULL; ssize_t length; int new_value; mutex_lock(&sel_mutex); length = task_has_security(current, SECURITY__SETBOOL); if (length) goto out; if (count >= PAGE_SIZE) { length = -ENOMEM; goto out; } if (*ppos != 0) { /* No partial writes. */ goto out; } page = (char*)get_zeroed_page(GFP_KERNEL); if (!page) { length = -ENOMEM; goto out; } length = -EFAULT; if (copy_from_user(page, buf, count)) goto out; length = -EINVAL; if (sscanf(page, "%d", &new_value) != 1) goto out; if (new_value && bool_pending_values) { security_set_bools(bool_num, bool_pending_values); } length = count;out: mutex_unlock(&sel_mutex); if (page) free_page((unsigned long) page); return length;}static const struct file_operations sel_commit_bools_ops = { .write = sel_commit_bools_write,};static void sel_remove_entries(struct dentry *de){ struct list_head *node; spin_lock(&dcache_lock); node = de->d_subdirs.next; while (node != &de->d_subdirs) { struct dentry *d = list_entry(node, struct dentry, d_u.d_child); list_del_init(node); if (d->d_inode) { d = dget_locked(d); spin_unlock(&dcache_lock); d_delete(d); simple_unlink(de->d_inode, d); dput(d); spin_lock(&dcache_lock); } node = de->d_subdirs.next; } spin_unlock(&dcache_lock);}#define BOOL_DIR_NAME "booleans"static int sel_make_bools(void){ int i, ret = 0; ssize_t len; struct dentry *dentry = NULL; struct dentry *dir = bool_dir; struct inode *inode = NULL; struct inode_security_struct *isec; char **names = NULL, *page; int num; int *values = NULL; u32 sid; /* remove any existing files */ kfree(bool_pending_names); kfree(bool_pending_values); bool_pending_names = NULL; bool_pending_values = NULL; sel_remove_entries(dir); if (!(page = (char*)get_zeroed_page(GFP_KERNEL))) return -ENOMEM; ret = security_get_bools(&num, &names, &values); if (ret != 0) goto out; for (i = 0; i < num; i++) { dentry = d_alloc_name(dir, names[i]); if (!dentry) { ret = -ENOMEM; goto err; } inode = sel_make_inode(dir->d_sb, S_IFREG | S_IRUGO | S_IWUSR); if (!inode) { ret = -ENOMEM; goto err; } len = snprintf(page, PAGE_SIZE, "/%s/%s", BOOL_DIR_NAME, names[i]); if (len < 0) { ret = -EINVAL; goto err; } else if (len >= PAGE_SIZE) { ret = -ENAMETOOLONG; goto err; } isec = (struct inode_security_struct*)inode->i_security; if ((ret = security_genfs_sid("selinuxfs", page, SECCLASS_FILE, &sid))) goto err; isec->sid = sid; isec->initialized = 1; inode->i_fop = &sel_bool_ops; inode->i_ino = i|SEL_BOOL_INO_OFFSET; d_add(dentry, inode); } bool_num = num; bool_pending_names = names; bool_pending_values = values;out: free_page((unsigned long)page); return ret;err: if (names) { for (i = 0; i < num; i++) kfree(names[i]); kfree(names); } kfree(values); sel_remove_entries(dir); ret = -ENOMEM; goto out;}#define NULL_FILE_NAME "null"struct dentry *selinux_null = NULL;static ssize_t sel_read_avc_cache_threshold(struct file *filp, char __user *buf, size_t count, loff_t *ppos){ char tmpbuf[TMPBUFLEN]; ssize_t length; length = scnprintf(tmpbuf, TMPBUFLEN, "%u", avc_cache_threshold); return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);}static ssize_t sel_write_avc_cache_threshold(struct file * file, const char __user * buf, size_t count, loff_t *ppos){ char *page; ssize_t ret; int new_value; if (count >= PAGE_SIZE) { ret = -ENOMEM; goto out; } if (*ppos != 0) { /* No partial writes. */ ret = -EINVAL; goto out; } page = (char*)get_zeroed_page(GFP_KERNEL); if (!page) { ret = -ENOMEM; goto out; } if (copy_from_user(page, buf, count)) { ret = -EFAULT; goto out_free; } if (sscanf(page, "%u", &new_value) != 1) { ret = -EINVAL; goto out; } if (new_value != avc_cache_threshold) { ret = task_has_security(current, SECURITY__SETSECPARAM); if (ret) goto out_free; avc_cache_threshold = new_value; } ret = count;out_free: free_page((unsigned long)page);out: return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -