📄 selinuxfs.c
字号:
static ssize_t sel_read_avc_hash_stats(struct file *filp, char __user *buf, size_t count, loff_t *ppos){ char *page; ssize_t ret = 0; page = (char *)__get_free_page(GFP_KERNEL); if (!page) { ret = -ENOMEM; goto out; } ret = avc_get_hash_stats(page); if (ret >= 0) ret = simple_read_from_buffer(buf, count, ppos, page, ret); free_page((unsigned long)page);out: return ret;}static const struct file_operations sel_avc_cache_threshold_ops = { .read = sel_read_avc_cache_threshold, .write = sel_write_avc_cache_threshold,};static const struct file_operations sel_avc_hash_stats_ops = { .read = sel_read_avc_hash_stats,};#ifdef CONFIG_SECURITY_SELINUX_AVC_STATSstatic struct avc_cache_stats *sel_avc_get_stat_idx(loff_t *idx){ int cpu; for (cpu = *idx; cpu < NR_CPUS; ++cpu) { if (!cpu_possible(cpu)) continue; *idx = cpu + 1; return &per_cpu(avc_cache_stats, cpu); } return NULL;}static void *sel_avc_stats_seq_start(struct seq_file *seq, loff_t *pos){ loff_t n = *pos - 1; if (*pos == 0) return SEQ_START_TOKEN; return sel_avc_get_stat_idx(&n);}static void *sel_avc_stats_seq_next(struct seq_file *seq, void *v, loff_t *pos){ return sel_avc_get_stat_idx(pos);}static int sel_avc_stats_seq_show(struct seq_file *seq, void *v){ struct avc_cache_stats *st = v; if (v == SEQ_START_TOKEN) seq_printf(seq, "lookups hits misses allocations reclaims " "frees\n"); else seq_printf(seq, "%u %u %u %u %u %u\n", st->lookups, st->hits, st->misses, st->allocations, st->reclaims, st->frees); return 0;}static void sel_avc_stats_seq_stop(struct seq_file *seq, void *v){ }static struct seq_operations sel_avc_cache_stats_seq_ops = { .start = sel_avc_stats_seq_start, .next = sel_avc_stats_seq_next, .show = sel_avc_stats_seq_show, .stop = sel_avc_stats_seq_stop,};static int sel_open_avc_cache_stats(struct inode *inode, struct file *file){ return seq_open(file, &sel_avc_cache_stats_seq_ops);}static const struct file_operations sel_avc_cache_stats_ops = { .open = sel_open_avc_cache_stats, .read = seq_read, .llseek = seq_lseek, .release = seq_release,};#endifstatic int sel_make_avc_files(struct dentry *dir){ int i, ret = 0; static struct tree_descr files[] = { { "cache_threshold", &sel_avc_cache_threshold_ops, S_IRUGO|S_IWUSR }, { "hash_stats", &sel_avc_hash_stats_ops, S_IRUGO },#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS { "cache_stats", &sel_avc_cache_stats_ops, S_IRUGO },#endif }; for (i = 0; i < ARRAY_SIZE(files); i++) { struct inode *inode; struct dentry *dentry; dentry = d_alloc_name(dir, files[i].name); if (!dentry) { ret = -ENOMEM; goto out; } inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode); if (!inode) { ret = -ENOMEM; goto out; } inode->i_fop = files[i].ops; inode->i_ino = ++sel_last_ino; d_add(dentry, inode); }out: return ret;}static ssize_t sel_read_initcon(struct file * file, char __user *buf, size_t count, loff_t *ppos){ struct inode *inode; char *con; u32 sid, len; ssize_t ret; inode = file->f_path.dentry->d_inode; sid = inode->i_ino&SEL_INO_MASK; ret = security_sid_to_context(sid, &con, &len); if (ret < 0) return ret; ret = simple_read_from_buffer(buf, count, ppos, con, len); kfree(con); return ret;}static const struct file_operations sel_initcon_ops = { .read = sel_read_initcon,};static int sel_make_initcon_files(struct dentry *dir){ int i, ret = 0; for (i = 1; i <= SECINITSID_NUM; i++) { struct inode *inode; struct dentry *dentry; dentry = d_alloc_name(dir, security_get_initial_sid_context(i)); if (!dentry) { ret = -ENOMEM; goto out; } inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO); if (!inode) { ret = -ENOMEM; goto out; } inode->i_fop = &sel_initcon_ops; inode->i_ino = i|SEL_INITCON_INO_OFFSET; d_add(dentry, inode); }out: return ret;}static inline unsigned int sel_div(unsigned long a, unsigned long b){ return a / b - (a % b < 0);}static inline unsigned long sel_class_to_ino(u16 class){ return (class * (SEL_VEC_MAX + 1)) | SEL_CLASS_INO_OFFSET;}static inline u16 sel_ino_to_class(unsigned long ino){ return sel_div(ino & SEL_INO_MASK, SEL_VEC_MAX + 1);}static inline unsigned long sel_perm_to_ino(u16 class, u32 perm){ return (class * (SEL_VEC_MAX + 1) + perm) | SEL_CLASS_INO_OFFSET;}static inline u32 sel_ino_to_perm(unsigned long ino){ return (ino & SEL_INO_MASK) % (SEL_VEC_MAX + 1);}static ssize_t sel_read_class(struct file * file, char __user *buf, size_t count, loff_t *ppos){ ssize_t rc, len; char *page; unsigned long ino = file->f_path.dentry->d_inode->i_ino; page = (char *)__get_free_page(GFP_KERNEL); if (!page) { rc = -ENOMEM; goto out; } len = snprintf(page, PAGE_SIZE, "%d", sel_ino_to_class(ino)); rc = simple_read_from_buffer(buf, count, ppos, page, len); free_page((unsigned long)page);out: return rc;}static const struct file_operations sel_class_ops = { .read = sel_read_class,};static ssize_t sel_read_perm(struct file * file, char __user *buf, size_t count, loff_t *ppos){ ssize_t rc, len; char *page; unsigned long ino = file->f_path.dentry->d_inode->i_ino; page = (char *)__get_free_page(GFP_KERNEL); if (!page) { rc = -ENOMEM; goto out; } len = snprintf(page, PAGE_SIZE,"%d", sel_ino_to_perm(ino)); rc = simple_read_from_buffer(buf, count, ppos, page, len); free_page((unsigned long)page);out: return rc;}static const struct file_operations sel_perm_ops = { .read = sel_read_perm,};static int sel_make_perm_files(char *objclass, int classvalue, struct dentry *dir){ int i, rc = 0, nperms; char **perms; rc = security_get_permissions(objclass, &perms, &nperms); if (rc) goto out; for (i = 0; i < nperms; i++) { struct inode *inode; struct dentry *dentry; dentry = d_alloc_name(dir, perms[i]); if (!dentry) { rc = -ENOMEM; goto out1; } inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO); if (!inode) { rc = -ENOMEM; goto out1; } inode->i_fop = &sel_perm_ops; /* i+1 since perm values are 1-indexed */ inode->i_ino = sel_perm_to_ino(classvalue, i+1); d_add(dentry, inode); }out1: for (i = 0; i < nperms; i++) kfree(perms[i]); kfree(perms);out: return rc;}static int sel_make_class_dir_entries(char *classname, int index, struct dentry *dir){ struct dentry *dentry = NULL; struct inode *inode = NULL; int rc; dentry = d_alloc_name(dir, "index"); if (!dentry) { rc = -ENOMEM; goto out; } inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO); if (!inode) { rc = -ENOMEM; goto out; } inode->i_fop = &sel_class_ops; inode->i_ino = sel_class_to_ino(index); d_add(dentry, inode); dentry = d_alloc_name(dir, "perms"); if (!dentry) { rc = -ENOMEM; goto out; } rc = sel_make_dir(dir->d_inode, dentry, &last_class_ino); if (rc) goto out; rc = sel_make_perm_files(classname, index, dentry);out: return rc;}static void sel_remove_classes(void){ struct list_head *class_node; list_for_each(class_node, &class_dir->d_subdirs) { struct dentry *class_subdir = list_entry(class_node, struct dentry, d_u.d_child); struct list_head *class_subdir_node; list_for_each(class_subdir_node, &class_subdir->d_subdirs) { struct dentry *d = list_entry(class_subdir_node, struct dentry, d_u.d_child); if (d->d_inode) if (d->d_inode->i_mode & S_IFDIR) sel_remove_entries(d); } sel_remove_entries(class_subdir); } sel_remove_entries(class_dir);}static int sel_make_classes(void){ int rc = 0, nclasses, i; char **classes; /* delete any existing entries */ sel_remove_classes(); rc = security_get_classes(&classes, &nclasses); if (rc < 0) goto out; /* +2 since classes are 1-indexed */ last_class_ino = sel_class_to_ino(nclasses+2); for (i = 0; i < nclasses; i++) { struct dentry *class_name_dir; class_name_dir = d_alloc_name(class_dir, classes[i]); if (!class_name_dir) { rc = -ENOMEM; goto out1; } rc = sel_make_dir(class_dir->d_inode, class_name_dir, &last_class_ino); if (rc) goto out1; /* i+1 since class values are 1-indexed */ rc = sel_make_class_dir_entries(classes[i], i+1, class_name_dir); if (rc) goto out1; }out1: for (i = 0; i < nclasses; i++) kfree(classes[i]); kfree(classes);out: return rc;}static int sel_make_dir(struct inode *dir, struct dentry *dentry, unsigned long *ino){ int ret = 0; struct inode *inode; inode = sel_make_inode(dir->i_sb, S_IFDIR | S_IRUGO | S_IXUGO); if (!inode) { ret = -ENOMEM; goto out; } inode->i_op = &simple_dir_inode_operations; inode->i_fop = &simple_dir_operations; inode->i_ino = ++(*ino); /* directory inodes start off with i_nlink == 2 (for "." entry) */ inc_nlink(inode); d_add(dentry, inode); /* bump link count on parent directory, too */ inc_nlink(dir);out: return ret;}static int sel_fill_super(struct super_block * sb, void * data, int silent){ int ret; struct dentry *dentry; struct inode *inode, *root_inode; 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", &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}, [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}, [SEL_MEMBER] = {"member", &transaction_ops, S_IRUGO|S_IWUGO}, [SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR}, [SEL_COMPAT_NET] = {"compat_net", &sel_compat_net_ops, S_IRUGO|S_IWUSR}, [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO}, [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO}, /* last one */ {""} }; ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); if (ret) goto err; root_inode = sb->s_root->d_inode; dentry = d_alloc_name(sb->s_root, BOOL_DIR_NAME); if (!dentry) { ret = -ENOMEM; goto err; } ret = sel_make_dir(root_inode, dentry, &sel_last_ino); if (ret) goto err; bool_dir = dentry; dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME); if (!dentry) { ret = -ENOMEM; goto err; } inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO); if (!inode) { ret = -ENOMEM; goto err; } inode->i_ino = ++sel_last_ino; 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; dentry = d_alloc_name(sb->s_root, "avc"); if (!dentry) { ret = -ENOMEM; goto err; } ret = sel_make_dir(root_inode, dentry, &sel_last_ino); if (ret) goto err; ret = sel_make_avc_files(dentry); if (ret) goto err; dentry = d_alloc_name(sb->s_root, "initial_contexts"); if (!dentry) { ret = -ENOMEM; goto err; } ret = sel_make_dir(root_inode, dentry, &sel_last_ino); if (ret) goto err; ret = sel_make_initcon_files(dentry); if (ret) goto err; dentry = d_alloc_name(sb->s_root, "class"); if (!dentry) { ret = -ENOMEM; goto err; } ret = sel_make_dir(root_inode, dentry, &sel_last_ino); if (ret) goto err; class_dir = dentry;out: return ret;err: printk(KERN_ERR "%s: failed while creating inodes\n", __FUNCTION__); goto out;}static int sel_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt){ return get_sb_single(fs_type, flags, data, sel_fill_super, mnt);}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 + -