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); |
