diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-06-30 14:15:12 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-06-30 14:15:12 -0400 |
commit | 34a484d58c1d0cdce4c5d63249ae89539dfad6b2 (patch) | |
tree | 92ba524b241b8866001ce07b78fe8ec4b202981e | |
parent | e6e5bec43c0d5dec97355ebf9f6c9bbf4d4c29d5 (diff) | |
parent | 0da74120c5341389b97c4ee27487a97224999ee1 (diff) |
Merge tag 'selinux-pr-20180629' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux
Pull selinux fix from Paul Moore:
"One fairly straightforward patch to fix a longstanding issue where a
process could stall while accessing files in selinuxfs and block
everyone else due to a held mutex.
The patch passes all our tests and looks to apply cleanly to your
current tree"
* tag 'selinux-pr-20180629' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
selinux: move user accesses in selinuxfs out of locked regions
-rw-r--r-- | security/selinux/selinuxfs.c | 78 |
1 files changed, 33 insertions, 45 deletions
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index f3d374d2ca04..79d3709b0671 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
@@ -441,22 +441,16 @@ static int sel_release_policy(struct inode *inode, struct file *filp) | |||
441 | static ssize_t sel_read_policy(struct file *filp, char __user *buf, | 441 | static ssize_t sel_read_policy(struct file *filp, char __user *buf, |
442 | size_t count, loff_t *ppos) | 442 | size_t count, loff_t *ppos) |
443 | { | 443 | { |
444 | struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info; | ||
445 | struct policy_load_memory *plm = filp->private_data; | 444 | struct policy_load_memory *plm = filp->private_data; |
446 | int ret; | 445 | int ret; |
447 | 446 | ||
448 | mutex_lock(&fsi->mutex); | ||
449 | |||
450 | ret = avc_has_perm(&selinux_state, | 447 | ret = avc_has_perm(&selinux_state, |
451 | current_sid(), SECINITSID_SECURITY, | 448 | current_sid(), SECINITSID_SECURITY, |
452 | SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL); | 449 | SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL); |
453 | if (ret) | 450 | if (ret) |
454 | goto out; | 451 | return ret; |
455 | 452 | ||
456 | ret = simple_read_from_buffer(buf, count, ppos, plm->data, plm->len); | 453 | return simple_read_from_buffer(buf, count, ppos, plm->data, plm->len); |
457 | out: | ||
458 | mutex_unlock(&fsi->mutex); | ||
459 | return ret; | ||
460 | } | 454 | } |
461 | 455 | ||
462 | static vm_fault_t sel_mmap_policy_fault(struct vm_fault *vmf) | 456 | static vm_fault_t sel_mmap_policy_fault(struct vm_fault *vmf) |
@@ -1188,25 +1182,29 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, | |||
1188 | ret = -EINVAL; | 1182 | ret = -EINVAL; |
1189 | if (index >= fsi->bool_num || strcmp(name, | 1183 | if (index >= fsi->bool_num || strcmp(name, |
1190 | fsi->bool_pending_names[index])) | 1184 | fsi->bool_pending_names[index])) |
1191 | goto out; | 1185 | goto out_unlock; |
1192 | 1186 | ||
1193 | ret = -ENOMEM; | 1187 | ret = -ENOMEM; |
1194 | page = (char *)get_zeroed_page(GFP_KERNEL); | 1188 | page = (char *)get_zeroed_page(GFP_KERNEL); |
1195 | if (!page) | 1189 | if (!page) |
1196 | goto out; | 1190 | goto out_unlock; |
1197 | 1191 | ||
1198 | cur_enforcing = security_get_bool_value(fsi->state, index); | 1192 | cur_enforcing = security_get_bool_value(fsi->state, index); |
1199 | if (cur_enforcing < 0) { | 1193 | if (cur_enforcing < 0) { |
1200 | ret = cur_enforcing; | 1194 | ret = cur_enforcing; |
1201 | goto out; | 1195 | goto out_unlock; |
1202 | } | 1196 | } |
1203 | length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing, | 1197 | length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing, |
1204 | fsi->bool_pending_values[index]); | 1198 | fsi->bool_pending_values[index]); |
1205 | ret = simple_read_from_buffer(buf, count, ppos, page, length); | ||
1206 | out: | ||
1207 | mutex_unlock(&fsi->mutex); | 1199 | mutex_unlock(&fsi->mutex); |
1200 | ret = simple_read_from_buffer(buf, count, ppos, page, length); | ||
1201 | out_free: | ||
1208 | free_page((unsigned long)page); | 1202 | free_page((unsigned long)page); |
1209 | return ret; | 1203 | return ret; |
1204 | |||
1205 | out_unlock: | ||
1206 | mutex_unlock(&fsi->mutex); | ||
1207 | goto out_free; | ||
1210 | } | 1208 | } |
1211 | 1209 | ||
1212 | static ssize_t sel_write_bool(struct file *filep, const char __user *buf, | 1210 | static ssize_t sel_write_bool(struct file *filep, const char __user *buf, |
@@ -1219,6 +1217,17 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, | |||
1219 | unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK; | 1217 | unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK; |
1220 | const char *name = filep->f_path.dentry->d_name.name; | 1218 | const char *name = filep->f_path.dentry->d_name.name; |
1221 | 1219 | ||
1220 | if (count >= PAGE_SIZE) | ||
1221 | return -ENOMEM; | ||
1222 | |||
1223 | /* No partial writes. */ | ||
1224 | if (*ppos != 0) | ||
1225 | return -EINVAL; | ||
1226 | |||
1227 | page = memdup_user_nul(buf, count); | ||
1228 | if (IS_ERR(page)) | ||
1229 | return PTR_ERR(page); | ||
1230 | |||
1222 | mutex_lock(&fsi->mutex); | 1231 | mutex_lock(&fsi->mutex); |
1223 | 1232 | ||
1224 | length = avc_has_perm(&selinux_state, | 1233 | length = avc_has_perm(&selinux_state, |
@@ -1233,22 +1242,6 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, | |||
1233 | fsi->bool_pending_names[index])) | 1242 | fsi->bool_pending_names[index])) |
1234 | goto out; | 1243 | goto out; |
1235 | 1244 | ||
1236 | length = -ENOMEM; | ||
1237 | if (count >= PAGE_SIZE) | ||
1238 | goto out; | ||
1239 | |||
1240 | /* No partial writes. */ | ||
1241 | length = -EINVAL; | ||
1242 | if (*ppos != 0) | ||
1243 | goto out; | ||
1244 | |||
1245 | page = memdup_user_nul(buf, count); | ||
1246 | if (IS_ERR(page)) { | ||
1247 | length = PTR_ERR(page); | ||
1248 | page = NULL; | ||
1249 | goto out; | ||
1250 | } | ||
1251 | |||
1252 | length = -EINVAL; | 1245 | length = -EINVAL; |
1253 | if (sscanf(page, "%d", &new_value) != 1) | 1246 | if (sscanf(page, "%d", &new_value) != 1) |
1254 | goto out; | 1247 | goto out; |
@@ -1280,6 +1273,17 @@ static ssize_t sel_commit_bools_write(struct file *filep, | |||
1280 | ssize_t length; | 1273 | ssize_t length; |
1281 | int new_value; | 1274 | int new_value; |
1282 | 1275 | ||
1276 | if (count >= PAGE_SIZE) | ||
1277 | return -ENOMEM; | ||
1278 | |||
1279 | /* No partial writes. */ | ||
1280 | if (*ppos != 0) | ||
1281 | return -EINVAL; | ||
1282 | |||
1283 | page = memdup_user_nul(buf, count); | ||
1284 | if (IS_ERR(page)) | ||
1285 | return PTR_ERR(page); | ||
1286 | |||
1283 | mutex_lock(&fsi->mutex); | 1287 | mutex_lock(&fsi->mutex); |
1284 | 1288 | ||
1285 | length = avc_has_perm(&selinux_state, | 1289 | length = avc_has_perm(&selinux_state, |
@@ -1289,22 +1293,6 @@ static ssize_t sel_commit_bools_write(struct file *filep, | |||
1289 | if (length) | 1293 | if (length) |
1290 | goto out; | 1294 | goto out; |
1291 | 1295 | ||
1292 | length = -ENOMEM; | ||
1293 | if (count >= PAGE_SIZE) | ||
1294 | goto out; | ||
1295 | |||
1296 | /* No partial writes. */ | ||
1297 | length = -EINVAL; | ||
1298 | if (*ppos != 0) | ||
1299 | goto out; | ||
1300 | |||
1301 | page = memdup_user_nul(buf, count); | ||
1302 | if (IS_ERR(page)) { | ||
1303 | length = PTR_ERR(page); | ||
1304 | page = NULL; | ||
1305 | goto out; | ||
1306 | } | ||
1307 | |||
1308 | length = -EINVAL; | 1296 | length = -EINVAL; |
1309 | if (sscanf(page, "%d", &new_value) != 1) | 1297 | if (sscanf(page, "%d", &new_value) != 1) |
1310 | goto out; | 1298 | goto out; |