📄 selinuxfs.c
字号:
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 = kmalloc(size+1, GFP_KERNEL); if (!con) return length; memset(con, 0, size+1); user = kmalloc(size+1, GFP_KERNEL); if (!user) goto out; memset(user, 0, size+1); 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 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_blksize = PAGE_CACHE_SIZE; ret->i_blocks = 0; ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME; } return ret;}#define BOOL_INO_OFFSET 30static 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 end; ssize_t ret; int cur_enforcing; struct inode *inode; down(&sel_sem); ret = -EFAULT; /* check to see if this file has been deleted */ if (!filep->f_op) goto out; if (count < 0 || count > PAGE_SIZE) { ret = -EINVAL; goto out; } if (!(page = (char*)get_zeroed_page(GFP_KERNEL))) { ret = -ENOMEM; goto out; } inode = filep->f_dentry->d_inode; cur_enforcing = security_get_bool_value(inode->i_ino - BOOL_INO_OFFSET); if (cur_enforcing < 0) { ret = cur_enforcing; goto out; } length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing, bool_pending_values[inode->i_ino - BOOL_INO_OFFSET]); if (length < 0) { ret = length; goto out; } if (*ppos >= length) { ret = 0; goto out; } if (count + *ppos > length) count = length - *ppos; end = count + *ppos; if (copy_to_user(buf, (char *) page + *ppos, count)) { ret = -EFAULT; goto out; } *ppos = end; ret = count;out: up(&sel_sem); 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 = -EFAULT; int new_value; struct inode *inode; down(&sel_sem); length = task_has_security(current, SECURITY__SETBOOL); if (length) goto out; /* check to see if this file has been deleted */ if (!filep->f_op) goto out; if (count < 0 || 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; } 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; inode = filep->f_dentry->d_inode; bool_pending_values[inode->i_ino - BOOL_INO_OFFSET] = new_value; length = count;out: up(&sel_sem); if (page) free_page((unsigned long) page); return length;}static 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 = -EFAULT; int new_value; down(&sel_sem); length = task_has_security(current, SECURITY__SETBOOL); if (length) goto out; /* check to see if this file has been deleted */ if (!filep->f_op) goto out; if (count < 0 || 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; } if (copy_from_user(page, buf, count)) goto out; length = -EINVAL; if (sscanf(page, "%d", &new_value) != 1) goto out; if (new_value) { security_set_bools(bool_num, bool_pending_values); } length = count;out: up(&sel_sem); if (page) free_page((unsigned long) page); return length;}static struct file_operations sel_commit_bools_ops = { .write = sel_commit_bools_write,};/* delete booleans - partial revoke() from * fs/proc/generic.c proc_kill_inodes */static void sel_remove_bools(struct dentry *de){ struct list_head *p, *node; struct super_block *sb = de->d_sb; spin_lock(&dcache_lock); node = de->d_subdirs.next; while (node != &de->d_subdirs) { struct dentry *d = list_entry(node, struct dentry, 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); file_list_lock(); list_for_each(p, &sb->s_files) { struct file * filp = list_entry(p, struct file, f_list); struct dentry * dentry = filp->f_dentry; if (dentry->d_parent != de) { continue; } filp->f_op = NULL; } file_list_unlock();}#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; struct qstr qname; char **names = NULL, *page; int num; int *values = NULL; u32 sid; /* remove any existing files */ if (bool_pending_values) kfree(bool_pending_values); sel_remove_bools(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++) { qname.name = names[i]; qname.len = strlen(qname.name); qname.hash = full_name_hash(qname.name, qname.len); dentry = d_alloc(dir, &qname); 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 + BOOL_INO_OFFSET; d_add(dentry, inode); } bool_num = num; bool_pending_values = values;out: free_page((unsigned long)page); if (names) { for (i = 0; i < num; i++) { if (names[i]) kfree(names[i]); } kfree(names); } return ret;err: d_genocide(dir); ret = -ENOMEM; goto out;}#define NULL_FILE_NAME "null"struct dentry *selinux_null = NULL;static int sel_fill_super(struct super_block * sb, void * data, int silent){ int ret; struct dentry *dentry; struct inode *inode; struct qstr qname; struct inode_security_struct *isec; 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_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}, [SEL_USER] = {"user", &transaction_ops, S_IRUGO|S_IWUGO}, [SEL_POLICYVERS] = {"policyvers", &sel_policyvers_ops, S_IRUGO}, [SEL_COMMIT_BOOLS] = {"commit_pending_bools", &sel_commit_bools_ops, S_IWUSR}, [SEL_MLS] = {"mls", &sel_mls_ops, S_IRUGO}, [SEL_DISABLE] = {"disable", &sel_disable_ops, S_IWUSR}, /* last one */ {""} }; ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); if (ret) return ret; qname.name = BOOL_DIR_NAME; qname.len = strlen(qname.name); qname.hash = full_name_hash(qname.name, qname.len); dentry = d_alloc(sb->s_root, &qname); if (!dentry) return -ENOMEM; inode = sel_make_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO); if (!inode) goto out; inode->i_op = &simple_dir_inode_operations; inode->i_fop = &simple_dir_operations; d_add(dentry, inode); bool_dir = dentry; ret = sel_make_bools(); if (ret) goto out; qname.name = NULL_FILE_NAME; qname.len = strlen(qname.name); qname.hash = full_name_hash(qname.name, qname.len); dentry = d_alloc(sb->s_root, &qname); if (!dentry) return -ENOMEM; inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO); if (!inode) goto out; isec = (struct inode_security_struct*)inode->i_security; isec->sid = SECINITSID_DEVNULL; isec->sclass = SECCLASS_CHR_FILE; isec->initialized = 1; init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO, MKDEV(MEM_MAJOR, 3)); d_add(dentry, inode); selinux_null = dentry; return 0;out: dput(dentry); printk(KERN_ERR "%s: failed while creating inodes\n", __FUNCTION__); return -ENOMEM;}static struct super_block *sel_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data){ return get_sb_single(fs_type, flags, data, sel_fill_super);}static struct file_system_type sel_fs_type = { .name = "selinuxfs", .get_sb = sel_get_sb, .kill_sb = kill_litter_super,};struct vfsmount *selinuxfs_mount;static int __init init_sel_fs(void){ int err; if (!selinux_enabled) return 0; err = register_filesystem(&sel_fs_type); if (!err) { selinuxfs_mount = kern_mount(&sel_fs_type); if (IS_ERR(selinuxfs_mount)) { printk(KERN_ERR "selinuxfs: could not mount!\n"); err = PTR_ERR(selinuxfs_mount); selinuxfs_mount = NULL; } } return err;}__initcall(init_sel_fs);#ifdef CONFIG_SECURITY_SELINUX_DISABLEvoid exit_sel_fs(void){ unregister_filesystem(&sel_fs_type);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -