diff options
Diffstat (limited to 'security/selinux/selinuxfs.c')
-rw-r--r-- | security/selinux/selinuxfs.c | 112 |
1 files changed, 50 insertions, 62 deletions
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 5eba6664eac0..a4efc966f065 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/vmalloc.h> | 16 | #include <linux/vmalloc.h> |
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/mutex.h> | ||
18 | #include <linux/init.h> | 19 | #include <linux/init.h> |
19 | #include <linux/string.h> | 20 | #include <linux/string.h> |
20 | #include <linux/security.h> | 21 | #include <linux/security.h> |
@@ -45,7 +46,7 @@ static int __init checkreqprot_setup(char *str) | |||
45 | __setup("checkreqprot=", checkreqprot_setup); | 46 | __setup("checkreqprot=", checkreqprot_setup); |
46 | 47 | ||
47 | 48 | ||
48 | static DECLARE_MUTEX(sel_sem); | 49 | static DEFINE_MUTEX(sel_mutex); |
49 | 50 | ||
50 | /* global data for booleans */ | 51 | /* global data for booleans */ |
51 | static struct dentry *bool_dir = NULL; | 52 | static struct dentry *bool_dir = NULL; |
@@ -238,7 +239,7 @@ static ssize_t sel_write_load(struct file * file, const char __user * buf, | |||
238 | ssize_t length; | 239 | ssize_t length; |
239 | void *data = NULL; | 240 | void *data = NULL; |
240 | 241 | ||
241 | down(&sel_sem); | 242 | mutex_lock(&sel_mutex); |
242 | 243 | ||
243 | length = task_has_security(current, SECURITY__LOAD_POLICY); | 244 | length = task_has_security(current, SECURITY__LOAD_POLICY); |
244 | if (length) | 245 | if (length) |
@@ -273,7 +274,7 @@ static ssize_t sel_write_load(struct file * file, const char __user * buf, | |||
273 | "policy loaded auid=%u", | 274 | "policy loaded auid=%u", |
274 | audit_get_loginuid(current->audit_context)); | 275 | audit_get_loginuid(current->audit_context)); |
275 | out: | 276 | out: |
276 | up(&sel_sem); | 277 | mutex_unlock(&sel_mutex); |
277 | vfree(data); | 278 | vfree(data); |
278 | return length; | 279 | return length; |
279 | } | 280 | } |
@@ -720,12 +721,11 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, | |||
720 | { | 721 | { |
721 | char *page = NULL; | 722 | char *page = NULL; |
722 | ssize_t length; | 723 | ssize_t length; |
723 | ssize_t end; | ||
724 | ssize_t ret; | 724 | ssize_t ret; |
725 | int cur_enforcing; | 725 | int cur_enforcing; |
726 | struct inode *inode; | 726 | struct inode *inode; |
727 | 727 | ||
728 | down(&sel_sem); | 728 | mutex_lock(&sel_mutex); |
729 | 729 | ||
730 | ret = -EFAULT; | 730 | ret = -EFAULT; |
731 | 731 | ||
@@ -751,26 +751,9 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, | |||
751 | 751 | ||
752 | length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing, | 752 | length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing, |
753 | bool_pending_values[inode->i_ino - BOOL_INO_OFFSET]); | 753 | bool_pending_values[inode->i_ino - BOOL_INO_OFFSET]); |
754 | if (length < 0) { | 754 | ret = simple_read_from_buffer(buf, count, ppos, page, length); |
755 | ret = length; | ||
756 | goto out; | ||
757 | } | ||
758 | |||
759 | if (*ppos >= length) { | ||
760 | ret = 0; | ||
761 | goto out; | ||
762 | } | ||
763 | if (count + *ppos > length) | ||
764 | count = length - *ppos; | ||
765 | end = count + *ppos; | ||
766 | if (copy_to_user(buf, (char *) page + *ppos, count)) { | ||
767 | ret = -EFAULT; | ||
768 | goto out; | ||
769 | } | ||
770 | *ppos = end; | ||
771 | ret = count; | ||
772 | out: | 755 | out: |
773 | up(&sel_sem); | 756 | mutex_unlock(&sel_mutex); |
774 | if (page) | 757 | if (page) |
775 | free_page((unsigned long)page); | 758 | free_page((unsigned long)page); |
776 | return ret; | 759 | return ret; |
@@ -784,7 +767,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, | |||
784 | int new_value; | 767 | int new_value; |
785 | struct inode *inode; | 768 | struct inode *inode; |
786 | 769 | ||
787 | down(&sel_sem); | 770 | mutex_lock(&sel_mutex); |
788 | 771 | ||
789 | length = task_has_security(current, SECURITY__SETBOOL); | 772 | length = task_has_security(current, SECURITY__SETBOOL); |
790 | if (length) | 773 | if (length) |
@@ -823,7 +806,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, | |||
823 | length = count; | 806 | length = count; |
824 | 807 | ||
825 | out: | 808 | out: |
826 | up(&sel_sem); | 809 | mutex_unlock(&sel_mutex); |
827 | if (page) | 810 | if (page) |
828 | free_page((unsigned long) page); | 811 | free_page((unsigned long) page); |
829 | return length; | 812 | return length; |
@@ -842,7 +825,7 @@ static ssize_t sel_commit_bools_write(struct file *filep, | |||
842 | ssize_t length = -EFAULT; | 825 | ssize_t length = -EFAULT; |
843 | int new_value; | 826 | int new_value; |
844 | 827 | ||
845 | down(&sel_sem); | 828 | mutex_lock(&sel_mutex); |
846 | 829 | ||
847 | length = task_has_security(current, SECURITY__SETBOOL); | 830 | length = task_has_security(current, SECURITY__SETBOOL); |
848 | if (length) | 831 | if (length) |
@@ -880,7 +863,7 @@ static ssize_t sel_commit_bools_write(struct file *filep, | |||
880 | length = count; | 863 | length = count; |
881 | 864 | ||
882 | out: | 865 | out: |
883 | up(&sel_sem); | 866 | mutex_unlock(&sel_mutex); |
884 | if (page) | 867 | if (page) |
885 | free_page((unsigned long) page); | 868 | free_page((unsigned long) page); |
886 | return length; | 869 | return length; |
@@ -998,7 +981,7 @@ out: | |||
998 | return ret; | 981 | return ret; |
999 | err: | 982 | err: |
1000 | kfree(values); | 983 | kfree(values); |
1001 | d_genocide(dir); | 984 | sel_remove_bools(dir); |
1002 | ret = -ENOMEM; | 985 | ret = -ENOMEM; |
1003 | goto out; | 986 | goto out; |
1004 | } | 987 | } |
@@ -1179,37 +1162,38 @@ static int sel_make_avc_files(struct dentry *dir) | |||
1179 | dentry = d_alloc_name(dir, files[i].name); | 1162 | dentry = d_alloc_name(dir, files[i].name); |
1180 | if (!dentry) { | 1163 | if (!dentry) { |
1181 | ret = -ENOMEM; | 1164 | ret = -ENOMEM; |
1182 | goto err; | 1165 | goto out; |
1183 | } | 1166 | } |
1184 | 1167 | ||
1185 | inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode); | 1168 | inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode); |
1186 | if (!inode) { | 1169 | if (!inode) { |
1187 | ret = -ENOMEM; | 1170 | ret = -ENOMEM; |
1188 | goto err; | 1171 | goto out; |
1189 | } | 1172 | } |
1190 | inode->i_fop = files[i].ops; | 1173 | inode->i_fop = files[i].ops; |
1191 | d_add(dentry, inode); | 1174 | d_add(dentry, inode); |
1192 | } | 1175 | } |
1193 | out: | 1176 | out: |
1194 | return ret; | 1177 | return ret; |
1195 | err: | ||
1196 | d_genocide(dir); | ||
1197 | goto out; | ||
1198 | } | 1178 | } |
1199 | 1179 | ||
1200 | static int sel_make_dir(struct super_block *sb, struct dentry *dentry) | 1180 | static int sel_make_dir(struct inode *dir, struct dentry *dentry) |
1201 | { | 1181 | { |
1202 | int ret = 0; | 1182 | int ret = 0; |
1203 | struct inode *inode; | 1183 | struct inode *inode; |
1204 | 1184 | ||
1205 | inode = sel_make_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO); | 1185 | inode = sel_make_inode(dir->i_sb, S_IFDIR | S_IRUGO | S_IXUGO); |
1206 | if (!inode) { | 1186 | if (!inode) { |
1207 | ret = -ENOMEM; | 1187 | ret = -ENOMEM; |
1208 | goto out; | 1188 | goto out; |
1209 | } | 1189 | } |
1210 | inode->i_op = &simple_dir_inode_operations; | 1190 | inode->i_op = &simple_dir_inode_operations; |
1211 | inode->i_fop = &simple_dir_operations; | 1191 | inode->i_fop = &simple_dir_operations; |
1192 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ | ||
1193 | inode->i_nlink++; | ||
1212 | d_add(dentry, inode); | 1194 | d_add(dentry, inode); |
1195 | /* bump link count on parent directory, too */ | ||
1196 | dir->i_nlink++; | ||
1213 | out: | 1197 | out: |
1214 | return ret; | 1198 | return ret; |
1215 | } | 1199 | } |
@@ -1218,7 +1202,7 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent) | |||
1218 | { | 1202 | { |
1219 | int ret; | 1203 | int ret; |
1220 | struct dentry *dentry; | 1204 | struct dentry *dentry; |
1221 | struct inode *inode; | 1205 | struct inode *inode, *root_inode; |
1222 | struct inode_security_struct *isec; | 1206 | struct inode_security_struct *isec; |
1223 | 1207 | ||
1224 | static struct tree_descr selinux_files[] = { | 1208 | static struct tree_descr selinux_files[] = { |
@@ -1239,30 +1223,33 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent) | |||
1239 | }; | 1223 | }; |
1240 | ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); | 1224 | ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); |
1241 | if (ret) | 1225 | if (ret) |
1242 | return ret; | 1226 | goto err; |
1227 | |||
1228 | root_inode = sb->s_root->d_inode; | ||
1243 | 1229 | ||
1244 | dentry = d_alloc_name(sb->s_root, BOOL_DIR_NAME); | 1230 | dentry = d_alloc_name(sb->s_root, BOOL_DIR_NAME); |
1245 | if (!dentry) | 1231 | if (!dentry) { |
1246 | return -ENOMEM; | 1232 | ret = -ENOMEM; |
1233 | goto err; | ||
1234 | } | ||
1247 | 1235 | ||
1248 | inode = sel_make_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO); | 1236 | ret = sel_make_dir(root_inode, dentry); |
1249 | if (!inode) | ||
1250 | goto out; | ||
1251 | inode->i_op = &simple_dir_inode_operations; | ||
1252 | inode->i_fop = &simple_dir_operations; | ||
1253 | d_add(dentry, inode); | ||
1254 | bool_dir = dentry; | ||
1255 | ret = sel_make_bools(); | ||
1256 | if (ret) | 1237 | if (ret) |
1257 | goto out; | 1238 | goto err; |
1239 | |||
1240 | bool_dir = dentry; | ||
1258 | 1241 | ||
1259 | dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME); | 1242 | dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME); |
1260 | if (!dentry) | 1243 | if (!dentry) { |
1261 | return -ENOMEM; | 1244 | ret = -ENOMEM; |
1245 | goto err; | ||
1246 | } | ||
1262 | 1247 | ||
1263 | inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO); | 1248 | inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO); |
1264 | if (!inode) | 1249 | if (!inode) { |
1265 | goto out; | 1250 | ret = -ENOMEM; |
1251 | goto err; | ||
1252 | } | ||
1266 | isec = (struct inode_security_struct*)inode->i_security; | 1253 | isec = (struct inode_security_struct*)inode->i_security; |
1267 | isec->sid = SECINITSID_DEVNULL; | 1254 | isec->sid = SECINITSID_DEVNULL; |
1268 | isec->sclass = SECCLASS_CHR_FILE; | 1255 | isec->sclass = SECCLASS_CHR_FILE; |
@@ -1273,22 +1260,23 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent) | |||
1273 | selinux_null = dentry; | 1260 | selinux_null = dentry; |
1274 | 1261 | ||
1275 | dentry = d_alloc_name(sb->s_root, "avc"); | 1262 | dentry = d_alloc_name(sb->s_root, "avc"); |
1276 | if (!dentry) | 1263 | if (!dentry) { |
1277 | return -ENOMEM; | 1264 | ret = -ENOMEM; |
1265 | goto err; | ||
1266 | } | ||
1278 | 1267 | ||
1279 | ret = sel_make_dir(sb, dentry); | 1268 | ret = sel_make_dir(root_inode, dentry); |
1280 | if (ret) | 1269 | if (ret) |
1281 | goto out; | 1270 | goto err; |
1282 | 1271 | ||
1283 | ret = sel_make_avc_files(dentry); | 1272 | ret = sel_make_avc_files(dentry); |
1284 | if (ret) | 1273 | if (ret) |
1285 | goto out; | 1274 | goto err; |
1286 | |||
1287 | return 0; | ||
1288 | out: | 1275 | out: |
1289 | dput(dentry); | 1276 | return ret; |
1277 | err: | ||
1290 | printk(KERN_ERR "%s: failed while creating inodes\n", __FUNCTION__); | 1278 | printk(KERN_ERR "%s: failed while creating inodes\n", __FUNCTION__); |
1291 | return -ENOMEM; | 1279 | goto out; |
1292 | } | 1280 | } |
1293 | 1281 | ||
1294 | static struct super_block *sel_get_sb(struct file_system_type *fs_type, | 1282 | static struct super_block *sel_get_sb(struct file_system_type *fs_type, |