diff options
Diffstat (limited to 'security/selinux')
| -rw-r--r-- | security/selinux/selinuxfs.c | 185 |
1 files changed, 78 insertions, 107 deletions
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index d98fbc4d068f..896acad1f5f7 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -76,7 +76,6 @@ struct selinux_fs_info { struct dentry *class_dir; unsigned long last_class_ino; bool policy_opened; - struct dentry *policycap_dir; unsigned long last_ino; struct super_block *sb; }; @@ -118,7 +117,6 @@ static void selinux_fs_info_free(struct super_block *sb) #define BOOL_DIR_NAME "booleans" #define CLASS_DIR_NAME "class" -#define POLICYCAP_DIR_NAME "policy_capabilities" #define TMPBUFLEN 12 static ssize_t sel_read_enforce(struct file *filp, char __user *buf, @@ -1211,6 +1209,26 @@ static struct inode *sel_make_inode(struct super_block *sb, umode_t mode) return ret; } +static struct dentry *sel_attach(struct dentry *parent, const char *name, + struct inode *inode) +{ + struct dentry *dentry = d_alloc_name(parent, name); + if (unlikely(!dentry)) { + iput(inode); + return ERR_PTR(-ENOMEM); + } + d_make_persistent(dentry, inode); + dput(dentry); + return dentry; +} + +static int sel_attach_file(struct dentry *parent, const char *name, + struct inode *inode) +{ + struct dentry *dentry = sel_attach(parent, name, inode); + return PTR_ERR_OR_ZERO(dentry); +} + static ssize_t sel_read_bool(struct file *filep, char __user *buf, size_t count, loff_t *ppos) { @@ -1370,8 +1388,7 @@ static int sel_make_bools(struct selinux_policy *newpolicy, struct dentry *bool_ *bool_num = num; *bool_pending_names = names; - for (i = 0; i < num; i++) { - struct dentry *dentry; + for (i = 0; !ret && i < num; i++) { struct inode *inode; struct inode_security_struct *isec; ssize_t len; @@ -1382,15 +1399,9 @@ static int sel_make_bools(struct selinux_policy *newpolicy, struct dentry *bool_ ret = -ENAMETOOLONG; break; } - dentry = d_alloc_name(bool_dir, names[i]); - if (!dentry) { - ret = -ENOMEM; - break; - } inode = sel_make_inode(bool_dir->d_sb, S_IFREG | S_IRUGO | S_IWUSR); if (!inode) { - dput(dentry); ret = -ENOMEM; break; } @@ -1408,7 +1419,8 @@ static int sel_make_bools(struct selinux_policy *newpolicy, struct dentry *bool_ isec->initialized = LABEL_INITIALIZED; inode->i_fop = &sel_bool_ops; inode->i_ino = i|SEL_BOOL_INO_OFFSET; - d_add(dentry, inode); + + ret = sel_attach_file(bool_dir, names[i], inode); } out: free_page((unsigned long)page); @@ -1593,6 +1605,7 @@ static int sel_make_avc_files(struct dentry *dir) struct super_block *sb = dir->d_sb; struct selinux_fs_info *fsi = sb->s_fs_info; unsigned int i; + int err = 0; static const struct tree_descr files[] = { { "cache_threshold", &sel_avc_cache_threshold_ops, S_IRUGO|S_IWUSR }, @@ -1602,26 +1615,20 @@ static int sel_make_avc_files(struct dentry *dir) #endif }; - for (i = 0; i < ARRAY_SIZE(files); i++) { + for (i = 0; !err && i < ARRAY_SIZE(files); i++) { struct inode *inode; - struct dentry *dentry; - - dentry = d_alloc_name(dir, files[i].name); - if (!dentry) - return -ENOMEM; inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode); - if (!inode) { - dput(dentry); + if (!inode) return -ENOMEM; - } inode->i_fop = files[i].ops; inode->i_ino = ++fsi->last_ino; - d_add(dentry, inode); + + err = sel_attach_file(dir, files[i].name, inode); } - return 0; + return err; } static int sel_make_ss_files(struct dentry *dir) @@ -1629,30 +1636,25 @@ static int sel_make_ss_files(struct dentry *dir) struct super_block *sb = dir->d_sb; struct selinux_fs_info *fsi = sb->s_fs_info; unsigned int i; + int err = 0; static const struct tree_descr files[] = { { "sidtab_hash_stats", &sel_sidtab_hash_stats_ops, S_IRUGO }, }; - for (i = 0; i < ARRAY_SIZE(files); i++) { + for (i = 0; !err && i < ARRAY_SIZE(files); i++) { struct inode *inode; - struct dentry *dentry; - - dentry = d_alloc_name(dir, files[i].name); - if (!dentry) - return -ENOMEM; inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode); - if (!inode) { - dput(dentry); + if (!inode) return -ENOMEM; - } inode->i_fop = files[i].ops; inode->i_ino = ++fsi->last_ino; - d_add(dentry, inode); + + err = sel_attach_file(dir, files[i].name, inode); } - return 0; + return err; } static ssize_t sel_read_initcon(struct file *file, char __user *buf, @@ -1680,30 +1682,25 @@ static const struct file_operations sel_initcon_ops = { static int sel_make_initcon_files(struct dentry *dir) { unsigned int i; + int err = 0; - for (i = 1; i <= SECINITSID_NUM; i++) { - struct inode *inode; - struct dentry *dentry; + for (i = 1; !err && i <= SECINITSID_NUM; i++) { const char *s = security_get_initial_sid_context(i); + struct inode *inode; if (!s) continue; - dentry = d_alloc_name(dir, s); - if (!dentry) - return -ENOMEM; inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO); - if (!inode) { - dput(dentry); + if (!inode) return -ENOMEM; - } inode->i_fop = &sel_initcon_ops; inode->i_ino = i|SEL_INITCON_INO_OFFSET; - d_add(dentry, inode); + err = sel_attach_file(dir, s, inode); } - return 0; + return err; } static inline unsigned long sel_class_to_ino(u16 class) @@ -1785,29 +1782,21 @@ static int sel_make_perm_files(struct selinux_policy *newpolicy, if (rc) return rc; - for (i = 0; i < nperms; i++) { + for (i = 0; !rc && i < nperms; i++) { struct inode *inode; - struct dentry *dentry; - rc = -ENOMEM; - dentry = d_alloc_name(dir, perms[i]); - if (!dentry) - goto out; - - rc = -ENOMEM; inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO); if (!inode) { - dput(dentry); - goto out; + rc = -ENOMEM; + break; } 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); + + rc = sel_attach_file(dir, perms[i], inode); } - rc = 0; -out: for (i = 0; i < nperms; i++) kfree(perms[i]); kfree(perms); @@ -1822,20 +1811,18 @@ static int sel_make_class_dir_entries(struct selinux_policy *newpolicy, struct selinux_fs_info *fsi = sb->s_fs_info; struct dentry *dentry = NULL; struct inode *inode = NULL; - - dentry = d_alloc_name(dir, "index"); - if (!dentry) - return -ENOMEM; + int err; inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO); - if (!inode) { - dput(dentry); + if (!inode) return -ENOMEM; - } inode->i_fop = &sel_class_ops; inode->i_ino = sel_class_to_ino(index); - d_add(dentry, inode); + + err = sel_attach_file(dir, "index", inode); + if (err) + return err; dentry = sel_make_dir(dir, "perms", &fsi->last_class_ino); if (IS_ERR(dentry)) @@ -1883,61 +1870,51 @@ out: return rc; } -static int sel_make_policycap(struct selinux_fs_info *fsi) +static int sel_make_policycap(struct dentry *dir) { + struct super_block *sb = dir->d_sb; unsigned int iter; - struct dentry *dentry = NULL; struct inode *inode = NULL; + int err = 0; + + for (iter = 0; !err && iter <= POLICYDB_CAP_MAX; iter++) { + const char *name; - for (iter = 0; iter <= POLICYDB_CAP_MAX; iter++) { if (iter < ARRAY_SIZE(selinux_policycap_names)) - dentry = d_alloc_name(fsi->policycap_dir, - selinux_policycap_names[iter]); + name = selinux_policycap_names[iter]; else - dentry = d_alloc_name(fsi->policycap_dir, "unknown"); + name = "unknown"; - if (dentry == NULL) + inode = sel_make_inode(sb, S_IFREG | 0444); + if (!inode) return -ENOMEM; - inode = sel_make_inode(fsi->sb, S_IFREG | 0444); - if (inode == NULL) { - dput(dentry); - return -ENOMEM; - } - inode->i_fop = &sel_policycap_ops; inode->i_ino = iter | SEL_POLICYCAP_INO_OFFSET; - d_add(dentry, inode); + err = sel_attach_file(dir, name, inode); } - return 0; + return err; } static struct dentry *sel_make_dir(struct dentry *dir, const char *name, unsigned long *ino) { - struct dentry *dentry = d_alloc_name(dir, name); struct inode *inode; - if (!dentry) - return ERR_PTR(-ENOMEM); - inode = sel_make_inode(dir->d_sb, S_IFDIR | S_IRUGO | S_IXUGO); - if (!inode) { - dput(dentry); + if (!inode) return ERR_PTR(-ENOMEM); - } 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(d_inode(dir)); - return dentry; + return sel_attach(dir, name, inode); } static int reject_all(struct mnt_idmap *idmap, struct inode *inode, int mask) @@ -1970,10 +1947,11 @@ static struct dentry *sel_make_swapover_dir(struct super_block *sb, /* directory inodes start off with i_nlink == 2 (for "." entry) */ inc_nlink(inode); inode_lock(sb->s_root->d_inode); - d_add(dentry, inode); + d_make_persistent(dentry, inode); inc_nlink(sb->s_root->d_inode); inode_unlock(sb->s_root->d_inode); - return dentry; + dput(dentry); + return dentry; // borrowed } #define NULL_FILE_NAME "null" @@ -2026,16 +2004,9 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc) } ret = -ENOMEM; - dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME); - if (!dentry) - goto err; - - ret = -ENOMEM; inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO); - if (!inode) { - dput(dentry); + if (!inode) goto err; - } inode->i_ino = ++fsi->last_ino; isec = selinux_inode(inode); @@ -2044,7 +2015,9 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc) isec->initialized = LABEL_INITIALIZED; init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO, MKDEV(MEM_MAJOR, 3)); - d_add(dentry, inode); + ret = sel_attach_file(sb->s_root, NULL_FILE_NAME, inode); + if (ret) + goto err; dentry = sel_make_dir(sb->s_root, "avc", &fsi->last_ino); if (IS_ERR(dentry)) { @@ -2083,15 +2056,13 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc) goto err; } - fsi->policycap_dir = sel_make_dir(sb->s_root, POLICYCAP_DIR_NAME, - &fsi->last_ino); - if (IS_ERR(fsi->policycap_dir)) { - ret = PTR_ERR(fsi->policycap_dir); - fsi->policycap_dir = NULL; + dentry = sel_make_dir(sb->s_root, "policy_capabilities", &fsi->last_ino); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); goto err; } - ret = sel_make_policycap(fsi); + ret = sel_make_policycap(dentry); if (ret) { pr_err("SELinux: failed to load policy capabilities\n"); goto err; @@ -2123,7 +2094,7 @@ static int sel_init_fs_context(struct fs_context *fc) static void sel_kill_sb(struct super_block *sb) { selinux_fs_info_free(sb); - kill_litter_super(sb); + kill_anon_super(sb); } static struct file_system_type sel_fs_type = { |
