diff options
Diffstat (limited to 'security/selinux/selinuxfs.c')
-rw-r--r-- | security/selinux/selinuxfs.c | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index a2e7a8563b38..8eb102c72606 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
@@ -68,6 +68,8 @@ static int *bool_pending_values; | |||
68 | static struct dentry *class_dir; | 68 | static struct dentry *class_dir; |
69 | static unsigned long last_class_ino; | 69 | static unsigned long last_class_ino; |
70 | 70 | ||
71 | static char policy_opened; | ||
72 | |||
71 | /* global data for policy capabilities */ | 73 | /* global data for policy capabilities */ |
72 | static struct dentry *policycap_dir; | 74 | static struct dentry *policycap_dir; |
73 | 75 | ||
@@ -111,6 +113,7 @@ enum sel_inos { | |||
111 | SEL_REJECT_UNKNOWN, /* export unknown reject handling to userspace */ | 113 | SEL_REJECT_UNKNOWN, /* export unknown reject handling to userspace */ |
112 | SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */ | 114 | SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */ |
113 | SEL_STATUS, /* export current status using mmap() */ | 115 | SEL_STATUS, /* export current status using mmap() */ |
116 | SEL_POLICY, /* allow userspace to read the in kernel policy */ | ||
114 | SEL_INO_NEXT, /* The next inode number to use */ | 117 | SEL_INO_NEXT, /* The next inode number to use */ |
115 | }; | 118 | }; |
116 | 119 | ||
@@ -351,6 +354,97 @@ static const struct file_operations sel_mls_ops = { | |||
351 | .llseek = generic_file_llseek, | 354 | .llseek = generic_file_llseek, |
352 | }; | 355 | }; |
353 | 356 | ||
357 | struct policy_load_memory { | ||
358 | size_t len; | ||
359 | void *data; | ||
360 | }; | ||
361 | |||
362 | static int sel_open_policy(struct inode *inode, struct file *filp) | ||
363 | { | ||
364 | struct policy_load_memory *plm = NULL; | ||
365 | int rc; | ||
366 | |||
367 | BUG_ON(filp->private_data); | ||
368 | |||
369 | mutex_lock(&sel_mutex); | ||
370 | |||
371 | rc = task_has_security(current, SECURITY__READ_POLICY); | ||
372 | if (rc) | ||
373 | goto err; | ||
374 | |||
375 | rc = -EBUSY; | ||
376 | if (policy_opened) | ||
377 | goto err; | ||
378 | |||
379 | rc = -ENOMEM; | ||
380 | plm = kzalloc(sizeof(*plm), GFP_KERNEL); | ||
381 | if (!plm) | ||
382 | goto err; | ||
383 | |||
384 | if (i_size_read(inode) != security_policydb_len()) { | ||
385 | mutex_lock(&inode->i_mutex); | ||
386 | i_size_write(inode, security_policydb_len()); | ||
387 | mutex_unlock(&inode->i_mutex); | ||
388 | } | ||
389 | |||
390 | rc = security_read_policy(&plm->data, &plm->len); | ||
391 | if (rc) | ||
392 | goto err; | ||
393 | |||
394 | policy_opened = 1; | ||
395 | |||
396 | filp->private_data = plm; | ||
397 | |||
398 | mutex_unlock(&sel_mutex); | ||
399 | |||
400 | return 0; | ||
401 | err: | ||
402 | mutex_unlock(&sel_mutex); | ||
403 | |||
404 | if (plm) | ||
405 | vfree(plm->data); | ||
406 | kfree(plm); | ||
407 | return rc; | ||
408 | } | ||
409 | |||
410 | static int sel_release_policy(struct inode *inode, struct file *filp) | ||
411 | { | ||
412 | struct policy_load_memory *plm = filp->private_data; | ||
413 | |||
414 | BUG_ON(!plm); | ||
415 | |||
416 | policy_opened = 0; | ||
417 | |||
418 | vfree(plm->data); | ||
419 | kfree(plm); | ||
420 | |||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | static ssize_t sel_read_policy(struct file *filp, char __user *buf, | ||
425 | size_t count, loff_t *ppos) | ||
426 | { | ||
427 | struct policy_load_memory *plm = filp->private_data; | ||
428 | int ret; | ||
429 | |||
430 | mutex_lock(&sel_mutex); | ||
431 | |||
432 | ret = task_has_security(current, SECURITY__READ_POLICY); | ||
433 | if (ret) | ||
434 | goto out; | ||
435 | |||
436 | ret = simple_read_from_buffer(buf, count, ppos, plm->data, plm->len); | ||
437 | out: | ||
438 | mutex_unlock(&sel_mutex); | ||
439 | return ret; | ||
440 | } | ||
441 | |||
442 | static const struct file_operations sel_policy_ops = { | ||
443 | .open = sel_open_policy, | ||
444 | .read = sel_read_policy, | ||
445 | .release = sel_release_policy, | ||
446 | }; | ||
447 | |||
354 | static ssize_t sel_write_load(struct file *file, const char __user *buf, | 448 | static ssize_t sel_write_load(struct file *file, const char __user *buf, |
355 | size_t count, loff_t *ppos) | 449 | size_t count, loff_t *ppos) |
356 | 450 | ||
@@ -1668,6 +1762,7 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) | |||
1668 | [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO}, | 1762 | [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO}, |
1669 | [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO}, | 1763 | [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO}, |
1670 | [SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO}, | 1764 | [SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO}, |
1765 | [SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUSR}, | ||
1671 | /* last one */ {""} | 1766 | /* last one */ {""} |
1672 | }; | 1767 | }; |
1673 | ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); | 1768 | ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); |