diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /security/selinux/selinuxfs.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'security/selinux/selinuxfs.c')
-rw-r--r-- | security/selinux/selinuxfs.c | 939 |
1 files changed, 586 insertions, 353 deletions
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 79a1bb635662..35459340019e 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
@@ -28,6 +28,8 @@ | |||
28 | #include <linux/percpu.h> | 28 | #include <linux/percpu.h> |
29 | #include <linux/audit.h> | 29 | #include <linux/audit.h> |
30 | #include <linux/uaccess.h> | 30 | #include <linux/uaccess.h> |
31 | #include <linux/kobject.h> | ||
32 | #include <linux/ctype.h> | ||
31 | 33 | ||
32 | /* selinuxfs pseudo filesystem for exporting the security policy API. | 34 | /* selinuxfs pseudo filesystem for exporting the security policy API. |
33 | Based on the proc code and the fs/nfsd/nfsctl.c code. */ | 35 | Based on the proc code and the fs/nfsd/nfsctl.c code. */ |
@@ -68,6 +70,8 @@ static int *bool_pending_values; | |||
68 | static struct dentry *class_dir; | 70 | static struct dentry *class_dir; |
69 | static unsigned long last_class_ino; | 71 | static unsigned long last_class_ino; |
70 | 72 | ||
73 | static char policy_opened; | ||
74 | |||
71 | /* global data for policy capabilities */ | 75 | /* global data for policy capabilities */ |
72 | static struct dentry *policycap_dir; | 76 | static struct dentry *policycap_dir; |
73 | 77 | ||
@@ -110,6 +114,8 @@ enum sel_inos { | |||
110 | SEL_COMPAT_NET, /* whether to use old compat network packet controls */ | 114 | SEL_COMPAT_NET, /* whether to use old compat network packet controls */ |
111 | SEL_REJECT_UNKNOWN, /* export unknown reject handling to userspace */ | 115 | SEL_REJECT_UNKNOWN, /* export unknown reject handling to userspace */ |
112 | SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */ | 116 | SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */ |
117 | SEL_STATUS, /* export current status using mmap() */ | ||
118 | SEL_POLICY, /* allow userspace to read the in kernel policy */ | ||
113 | SEL_INO_NEXT, /* The next inode number to use */ | 119 | SEL_INO_NEXT, /* The next inode number to use */ |
114 | }; | 120 | }; |
115 | 121 | ||
@@ -137,19 +143,24 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf, | |||
137 | size_t count, loff_t *ppos) | 143 | size_t count, loff_t *ppos) |
138 | 144 | ||
139 | { | 145 | { |
140 | char *page; | 146 | char *page = NULL; |
141 | ssize_t length; | 147 | ssize_t length; |
142 | int new_value; | 148 | int new_value; |
143 | 149 | ||
150 | length = -ENOMEM; | ||
144 | if (count >= PAGE_SIZE) | 151 | if (count >= PAGE_SIZE) |
145 | return -ENOMEM; | 152 | goto out; |
146 | if (*ppos != 0) { | 153 | |
147 | /* No partial writes. */ | 154 | /* No partial writes. */ |
148 | return -EINVAL; | 155 | length = EINVAL; |
149 | } | 156 | if (*ppos != 0) |
157 | goto out; | ||
158 | |||
159 | length = -ENOMEM; | ||
150 | page = (char *)get_zeroed_page(GFP_KERNEL); | 160 | page = (char *)get_zeroed_page(GFP_KERNEL); |
151 | if (!page) | 161 | if (!page) |
152 | return -ENOMEM; | 162 | goto out; |
163 | |||
153 | length = -EFAULT; | 164 | length = -EFAULT; |
154 | if (copy_from_user(page, buf, count)) | 165 | if (copy_from_user(page, buf, count)) |
155 | goto out; | 166 | goto out; |
@@ -171,6 +182,7 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf, | |||
171 | if (selinux_enforcing) | 182 | if (selinux_enforcing) |
172 | avc_ss_reset(0); | 183 | avc_ss_reset(0); |
173 | selnl_notify_setenforce(selinux_enforcing); | 184 | selnl_notify_setenforce(selinux_enforcing); |
185 | selinux_status_update_setenforce(selinux_enforcing); | ||
174 | } | 186 | } |
175 | length = count; | 187 | length = count; |
176 | out: | 188 | out: |
@@ -205,25 +217,83 @@ static const struct file_operations sel_handle_unknown_ops = { | |||
205 | .llseek = generic_file_llseek, | 217 | .llseek = generic_file_llseek, |
206 | }; | 218 | }; |
207 | 219 | ||
220 | static int sel_open_handle_status(struct inode *inode, struct file *filp) | ||
221 | { | ||
222 | struct page *status = selinux_kernel_status_page(); | ||
223 | |||
224 | if (!status) | ||
225 | return -ENOMEM; | ||
226 | |||
227 | filp->private_data = status; | ||
228 | |||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | static ssize_t sel_read_handle_status(struct file *filp, char __user *buf, | ||
233 | size_t count, loff_t *ppos) | ||
234 | { | ||
235 | struct page *status = filp->private_data; | ||
236 | |||
237 | BUG_ON(!status); | ||
238 | |||
239 | return simple_read_from_buffer(buf, count, ppos, | ||
240 | page_address(status), | ||
241 | sizeof(struct selinux_kernel_status)); | ||
242 | } | ||
243 | |||
244 | static int sel_mmap_handle_status(struct file *filp, | ||
245 | struct vm_area_struct *vma) | ||
246 | { | ||
247 | struct page *status = filp->private_data; | ||
248 | unsigned long size = vma->vm_end - vma->vm_start; | ||
249 | |||
250 | BUG_ON(!status); | ||
251 | |||
252 | /* only allows one page from the head */ | ||
253 | if (vma->vm_pgoff > 0 || size != PAGE_SIZE) | ||
254 | return -EIO; | ||
255 | /* disallow writable mapping */ | ||
256 | if (vma->vm_flags & VM_WRITE) | ||
257 | return -EPERM; | ||
258 | /* disallow mprotect() turns it into writable */ | ||
259 | vma->vm_flags &= ~VM_MAYWRITE; | ||
260 | |||
261 | return remap_pfn_range(vma, vma->vm_start, | ||
262 | page_to_pfn(status), | ||
263 | size, vma->vm_page_prot); | ||
264 | } | ||
265 | |||
266 | static const struct file_operations sel_handle_status_ops = { | ||
267 | .open = sel_open_handle_status, | ||
268 | .read = sel_read_handle_status, | ||
269 | .mmap = sel_mmap_handle_status, | ||
270 | .llseek = generic_file_llseek, | ||
271 | }; | ||
272 | |||
208 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE | 273 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE |
209 | static ssize_t sel_write_disable(struct file *file, const char __user *buf, | 274 | static ssize_t sel_write_disable(struct file *file, const char __user *buf, |
210 | size_t count, loff_t *ppos) | 275 | size_t count, loff_t *ppos) |
211 | 276 | ||
212 | { | 277 | { |
213 | char *page; | 278 | char *page = NULL; |
214 | ssize_t length; | 279 | ssize_t length; |
215 | int new_value; | 280 | int new_value; |
216 | extern int selinux_disable(void); | 281 | extern int selinux_disable(void); |
217 | 282 | ||
283 | length = -ENOMEM; | ||
218 | if (count >= PAGE_SIZE) | 284 | if (count >= PAGE_SIZE) |
219 | return -ENOMEM; | 285 | goto out; |
220 | if (*ppos != 0) { | 286 | |
221 | /* No partial writes. */ | 287 | /* No partial writes. */ |
222 | return -EINVAL; | 288 | length = -EINVAL; |
223 | } | 289 | if (*ppos != 0) |
290 | goto out; | ||
291 | |||
292 | length = -ENOMEM; | ||
224 | page = (char *)get_zeroed_page(GFP_KERNEL); | 293 | page = (char *)get_zeroed_page(GFP_KERNEL); |
225 | if (!page) | 294 | if (!page) |
226 | return -ENOMEM; | 295 | goto out; |
296 | |||
227 | length = -EFAULT; | 297 | length = -EFAULT; |
228 | if (copy_from_user(page, buf, count)) | 298 | if (copy_from_user(page, buf, count)) |
229 | goto out; | 299 | goto out; |
@@ -234,7 +304,7 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf, | |||
234 | 304 | ||
235 | if (new_value) { | 305 | if (new_value) { |
236 | length = selinux_disable(); | 306 | length = selinux_disable(); |
237 | if (length < 0) | 307 | if (length) |
238 | goto out; | 308 | goto out; |
239 | audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS, | 309 | audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS, |
240 | "selinux=0 auid=%u ses=%u", | 310 | "selinux=0 auid=%u ses=%u", |
@@ -296,11 +366,145 @@ static const struct file_operations sel_mls_ops = { | |||
296 | .llseek = generic_file_llseek, | 366 | .llseek = generic_file_llseek, |
297 | }; | 367 | }; |
298 | 368 | ||
369 | struct policy_load_memory { | ||
370 | size_t len; | ||
371 | void *data; | ||
372 | }; | ||
373 | |||
374 | static int sel_open_policy(struct inode *inode, struct file *filp) | ||
375 | { | ||
376 | struct policy_load_memory *plm = NULL; | ||
377 | int rc; | ||
378 | |||
379 | BUG_ON(filp->private_data); | ||
380 | |||
381 | mutex_lock(&sel_mutex); | ||
382 | |||
383 | rc = task_has_security(current, SECURITY__READ_POLICY); | ||
384 | if (rc) | ||
385 | goto err; | ||
386 | |||
387 | rc = -EBUSY; | ||
388 | if (policy_opened) | ||
389 | goto err; | ||
390 | |||
391 | rc = -ENOMEM; | ||
392 | plm = kzalloc(sizeof(*plm), GFP_KERNEL); | ||
393 | if (!plm) | ||
394 | goto err; | ||
395 | |||
396 | if (i_size_read(inode) != security_policydb_len()) { | ||
397 | mutex_lock(&inode->i_mutex); | ||
398 | i_size_write(inode, security_policydb_len()); | ||
399 | mutex_unlock(&inode->i_mutex); | ||
400 | } | ||
401 | |||
402 | rc = security_read_policy(&plm->data, &plm->len); | ||
403 | if (rc) | ||
404 | goto err; | ||
405 | |||
406 | policy_opened = 1; | ||
407 | |||
408 | filp->private_data = plm; | ||
409 | |||
410 | mutex_unlock(&sel_mutex); | ||
411 | |||
412 | return 0; | ||
413 | err: | ||
414 | mutex_unlock(&sel_mutex); | ||
415 | |||
416 | if (plm) | ||
417 | vfree(plm->data); | ||
418 | kfree(plm); | ||
419 | return rc; | ||
420 | } | ||
421 | |||
422 | static int sel_release_policy(struct inode *inode, struct file *filp) | ||
423 | { | ||
424 | struct policy_load_memory *plm = filp->private_data; | ||
425 | |||
426 | BUG_ON(!plm); | ||
427 | |||
428 | policy_opened = 0; | ||
429 | |||
430 | vfree(plm->data); | ||
431 | kfree(plm); | ||
432 | |||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | static ssize_t sel_read_policy(struct file *filp, char __user *buf, | ||
437 | size_t count, loff_t *ppos) | ||
438 | { | ||
439 | struct policy_load_memory *plm = filp->private_data; | ||
440 | int ret; | ||
441 | |||
442 | mutex_lock(&sel_mutex); | ||
443 | |||
444 | ret = task_has_security(current, SECURITY__READ_POLICY); | ||
445 | if (ret) | ||
446 | goto out; | ||
447 | |||
448 | ret = simple_read_from_buffer(buf, count, ppos, plm->data, plm->len); | ||
449 | out: | ||
450 | mutex_unlock(&sel_mutex); | ||
451 | return ret; | ||
452 | } | ||
453 | |||
454 | static int sel_mmap_policy_fault(struct vm_area_struct *vma, | ||
455 | struct vm_fault *vmf) | ||
456 | { | ||
457 | struct policy_load_memory *plm = vma->vm_file->private_data; | ||
458 | unsigned long offset; | ||
459 | struct page *page; | ||
460 | |||
461 | if (vmf->flags & (FAULT_FLAG_MKWRITE | FAULT_FLAG_WRITE)) | ||
462 | return VM_FAULT_SIGBUS; | ||
463 | |||
464 | offset = vmf->pgoff << PAGE_SHIFT; | ||
465 | if (offset >= roundup(plm->len, PAGE_SIZE)) | ||
466 | return VM_FAULT_SIGBUS; | ||
467 | |||
468 | page = vmalloc_to_page(plm->data + offset); | ||
469 | get_page(page); | ||
470 | |||
471 | vmf->page = page; | ||
472 | |||
473 | return 0; | ||
474 | } | ||
475 | |||
476 | static struct vm_operations_struct sel_mmap_policy_ops = { | ||
477 | .fault = sel_mmap_policy_fault, | ||
478 | .page_mkwrite = sel_mmap_policy_fault, | ||
479 | }; | ||
480 | |||
481 | int sel_mmap_policy(struct file *filp, struct vm_area_struct *vma) | ||
482 | { | ||
483 | if (vma->vm_flags & VM_SHARED) { | ||
484 | /* do not allow mprotect to make mapping writable */ | ||
485 | vma->vm_flags &= ~VM_MAYWRITE; | ||
486 | |||
487 | if (vma->vm_flags & VM_WRITE) | ||
488 | return -EACCES; | ||
489 | } | ||
490 | |||
491 | vma->vm_flags |= VM_RESERVED; | ||
492 | vma->vm_ops = &sel_mmap_policy_ops; | ||
493 | |||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | static const struct file_operations sel_policy_ops = { | ||
498 | .open = sel_open_policy, | ||
499 | .read = sel_read_policy, | ||
500 | .mmap = sel_mmap_policy, | ||
501 | .release = sel_release_policy, | ||
502 | }; | ||
503 | |||
299 | static ssize_t sel_write_load(struct file *file, const char __user *buf, | 504 | static ssize_t sel_write_load(struct file *file, const char __user *buf, |
300 | size_t count, loff_t *ppos) | 505 | size_t count, loff_t *ppos) |
301 | 506 | ||
302 | { | 507 | { |
303 | int ret; | ||
304 | ssize_t length; | 508 | ssize_t length; |
305 | void *data = NULL; | 509 | void *data = NULL; |
306 | 510 | ||
@@ -310,17 +514,19 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, | |||
310 | if (length) | 514 | if (length) |
311 | goto out; | 515 | goto out; |
312 | 516 | ||
313 | if (*ppos != 0) { | 517 | /* No partial writes. */ |
314 | /* No partial writes. */ | 518 | length = -EINVAL; |
315 | length = -EINVAL; | 519 | if (*ppos != 0) |
316 | goto out; | 520 | goto out; |
317 | } | ||
318 | 521 | ||
319 | if ((count > 64 * 1024 * 1024) | 522 | length = -EFBIG; |
320 | || (data = vmalloc(count)) == NULL) { | 523 | if (count > 64 * 1024 * 1024) |
321 | length = -ENOMEM; | 524 | goto out; |
525 | |||
526 | length = -ENOMEM; | ||
527 | data = vmalloc(count); | ||
528 | if (!data) | ||
322 | goto out; | 529 | goto out; |
323 | } | ||
324 | 530 | ||
325 | length = -EFAULT; | 531 | length = -EFAULT; |
326 | if (copy_from_user(data, buf, count) != 0) | 532 | if (copy_from_user(data, buf, count) != 0) |
@@ -330,23 +536,19 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, | |||
330 | if (length) | 536 | if (length) |
331 | goto out; | 537 | goto out; |
332 | 538 | ||
333 | ret = sel_make_bools(); | 539 | length = sel_make_bools(); |
334 | if (ret) { | 540 | if (length) |
335 | length = ret; | ||
336 | goto out1; | 541 | goto out1; |
337 | } | ||
338 | 542 | ||
339 | ret = sel_make_classes(); | 543 | length = sel_make_classes(); |
340 | if (ret) { | 544 | if (length) |
341 | length = ret; | ||
342 | goto out1; | 545 | goto out1; |
343 | } | ||
344 | 546 | ||
345 | ret = sel_make_policycap(); | 547 | length = sel_make_policycap(); |
346 | if (ret) | 548 | if (length) |
347 | length = ret; | 549 | goto out1; |
348 | else | 550 | |
349 | length = count; | 551 | length = count; |
350 | 552 | ||
351 | out1: | 553 | out1: |
352 | audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD, | 554 | audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD, |
@@ -366,26 +568,26 @@ static const struct file_operations sel_load_ops = { | |||
366 | 568 | ||
367 | static ssize_t sel_write_context(struct file *file, char *buf, size_t size) | 569 | static ssize_t sel_write_context(struct file *file, char *buf, size_t size) |
368 | { | 570 | { |
369 | char *canon; | 571 | char *canon = NULL; |
370 | u32 sid, len; | 572 | u32 sid, len; |
371 | ssize_t length; | 573 | ssize_t length; |
372 | 574 | ||
373 | length = task_has_security(current, SECURITY__CHECK_CONTEXT); | 575 | length = task_has_security(current, SECURITY__CHECK_CONTEXT); |
374 | if (length) | 576 | if (length) |
375 | return length; | 577 | goto out; |
376 | 578 | ||
377 | length = security_context_to_sid(buf, size, &sid); | 579 | length = security_context_to_sid(buf, size, &sid); |
378 | if (length < 0) | 580 | if (length) |
379 | return length; | 581 | goto out; |
380 | 582 | ||
381 | length = security_sid_to_context(sid, &canon, &len); | 583 | length = security_sid_to_context(sid, &canon, &len); |
382 | if (length < 0) | 584 | if (length) |
383 | return length; | 585 | goto out; |
384 | 586 | ||
587 | length = -ERANGE; | ||
385 | if (len > SIMPLE_TRANSACTION_LIMIT) { | 588 | if (len > SIMPLE_TRANSACTION_LIMIT) { |
386 | printk(KERN_ERR "SELinux: %s: context size (%u) exceeds " | 589 | printk(KERN_ERR "SELinux: %s: context size (%u) exceeds " |
387 | "payload max\n", __func__, len); | 590 | "payload max\n", __func__, len); |
388 | length = -ERANGE; | ||
389 | goto out; | 591 | goto out; |
390 | } | 592 | } |
391 | 593 | ||
@@ -409,23 +611,28 @@ static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf, | |||
409 | static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf, | 611 | static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf, |
410 | size_t count, loff_t *ppos) | 612 | size_t count, loff_t *ppos) |
411 | { | 613 | { |
412 | char *page; | 614 | char *page = NULL; |
413 | ssize_t length; | 615 | ssize_t length; |
414 | unsigned int new_value; | 616 | unsigned int new_value; |
415 | 617 | ||
416 | length = task_has_security(current, SECURITY__SETCHECKREQPROT); | 618 | length = task_has_security(current, SECURITY__SETCHECKREQPROT); |
417 | if (length) | 619 | if (length) |
418 | return length; | 620 | goto out; |
419 | 621 | ||
622 | length = -ENOMEM; | ||
420 | if (count >= PAGE_SIZE) | 623 | if (count >= PAGE_SIZE) |
421 | return -ENOMEM; | 624 | goto out; |
422 | if (*ppos != 0) { | 625 | |
423 | /* No partial writes. */ | 626 | /* No partial writes. */ |
424 | return -EINVAL; | 627 | length = -EINVAL; |
425 | } | 628 | if (*ppos != 0) |
629 | goto out; | ||
630 | |||
631 | length = -ENOMEM; | ||
426 | page = (char *)get_zeroed_page(GFP_KERNEL); | 632 | page = (char *)get_zeroed_page(GFP_KERNEL); |
427 | if (!page) | 633 | if (!page) |
428 | return -ENOMEM; | 634 | goto out; |
635 | |||
429 | length = -EFAULT; | 636 | length = -EFAULT; |
430 | if (copy_from_user(page, buf, count)) | 637 | if (copy_from_user(page, buf, count)) |
431 | goto out; | 638 | goto out; |
@@ -500,7 +707,7 @@ static const struct file_operations transaction_ops = { | |||
500 | 707 | ||
501 | static ssize_t sel_write_access(struct file *file, char *buf, size_t size) | 708 | static ssize_t sel_write_access(struct file *file, char *buf, size_t size) |
502 | { | 709 | { |
503 | char *scon, *tcon; | 710 | char *scon = NULL, *tcon = NULL; |
504 | u32 ssid, tsid; | 711 | u32 ssid, tsid; |
505 | u16 tclass; | 712 | u16 tclass; |
506 | struct av_decision avd; | 713 | struct av_decision avd; |
@@ -508,27 +715,29 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) | |||
508 | 715 | ||
509 | length = task_has_security(current, SECURITY__COMPUTE_AV); | 716 | length = task_has_security(current, SECURITY__COMPUTE_AV); |
510 | if (length) | 717 | if (length) |
511 | return length; | 718 | goto out; |
512 | 719 | ||
513 | length = -ENOMEM; | 720 | length = -ENOMEM; |
514 | scon = kzalloc(size + 1, GFP_KERNEL); | 721 | scon = kzalloc(size + 1, GFP_KERNEL); |
515 | if (!scon) | 722 | if (!scon) |
516 | return length; | 723 | goto out; |
517 | 724 | ||
725 | length = -ENOMEM; | ||
518 | tcon = kzalloc(size + 1, GFP_KERNEL); | 726 | tcon = kzalloc(size + 1, GFP_KERNEL); |
519 | if (!tcon) | 727 | if (!tcon) |
520 | goto out; | 728 | goto out; |
521 | 729 | ||
522 | length = -EINVAL; | 730 | length = -EINVAL; |
523 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) | 731 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) |
524 | goto out2; | 732 | goto out; |
525 | 733 | ||
526 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); | 734 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); |
527 | if (length < 0) | 735 | if (length) |
528 | goto out2; | 736 | goto out; |
737 | |||
529 | length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); | 738 | length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); |
530 | if (length < 0) | 739 | if (length) |
531 | goto out2; | 740 | goto out; |
532 | 741 | ||
533 | security_compute_av_user(ssid, tsid, tclass, &avd); | 742 | security_compute_av_user(ssid, tsid, tclass, &avd); |
534 | 743 | ||
@@ -537,133 +746,177 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) | |||
537 | avd.allowed, 0xffffffff, | 746 | avd.allowed, 0xffffffff, |
538 | avd.auditallow, avd.auditdeny, | 747 | avd.auditallow, avd.auditdeny, |
539 | avd.seqno, avd.flags); | 748 | avd.seqno, avd.flags); |
540 | out2: | ||
541 | kfree(tcon); | ||
542 | out: | 749 | out: |
750 | kfree(tcon); | ||
543 | kfree(scon); | 751 | kfree(scon); |
544 | return length; | 752 | return length; |
545 | } | 753 | } |
546 | 754 | ||
755 | static inline int hexcode_to_int(int code) { | ||
756 | if (code == '\0' || !isxdigit(code)) | ||
757 | return -1; | ||
758 | if (isdigit(code)) | ||
759 | return code - '0'; | ||
760 | return tolower(code) - 'a' + 10; | ||
761 | } | ||
762 | |||
547 | static ssize_t sel_write_create(struct file *file, char *buf, size_t size) | 763 | static ssize_t sel_write_create(struct file *file, char *buf, size_t size) |
548 | { | 764 | { |
549 | char *scon, *tcon; | 765 | char *scon = NULL, *tcon = NULL; |
766 | char *namebuf = NULL, *objname = NULL; | ||
550 | u32 ssid, tsid, newsid; | 767 | u32 ssid, tsid, newsid; |
551 | u16 tclass; | 768 | u16 tclass; |
552 | ssize_t length; | 769 | ssize_t length; |
553 | char *newcon; | 770 | char *newcon = NULL; |
554 | u32 len; | 771 | u32 len; |
772 | int nargs; | ||
555 | 773 | ||
556 | length = task_has_security(current, SECURITY__COMPUTE_CREATE); | 774 | length = task_has_security(current, SECURITY__COMPUTE_CREATE); |
557 | if (length) | 775 | if (length) |
558 | return length; | 776 | goto out; |
559 | 777 | ||
560 | length = -ENOMEM; | 778 | length = -ENOMEM; |
561 | scon = kzalloc(size + 1, GFP_KERNEL); | 779 | scon = kzalloc(size + 1, GFP_KERNEL); |
562 | if (!scon) | 780 | if (!scon) |
563 | return length; | 781 | goto out; |
564 | 782 | ||
783 | length = -ENOMEM; | ||
565 | tcon = kzalloc(size + 1, GFP_KERNEL); | 784 | tcon = kzalloc(size + 1, GFP_KERNEL); |
566 | if (!tcon) | 785 | if (!tcon) |
567 | goto out; | 786 | goto out; |
568 | 787 | ||
788 | length = -ENOMEM; | ||
789 | namebuf = kzalloc(size + 1, GFP_KERNEL); | ||
790 | if (!namebuf) | ||
791 | goto out; | ||
792 | |||
569 | length = -EINVAL; | 793 | length = -EINVAL; |
570 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) | 794 | nargs = sscanf(buf, "%s %s %hu %s", scon, tcon, &tclass, namebuf); |
571 | goto out2; | 795 | if (nargs < 3 || nargs > 4) |
796 | goto out; | ||
797 | if (nargs == 4) { | ||
798 | /* | ||
799 | * If and when the name of new object to be queried contains | ||
800 | * either whitespace or multibyte characters, they shall be | ||
801 | * encoded based on the percentage-encoding rule. | ||
802 | * If not encoded, the sscanf logic picks up only left-half | ||
803 | * of the supplied name; splitted by a whitespace unexpectedly. | ||
804 | */ | ||
805 | char *r, *w; | ||
806 | int c1, c2; | ||
807 | |||
808 | r = w = namebuf; | ||
809 | do { | ||
810 | c1 = *r++; | ||
811 | if (c1 == '+') | ||
812 | c1 = ' '; | ||
813 | else if (c1 == '%') { | ||
814 | if ((c1 = hexcode_to_int(*r++)) < 0) | ||
815 | goto out; | ||
816 | if ((c2 = hexcode_to_int(*r++)) < 0) | ||
817 | goto out; | ||
818 | c1 = (c1 << 4) | c2; | ||
819 | } | ||
820 | *w++ = c1; | ||
821 | } while (c1 != '\0'); | ||
822 | |||
823 | objname = namebuf; | ||
824 | } | ||
572 | 825 | ||
573 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); | 826 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); |
574 | if (length < 0) | 827 | if (length) |
575 | goto out2; | 828 | goto out; |
829 | |||
576 | length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); | 830 | length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); |
577 | if (length < 0) | 831 | if (length) |
578 | goto out2; | 832 | goto out; |
579 | 833 | ||
580 | length = security_transition_sid_user(ssid, tsid, tclass, &newsid); | 834 | length = security_transition_sid_user(ssid, tsid, tclass, |
581 | if (length < 0) | 835 | objname, &newsid); |
582 | goto out2; | 836 | if (length) |
837 | goto out; | ||
583 | 838 | ||
584 | length = security_sid_to_context(newsid, &newcon, &len); | 839 | length = security_sid_to_context(newsid, &newcon, &len); |
585 | if (length < 0) | 840 | if (length) |
586 | goto out2; | 841 | goto out; |
587 | 842 | ||
843 | length = -ERANGE; | ||
588 | if (len > SIMPLE_TRANSACTION_LIMIT) { | 844 | if (len > SIMPLE_TRANSACTION_LIMIT) { |
589 | printk(KERN_ERR "SELinux: %s: context size (%u) exceeds " | 845 | printk(KERN_ERR "SELinux: %s: context size (%u) exceeds " |
590 | "payload max\n", __func__, len); | 846 | "payload max\n", __func__, len); |
591 | length = -ERANGE; | 847 | goto out; |
592 | goto out3; | ||
593 | } | 848 | } |
594 | 849 | ||
595 | memcpy(buf, newcon, len); | 850 | memcpy(buf, newcon, len); |
596 | length = len; | 851 | length = len; |
597 | out3: | 852 | out: |
598 | kfree(newcon); | 853 | kfree(newcon); |
599 | out2: | 854 | kfree(namebuf); |
600 | kfree(tcon); | 855 | kfree(tcon); |
601 | out: | ||
602 | kfree(scon); | 856 | kfree(scon); |
603 | return length; | 857 | return length; |
604 | } | 858 | } |
605 | 859 | ||
606 | static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size) | 860 | static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size) |
607 | { | 861 | { |
608 | char *scon, *tcon; | 862 | char *scon = NULL, *tcon = NULL; |
609 | u32 ssid, tsid, newsid; | 863 | u32 ssid, tsid, newsid; |
610 | u16 tclass; | 864 | u16 tclass; |
611 | ssize_t length; | 865 | ssize_t length; |
612 | char *newcon; | 866 | char *newcon = NULL; |
613 | u32 len; | 867 | u32 len; |
614 | 868 | ||
615 | length = task_has_security(current, SECURITY__COMPUTE_RELABEL); | 869 | length = task_has_security(current, SECURITY__COMPUTE_RELABEL); |
616 | if (length) | 870 | if (length) |
617 | return length; | 871 | goto out; |
618 | 872 | ||
619 | length = -ENOMEM; | 873 | length = -ENOMEM; |
620 | scon = kzalloc(size + 1, GFP_KERNEL); | 874 | scon = kzalloc(size + 1, GFP_KERNEL); |
621 | if (!scon) | 875 | if (!scon) |
622 | return length; | 876 | goto out; |
623 | 877 | ||
878 | length = -ENOMEM; | ||
624 | tcon = kzalloc(size + 1, GFP_KERNEL); | 879 | tcon = kzalloc(size + 1, GFP_KERNEL); |
625 | if (!tcon) | 880 | if (!tcon) |
626 | goto out; | 881 | goto out; |
627 | 882 | ||
628 | length = -EINVAL; | 883 | length = -EINVAL; |
629 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) | 884 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) |
630 | goto out2; | 885 | goto out; |
631 | 886 | ||
632 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); | 887 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); |
633 | if (length < 0) | 888 | if (length) |
634 | goto out2; | 889 | goto out; |
890 | |||
635 | length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); | 891 | length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); |
636 | if (length < 0) | 892 | if (length) |
637 | goto out2; | 893 | goto out; |
638 | 894 | ||
639 | length = security_change_sid(ssid, tsid, tclass, &newsid); | 895 | length = security_change_sid(ssid, tsid, tclass, &newsid); |
640 | if (length < 0) | 896 | if (length) |
641 | goto out2; | 897 | goto out; |
642 | 898 | ||
643 | length = security_sid_to_context(newsid, &newcon, &len); | 899 | length = security_sid_to_context(newsid, &newcon, &len); |
644 | if (length < 0) | 900 | if (length) |
645 | goto out2; | 901 | goto out; |
646 | 902 | ||
647 | if (len > SIMPLE_TRANSACTION_LIMIT) { | 903 | length = -ERANGE; |
648 | length = -ERANGE; | 904 | if (len > SIMPLE_TRANSACTION_LIMIT) |
649 | goto out3; | 905 | goto out; |
650 | } | ||
651 | 906 | ||
652 | memcpy(buf, newcon, len); | 907 | memcpy(buf, newcon, len); |
653 | length = len; | 908 | length = len; |
654 | out3: | 909 | out: |
655 | kfree(newcon); | 910 | kfree(newcon); |
656 | out2: | ||
657 | kfree(tcon); | 911 | kfree(tcon); |
658 | out: | ||
659 | kfree(scon); | 912 | kfree(scon); |
660 | return length; | 913 | return length; |
661 | } | 914 | } |
662 | 915 | ||
663 | static ssize_t sel_write_user(struct file *file, char *buf, size_t size) | 916 | static ssize_t sel_write_user(struct file *file, char *buf, size_t size) |
664 | { | 917 | { |
665 | char *con, *user, *ptr; | 918 | char *con = NULL, *user = NULL, *ptr; |
666 | u32 sid, *sids; | 919 | u32 sid, *sids = NULL; |
667 | ssize_t length; | 920 | ssize_t length; |
668 | char *newcon; | 921 | char *newcon; |
669 | int i, rc; | 922 | int i, rc; |
@@ -671,28 +924,29 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size) | |||
671 | 924 | ||
672 | length = task_has_security(current, SECURITY__COMPUTE_USER); | 925 | length = task_has_security(current, SECURITY__COMPUTE_USER); |
673 | if (length) | 926 | if (length) |
674 | return length; | 927 | goto out; |
675 | 928 | ||
676 | length = -ENOMEM; | 929 | length = -ENOMEM; |
677 | con = kzalloc(size + 1, GFP_KERNEL); | 930 | con = kzalloc(size + 1, GFP_KERNEL); |
678 | if (!con) | 931 | if (!con) |
679 | return length; | 932 | goto out; |
680 | 933 | ||
934 | length = -ENOMEM; | ||
681 | user = kzalloc(size + 1, GFP_KERNEL); | 935 | user = kzalloc(size + 1, GFP_KERNEL); |
682 | if (!user) | 936 | if (!user) |
683 | goto out; | 937 | goto out; |
684 | 938 | ||
685 | length = -EINVAL; | 939 | length = -EINVAL; |
686 | if (sscanf(buf, "%s %s", con, user) != 2) | 940 | if (sscanf(buf, "%s %s", con, user) != 2) |
687 | goto out2; | 941 | goto out; |
688 | 942 | ||
689 | length = security_context_to_sid(con, strlen(con) + 1, &sid); | 943 | length = security_context_to_sid(con, strlen(con) + 1, &sid); |
690 | if (length < 0) | 944 | if (length) |
691 | goto out2; | 945 | goto out; |
692 | 946 | ||
693 | length = security_get_user_sids(sid, user, &sids, &nsids); | 947 | length = security_get_user_sids(sid, user, &sids, &nsids); |
694 | if (length < 0) | 948 | if (length) |
695 | goto out2; | 949 | goto out; |
696 | 950 | ||
697 | length = sprintf(buf, "%u", nsids) + 1; | 951 | length = sprintf(buf, "%u", nsids) + 1; |
698 | ptr = buf + length; | 952 | ptr = buf + length; |
@@ -700,82 +954,80 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size) | |||
700 | rc = security_sid_to_context(sids[i], &newcon, &len); | 954 | rc = security_sid_to_context(sids[i], &newcon, &len); |
701 | if (rc) { | 955 | if (rc) { |
702 | length = rc; | 956 | length = rc; |
703 | goto out3; | 957 | goto out; |
704 | } | 958 | } |
705 | if ((length + len) >= SIMPLE_TRANSACTION_LIMIT) { | 959 | if ((length + len) >= SIMPLE_TRANSACTION_LIMIT) { |
706 | kfree(newcon); | 960 | kfree(newcon); |
707 | length = -ERANGE; | 961 | length = -ERANGE; |
708 | goto out3; | 962 | goto out; |
709 | } | 963 | } |
710 | memcpy(ptr, newcon, len); | 964 | memcpy(ptr, newcon, len); |
711 | kfree(newcon); | 965 | kfree(newcon); |
712 | ptr += len; | 966 | ptr += len; |
713 | length += len; | 967 | length += len; |
714 | } | 968 | } |
715 | out3: | 969 | out: |
716 | kfree(sids); | 970 | kfree(sids); |
717 | out2: | ||
718 | kfree(user); | 971 | kfree(user); |
719 | out: | ||
720 | kfree(con); | 972 | kfree(con); |
721 | return length; | 973 | return length; |
722 | } | 974 | } |
723 | 975 | ||
724 | static ssize_t sel_write_member(struct file *file, char *buf, size_t size) | 976 | static ssize_t sel_write_member(struct file *file, char *buf, size_t size) |
725 | { | 977 | { |
726 | char *scon, *tcon; | 978 | char *scon = NULL, *tcon = NULL; |
727 | u32 ssid, tsid, newsid; | 979 | u32 ssid, tsid, newsid; |
728 | u16 tclass; | 980 | u16 tclass; |
729 | ssize_t length; | 981 | ssize_t length; |
730 | char *newcon; | 982 | char *newcon = NULL; |
731 | u32 len; | 983 | u32 len; |
732 | 984 | ||
733 | length = task_has_security(current, SECURITY__COMPUTE_MEMBER); | 985 | length = task_has_security(current, SECURITY__COMPUTE_MEMBER); |
734 | if (length) | 986 | if (length) |
735 | return length; | 987 | goto out; |
736 | 988 | ||
737 | length = -ENOMEM; | 989 | length = -ENOMEM; |
738 | scon = kzalloc(size + 1, GFP_KERNEL); | 990 | scon = kzalloc(size + 1, GFP_KERNEL); |
739 | if (!scon) | 991 | if (!scon) |
740 | return length; | 992 | goto out; |
741 | 993 | ||
994 | length = -ENOMEM; | ||
742 | tcon = kzalloc(size + 1, GFP_KERNEL); | 995 | tcon = kzalloc(size + 1, GFP_KERNEL); |
743 | if (!tcon) | 996 | if (!tcon) |
744 | goto out; | 997 | goto out; |
745 | 998 | ||
746 | length = -EINVAL; | 999 | length = -EINVAL; |
747 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) | 1000 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) |
748 | goto out2; | 1001 | goto out; |
749 | 1002 | ||
750 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); | 1003 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); |
751 | if (length < 0) | 1004 | if (length) |
752 | goto out2; | 1005 | goto out; |
1006 | |||
753 | length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); | 1007 | length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); |
754 | if (length < 0) | 1008 | if (length) |
755 | goto out2; | 1009 | goto out; |
756 | 1010 | ||
757 | length = security_member_sid(ssid, tsid, tclass, &newsid); | 1011 | length = security_member_sid(ssid, tsid, tclass, &newsid); |
758 | if (length < 0) | 1012 | if (length) |
759 | goto out2; | 1013 | goto out; |
760 | 1014 | ||
761 | length = security_sid_to_context(newsid, &newcon, &len); | 1015 | length = security_sid_to_context(newsid, &newcon, &len); |
762 | if (length < 0) | 1016 | if (length) |
763 | goto out2; | 1017 | goto out; |
764 | 1018 | ||
1019 | length = -ERANGE; | ||
765 | if (len > SIMPLE_TRANSACTION_LIMIT) { | 1020 | if (len > SIMPLE_TRANSACTION_LIMIT) { |
766 | printk(KERN_ERR "SELinux: %s: context size (%u) exceeds " | 1021 | printk(KERN_ERR "SELinux: %s: context size (%u) exceeds " |
767 | "payload max\n", __func__, len); | 1022 | "payload max\n", __func__, len); |
768 | length = -ERANGE; | 1023 | goto out; |
769 | goto out3; | ||
770 | } | 1024 | } |
771 | 1025 | ||
772 | memcpy(buf, newcon, len); | 1026 | memcpy(buf, newcon, len); |
773 | length = len; | 1027 | length = len; |
774 | out3: | 1028 | out: |
775 | kfree(newcon); | 1029 | kfree(newcon); |
776 | out2: | ||
777 | kfree(tcon); | 1030 | kfree(tcon); |
778 | out: | ||
779 | kfree(scon); | 1031 | kfree(scon); |
780 | return length; | 1032 | return length; |
781 | } | 1033 | } |
@@ -804,16 +1056,14 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, | |||
804 | 1056 | ||
805 | mutex_lock(&sel_mutex); | 1057 | mutex_lock(&sel_mutex); |
806 | 1058 | ||
807 | if (index >= bool_num || strcmp(name, bool_pending_names[index])) { | 1059 | ret = -EINVAL; |
808 | ret = -EINVAL; | 1060 | if (index >= bool_num || strcmp(name, bool_pending_names[index])) |
809 | goto out; | 1061 | goto out; |
810 | } | ||
811 | 1062 | ||
1063 | ret = -ENOMEM; | ||
812 | page = (char *)get_zeroed_page(GFP_KERNEL); | 1064 | page = (char *)get_zeroed_page(GFP_KERNEL); |
813 | if (!page) { | 1065 | if (!page) |
814 | ret = -ENOMEM; | ||
815 | goto out; | 1066 | goto out; |
816 | } | ||
817 | 1067 | ||
818 | cur_enforcing = security_get_bool_value(index); | 1068 | cur_enforcing = security_get_bool_value(index); |
819 | if (cur_enforcing < 0) { | 1069 | if (cur_enforcing < 0) { |
@@ -825,8 +1075,7 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, | |||
825 | ret = simple_read_from_buffer(buf, count, ppos, page, length); | 1075 | ret = simple_read_from_buffer(buf, count, ppos, page, length); |
826 | out: | 1076 | out: |
827 | mutex_unlock(&sel_mutex); | 1077 | mutex_unlock(&sel_mutex); |
828 | if (page) | 1078 | free_page((unsigned long)page); |
829 | free_page((unsigned long)page); | ||
830 | return ret; | 1079 | return ret; |
831 | } | 1080 | } |
832 | 1081 | ||
@@ -846,26 +1095,23 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, | |||
846 | if (length) | 1095 | if (length) |
847 | goto out; | 1096 | goto out; |
848 | 1097 | ||
849 | if (index >= bool_num || strcmp(name, bool_pending_names[index])) { | 1098 | length = -EINVAL; |
850 | length = -EINVAL; | 1099 | if (index >= bool_num || strcmp(name, bool_pending_names[index])) |
851 | goto out; | 1100 | goto out; |
852 | } | ||
853 | 1101 | ||
854 | if (count >= PAGE_SIZE) { | 1102 | length = -ENOMEM; |
855 | length = -ENOMEM; | 1103 | if (count >= PAGE_SIZE) |
856 | goto out; | 1104 | goto out; |
857 | } | ||
858 | 1105 | ||
859 | if (*ppos != 0) { | 1106 | /* No partial writes. */ |
860 | /* No partial writes. */ | 1107 | length = -EINVAL; |
861 | length = -EINVAL; | 1108 | if (*ppos != 0) |
862 | goto out; | 1109 | goto out; |
863 | } | 1110 | |
1111 | length = -ENOMEM; | ||
864 | page = (char *)get_zeroed_page(GFP_KERNEL); | 1112 | page = (char *)get_zeroed_page(GFP_KERNEL); |
865 | if (!page) { | 1113 | if (!page) |
866 | length = -ENOMEM; | ||
867 | goto out; | 1114 | goto out; |
868 | } | ||
869 | 1115 | ||
870 | length = -EFAULT; | 1116 | length = -EFAULT; |
871 | if (copy_from_user(page, buf, count)) | 1117 | if (copy_from_user(page, buf, count)) |
@@ -883,8 +1129,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, | |||
883 | 1129 | ||
884 | out: | 1130 | out: |
885 | mutex_unlock(&sel_mutex); | 1131 | mutex_unlock(&sel_mutex); |
886 | if (page) | 1132 | free_page((unsigned long) page); |
887 | free_page((unsigned long) page); | ||
888 | return length; | 1133 | return length; |
889 | } | 1134 | } |
890 | 1135 | ||
@@ -908,19 +1153,19 @@ static ssize_t sel_commit_bools_write(struct file *filep, | |||
908 | if (length) | 1153 | if (length) |
909 | goto out; | 1154 | goto out; |
910 | 1155 | ||
911 | if (count >= PAGE_SIZE) { | 1156 | length = -ENOMEM; |
912 | length = -ENOMEM; | 1157 | if (count >= PAGE_SIZE) |
913 | goto out; | 1158 | goto out; |
914 | } | 1159 | |
915 | if (*ppos != 0) { | 1160 | /* No partial writes. */ |
916 | /* No partial writes. */ | 1161 | length = -EINVAL; |
1162 | if (*ppos != 0) | ||
917 | goto out; | 1163 | goto out; |
918 | } | 1164 | |
1165 | length = -ENOMEM; | ||
919 | page = (char *)get_zeroed_page(GFP_KERNEL); | 1166 | page = (char *)get_zeroed_page(GFP_KERNEL); |
920 | if (!page) { | 1167 | if (!page) |
921 | length = -ENOMEM; | ||
922 | goto out; | 1168 | goto out; |
923 | } | ||
924 | 1169 | ||
925 | length = -EFAULT; | 1170 | length = -EFAULT; |
926 | if (copy_from_user(page, buf, count)) | 1171 | if (copy_from_user(page, buf, count)) |
@@ -930,15 +1175,16 @@ static ssize_t sel_commit_bools_write(struct file *filep, | |||
930 | if (sscanf(page, "%d", &new_value) != 1) | 1175 | if (sscanf(page, "%d", &new_value) != 1) |
931 | goto out; | 1176 | goto out; |
932 | 1177 | ||
1178 | length = 0; | ||
933 | if (new_value && bool_pending_values) | 1179 | if (new_value && bool_pending_values) |
934 | security_set_bools(bool_num, bool_pending_values); | 1180 | length = security_set_bools(bool_num, bool_pending_values); |
935 | 1181 | ||
936 | length = count; | 1182 | if (!length) |
1183 | length = count; | ||
937 | 1184 | ||
938 | out: | 1185 | out: |
939 | mutex_unlock(&sel_mutex); | 1186 | mutex_unlock(&sel_mutex); |
940 | if (page) | 1187 | free_page((unsigned long) page); |
941 | free_page((unsigned long) page); | ||
942 | return length; | 1188 | return length; |
943 | } | 1189 | } |
944 | 1190 | ||
@@ -951,31 +1197,35 @@ static void sel_remove_entries(struct dentry *de) | |||
951 | { | 1197 | { |
952 | struct list_head *node; | 1198 | struct list_head *node; |
953 | 1199 | ||
954 | spin_lock(&dcache_lock); | 1200 | spin_lock(&de->d_lock); |
955 | node = de->d_subdirs.next; | 1201 | node = de->d_subdirs.next; |
956 | while (node != &de->d_subdirs) { | 1202 | while (node != &de->d_subdirs) { |
957 | struct dentry *d = list_entry(node, struct dentry, d_u.d_child); | 1203 | struct dentry *d = list_entry(node, struct dentry, d_u.d_child); |
1204 | |||
1205 | spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED); | ||
958 | list_del_init(node); | 1206 | list_del_init(node); |
959 | 1207 | ||
960 | if (d->d_inode) { | 1208 | if (d->d_inode) { |
961 | d = dget_locked(d); | 1209 | dget_dlock(d); |
962 | spin_unlock(&dcache_lock); | 1210 | spin_unlock(&de->d_lock); |
1211 | spin_unlock(&d->d_lock); | ||
963 | d_delete(d); | 1212 | d_delete(d); |
964 | simple_unlink(de->d_inode, d); | 1213 | simple_unlink(de->d_inode, d); |
965 | dput(d); | 1214 | dput(d); |
966 | spin_lock(&dcache_lock); | 1215 | spin_lock(&de->d_lock); |
967 | } | 1216 | } else |
1217 | spin_unlock(&d->d_lock); | ||
968 | node = de->d_subdirs.next; | 1218 | node = de->d_subdirs.next; |
969 | } | 1219 | } |
970 | 1220 | ||
971 | spin_unlock(&dcache_lock); | 1221 | spin_unlock(&de->d_lock); |
972 | } | 1222 | } |
973 | 1223 | ||
974 | #define BOOL_DIR_NAME "booleans" | 1224 | #define BOOL_DIR_NAME "booleans" |
975 | 1225 | ||
976 | static int sel_make_bools(void) | 1226 | static int sel_make_bools(void) |
977 | { | 1227 | { |
978 | int i, ret = 0; | 1228 | int i, ret; |
979 | ssize_t len; | 1229 | ssize_t len; |
980 | struct dentry *dentry = NULL; | 1230 | struct dentry *dentry = NULL; |
981 | struct dentry *dir = bool_dir; | 1231 | struct dentry *dir = bool_dir; |
@@ -996,38 +1246,40 @@ static int sel_make_bools(void) | |||
996 | 1246 | ||
997 | sel_remove_entries(dir); | 1247 | sel_remove_entries(dir); |
998 | 1248 | ||
1249 | ret = -ENOMEM; | ||
999 | page = (char *)get_zeroed_page(GFP_KERNEL); | 1250 | page = (char *)get_zeroed_page(GFP_KERNEL); |
1000 | if (!page) | 1251 | if (!page) |
1001 | return -ENOMEM; | 1252 | goto out; |
1002 | 1253 | ||
1003 | ret = security_get_bools(&num, &names, &values); | 1254 | ret = security_get_bools(&num, &names, &values); |
1004 | if (ret != 0) | 1255 | if (ret) |
1005 | goto out; | 1256 | goto out; |
1006 | 1257 | ||
1007 | for (i = 0; i < num; i++) { | 1258 | for (i = 0; i < num; i++) { |
1259 | ret = -ENOMEM; | ||
1008 | dentry = d_alloc_name(dir, names[i]); | 1260 | dentry = d_alloc_name(dir, names[i]); |
1009 | if (!dentry) { | 1261 | if (!dentry) |
1010 | ret = -ENOMEM; | 1262 | goto out; |
1011 | goto err; | 1263 | |
1012 | } | 1264 | ret = -ENOMEM; |
1013 | inode = sel_make_inode(dir->d_sb, S_IFREG | S_IRUGO | S_IWUSR); | 1265 | inode = sel_make_inode(dir->d_sb, S_IFREG | S_IRUGO | S_IWUSR); |
1014 | if (!inode) { | 1266 | if (!inode) |
1015 | ret = -ENOMEM; | 1267 | goto out; |
1016 | goto err; | ||
1017 | } | ||
1018 | 1268 | ||
1269 | ret = -EINVAL; | ||
1019 | len = snprintf(page, PAGE_SIZE, "/%s/%s", BOOL_DIR_NAME, names[i]); | 1270 | len = snprintf(page, PAGE_SIZE, "/%s/%s", BOOL_DIR_NAME, names[i]); |
1020 | if (len < 0) { | 1271 | if (len < 0) |
1021 | ret = -EINVAL; | 1272 | goto out; |
1022 | goto err; | 1273 | |
1023 | } else if (len >= PAGE_SIZE) { | 1274 | ret = -ENAMETOOLONG; |
1024 | ret = -ENAMETOOLONG; | 1275 | if (len >= PAGE_SIZE) |
1025 | goto err; | 1276 | goto out; |
1026 | } | 1277 | |
1027 | isec = (struct inode_security_struct *)inode->i_security; | 1278 | isec = (struct inode_security_struct *)inode->i_security; |
1028 | ret = security_genfs_sid("selinuxfs", page, SECCLASS_FILE, &sid); | 1279 | ret = security_genfs_sid("selinuxfs", page, SECCLASS_FILE, &sid); |
1029 | if (ret) | 1280 | if (ret) |
1030 | goto err; | 1281 | goto out; |
1282 | |||
1031 | isec->sid = sid; | 1283 | isec->sid = sid; |
1032 | isec->initialized = 1; | 1284 | isec->initialized = 1; |
1033 | inode->i_fop = &sel_bool_ops; | 1285 | inode->i_fop = &sel_bool_ops; |
@@ -1037,10 +1289,12 @@ static int sel_make_bools(void) | |||
1037 | bool_num = num; | 1289 | bool_num = num; |
1038 | bool_pending_names = names; | 1290 | bool_pending_names = names; |
1039 | bool_pending_values = values; | 1291 | bool_pending_values = values; |
1292 | |||
1293 | free_page((unsigned long)page); | ||
1294 | return 0; | ||
1040 | out: | 1295 | out: |
1041 | free_page((unsigned long)page); | 1296 | free_page((unsigned long)page); |
1042 | return ret; | 1297 | |
1043 | err: | ||
1044 | if (names) { | 1298 | if (names) { |
1045 | for (i = 0; i < num; i++) | 1299 | for (i = 0; i < num; i++) |
1046 | kfree(names[i]); | 1300 | kfree(names[i]); |
@@ -1048,8 +1302,8 @@ err: | |||
1048 | } | 1302 | } |
1049 | kfree(values); | 1303 | kfree(values); |
1050 | sel_remove_entries(dir); | 1304 | sel_remove_entries(dir); |
1051 | ret = -ENOMEM; | 1305 | |
1052 | goto out; | 1306 | return ret; |
1053 | } | 1307 | } |
1054 | 1308 | ||
1055 | #define NULL_FILE_NAME "null" | 1309 | #define NULL_FILE_NAME "null" |
@@ -1071,47 +1325,41 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file, | |||
1071 | size_t count, loff_t *ppos) | 1325 | size_t count, loff_t *ppos) |
1072 | 1326 | ||
1073 | { | 1327 | { |
1074 | char *page; | 1328 | char *page = NULL; |
1075 | ssize_t ret; | 1329 | ssize_t ret; |
1076 | int new_value; | 1330 | int new_value; |
1077 | 1331 | ||
1078 | if (count >= PAGE_SIZE) { | 1332 | ret = task_has_security(current, SECURITY__SETSECPARAM); |
1079 | ret = -ENOMEM; | 1333 | if (ret) |
1080 | goto out; | 1334 | goto out; |
1081 | } | ||
1082 | 1335 | ||
1083 | if (*ppos != 0) { | 1336 | ret = -ENOMEM; |
1084 | /* No partial writes. */ | 1337 | if (count >= PAGE_SIZE) |
1085 | ret = -EINVAL; | 1338 | goto out; |
1339 | |||
1340 | /* No partial writes. */ | ||
1341 | ret = -EINVAL; | ||
1342 | if (*ppos != 0) | ||
1086 | goto out; | 1343 | goto out; |
1087 | } | ||
1088 | 1344 | ||
1345 | ret = -ENOMEM; | ||
1089 | page = (char *)get_zeroed_page(GFP_KERNEL); | 1346 | page = (char *)get_zeroed_page(GFP_KERNEL); |
1090 | if (!page) { | 1347 | if (!page) |
1091 | ret = -ENOMEM; | ||
1092 | goto out; | 1348 | goto out; |
1093 | } | ||
1094 | 1349 | ||
1095 | if (copy_from_user(page, buf, count)) { | 1350 | ret = -EFAULT; |
1096 | ret = -EFAULT; | 1351 | if (copy_from_user(page, buf, count)) |
1097 | goto out_free; | 1352 | goto out; |
1098 | } | ||
1099 | 1353 | ||
1100 | if (sscanf(page, "%u", &new_value) != 1) { | 1354 | ret = -EINVAL; |
1101 | ret = -EINVAL; | 1355 | if (sscanf(page, "%u", &new_value) != 1) |
1102 | goto out; | 1356 | goto out; |
1103 | } | ||
1104 | 1357 | ||
1105 | if (new_value != avc_cache_threshold) { | 1358 | avc_cache_threshold = new_value; |
1106 | ret = task_has_security(current, SECURITY__SETSECPARAM); | 1359 | |
1107 | if (ret) | ||
1108 | goto out_free; | ||
1109 | avc_cache_threshold = new_value; | ||
1110 | } | ||
1111 | ret = count; | 1360 | ret = count; |
1112 | out_free: | ||
1113 | free_page((unsigned long)page); | ||
1114 | out: | 1361 | out: |
1362 | free_page((unsigned long)page); | ||
1115 | return ret; | 1363 | return ret; |
1116 | } | 1364 | } |
1117 | 1365 | ||
@@ -1119,19 +1367,18 @@ static ssize_t sel_read_avc_hash_stats(struct file *filp, char __user *buf, | |||
1119 | size_t count, loff_t *ppos) | 1367 | size_t count, loff_t *ppos) |
1120 | { | 1368 | { |
1121 | char *page; | 1369 | char *page; |
1122 | ssize_t ret = 0; | 1370 | ssize_t length; |
1123 | 1371 | ||
1124 | page = (char *)__get_free_page(GFP_KERNEL); | 1372 | page = (char *)__get_free_page(GFP_KERNEL); |
1125 | if (!page) { | 1373 | if (!page) |
1126 | ret = -ENOMEM; | 1374 | return -ENOMEM; |
1127 | goto out; | 1375 | |
1128 | } | 1376 | length = avc_get_hash_stats(page); |
1129 | ret = avc_get_hash_stats(page); | 1377 | if (length >= 0) |
1130 | if (ret >= 0) | 1378 | length = simple_read_from_buffer(buf, count, ppos, page, length); |
1131 | ret = simple_read_from_buffer(buf, count, ppos, page, ret); | ||
1132 | free_page((unsigned long)page); | 1379 | free_page((unsigned long)page); |
1133 | out: | 1380 | |
1134 | return ret; | 1381 | return length; |
1135 | } | 1382 | } |
1136 | 1383 | ||
1137 | static const struct file_operations sel_avc_cache_threshold_ops = { | 1384 | static const struct file_operations sel_avc_cache_threshold_ops = { |
@@ -1181,10 +1428,14 @@ static int sel_avc_stats_seq_show(struct seq_file *seq, void *v) | |||
1181 | if (v == SEQ_START_TOKEN) | 1428 | if (v == SEQ_START_TOKEN) |
1182 | seq_printf(seq, "lookups hits misses allocations reclaims " | 1429 | seq_printf(seq, "lookups hits misses allocations reclaims " |
1183 | "frees\n"); | 1430 | "frees\n"); |
1184 | else | 1431 | else { |
1185 | seq_printf(seq, "%u %u %u %u %u %u\n", st->lookups, | 1432 | unsigned int lookups = st->lookups; |
1186 | st->hits, st->misses, st->allocations, | 1433 | unsigned int misses = st->misses; |
1434 | unsigned int hits = lookups - misses; | ||
1435 | seq_printf(seq, "%u %u %u %u %u %u\n", lookups, | ||
1436 | hits, misses, st->allocations, | ||
1187 | st->reclaims, st->frees); | 1437 | st->reclaims, st->frees); |
1438 | } | ||
1188 | return 0; | 1439 | return 0; |
1189 | } | 1440 | } |
1190 | 1441 | ||
@@ -1213,7 +1464,7 @@ static const struct file_operations sel_avc_cache_stats_ops = { | |||
1213 | 1464 | ||
1214 | static int sel_make_avc_files(struct dentry *dir) | 1465 | static int sel_make_avc_files(struct dentry *dir) |
1215 | { | 1466 | { |
1216 | int i, ret = 0; | 1467 | int i; |
1217 | static struct tree_descr files[] = { | 1468 | static struct tree_descr files[] = { |
1218 | { "cache_threshold", | 1469 | { "cache_threshold", |
1219 | &sel_avc_cache_threshold_ops, S_IRUGO|S_IWUSR }, | 1470 | &sel_avc_cache_threshold_ops, S_IRUGO|S_IWUSR }, |
@@ -1228,22 +1479,19 @@ static int sel_make_avc_files(struct dentry *dir) | |||
1228 | struct dentry *dentry; | 1479 | struct dentry *dentry; |
1229 | 1480 | ||
1230 | dentry = d_alloc_name(dir, files[i].name); | 1481 | dentry = d_alloc_name(dir, files[i].name); |
1231 | if (!dentry) { | 1482 | if (!dentry) |
1232 | ret = -ENOMEM; | 1483 | return -ENOMEM; |
1233 | goto out; | ||
1234 | } | ||
1235 | 1484 | ||
1236 | inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode); | 1485 | inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode); |
1237 | if (!inode) { | 1486 | if (!inode) |
1238 | ret = -ENOMEM; | 1487 | return -ENOMEM; |
1239 | goto out; | 1488 | |
1240 | } | ||
1241 | inode->i_fop = files[i].ops; | 1489 | inode->i_fop = files[i].ops; |
1242 | inode->i_ino = ++sel_last_ino; | 1490 | inode->i_ino = ++sel_last_ino; |
1243 | d_add(dentry, inode); | 1491 | d_add(dentry, inode); |
1244 | } | 1492 | } |
1245 | out: | 1493 | |
1246 | return ret; | 1494 | return 0; |
1247 | } | 1495 | } |
1248 | 1496 | ||
1249 | static ssize_t sel_read_initcon(struct file *file, char __user *buf, | 1497 | static ssize_t sel_read_initcon(struct file *file, char __user *buf, |
@@ -1257,7 +1505,7 @@ static ssize_t sel_read_initcon(struct file *file, char __user *buf, | |||
1257 | inode = file->f_path.dentry->d_inode; | 1505 | inode = file->f_path.dentry->d_inode; |
1258 | sid = inode->i_ino&SEL_INO_MASK; | 1506 | sid = inode->i_ino&SEL_INO_MASK; |
1259 | ret = security_sid_to_context(sid, &con, &len); | 1507 | ret = security_sid_to_context(sid, &con, &len); |
1260 | if (ret < 0) | 1508 | if (ret) |
1261 | return ret; | 1509 | return ret; |
1262 | 1510 | ||
1263 | ret = simple_read_from_buffer(buf, count, ppos, con, len); | 1511 | ret = simple_read_from_buffer(buf, count, ppos, con, len); |
@@ -1272,28 +1520,25 @@ static const struct file_operations sel_initcon_ops = { | |||
1272 | 1520 | ||
1273 | static int sel_make_initcon_files(struct dentry *dir) | 1521 | static int sel_make_initcon_files(struct dentry *dir) |
1274 | { | 1522 | { |
1275 | int i, ret = 0; | 1523 | int i; |
1276 | 1524 | ||
1277 | for (i = 1; i <= SECINITSID_NUM; i++) { | 1525 | for (i = 1; i <= SECINITSID_NUM; i++) { |
1278 | struct inode *inode; | 1526 | struct inode *inode; |
1279 | struct dentry *dentry; | 1527 | struct dentry *dentry; |
1280 | dentry = d_alloc_name(dir, security_get_initial_sid_context(i)); | 1528 | dentry = d_alloc_name(dir, security_get_initial_sid_context(i)); |
1281 | if (!dentry) { | 1529 | if (!dentry) |
1282 | ret = -ENOMEM; | 1530 | return -ENOMEM; |
1283 | goto out; | ||
1284 | } | ||
1285 | 1531 | ||
1286 | inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO); | 1532 | inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO); |
1287 | if (!inode) { | 1533 | if (!inode) |
1288 | ret = -ENOMEM; | 1534 | return -ENOMEM; |
1289 | goto out; | 1535 | |
1290 | } | ||
1291 | inode->i_fop = &sel_initcon_ops; | 1536 | inode->i_fop = &sel_initcon_ops; |
1292 | inode->i_ino = i|SEL_INITCON_INO_OFFSET; | 1537 | inode->i_ino = i|SEL_INITCON_INO_OFFSET; |
1293 | d_add(dentry, inode); | 1538 | d_add(dentry, inode); |
1294 | } | 1539 | } |
1295 | out: | 1540 | |
1296 | return ret; | 1541 | return 0; |
1297 | } | 1542 | } |
1298 | 1543 | ||
1299 | static inline unsigned int sel_div(unsigned long a, unsigned long b) | 1544 | static inline unsigned int sel_div(unsigned long a, unsigned long b) |
@@ -1329,15 +1574,13 @@ static ssize_t sel_read_class(struct file *file, char __user *buf, | |||
1329 | unsigned long ino = file->f_path.dentry->d_inode->i_ino; | 1574 | unsigned long ino = file->f_path.dentry->d_inode->i_ino; |
1330 | 1575 | ||
1331 | page = (char *)__get_free_page(GFP_KERNEL); | 1576 | page = (char *)__get_free_page(GFP_KERNEL); |
1332 | if (!page) { | 1577 | if (!page) |
1333 | rc = -ENOMEM; | 1578 | return -ENOMEM; |
1334 | goto out; | ||
1335 | } | ||
1336 | 1579 | ||
1337 | len = snprintf(page, PAGE_SIZE, "%d", sel_ino_to_class(ino)); | 1580 | len = snprintf(page, PAGE_SIZE, "%d", sel_ino_to_class(ino)); |
1338 | rc = simple_read_from_buffer(buf, count, ppos, page, len); | 1581 | rc = simple_read_from_buffer(buf, count, ppos, page, len); |
1339 | free_page((unsigned long)page); | 1582 | free_page((unsigned long)page); |
1340 | out: | 1583 | |
1341 | return rc; | 1584 | return rc; |
1342 | } | 1585 | } |
1343 | 1586 | ||
@@ -1354,15 +1597,13 @@ static ssize_t sel_read_perm(struct file *file, char __user *buf, | |||
1354 | unsigned long ino = file->f_path.dentry->d_inode->i_ino; | 1597 | unsigned long ino = file->f_path.dentry->d_inode->i_ino; |
1355 | 1598 | ||
1356 | page = (char *)__get_free_page(GFP_KERNEL); | 1599 | page = (char *)__get_free_page(GFP_KERNEL); |
1357 | if (!page) { | 1600 | if (!page) |
1358 | rc = -ENOMEM; | 1601 | return -ENOMEM; |
1359 | goto out; | ||
1360 | } | ||
1361 | 1602 | ||
1362 | len = snprintf(page, PAGE_SIZE, "%d", sel_ino_to_perm(ino)); | 1603 | len = snprintf(page, PAGE_SIZE, "%d", sel_ino_to_perm(ino)); |
1363 | rc = simple_read_from_buffer(buf, count, ppos, page, len); | 1604 | rc = simple_read_from_buffer(buf, count, ppos, page, len); |
1364 | free_page((unsigned long)page); | 1605 | free_page((unsigned long)page); |
1365 | out: | 1606 | |
1366 | return rc; | 1607 | return rc; |
1367 | } | 1608 | } |
1368 | 1609 | ||
@@ -1393,39 +1634,37 @@ static const struct file_operations sel_policycap_ops = { | |||
1393 | static int sel_make_perm_files(char *objclass, int classvalue, | 1634 | static int sel_make_perm_files(char *objclass, int classvalue, |
1394 | struct dentry *dir) | 1635 | struct dentry *dir) |
1395 | { | 1636 | { |
1396 | int i, rc = 0, nperms; | 1637 | int i, rc, nperms; |
1397 | char **perms; | 1638 | char **perms; |
1398 | 1639 | ||
1399 | rc = security_get_permissions(objclass, &perms, &nperms); | 1640 | rc = security_get_permissions(objclass, &perms, &nperms); |
1400 | if (rc) | 1641 | if (rc) |
1401 | goto out; | 1642 | return rc; |
1402 | 1643 | ||
1403 | for (i = 0; i < nperms; i++) { | 1644 | for (i = 0; i < nperms; i++) { |
1404 | struct inode *inode; | 1645 | struct inode *inode; |
1405 | struct dentry *dentry; | 1646 | struct dentry *dentry; |
1406 | 1647 | ||
1648 | rc = -ENOMEM; | ||
1407 | dentry = d_alloc_name(dir, perms[i]); | 1649 | dentry = d_alloc_name(dir, perms[i]); |
1408 | if (!dentry) { | 1650 | if (!dentry) |
1409 | rc = -ENOMEM; | 1651 | goto out; |
1410 | goto out1; | ||
1411 | } | ||
1412 | 1652 | ||
1653 | rc = -ENOMEM; | ||
1413 | inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO); | 1654 | inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO); |
1414 | if (!inode) { | 1655 | if (!inode) |
1415 | rc = -ENOMEM; | 1656 | goto out; |
1416 | goto out1; | 1657 | |
1417 | } | ||
1418 | inode->i_fop = &sel_perm_ops; | 1658 | inode->i_fop = &sel_perm_ops; |
1419 | /* i+1 since perm values are 1-indexed */ | 1659 | /* i+1 since perm values are 1-indexed */ |
1420 | inode->i_ino = sel_perm_to_ino(classvalue, i + 1); | 1660 | inode->i_ino = sel_perm_to_ino(classvalue, i + 1); |
1421 | d_add(dentry, inode); | 1661 | d_add(dentry, inode); |
1422 | } | 1662 | } |
1423 | 1663 | rc = 0; | |
1424 | out1: | 1664 | out: |
1425 | for (i = 0; i < nperms; i++) | 1665 | for (i = 0; i < nperms; i++) |
1426 | kfree(perms[i]); | 1666 | kfree(perms[i]); |
1427 | kfree(perms); | 1667 | kfree(perms); |
1428 | out: | ||
1429 | return rc; | 1668 | return rc; |
1430 | } | 1669 | } |
1431 | 1670 | ||
@@ -1437,34 +1676,27 @@ static int sel_make_class_dir_entries(char *classname, int index, | |||
1437 | int rc; | 1676 | int rc; |
1438 | 1677 | ||
1439 | dentry = d_alloc_name(dir, "index"); | 1678 | dentry = d_alloc_name(dir, "index"); |
1440 | if (!dentry) { | 1679 | if (!dentry) |
1441 | rc = -ENOMEM; | 1680 | return -ENOMEM; |
1442 | goto out; | ||
1443 | } | ||
1444 | 1681 | ||
1445 | inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO); | 1682 | inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO); |
1446 | if (!inode) { | 1683 | if (!inode) |
1447 | rc = -ENOMEM; | 1684 | return -ENOMEM; |
1448 | goto out; | ||
1449 | } | ||
1450 | 1685 | ||
1451 | inode->i_fop = &sel_class_ops; | 1686 | inode->i_fop = &sel_class_ops; |
1452 | inode->i_ino = sel_class_to_ino(index); | 1687 | inode->i_ino = sel_class_to_ino(index); |
1453 | d_add(dentry, inode); | 1688 | d_add(dentry, inode); |
1454 | 1689 | ||
1455 | dentry = d_alloc_name(dir, "perms"); | 1690 | dentry = d_alloc_name(dir, "perms"); |
1456 | if (!dentry) { | 1691 | if (!dentry) |
1457 | rc = -ENOMEM; | 1692 | return -ENOMEM; |
1458 | goto out; | ||
1459 | } | ||
1460 | 1693 | ||
1461 | rc = sel_make_dir(dir->d_inode, dentry, &last_class_ino); | 1694 | rc = sel_make_dir(dir->d_inode, dentry, &last_class_ino); |
1462 | if (rc) | 1695 | if (rc) |
1463 | goto out; | 1696 | return rc; |
1464 | 1697 | ||
1465 | rc = sel_make_perm_files(classname, index, dentry); | 1698 | rc = sel_make_perm_files(classname, index, dentry); |
1466 | 1699 | ||
1467 | out: | ||
1468 | return rc; | 1700 | return rc; |
1469 | } | 1701 | } |
1470 | 1702 | ||
@@ -1494,15 +1726,15 @@ static void sel_remove_classes(void) | |||
1494 | 1726 | ||
1495 | static int sel_make_classes(void) | 1727 | static int sel_make_classes(void) |
1496 | { | 1728 | { |
1497 | int rc = 0, nclasses, i; | 1729 | int rc, nclasses, i; |
1498 | char **classes; | 1730 | char **classes; |
1499 | 1731 | ||
1500 | /* delete any existing entries */ | 1732 | /* delete any existing entries */ |
1501 | sel_remove_classes(); | 1733 | sel_remove_classes(); |
1502 | 1734 | ||
1503 | rc = security_get_classes(&classes, &nclasses); | 1735 | rc = security_get_classes(&classes, &nclasses); |
1504 | if (rc < 0) | 1736 | if (rc) |
1505 | goto out; | 1737 | return rc; |
1506 | 1738 | ||
1507 | /* +2 since classes are 1-indexed */ | 1739 | /* +2 since classes are 1-indexed */ |
1508 | last_class_ino = sel_class_to_ino(nclasses + 2); | 1740 | last_class_ino = sel_class_to_ino(nclasses + 2); |
@@ -1510,29 +1742,27 @@ static int sel_make_classes(void) | |||
1510 | for (i = 0; i < nclasses; i++) { | 1742 | for (i = 0; i < nclasses; i++) { |
1511 | struct dentry *class_name_dir; | 1743 | struct dentry *class_name_dir; |
1512 | 1744 | ||
1745 | rc = -ENOMEM; | ||
1513 | class_name_dir = d_alloc_name(class_dir, classes[i]); | 1746 | class_name_dir = d_alloc_name(class_dir, classes[i]); |
1514 | if (!class_name_dir) { | 1747 | if (!class_name_dir) |
1515 | rc = -ENOMEM; | 1748 | goto out; |
1516 | goto out1; | ||
1517 | } | ||
1518 | 1749 | ||
1519 | rc = sel_make_dir(class_dir->d_inode, class_name_dir, | 1750 | rc = sel_make_dir(class_dir->d_inode, class_name_dir, |
1520 | &last_class_ino); | 1751 | &last_class_ino); |
1521 | if (rc) | 1752 | if (rc) |
1522 | goto out1; | 1753 | goto out; |
1523 | 1754 | ||
1524 | /* i+1 since class values are 1-indexed */ | 1755 | /* i+1 since class values are 1-indexed */ |
1525 | rc = sel_make_class_dir_entries(classes[i], i + 1, | 1756 | rc = sel_make_class_dir_entries(classes[i], i + 1, |
1526 | class_name_dir); | 1757 | class_name_dir); |
1527 | if (rc) | 1758 | if (rc) |
1528 | goto out1; | 1759 | goto out; |
1529 | } | 1760 | } |
1530 | 1761 | rc = 0; | |
1531 | out1: | 1762 | out: |
1532 | for (i = 0; i < nclasses; i++) | 1763 | for (i = 0; i < nclasses; i++) |
1533 | kfree(classes[i]); | 1764 | kfree(classes[i]); |
1534 | kfree(classes); | 1765 | kfree(classes); |
1535 | out: | ||
1536 | return rc; | 1766 | return rc; |
1537 | } | 1767 | } |
1538 | 1768 | ||
@@ -1569,14 +1799,12 @@ static int sel_make_policycap(void) | |||
1569 | static int sel_make_dir(struct inode *dir, struct dentry *dentry, | 1799 | static int sel_make_dir(struct inode *dir, struct dentry *dentry, |
1570 | unsigned long *ino) | 1800 | unsigned long *ino) |
1571 | { | 1801 | { |
1572 | int ret = 0; | ||
1573 | struct inode *inode; | 1802 | struct inode *inode; |
1574 | 1803 | ||
1575 | inode = sel_make_inode(dir->i_sb, S_IFDIR | S_IRUGO | S_IXUGO); | 1804 | inode = sel_make_inode(dir->i_sb, S_IFDIR | S_IRUGO | S_IXUGO); |
1576 | if (!inode) { | 1805 | if (!inode) |
1577 | ret = -ENOMEM; | 1806 | return -ENOMEM; |
1578 | goto out; | 1807 | |
1579 | } | ||
1580 | inode->i_op = &simple_dir_inode_operations; | 1808 | inode->i_op = &simple_dir_inode_operations; |
1581 | inode->i_fop = &simple_dir_operations; | 1809 | inode->i_fop = &simple_dir_operations; |
1582 | inode->i_ino = ++(*ino); | 1810 | inode->i_ino = ++(*ino); |
@@ -1585,8 +1813,8 @@ static int sel_make_dir(struct inode *dir, struct dentry *dentry, | |||
1585 | d_add(dentry, inode); | 1813 | d_add(dentry, inode); |
1586 | /* bump link count on parent directory, too */ | 1814 | /* bump link count on parent directory, too */ |
1587 | inc_nlink(dir); | 1815 | inc_nlink(dir); |
1588 | out: | 1816 | |
1589 | return ret; | 1817 | return 0; |
1590 | } | 1818 | } |
1591 | 1819 | ||
1592 | static int sel_fill_super(struct super_block *sb, void *data, int silent) | 1820 | static int sel_fill_super(struct super_block *sb, void *data, int silent) |
@@ -1612,6 +1840,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}, | 1840 | [SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR}, |
1613 | [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO}, | 1841 | [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO}, |
1614 | [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO}, | 1842 | [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO}, |
1843 | [SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO}, | ||
1844 | [SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUSR}, | ||
1615 | /* last one */ {""} | 1845 | /* last one */ {""} |
1616 | }; | 1846 | }; |
1617 | ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); | 1847 | ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); |
@@ -1620,11 +1850,10 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) | |||
1620 | 1850 | ||
1621 | root_inode = sb->s_root->d_inode; | 1851 | root_inode = sb->s_root->d_inode; |
1622 | 1852 | ||
1853 | ret = -ENOMEM; | ||
1623 | dentry = d_alloc_name(sb->s_root, BOOL_DIR_NAME); | 1854 | dentry = d_alloc_name(sb->s_root, BOOL_DIR_NAME); |
1624 | if (!dentry) { | 1855 | if (!dentry) |
1625 | ret = -ENOMEM; | ||
1626 | goto err; | 1856 | goto err; |
1627 | } | ||
1628 | 1857 | ||
1629 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); | 1858 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); |
1630 | if (ret) | 1859 | if (ret) |
@@ -1632,17 +1861,16 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) | |||
1632 | 1861 | ||
1633 | bool_dir = dentry; | 1862 | bool_dir = dentry; |
1634 | 1863 | ||
1864 | ret = -ENOMEM; | ||
1635 | dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME); | 1865 | dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME); |
1636 | if (!dentry) { | 1866 | if (!dentry) |
1637 | ret = -ENOMEM; | ||
1638 | goto err; | 1867 | goto err; |
1639 | } | ||
1640 | 1868 | ||
1869 | ret = -ENOMEM; | ||
1641 | inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO); | 1870 | inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO); |
1642 | if (!inode) { | 1871 | if (!inode) |
1643 | ret = -ENOMEM; | ||
1644 | goto err; | 1872 | goto err; |
1645 | } | 1873 | |
1646 | inode->i_ino = ++sel_last_ino; | 1874 | inode->i_ino = ++sel_last_ino; |
1647 | isec = (struct inode_security_struct *)inode->i_security; | 1875 | isec = (struct inode_security_struct *)inode->i_security; |
1648 | isec->sid = SECINITSID_DEVNULL; | 1876 | isec->sid = SECINITSID_DEVNULL; |
@@ -1653,11 +1881,10 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) | |||
1653 | d_add(dentry, inode); | 1881 | d_add(dentry, inode); |
1654 | selinux_null = dentry; | 1882 | selinux_null = dentry; |
1655 | 1883 | ||
1884 | ret = -ENOMEM; | ||
1656 | dentry = d_alloc_name(sb->s_root, "avc"); | 1885 | dentry = d_alloc_name(sb->s_root, "avc"); |
1657 | if (!dentry) { | 1886 | if (!dentry) |
1658 | ret = -ENOMEM; | ||
1659 | goto err; | 1887 | goto err; |
1660 | } | ||
1661 | 1888 | ||
1662 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); | 1889 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); |
1663 | if (ret) | 1890 | if (ret) |
@@ -1667,11 +1894,10 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) | |||
1667 | if (ret) | 1894 | if (ret) |
1668 | goto err; | 1895 | goto err; |
1669 | 1896 | ||
1897 | ret = -ENOMEM; | ||
1670 | dentry = d_alloc_name(sb->s_root, "initial_contexts"); | 1898 | dentry = d_alloc_name(sb->s_root, "initial_contexts"); |
1671 | if (!dentry) { | 1899 | if (!dentry) |
1672 | ret = -ENOMEM; | ||
1673 | goto err; | 1900 | goto err; |
1674 | } | ||
1675 | 1901 | ||
1676 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); | 1902 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); |
1677 | if (ret) | 1903 | if (ret) |
@@ -1681,11 +1907,10 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) | |||
1681 | if (ret) | 1907 | if (ret) |
1682 | goto err; | 1908 | goto err; |
1683 | 1909 | ||
1910 | ret = -ENOMEM; | ||
1684 | dentry = d_alloc_name(sb->s_root, "class"); | 1911 | dentry = d_alloc_name(sb->s_root, "class"); |
1685 | if (!dentry) { | 1912 | if (!dentry) |
1686 | ret = -ENOMEM; | ||
1687 | goto err; | 1913 | goto err; |
1688 | } | ||
1689 | 1914 | ||
1690 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); | 1915 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); |
1691 | if (ret) | 1916 | if (ret) |
@@ -1693,11 +1918,10 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) | |||
1693 | 1918 | ||
1694 | class_dir = dentry; | 1919 | class_dir = dentry; |
1695 | 1920 | ||
1921 | ret = -ENOMEM; | ||
1696 | dentry = d_alloc_name(sb->s_root, "policy_capabilities"); | 1922 | dentry = d_alloc_name(sb->s_root, "policy_capabilities"); |
1697 | if (!dentry) { | 1923 | if (!dentry) |
1698 | ret = -ENOMEM; | ||
1699 | goto err; | 1924 | goto err; |
1700 | } | ||
1701 | 1925 | ||
1702 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); | 1926 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); |
1703 | if (ret) | 1927 | if (ret) |
@@ -1705,28 +1929,27 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) | |||
1705 | 1929 | ||
1706 | policycap_dir = dentry; | 1930 | policycap_dir = dentry; |
1707 | 1931 | ||
1708 | out: | 1932 | return 0; |
1709 | return ret; | ||
1710 | err: | 1933 | err: |
1711 | printk(KERN_ERR "SELinux: %s: failed while creating inodes\n", | 1934 | printk(KERN_ERR "SELinux: %s: failed while creating inodes\n", |
1712 | __func__); | 1935 | __func__); |
1713 | goto out; | 1936 | return ret; |
1714 | } | 1937 | } |
1715 | 1938 | ||
1716 | static int sel_get_sb(struct file_system_type *fs_type, | 1939 | static struct dentry *sel_mount(struct file_system_type *fs_type, |
1717 | int flags, const char *dev_name, void *data, | 1940 | int flags, const char *dev_name, void *data) |
1718 | struct vfsmount *mnt) | ||
1719 | { | 1941 | { |
1720 | return get_sb_single(fs_type, flags, data, sel_fill_super, mnt); | 1942 | return mount_single(fs_type, flags, data, sel_fill_super); |
1721 | } | 1943 | } |
1722 | 1944 | ||
1723 | static struct file_system_type sel_fs_type = { | 1945 | static struct file_system_type sel_fs_type = { |
1724 | .name = "selinuxfs", | 1946 | .name = "selinuxfs", |
1725 | .get_sb = sel_get_sb, | 1947 | .mount = sel_mount, |
1726 | .kill_sb = kill_litter_super, | 1948 | .kill_sb = kill_litter_super, |
1727 | }; | 1949 | }; |
1728 | 1950 | ||
1729 | struct vfsmount *selinuxfs_mount; | 1951 | struct vfsmount *selinuxfs_mount; |
1952 | static struct kobject *selinuxfs_kobj; | ||
1730 | 1953 | ||
1731 | static int __init init_sel_fs(void) | 1954 | static int __init init_sel_fs(void) |
1732 | { | 1955 | { |
@@ -1734,15 +1957,24 @@ static int __init init_sel_fs(void) | |||
1734 | 1957 | ||
1735 | if (!selinux_enabled) | 1958 | if (!selinux_enabled) |
1736 | return 0; | 1959 | return 0; |
1960 | |||
1961 | selinuxfs_kobj = kobject_create_and_add("selinux", fs_kobj); | ||
1962 | if (!selinuxfs_kobj) | ||
1963 | return -ENOMEM; | ||
1964 | |||
1737 | err = register_filesystem(&sel_fs_type); | 1965 | err = register_filesystem(&sel_fs_type); |
1738 | if (!err) { | 1966 | if (err) { |
1739 | selinuxfs_mount = kern_mount(&sel_fs_type); | 1967 | kobject_put(selinuxfs_kobj); |
1740 | if (IS_ERR(selinuxfs_mount)) { | 1968 | return err; |
1741 | printk(KERN_ERR "selinuxfs: could not mount!\n"); | ||
1742 | err = PTR_ERR(selinuxfs_mount); | ||
1743 | selinuxfs_mount = NULL; | ||
1744 | } | ||
1745 | } | 1969 | } |
1970 | |||
1971 | selinuxfs_mount = kern_mount(&sel_fs_type); | ||
1972 | if (IS_ERR(selinuxfs_mount)) { | ||
1973 | printk(KERN_ERR "selinuxfs: could not mount!\n"); | ||
1974 | err = PTR_ERR(selinuxfs_mount); | ||
1975 | selinuxfs_mount = NULL; | ||
1976 | } | ||
1977 | |||
1746 | return err; | 1978 | return err; |
1747 | } | 1979 | } |
1748 | 1980 | ||
@@ -1751,6 +1983,7 @@ __initcall(init_sel_fs); | |||
1751 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE | 1983 | #ifdef CONFIG_SECURITY_SELINUX_DISABLE |
1752 | void exit_sel_fs(void) | 1984 | void exit_sel_fs(void) |
1753 | { | 1985 | { |
1986 | kobject_put(selinuxfs_kobj); | ||
1754 | unregister_filesystem(&sel_fs_type); | 1987 | unregister_filesystem(&sel_fs_type); |
1755 | } | 1988 | } |
1756 | #endif | 1989 | #endif |