diff options
Diffstat (limited to 'security/selinux/selinuxfs.c')
| -rw-r--r-- | security/selinux/selinuxfs.c | 195 | 
1 files changed, 195 insertions, 0 deletions
| diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 79a1bb635662..87e0556bae70 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 | ||
| @@ -110,6 +112,8 @@ enum sel_inos { | |||
| 110 | SEL_COMPAT_NET, /* whether to use old compat network packet controls */ | 112 | SEL_COMPAT_NET, /* whether to use old compat network packet controls */ | 
| 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 */ | 
| 115 | SEL_STATUS, /* export current status using mmap() */ | ||
| 116 | SEL_POLICY, /* allow userspace to read the in kernel policy */ | ||
| 113 | SEL_INO_NEXT, /* The next inode number to use */ | 117 | SEL_INO_NEXT, /* The next inode number to use */ | 
| 114 | }; | 118 | }; | 
| 115 | 119 | ||
| @@ -171,6 +175,7 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf, | |||
| 171 | if (selinux_enforcing) | 175 | if (selinux_enforcing) | 
| 172 | avc_ss_reset(0); | 176 | avc_ss_reset(0); | 
| 173 | selnl_notify_setenforce(selinux_enforcing); | 177 | selnl_notify_setenforce(selinux_enforcing); | 
| 178 | selinux_status_update_setenforce(selinux_enforcing); | ||
| 174 | } | 179 | } | 
| 175 | length = count; | 180 | length = count; | 
| 176 | out: | 181 | out: | 
| @@ -205,6 +210,59 @@ static const struct file_operations sel_handle_unknown_ops = { | |||
| 205 | .llseek = generic_file_llseek, | 210 | .llseek = generic_file_llseek, | 
| 206 | }; | 211 | }; | 
| 207 | 212 | ||
| 213 | static int sel_open_handle_status(struct inode *inode, struct file *filp) | ||
| 214 | { | ||
| 215 | struct page *status = selinux_kernel_status_page(); | ||
| 216 | |||
| 217 | if (!status) | ||
| 218 | return -ENOMEM; | ||
| 219 | |||
| 220 | filp->private_data = status; | ||
| 221 | |||
| 222 | return 0; | ||
| 223 | } | ||
| 224 | |||
| 225 | static ssize_t sel_read_handle_status(struct file *filp, char __user *buf, | ||
| 226 | size_t count, loff_t *ppos) | ||
| 227 | { | ||
| 228 | struct page *status = filp->private_data; | ||
| 229 | |||
| 230 | BUG_ON(!status); | ||
| 231 | |||
| 232 | return simple_read_from_buffer(buf, count, ppos, | ||
| 233 | page_address(status), | ||
| 234 | sizeof(struct selinux_kernel_status)); | ||
| 235 | } | ||
| 236 | |||
| 237 | static int sel_mmap_handle_status(struct file *filp, | ||
| 238 | struct vm_area_struct *vma) | ||
| 239 | { | ||
| 240 | struct page *status = filp->private_data; | ||
| 241 | unsigned long size = vma->vm_end - vma->vm_start; | ||
| 242 | |||
| 243 | BUG_ON(!status); | ||
| 244 | |||
| 245 | /* only allows one page from the head */ | ||
| 246 | if (vma->vm_pgoff > 0 || size != PAGE_SIZE) | ||
| 247 | return -EIO; | ||
| 248 | /* disallow writable mapping */ | ||
| 249 | if (vma->vm_flags & VM_WRITE) | ||
| 250 | return -EPERM; | ||
| 251 | /* disallow mprotect() turns it into writable */ | ||
| 252 | vma->vm_flags &= ~VM_MAYWRITE; | ||
| 253 | |||
| 254 | return remap_pfn_range(vma, vma->vm_start, | ||
| 255 | page_to_pfn(status), | ||
| 256 | size, vma->vm_page_prot); | ||
| 257 | } | ||
| 258 | |||
| 259 | static const struct file_operations sel_handle_status_ops = { | ||
| 260 | .open = sel_open_handle_status, | ||
| 261 | .read = sel_read_handle_status, | ||
| 262 | .mmap = sel_mmap_handle_status, | ||
| 263 | .llseek = generic_file_llseek, | ||
| 264 | }; | ||
| 265 | |||
| 208 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE | 266 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE | 
| 209 | static ssize_t sel_write_disable(struct file *file, const char __user *buf, | 267 | static ssize_t sel_write_disable(struct file *file, const char __user *buf, | 
| 210 | size_t count, loff_t *ppos) | 268 | size_t count, loff_t *ppos) | 
| @@ -296,6 +354,141 @@ static const struct file_operations sel_mls_ops = { | |||
| 296 | .llseek = generic_file_llseek, | 354 | .llseek = generic_file_llseek, | 
| 297 | }; | 355 | }; | 
| 298 | 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 int sel_mmap_policy_fault(struct vm_area_struct *vma, | ||
| 443 | struct vm_fault *vmf) | ||
| 444 | { | ||
| 445 | struct policy_load_memory *plm = vma->vm_file->private_data; | ||
| 446 | unsigned long offset; | ||
| 447 | struct page *page; | ||
| 448 | |||
| 449 | if (vmf->flags & (FAULT_FLAG_MKWRITE | FAULT_FLAG_WRITE)) | ||
| 450 | return VM_FAULT_SIGBUS; | ||
| 451 | |||
| 452 | offset = vmf->pgoff << PAGE_SHIFT; | ||
| 453 | if (offset >= roundup(plm->len, PAGE_SIZE)) | ||
| 454 | return VM_FAULT_SIGBUS; | ||
| 455 | |||
| 456 | page = vmalloc_to_page(plm->data + offset); | ||
| 457 | get_page(page); | ||
| 458 | |||
| 459 | vmf->page = page; | ||
| 460 | |||
| 461 | return 0; | ||
| 462 | } | ||
| 463 | |||
| 464 | static struct vm_operations_struct sel_mmap_policy_ops = { | ||
| 465 | .fault = sel_mmap_policy_fault, | ||
| 466 | .page_mkwrite = sel_mmap_policy_fault, | ||
| 467 | }; | ||
| 468 | |||
| 469 | int sel_mmap_policy(struct file *filp, struct vm_area_struct *vma) | ||
| 470 | { | ||
| 471 | if (vma->vm_flags & VM_SHARED) { | ||
| 472 | /* do not allow mprotect to make mapping writable */ | ||
| 473 | vma->vm_flags &= ~VM_MAYWRITE; | ||
| 474 | |||
| 475 | if (vma->vm_flags & VM_WRITE) | ||
| 476 | return -EACCES; | ||
| 477 | } | ||
| 478 | |||
| 479 | vma->vm_flags |= VM_RESERVED; | ||
| 480 | vma->vm_ops = &sel_mmap_policy_ops; | ||
| 481 | |||
| 482 | return 0; | ||
| 483 | } | ||
| 484 | |||
| 485 | static const struct file_operations sel_policy_ops = { | ||
| 486 | .open = sel_open_policy, | ||
| 487 | .read = sel_read_policy, | ||
| 488 | .mmap = sel_mmap_policy, | ||
| 489 | .release = sel_release_policy, | ||
| 490 | }; | ||
| 491 | |||
| 299 | static ssize_t sel_write_load(struct file *file, const char __user *buf, | 492 | static ssize_t sel_write_load(struct file *file, const char __user *buf, | 
| 300 | size_t count, loff_t *ppos) | 493 | size_t count, loff_t *ppos) | 
| 301 | 494 | ||
| @@ -1612,6 +1805,8 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) | |||
| 1612 | [SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR}, | 1805 | [SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR}, | 
| 1613 | [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO}, | 1806 | [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO}, | 
| 1614 | [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO}, | 1807 | [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO}, | 
| 1808 | [SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO}, | ||
| 1809 | [SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUSR}, | ||
| 1615 | /* last one */ {""} | 1810 | /* last one */ {""} | 
| 1616 | }; | 1811 | }; | 
| 1617 | ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); | 1812 | ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); | 
