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 /security | |
| 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
Diffstat (limited to 'security')
| -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; |
