aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-06-30 14:15:12 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-06-30 14:15:12 -0400
commit34a484d58c1d0cdce4c5d63249ae89539dfad6b2 (patch)
tree92ba524b241b8866001ce07b78fe8ec4b202981e
parente6e5bec43c0d5dec97355ebf9f6c9bbf4d4c29d5 (diff)
parent0da74120c5341389b97c4ee27487a97224999ee1 (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.c78
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)
441static ssize_t sel_read_policy(struct file *filp, char __user *buf, 441static 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);
457out:
458 mutex_unlock(&fsi->mutex);
459 return ret;
460} 454}
461 455
462static vm_fault_t sel_mmap_policy_fault(struct vm_fault *vmf) 456static 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);
1206out:
1207 mutex_unlock(&fsi->mutex); 1199 mutex_unlock(&fsi->mutex);
1200 ret = simple_read_from_buffer(buf, count, ppos, page, length);
1201out_free:
1208 free_page((unsigned long)page); 1202 free_page((unsigned long)page);
1209 return ret; 1203 return ret;
1204
1205out_unlock:
1206 mutex_unlock(&fsi->mutex);
1207 goto out_free;
1210} 1208}
1211 1209
1212static ssize_t sel_write_bool(struct file *filep, const char __user *buf, 1210static 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;