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 b5fa02d17b1e..f5d78365488f 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> |
@@ -44,7 +45,7 @@ static int __init checkreqprot_setup(char *str) | |||
44 | __setup("checkreqprot=", checkreqprot_setup); | 45 | __setup("checkreqprot=", checkreqprot_setup); |
45 | 46 | ||
46 | 47 | ||
47 | static DECLARE_MUTEX(sel_sem); | 48 | static DEFINE_MUTEX(sel_mutex); |
48 | 49 | ||
49 | /* global data for booleans */ | 50 | /* global data for booleans */ |
50 | static struct dentry *bool_dir = NULL; | 51 | static struct dentry *bool_dir = NULL; |
@@ -230,7 +231,7 @@ static ssize_t sel_write_load(struct file * file, const char __user * buf, | |||
230 | ssize_t length; | 231 | ssize_t length; |
231 | void *data = NULL; | 232 | void *data = NULL; |
232 | 233 | ||
233 | down(&sel_sem); | 234 | mutex_lock(&sel_mutex); |
234 | 235 | ||
235 | length = task_has_security(current, SECURITY__LOAD_POLICY); | 236 | length = task_has_security(current, SECURITY__LOAD_POLICY); |
236 | if (length) | 237 | if (length) |
@@ -262,7 +263,7 @@ static ssize_t sel_write_load(struct file * file, const char __user * buf, | |||
262 | else | 263 | else |
263 | length = count; | 264 | length = count; |
264 | out: | 265 | out: |
265 | up(&sel_sem); | 266 | mutex_unlock(&sel_mutex); |
266 | vfree(data); | 267 | vfree(data); |
267 | return length; | 268 | return length; |
268 | } | 269 | } |
@@ -709,12 +710,11 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, | |||
709 | { | 710 | { |
710 | char *page = NULL; | 711 | char *page = NULL; |
711 | ssize_t length; | 712 | ssize_t length; |
712 | ssize_t end; | ||
713 | ssize_t ret; | 713 | ssize_t ret; |
714 | int cur_enforcing; | 714 | int cur_enforcing; |
715 | struct inode *inode; | 715 | struct inode *inode; |
716 | 716 | ||
717 | down(&sel_sem); | 717 | mutex_lock(&sel_mutex); |
718 | 718 | ||
719 | ret = -EFAULT; | 719 | ret = -EFAULT; |
720 | 720 | ||
@@ -740,26 +740,9 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, | |||
740 | 740 | ||
741 | length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing, | 741 | length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing, |
742 | bool_pending_values[inode->i_ino - BOOL_INO_OFFSET]); | 742 | bool_pending_values[inode->i_ino - BOOL_INO_OFFSET]); |
743 | if (length < 0) { | 743 | ret = simple_read_from_buffer(buf, count, ppos, page, length); |
744 | ret = length; | ||
745 | goto out; | ||
746 | } | ||
747 | |||
748 | if (*ppos >= length) { | ||
749 | ret = 0; | ||
750 | goto out; | ||
751 | } | ||
752 | if (count + *ppos > length) | ||
753 | count = length - *ppos; | ||
754 | end = count + *ppos; | ||
755 | if (copy_to_user(buf, (char *) page + *ppos, count)) { | ||
756 | ret = -EFAULT; | ||
757 | goto out; | ||
758 | } | ||
759 | *ppos = end; | ||
760 | ret = count; | ||
761 | out: | 744 | out: |
762 | up(&sel_sem); | 745 | mutex_unlock(&sel_mutex); |
763 | if (page) | 746 | if (page) |
764 | free_page((unsigned long)page); | 747 | free_page((unsigned long)page); |
765 | return ret; | 748 | return ret; |
@@ -773,7 +756,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, | |||
773 | int new_value; | 756 | int new_value; |
774 | struct inode *inode; | 757 | struct inode *inode; |
775 | 758 | ||
776 | down(&sel_sem); | 759 | mutex_lock(&sel_mutex); |
777 | 760 | ||
778 | length = task_has_security(current, SECURITY__SETBOOL); | 761 | length = task_has_security(current, SECURITY__SETBOOL); |
779 | if (length) | 762 | if (length) |
@@ -812,7 +795,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, | |||
812 | length = count; | 795 | length = count; |
813 | 796 | ||
814 | out: | 797 | out: |
815 | up(&sel_sem); | 798 | mutex_unlock(&sel_mutex); |
816 | if (page) | 799 | if (page) |
817 | free_page((unsigned long) page); | 800 | free_page((unsigned long) page); |
818 | return length; | 801 | return length; |
@@ -831,7 +814,7 @@ static ssize_t sel_commit_bools_write(struct file *filep, | |||
831 | ssize_t length = -EFAULT; | 814 | ssize_t length = -EFAULT; |
832 | int new_value; | 815 | int new_value; |
833 | 816 | ||
834 | down(&sel_sem); | 817 | mutex_lock(&sel_mutex); |
835 | 818 | ||
836 | length = task_has_security(current, SECURITY__SETBOOL); | 819 | length = task_has_security(current, SECURITY__SETBOOL); |
837 | if (length) | 820 | if (length) |
@@ -869,7 +852,7 @@ static ssize_t sel_commit_bools_write(struct file *filep, | |||
869 | length = count; | 852 | length = count; |
870 | 853 | ||
871 | out: | 854 | out: |
872 | up(&sel_sem); | 855 | mutex_unlock(&sel_mutex); |
873 | if (page) | 856 | if (page) |
874 | free_page((unsigned long) page); | 857 | free_page((unsigned long) page); |
875 | return length; | 858 | return length; |
@@ -987,7 +970,7 @@ out: | |||
987 | return ret; | 970 | return ret; |
988 | err: | 971 | err: |
989 | kfree(values); | 972 | kfree(values); |
990 | d_genocide(dir); | 973 | sel_remove_bools(dir); |
991 | ret = -ENOMEM; | 974 | ret = -ENOMEM; |
992 | goto out; | 975 | goto out; |
993 | } | 976 | } |
@@ -1168,37 +1151,38 @@ static int sel_make_avc_files(struct dentry *dir) | |||
1168 | dentry = d_alloc_name(dir, files[i].name); | 1151 | dentry = d_alloc_name(dir, files[i].name); |
1169 | if (!dentry) { | 1152 | if (!dentry) { |
1170 | ret = -ENOMEM; | 1153 | ret = -ENOMEM; |
1171 | goto err; | 1154 | goto out; |
1172 | } | 1155 | } |
1173 | 1156 | ||
1174 | inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode); | 1157 | inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode); |
1175 | if (!inode) { | 1158 | if (!inode) { |
1176 | ret = -ENOMEM; | 1159 | ret = -ENOMEM; |
1177 | goto err; | 1160 | goto out; |
1178 | } | 1161 | } |
1179 | inode->i_fop = files[i].ops; | 1162 | inode->i_fop = files[i].ops; |
1180 | d_add(dentry, inode); | 1163 | d_add(dentry, inode); |
1181 | } | 1164 | } |
1182 | out: | 1165 | out: |
1183 | return ret; | 1166 | return ret; |
1184 | err: | ||
1185 | d_genocide(dir); | ||
1186 | goto out; | ||
1187 | } | 1167 | } |
1188 | 1168 | ||
1189 | static int sel_make_dir(struct super_block *sb, struct dentry *dentry) | 1169 | static int sel_make_dir(struct inode *dir, struct dentry *dentry) |
1190 | { | 1170 | { |
1191 | int ret = 0; | 1171 | int ret = 0; |
1192 | struct inode *inode; | 1172 | struct inode *inode; |
1193 | 1173 | ||
1194 | inode = sel_make_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO); | 1174 | inode = sel_make_inode(dir->i_sb, S_IFDIR | S_IRUGO | S_IXUGO); |
1195 | if (!inode) { | 1175 | if (!inode) { |
1196 | ret = -ENOMEM; | 1176 | ret = -ENOMEM; |
1197 | goto out; | 1177 | goto out; |
1198 | } | 1178 | } |
1199 | inode->i_op = &simple_dir_inode_operations; | 1179 | inode->i_op = &simple_dir_inode_operations; |
1200 | inode->i_fop = &simple_dir_operations; | 1180 | inode->i_fop = &simple_dir_operations; |
1181 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ | ||
1182 | inode->i_nlink++; | ||
1201 | d_add(dentry, inode); | 1183 | d_add(dentry, inode); |
1184 | /* bump link count on parent directory, too */ | ||
1185 | dir->i_nlink++; | ||
1202 | out: | 1186 | out: |
1203 | return ret; | 1187 | return ret; |
1204 | } | 1188 | } |
@@ -1207,7 +1191,7 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent) | |||
1207 | { | 1191 | { |
1208 | int ret; | 1192 | int ret; |
1209 | struct dentry *dentry; | 1193 | struct dentry *dentry; |
1210 | struct inode *inode; | 1194 | struct inode *inode, *root_inode; |
1211 | struct inode_security_struct *isec; | 1195 | struct inode_security_struct *isec; |
1212 | 1196 | ||
1213 | static struct tree_descr selinux_files[] = { | 1197 | static struct tree_descr selinux_files[] = { |
@@ -1228,30 +1212,33 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent) | |||
1228 | }; | 1212 | }; |
1229 | ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); | 1213 | ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); |
1230 | if (ret) | 1214 | if (ret) |
1231 | return ret; | 1215 | goto err; |
1216 | |||
1217 | root_inode = sb->s_root->d_inode; | ||
1232 | 1218 | ||
1233 | dentry = d_alloc_name(sb->s_root, BOOL_DIR_NAME); | 1219 | dentry = d_alloc_name(sb->s_root, BOOL_DIR_NAME); |
1234 | if (!dentry) | 1220 | if (!dentry) { |
1235 | return -ENOMEM; | 1221 | ret = -ENOMEM; |
1222 | goto err; | ||
1223 | } | ||
1236 | 1224 | ||
1237 | inode = sel_make_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO); | 1225 | ret = sel_make_dir(root_inode, dentry); |
1238 | if (!inode) | ||
1239 | goto out; | ||
1240 | inode->i_op = &simple_dir_inode_operations; | ||
1241 | inode->i_fop = &simple_dir_operations; | ||
1242 | d_add(dentry, inode); | ||
1243 | bool_dir = dentry; | ||
1244 | ret = sel_make_bools(); | ||
1245 | if (ret) | 1226 | if (ret) |
1246 | goto out; | 1227 | goto err; |
1228 | |||
1229 | bool_dir = dentry; | ||
1247 | 1230 | ||
1248 | dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME); | 1231 | dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME); |
1249 | if (!dentry) | 1232 | if (!dentry) { |
1250 | return -ENOMEM; | 1233 | ret = -ENOMEM; |
1234 | goto err; | ||
1235 | } | ||
1251 | 1236 | ||
1252 | inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO); | 1237 | inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO); |
1253 | if (!inode) | 1238 | if (!inode) { |
1254 | goto out; | 1239 | ret = -ENOMEM; |
1240 | goto err; | ||
1241 | } | ||
1255 | isec = (struct inode_security_struct*)inode->i_security; | 1242 | isec = (struct inode_security_struct*)inode->i_security; |
1256 | isec->sid = SECINITSID_DEVNULL; | 1243 | isec->sid = SECINITSID_DEVNULL; |
1257 | isec->sclass = SECCLASS_CHR_FILE; | 1244 | isec->sclass = SECCLASS_CHR_FILE; |
@@ -1262,22 +1249,23 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent) | |||
1262 | selinux_null = dentry; | 1249 | selinux_null = dentry; |
1263 | 1250 | ||
1264 | dentry = d_alloc_name(sb->s_root, "avc"); | 1251 | dentry = d_alloc_name(sb->s_root, "avc"); |
1265 | if (!dentry) | 1252 | if (!dentry) { |
1266 | return -ENOMEM; | 1253 | ret = -ENOMEM; |
1254 | goto err; | ||
1255 | } | ||
1267 | 1256 | ||
1268 | ret = sel_make_dir(sb, dentry); | 1257 | ret = sel_make_dir(root_inode, dentry); |
1269 | if (ret) | 1258 | if (ret) |
1270 | goto out; | 1259 | goto err; |
1271 | 1260 | ||
1272 | ret = sel_make_avc_files(dentry); | 1261 | ret = sel_make_avc_files(dentry); |
1273 | if (ret) | 1262 | if (ret) |
1274 | goto out; | 1263 | goto err; |
1275 | |||
1276 | return 0; | ||
1277 | out: | 1264 | out: |
1278 | dput(dentry); | 1265 | return ret; |
1266 | err: | ||
1279 | printk(KERN_ERR "%s: failed while creating inodes\n", __FUNCTION__); | 1267 | printk(KERN_ERR "%s: failed while creating inodes\n", __FUNCTION__); |
1280 | return -ENOMEM; | 1268 | goto out; |
1281 | } | 1269 | } |
1282 | 1270 | ||
1283 | static struct super_block *sel_get_sb(struct file_system_type *fs_type, | 1271 | static struct super_block *sel_get_sb(struct file_system_type *fs_type, |