diff options
Diffstat (limited to 'security/selinux/selinuxfs.c')
-rw-r--r-- | security/selinux/selinuxfs.c | 648 |
1 files changed, 311 insertions, 337 deletions
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 073fd5b0a53a..8bae68e21af9 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
@@ -141,19 +141,24 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf, | |||
141 | size_t count, loff_t *ppos) | 141 | size_t count, loff_t *ppos) |
142 | 142 | ||
143 | { | 143 | { |
144 | char *page; | 144 | char *page = NULL; |
145 | ssize_t length; | 145 | ssize_t length; |
146 | int new_value; | 146 | int new_value; |
147 | 147 | ||
148 | length = -ENOMEM; | ||
148 | if (count >= PAGE_SIZE) | 149 | if (count >= PAGE_SIZE) |
149 | return -ENOMEM; | 150 | goto out; |
150 | if (*ppos != 0) { | 151 | |
151 | /* No partial writes. */ | 152 | /* No partial writes. */ |
152 | return -EINVAL; | 153 | length = EINVAL; |
153 | } | 154 | if (*ppos != 0) |
155 | goto out; | ||
156 | |||
157 | length = -ENOMEM; | ||
154 | page = (char *)get_zeroed_page(GFP_KERNEL); | 158 | page = (char *)get_zeroed_page(GFP_KERNEL); |
155 | if (!page) | 159 | if (!page) |
156 | return -ENOMEM; | 160 | goto out; |
161 | |||
157 | length = -EFAULT; | 162 | length = -EFAULT; |
158 | if (copy_from_user(page, buf, count)) | 163 | if (copy_from_user(page, buf, count)) |
159 | goto out; | 164 | goto out; |
@@ -268,20 +273,25 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf, | |||
268 | size_t count, loff_t *ppos) | 273 | size_t count, loff_t *ppos) |
269 | 274 | ||
270 | { | 275 | { |
271 | char *page; | 276 | char *page = NULL; |
272 | ssize_t length; | 277 | ssize_t length; |
273 | int new_value; | 278 | int new_value; |
274 | extern int selinux_disable(void); | 279 | extern int selinux_disable(void); |
275 | 280 | ||
281 | length = -ENOMEM; | ||
276 | if (count >= PAGE_SIZE) | 282 | if (count >= PAGE_SIZE) |
277 | return -ENOMEM; | 283 | goto out;; |
278 | if (*ppos != 0) { | 284 | |
279 | /* No partial writes. */ | 285 | /* No partial writes. */ |
280 | return -EINVAL; | 286 | length = -EINVAL; |
281 | } | 287 | if (*ppos != 0) |
288 | goto out; | ||
289 | |||
290 | length = -ENOMEM; | ||
282 | page = (char *)get_zeroed_page(GFP_KERNEL); | 291 | page = (char *)get_zeroed_page(GFP_KERNEL); |
283 | if (!page) | 292 | if (!page) |
284 | return -ENOMEM; | 293 | goto out; |
294 | |||
285 | length = -EFAULT; | 295 | length = -EFAULT; |
286 | if (copy_from_user(page, buf, count)) | 296 | if (copy_from_user(page, buf, count)) |
287 | goto out; | 297 | goto out; |
@@ -292,7 +302,7 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf, | |||
292 | 302 | ||
293 | if (new_value) { | 303 | if (new_value) { |
294 | length = selinux_disable(); | 304 | length = selinux_disable(); |
295 | if (length < 0) | 305 | if (length) |
296 | goto out; | 306 | goto out; |
297 | audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS, | 307 | audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS, |
298 | "selinux=0 auid=%u ses=%u", | 308 | "selinux=0 auid=%u ses=%u", |
@@ -493,7 +503,6 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, | |||
493 | size_t count, loff_t *ppos) | 503 | size_t count, loff_t *ppos) |
494 | 504 | ||
495 | { | 505 | { |
496 | int ret; | ||
497 | ssize_t length; | 506 | ssize_t length; |
498 | void *data = NULL; | 507 | void *data = NULL; |
499 | 508 | ||
@@ -503,17 +512,19 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, | |||
503 | if (length) | 512 | if (length) |
504 | goto out; | 513 | goto out; |
505 | 514 | ||
506 | if (*ppos != 0) { | 515 | /* No partial writes. */ |
507 | /* No partial writes. */ | 516 | length = -EINVAL; |
508 | length = -EINVAL; | 517 | if (*ppos != 0) |
509 | goto out; | 518 | goto out; |
510 | } | ||
511 | 519 | ||
512 | if ((count > 64 * 1024 * 1024) | 520 | length = -EFBIG; |
513 | || (data = vmalloc(count)) == NULL) { | 521 | if (count > 64 * 1024 * 1024) |
514 | length = -ENOMEM; | 522 | goto out; |
523 | |||
524 | length = -ENOMEM; | ||
525 | data = vmalloc(count); | ||
526 | if (!data) | ||
515 | goto out; | 527 | goto out; |
516 | } | ||
517 | 528 | ||
518 | length = -EFAULT; | 529 | length = -EFAULT; |
519 | if (copy_from_user(data, buf, count) != 0) | 530 | if (copy_from_user(data, buf, count) != 0) |
@@ -523,23 +534,19 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, | |||
523 | if (length) | 534 | if (length) |
524 | goto out; | 535 | goto out; |
525 | 536 | ||
526 | ret = sel_make_bools(); | 537 | length = sel_make_bools(); |
527 | if (ret) { | 538 | if (length) |
528 | length = ret; | ||
529 | goto out1; | 539 | goto out1; |
530 | } | ||
531 | 540 | ||
532 | ret = sel_make_classes(); | 541 | length = sel_make_classes(); |
533 | if (ret) { | 542 | if (length) |
534 | length = ret; | ||
535 | goto out1; | 543 | goto out1; |
536 | } | ||
537 | 544 | ||
538 | ret = sel_make_policycap(); | 545 | length = sel_make_policycap(); |
539 | if (ret) | 546 | if (length) |
540 | length = ret; | 547 | goto out1; |
541 | else | 548 | |
542 | length = count; | 549 | length = count; |
543 | 550 | ||
544 | out1: | 551 | out1: |
545 | audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD, | 552 | audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD, |
@@ -559,26 +566,26 @@ static const struct file_operations sel_load_ops = { | |||
559 | 566 | ||
560 | static ssize_t sel_write_context(struct file *file, char *buf, size_t size) | 567 | static ssize_t sel_write_context(struct file *file, char *buf, size_t size) |
561 | { | 568 | { |
562 | char *canon; | 569 | char *canon = NULL; |
563 | u32 sid, len; | 570 | u32 sid, len; |
564 | ssize_t length; | 571 | ssize_t length; |
565 | 572 | ||
566 | length = task_has_security(current, SECURITY__CHECK_CONTEXT); | 573 | length = task_has_security(current, SECURITY__CHECK_CONTEXT); |
567 | if (length) | 574 | if (length) |
568 | return length; | 575 | goto out; |
569 | 576 | ||
570 | length = security_context_to_sid(buf, size, &sid); | 577 | length = security_context_to_sid(buf, size, &sid); |
571 | if (length < 0) | 578 | if (length) |
572 | return length; | 579 | goto out; |
573 | 580 | ||
574 | length = security_sid_to_context(sid, &canon, &len); | 581 | length = security_sid_to_context(sid, &canon, &len); |
575 | if (length < 0) | 582 | if (length) |
576 | return length; | 583 | goto out; |
577 | 584 | ||
585 | length = -ERANGE; | ||
578 | if (len > SIMPLE_TRANSACTION_LIMIT) { | 586 | if (len > SIMPLE_TRANSACTION_LIMIT) { |
579 | printk(KERN_ERR "SELinux: %s: context size (%u) exceeds " | 587 | printk(KERN_ERR "SELinux: %s: context size (%u) exceeds " |
580 | "payload max\n", __func__, len); | 588 | "payload max\n", __func__, len); |
581 | length = -ERANGE; | ||
582 | goto out; | 589 | goto out; |
583 | } | 590 | } |
584 | 591 | ||
@@ -602,23 +609,28 @@ static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf, | |||
602 | static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf, | 609 | static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf, |
603 | size_t count, loff_t *ppos) | 610 | size_t count, loff_t *ppos) |
604 | { | 611 | { |
605 | char *page; | 612 | char *page = NULL; |
606 | ssize_t length; | 613 | ssize_t length; |
607 | unsigned int new_value; | 614 | unsigned int new_value; |
608 | 615 | ||
609 | length = task_has_security(current, SECURITY__SETCHECKREQPROT); | 616 | length = task_has_security(current, SECURITY__SETCHECKREQPROT); |
610 | if (length) | 617 | if (length) |
611 | return length; | 618 | goto out; |
612 | 619 | ||
620 | length = -ENOMEM; | ||
613 | if (count >= PAGE_SIZE) | 621 | if (count >= PAGE_SIZE) |
614 | return -ENOMEM; | 622 | goto out; |
615 | if (*ppos != 0) { | 623 | |
616 | /* No partial writes. */ | 624 | /* No partial writes. */ |
617 | return -EINVAL; | 625 | length = -EINVAL; |
618 | } | 626 | if (*ppos != 0) |
627 | goto out; | ||
628 | |||
629 | length = -ENOMEM; | ||
619 | page = (char *)get_zeroed_page(GFP_KERNEL); | 630 | page = (char *)get_zeroed_page(GFP_KERNEL); |
620 | if (!page) | 631 | if (!page) |
621 | return -ENOMEM; | 632 | goto out; |
633 | |||
622 | length = -EFAULT; | 634 | length = -EFAULT; |
623 | if (copy_from_user(page, buf, count)) | 635 | if (copy_from_user(page, buf, count)) |
624 | goto out; | 636 | goto out; |
@@ -693,7 +705,7 @@ static const struct file_operations transaction_ops = { | |||
693 | 705 | ||
694 | static ssize_t sel_write_access(struct file *file, char *buf, size_t size) | 706 | static ssize_t sel_write_access(struct file *file, char *buf, size_t size) |
695 | { | 707 | { |
696 | char *scon, *tcon; | 708 | char *scon = NULL, *tcon = NULL; |
697 | u32 ssid, tsid; | 709 | u32 ssid, tsid; |
698 | u16 tclass; | 710 | u16 tclass; |
699 | struct av_decision avd; | 711 | struct av_decision avd; |
@@ -701,27 +713,29 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) | |||
701 | 713 | ||
702 | length = task_has_security(current, SECURITY__COMPUTE_AV); | 714 | length = task_has_security(current, SECURITY__COMPUTE_AV); |
703 | if (length) | 715 | if (length) |
704 | return length; | 716 | goto out; |
705 | 717 | ||
706 | length = -ENOMEM; | 718 | length = -ENOMEM; |
707 | scon = kzalloc(size + 1, GFP_KERNEL); | 719 | scon = kzalloc(size + 1, GFP_KERNEL); |
708 | if (!scon) | 720 | if (!scon) |
709 | return length; | 721 | goto out; |
710 | 722 | ||
723 | length = -ENOMEM; | ||
711 | tcon = kzalloc(size + 1, GFP_KERNEL); | 724 | tcon = kzalloc(size + 1, GFP_KERNEL); |
712 | if (!tcon) | 725 | if (!tcon) |
713 | goto out; | 726 | goto out; |
714 | 727 | ||
715 | length = -EINVAL; | 728 | length = -EINVAL; |
716 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) | 729 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) |
717 | goto out2; | 730 | goto out; |
718 | 731 | ||
719 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); | 732 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); |
720 | if (length < 0) | 733 | if (length) |
721 | goto out2; | 734 | goto out; |
735 | |||
722 | length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); | 736 | length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); |
723 | if (length < 0) | 737 | if (length) |
724 | goto out2; | 738 | goto out; |
725 | 739 | ||
726 | security_compute_av_user(ssid, tsid, tclass, &avd); | 740 | security_compute_av_user(ssid, tsid, tclass, &avd); |
727 | 741 | ||
@@ -730,133 +744,131 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) | |||
730 | avd.allowed, 0xffffffff, | 744 | avd.allowed, 0xffffffff, |
731 | avd.auditallow, avd.auditdeny, | 745 | avd.auditallow, avd.auditdeny, |
732 | avd.seqno, avd.flags); | 746 | avd.seqno, avd.flags); |
733 | out2: | ||
734 | kfree(tcon); | ||
735 | out: | 747 | out: |
748 | kfree(tcon); | ||
736 | kfree(scon); | 749 | kfree(scon); |
737 | return length; | 750 | return length; |
738 | } | 751 | } |
739 | 752 | ||
740 | static ssize_t sel_write_create(struct file *file, char *buf, size_t size) | 753 | static ssize_t sel_write_create(struct file *file, char *buf, size_t size) |
741 | { | 754 | { |
742 | char *scon, *tcon; | 755 | char *scon = NULL, *tcon = NULL; |
743 | u32 ssid, tsid, newsid; | 756 | u32 ssid, tsid, newsid; |
744 | u16 tclass; | 757 | u16 tclass; |
745 | ssize_t length; | 758 | ssize_t length; |
746 | char *newcon; | 759 | char *newcon = NULL; |
747 | u32 len; | 760 | u32 len; |
748 | 761 | ||
749 | length = task_has_security(current, SECURITY__COMPUTE_CREATE); | 762 | length = task_has_security(current, SECURITY__COMPUTE_CREATE); |
750 | if (length) | 763 | if (length) |
751 | return length; | 764 | goto out; |
752 | 765 | ||
753 | length = -ENOMEM; | 766 | length = -ENOMEM; |
754 | scon = kzalloc(size + 1, GFP_KERNEL); | 767 | scon = kzalloc(size + 1, GFP_KERNEL); |
755 | if (!scon) | 768 | if (!scon) |
756 | return length; | 769 | goto out; |
757 | 770 | ||
771 | length = -ENOMEM; | ||
758 | tcon = kzalloc(size + 1, GFP_KERNEL); | 772 | tcon = kzalloc(size + 1, GFP_KERNEL); |
759 | if (!tcon) | 773 | if (!tcon) |
760 | goto out; | 774 | goto out; |
761 | 775 | ||
762 | length = -EINVAL; | 776 | length = -EINVAL; |
763 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) | 777 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) |
764 | goto out2; | 778 | goto out; |
765 | 779 | ||
766 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); | 780 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); |
767 | if (length < 0) | 781 | if (length) |
768 | goto out2; | 782 | goto out; |
783 | |||
769 | length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); | 784 | length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); |
770 | if (length < 0) | 785 | if (length) |
771 | goto out2; | 786 | goto out; |
772 | 787 | ||
773 | length = security_transition_sid_user(ssid, tsid, tclass, &newsid); | 788 | length = security_transition_sid_user(ssid, tsid, tclass, &newsid); |
774 | if (length < 0) | 789 | if (length) |
775 | goto out2; | 790 | goto out; |
776 | 791 | ||
777 | length = security_sid_to_context(newsid, &newcon, &len); | 792 | length = security_sid_to_context(newsid, &newcon, &len); |
778 | if (length < 0) | 793 | if (length) |
779 | goto out2; | 794 | goto out; |
780 | 795 | ||
796 | length = -ERANGE; | ||
781 | if (len > SIMPLE_TRANSACTION_LIMIT) { | 797 | if (len > SIMPLE_TRANSACTION_LIMIT) { |
782 | printk(KERN_ERR "SELinux: %s: context size (%u) exceeds " | 798 | printk(KERN_ERR "SELinux: %s: context size (%u) exceeds " |
783 | "payload max\n", __func__, len); | 799 | "payload max\n", __func__, len); |
784 | length = -ERANGE; | 800 | goto out; |
785 | goto out3; | ||
786 | } | 801 | } |
787 | 802 | ||
788 | memcpy(buf, newcon, len); | 803 | memcpy(buf, newcon, len); |
789 | length = len; | 804 | length = len; |
790 | out3: | 805 | out: |
791 | kfree(newcon); | 806 | kfree(newcon); |
792 | out2: | ||
793 | kfree(tcon); | 807 | kfree(tcon); |
794 | out: | ||
795 | kfree(scon); | 808 | kfree(scon); |
796 | return length; | 809 | return length; |
797 | } | 810 | } |
798 | 811 | ||
799 | static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size) | 812 | static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size) |
800 | { | 813 | { |
801 | char *scon, *tcon; | 814 | char *scon = NULL, *tcon = NULL; |
802 | u32 ssid, tsid, newsid; | 815 | u32 ssid, tsid, newsid; |
803 | u16 tclass; | 816 | u16 tclass; |
804 | ssize_t length; | 817 | ssize_t length; |
805 | char *newcon; | 818 | char *newcon = NULL; |
806 | u32 len; | 819 | u32 len; |
807 | 820 | ||
808 | length = task_has_security(current, SECURITY__COMPUTE_RELABEL); | 821 | length = task_has_security(current, SECURITY__COMPUTE_RELABEL); |
809 | if (length) | 822 | if (length) |
810 | return length; | 823 | goto out; |
811 | 824 | ||
812 | length = -ENOMEM; | 825 | length = -ENOMEM; |
813 | scon = kzalloc(size + 1, GFP_KERNEL); | 826 | scon = kzalloc(size + 1, GFP_KERNEL); |
814 | if (!scon) | 827 | if (!scon) |
815 | return length; | 828 | goto out; |
816 | 829 | ||
830 | length = -ENOMEM; | ||
817 | tcon = kzalloc(size + 1, GFP_KERNEL); | 831 | tcon = kzalloc(size + 1, GFP_KERNEL); |
818 | if (!tcon) | 832 | if (!tcon) |
819 | goto out; | 833 | goto out; |
820 | 834 | ||
821 | length = -EINVAL; | 835 | length = -EINVAL; |
822 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) | 836 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) |
823 | goto out2; | 837 | goto out; |
824 | 838 | ||
825 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); | 839 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); |
826 | if (length < 0) | 840 | if (length) |
827 | goto out2; | 841 | goto out; |
842 | |||
828 | length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); | 843 | length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); |
829 | if (length < 0) | 844 | if (length) |
830 | goto out2; | 845 | goto out; |
831 | 846 | ||
832 | length = security_change_sid(ssid, tsid, tclass, &newsid); | 847 | length = security_change_sid(ssid, tsid, tclass, &newsid); |
833 | if (length < 0) | 848 | if (length) |
834 | goto out2; | 849 | goto out; |
835 | 850 | ||
836 | length = security_sid_to_context(newsid, &newcon, &len); | 851 | length = security_sid_to_context(newsid, &newcon, &len); |
837 | if (length < 0) | 852 | if (length) |
838 | goto out2; | 853 | goto out; |
839 | 854 | ||
840 | if (len > SIMPLE_TRANSACTION_LIMIT) { | 855 | length = -ERANGE; |
841 | length = -ERANGE; | 856 | if (len > SIMPLE_TRANSACTION_LIMIT) |
842 | goto out3; | 857 | goto out; |
843 | } | ||
844 | 858 | ||
845 | memcpy(buf, newcon, len); | 859 | memcpy(buf, newcon, len); |
846 | length = len; | 860 | length = len; |
847 | out3: | 861 | out: |
848 | kfree(newcon); | 862 | kfree(newcon); |
849 | out2: | ||
850 | kfree(tcon); | 863 | kfree(tcon); |
851 | out: | ||
852 | kfree(scon); | 864 | kfree(scon); |
853 | return length; | 865 | return length; |
854 | } | 866 | } |
855 | 867 | ||
856 | static ssize_t sel_write_user(struct file *file, char *buf, size_t size) | 868 | static ssize_t sel_write_user(struct file *file, char *buf, size_t size) |
857 | { | 869 | { |
858 | char *con, *user, *ptr; | 870 | char *con = NULL, *user = NULL, *ptr; |
859 | u32 sid, *sids; | 871 | u32 sid, *sids = NULL; |
860 | ssize_t length; | 872 | ssize_t length; |
861 | char *newcon; | 873 | char *newcon; |
862 | int i, rc; | 874 | int i, rc; |
@@ -864,28 +876,29 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size) | |||
864 | 876 | ||
865 | length = task_has_security(current, SECURITY__COMPUTE_USER); | 877 | length = task_has_security(current, SECURITY__COMPUTE_USER); |
866 | if (length) | 878 | if (length) |
867 | return length; | 879 | goto out;; |
868 | 880 | ||
869 | length = -ENOMEM; | 881 | length = -ENOMEM; |
870 | con = kzalloc(size + 1, GFP_KERNEL); | 882 | con = kzalloc(size + 1, GFP_KERNEL); |
871 | if (!con) | 883 | if (!con) |
872 | return length; | 884 | goto out;; |
873 | 885 | ||
886 | length = -ENOMEM; | ||
874 | user = kzalloc(size + 1, GFP_KERNEL); | 887 | user = kzalloc(size + 1, GFP_KERNEL); |
875 | if (!user) | 888 | if (!user) |
876 | goto out; | 889 | goto out; |
877 | 890 | ||
878 | length = -EINVAL; | 891 | length = -EINVAL; |
879 | if (sscanf(buf, "%s %s", con, user) != 2) | 892 | if (sscanf(buf, "%s %s", con, user) != 2) |
880 | goto out2; | 893 | goto out; |
881 | 894 | ||
882 | length = security_context_to_sid(con, strlen(con) + 1, &sid); | 895 | length = security_context_to_sid(con, strlen(con) + 1, &sid); |
883 | if (length < 0) | 896 | if (length) |
884 | goto out2; | 897 | goto out; |
885 | 898 | ||
886 | length = security_get_user_sids(sid, user, &sids, &nsids); | 899 | length = security_get_user_sids(sid, user, &sids, &nsids); |
887 | if (length < 0) | 900 | if (length) |
888 | goto out2; | 901 | goto out; |
889 | 902 | ||
890 | length = sprintf(buf, "%u", nsids) + 1; | 903 | length = sprintf(buf, "%u", nsids) + 1; |
891 | ptr = buf + length; | 904 | ptr = buf + length; |
@@ -893,82 +906,80 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size) | |||
893 | rc = security_sid_to_context(sids[i], &newcon, &len); | 906 | rc = security_sid_to_context(sids[i], &newcon, &len); |
894 | if (rc) { | 907 | if (rc) { |
895 | length = rc; | 908 | length = rc; |
896 | goto out3; | 909 | goto out; |
897 | } | 910 | } |
898 | if ((length + len) >= SIMPLE_TRANSACTION_LIMIT) { | 911 | if ((length + len) >= SIMPLE_TRANSACTION_LIMIT) { |
899 | kfree(newcon); | 912 | kfree(newcon); |
900 | length = -ERANGE; | 913 | length = -ERANGE; |
901 | goto out3; | 914 | goto out; |
902 | } | 915 | } |
903 | memcpy(ptr, newcon, len); | 916 | memcpy(ptr, newcon, len); |
904 | kfree(newcon); | 917 | kfree(newcon); |
905 | ptr += len; | 918 | ptr += len; |
906 | length += len; | 919 | length += len; |
907 | } | 920 | } |
908 | out3: | 921 | out: |
909 | kfree(sids); | 922 | kfree(sids); |
910 | out2: | ||
911 | kfree(user); | 923 | kfree(user); |
912 | out: | ||
913 | kfree(con); | 924 | kfree(con); |
914 | return length; | 925 | return length; |
915 | } | 926 | } |
916 | 927 | ||
917 | static ssize_t sel_write_member(struct file *file, char *buf, size_t size) | 928 | static ssize_t sel_write_member(struct file *file, char *buf, size_t size) |
918 | { | 929 | { |
919 | char *scon, *tcon; | 930 | char *scon = NULL, *tcon = NULL; |
920 | u32 ssid, tsid, newsid; | 931 | u32 ssid, tsid, newsid; |
921 | u16 tclass; | 932 | u16 tclass; |
922 | ssize_t length; | 933 | ssize_t length; |
923 | char *newcon; | 934 | char *newcon = NULL; |
924 | u32 len; | 935 | u32 len; |
925 | 936 | ||
926 | length = task_has_security(current, SECURITY__COMPUTE_MEMBER); | 937 | length = task_has_security(current, SECURITY__COMPUTE_MEMBER); |
927 | if (length) | 938 | if (length) |
928 | return length; | 939 | goto out; |
929 | 940 | ||
930 | length = -ENOMEM; | 941 | length = -ENOMEM; |
931 | scon = kzalloc(size + 1, GFP_KERNEL); | 942 | scon = kzalloc(size + 1, GFP_KERNEL); |
932 | if (!scon) | 943 | if (!scon) |
933 | return length; | 944 | goto out;; |
934 | 945 | ||
946 | length = -ENOMEM; | ||
935 | tcon = kzalloc(size + 1, GFP_KERNEL); | 947 | tcon = kzalloc(size + 1, GFP_KERNEL); |
936 | if (!tcon) | 948 | if (!tcon) |
937 | goto out; | 949 | goto out; |
938 | 950 | ||
939 | length = -EINVAL; | 951 | length = -EINVAL; |
940 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) | 952 | if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) |
941 | goto out2; | 953 | goto out; |
942 | 954 | ||
943 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); | 955 | length = security_context_to_sid(scon, strlen(scon) + 1, &ssid); |
944 | if (length < 0) | 956 | if (length) |
945 | goto out2; | 957 | goto out; |
958 | |||
946 | length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); | 959 | length = security_context_to_sid(tcon, strlen(tcon) + 1, &tsid); |
947 | if (length < 0) | 960 | if (length) |
948 | goto out2; | 961 | goto out; |
949 | 962 | ||
950 | length = security_member_sid(ssid, tsid, tclass, &newsid); | 963 | length = security_member_sid(ssid, tsid, tclass, &newsid); |
951 | if (length < 0) | 964 | if (length) |
952 | goto out2; | 965 | goto out; |
953 | 966 | ||
954 | length = security_sid_to_context(newsid, &newcon, &len); | 967 | length = security_sid_to_context(newsid, &newcon, &len); |
955 | if (length < 0) | 968 | if (length) |
956 | goto out2; | 969 | goto out; |
957 | 970 | ||
971 | length = -ERANGE; | ||
958 | if (len > SIMPLE_TRANSACTION_LIMIT) { | 972 | if (len > SIMPLE_TRANSACTION_LIMIT) { |
959 | printk(KERN_ERR "SELinux: %s: context size (%u) exceeds " | 973 | printk(KERN_ERR "SELinux: %s: context size (%u) exceeds " |
960 | "payload max\n", __func__, len); | 974 | "payload max\n", __func__, len); |
961 | length = -ERANGE; | 975 | goto out; |
962 | goto out3; | ||
963 | } | 976 | } |
964 | 977 | ||
965 | memcpy(buf, newcon, len); | 978 | memcpy(buf, newcon, len); |
966 | length = len; | 979 | length = len; |
967 | out3: | 980 | out: |
968 | kfree(newcon); | 981 | kfree(newcon); |
969 | out2: | ||
970 | kfree(tcon); | 982 | kfree(tcon); |
971 | out: | ||
972 | kfree(scon); | 983 | kfree(scon); |
973 | return length; | 984 | return length; |
974 | } | 985 | } |
@@ -998,16 +1009,14 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, | |||
998 | 1009 | ||
999 | mutex_lock(&sel_mutex); | 1010 | mutex_lock(&sel_mutex); |
1000 | 1011 | ||
1001 | if (index >= bool_num || strcmp(name, bool_pending_names[index])) { | 1012 | ret = -EINVAL; |
1002 | ret = -EINVAL; | 1013 | if (index >= bool_num || strcmp(name, bool_pending_names[index])) |
1003 | goto out; | 1014 | goto out; |
1004 | } | ||
1005 | 1015 | ||
1016 | ret = -ENOMEM; | ||
1006 | page = (char *)get_zeroed_page(GFP_KERNEL); | 1017 | page = (char *)get_zeroed_page(GFP_KERNEL); |
1007 | if (!page) { | 1018 | if (!page) |
1008 | ret = -ENOMEM; | ||
1009 | goto out; | 1019 | goto out; |
1010 | } | ||
1011 | 1020 | ||
1012 | cur_enforcing = security_get_bool_value(index); | 1021 | cur_enforcing = security_get_bool_value(index); |
1013 | if (cur_enforcing < 0) { | 1022 | if (cur_enforcing < 0) { |
@@ -1019,8 +1028,7 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, | |||
1019 | ret = simple_read_from_buffer(buf, count, ppos, page, length); | 1028 | ret = simple_read_from_buffer(buf, count, ppos, page, length); |
1020 | out: | 1029 | out: |
1021 | mutex_unlock(&sel_mutex); | 1030 | mutex_unlock(&sel_mutex); |
1022 | if (page) | 1031 | free_page((unsigned long)page); |
1023 | free_page((unsigned long)page); | ||
1024 | return ret; | 1032 | return ret; |
1025 | } | 1033 | } |
1026 | 1034 | ||
@@ -1040,26 +1048,23 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, | |||
1040 | if (length) | 1048 | if (length) |
1041 | goto out; | 1049 | goto out; |
1042 | 1050 | ||
1043 | if (index >= bool_num || strcmp(name, bool_pending_names[index])) { | 1051 | length = -EINVAL; |
1044 | length = -EINVAL; | 1052 | if (index >= bool_num || strcmp(name, bool_pending_names[index])) |
1045 | goto out; | 1053 | goto out; |
1046 | } | ||
1047 | 1054 | ||
1048 | if (count >= PAGE_SIZE) { | 1055 | length = -ENOMEM; |
1049 | length = -ENOMEM; | 1056 | if (count >= PAGE_SIZE) |
1050 | goto out; | 1057 | goto out; |
1051 | } | ||
1052 | 1058 | ||
1053 | if (*ppos != 0) { | 1059 | /* No partial writes. */ |
1054 | /* No partial writes. */ | 1060 | length = -EINVAL; |
1055 | length = -EINVAL; | 1061 | if (*ppos != 0) |
1056 | goto out; | 1062 | goto out; |
1057 | } | 1063 | |
1064 | length = -ENOMEM; | ||
1058 | page = (char *)get_zeroed_page(GFP_KERNEL); | 1065 | page = (char *)get_zeroed_page(GFP_KERNEL); |
1059 | if (!page) { | 1066 | if (!page) |
1060 | length = -ENOMEM; | ||
1061 | goto out; | 1067 | goto out; |
1062 | } | ||
1063 | 1068 | ||
1064 | length = -EFAULT; | 1069 | length = -EFAULT; |
1065 | if (copy_from_user(page, buf, count)) | 1070 | if (copy_from_user(page, buf, count)) |
@@ -1077,8 +1082,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, | |||
1077 | 1082 | ||
1078 | out: | 1083 | out: |
1079 | mutex_unlock(&sel_mutex); | 1084 | mutex_unlock(&sel_mutex); |
1080 | if (page) | 1085 | free_page((unsigned long) page); |
1081 | free_page((unsigned long) page); | ||
1082 | return length; | 1086 | return length; |
1083 | } | 1087 | } |
1084 | 1088 | ||
@@ -1102,19 +1106,19 @@ static ssize_t sel_commit_bools_write(struct file *filep, | |||
1102 | if (length) | 1106 | if (length) |
1103 | goto out; | 1107 | goto out; |
1104 | 1108 | ||
1105 | if (count >= PAGE_SIZE) { | 1109 | length = -ENOMEM; |
1106 | length = -ENOMEM; | 1110 | if (count >= PAGE_SIZE) |
1107 | goto out; | 1111 | goto out; |
1108 | } | 1112 | |
1109 | if (*ppos != 0) { | 1113 | /* No partial writes. */ |
1110 | /* No partial writes. */ | 1114 | length = -EINVAL; |
1115 | if (*ppos != 0) | ||
1111 | goto out; | 1116 | goto out; |
1112 | } | 1117 | |
1118 | length = -ENOMEM; | ||
1113 | page = (char *)get_zeroed_page(GFP_KERNEL); | 1119 | page = (char *)get_zeroed_page(GFP_KERNEL); |
1114 | if (!page) { | 1120 | if (!page) |
1115 | length = -ENOMEM; | ||
1116 | goto out; | 1121 | goto out; |
1117 | } | ||
1118 | 1122 | ||
1119 | length = -EFAULT; | 1123 | length = -EFAULT; |
1120 | if (copy_from_user(page, buf, count)) | 1124 | if (copy_from_user(page, buf, count)) |
@@ -1124,15 +1128,16 @@ static ssize_t sel_commit_bools_write(struct file *filep, | |||
1124 | if (sscanf(page, "%d", &new_value) != 1) | 1128 | if (sscanf(page, "%d", &new_value) != 1) |
1125 | goto out; | 1129 | goto out; |
1126 | 1130 | ||
1131 | length = 0; | ||
1127 | if (new_value && bool_pending_values) | 1132 | if (new_value && bool_pending_values) |
1128 | security_set_bools(bool_num, bool_pending_values); | 1133 | length = security_set_bools(bool_num, bool_pending_values); |
1129 | 1134 | ||
1130 | length = count; | 1135 | if (!length) |
1136 | length = count; | ||
1131 | 1137 | ||
1132 | out: | 1138 | out: |
1133 | mutex_unlock(&sel_mutex); | 1139 | mutex_unlock(&sel_mutex); |
1134 | if (page) | 1140 | free_page((unsigned long) page); |
1135 | free_page((unsigned long) page); | ||
1136 | return length; | 1141 | return length; |
1137 | } | 1142 | } |
1138 | 1143 | ||
@@ -1169,7 +1174,7 @@ static void sel_remove_entries(struct dentry *de) | |||
1169 | 1174 | ||
1170 | static int sel_make_bools(void) | 1175 | static int sel_make_bools(void) |
1171 | { | 1176 | { |
1172 | int i, ret = 0; | 1177 | int i, ret; |
1173 | ssize_t len; | 1178 | ssize_t len; |
1174 | struct dentry *dentry = NULL; | 1179 | struct dentry *dentry = NULL; |
1175 | struct dentry *dir = bool_dir; | 1180 | struct dentry *dir = bool_dir; |
@@ -1190,38 +1195,40 @@ static int sel_make_bools(void) | |||
1190 | 1195 | ||
1191 | sel_remove_entries(dir); | 1196 | sel_remove_entries(dir); |
1192 | 1197 | ||
1198 | ret = -ENOMEM; | ||
1193 | page = (char *)get_zeroed_page(GFP_KERNEL); | 1199 | page = (char *)get_zeroed_page(GFP_KERNEL); |
1194 | if (!page) | 1200 | if (!page) |
1195 | return -ENOMEM; | 1201 | goto out; |
1196 | 1202 | ||
1197 | ret = security_get_bools(&num, &names, &values); | 1203 | ret = security_get_bools(&num, &names, &values); |
1198 | if (ret != 0) | 1204 | if (ret) |
1199 | goto out; | 1205 | goto out; |
1200 | 1206 | ||
1201 | for (i = 0; i < num; i++) { | 1207 | for (i = 0; i < num; i++) { |
1208 | ret = -ENOMEM; | ||
1202 | dentry = d_alloc_name(dir, names[i]); | 1209 | dentry = d_alloc_name(dir, names[i]); |
1203 | if (!dentry) { | 1210 | if (!dentry) |
1204 | ret = -ENOMEM; | 1211 | goto out; |
1205 | goto err; | 1212 | |
1206 | } | 1213 | ret = -ENOMEM; |
1207 | inode = sel_make_inode(dir->d_sb, S_IFREG | S_IRUGO | S_IWUSR); | 1214 | inode = sel_make_inode(dir->d_sb, S_IFREG | S_IRUGO | S_IWUSR); |
1208 | if (!inode) { | 1215 | if (!inode) |
1209 | ret = -ENOMEM; | 1216 | goto out; |
1210 | goto err; | ||
1211 | } | ||
1212 | 1217 | ||
1218 | ret = -EINVAL; | ||
1213 | len = snprintf(page, PAGE_SIZE, "/%s/%s", BOOL_DIR_NAME, names[i]); | 1219 | len = snprintf(page, PAGE_SIZE, "/%s/%s", BOOL_DIR_NAME, names[i]); |
1214 | if (len < 0) { | 1220 | if (len < 0) |
1215 | ret = -EINVAL; | 1221 | goto out; |
1216 | goto err; | 1222 | |
1217 | } else if (len >= PAGE_SIZE) { | 1223 | ret = -ENAMETOOLONG; |
1218 | ret = -ENAMETOOLONG; | 1224 | if (len >= PAGE_SIZE) |
1219 | goto err; | 1225 | goto out; |
1220 | } | 1226 | |
1221 | isec = (struct inode_security_struct *)inode->i_security; | 1227 | isec = (struct inode_security_struct *)inode->i_security; |
1222 | ret = security_genfs_sid("selinuxfs", page, SECCLASS_FILE, &sid); | 1228 | ret = security_genfs_sid("selinuxfs", page, SECCLASS_FILE, &sid); |
1223 | if (ret) | 1229 | if (ret) |
1224 | goto err; | 1230 | goto out; |
1231 | |||
1225 | isec->sid = sid; | 1232 | isec->sid = sid; |
1226 | isec->initialized = 1; | 1233 | isec->initialized = 1; |
1227 | inode->i_fop = &sel_bool_ops; | 1234 | inode->i_fop = &sel_bool_ops; |
@@ -1231,10 +1238,12 @@ static int sel_make_bools(void) | |||
1231 | bool_num = num; | 1238 | bool_num = num; |
1232 | bool_pending_names = names; | 1239 | bool_pending_names = names; |
1233 | bool_pending_values = values; | 1240 | bool_pending_values = values; |
1241 | |||
1242 | free_page((unsigned long)page); | ||
1243 | return 0; | ||
1234 | out: | 1244 | out: |
1235 | free_page((unsigned long)page); | 1245 | free_page((unsigned long)page); |
1236 | return ret; | 1246 | |
1237 | err: | ||
1238 | if (names) { | 1247 | if (names) { |
1239 | for (i = 0; i < num; i++) | 1248 | for (i = 0; i < num; i++) |
1240 | kfree(names[i]); | 1249 | kfree(names[i]); |
@@ -1242,8 +1251,8 @@ err: | |||
1242 | } | 1251 | } |
1243 | kfree(values); | 1252 | kfree(values); |
1244 | sel_remove_entries(dir); | 1253 | sel_remove_entries(dir); |
1245 | ret = -ENOMEM; | 1254 | |
1246 | goto out; | 1255 | return ret; |
1247 | } | 1256 | } |
1248 | 1257 | ||
1249 | #define NULL_FILE_NAME "null" | 1258 | #define NULL_FILE_NAME "null" |
@@ -1265,47 +1274,41 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file, | |||
1265 | size_t count, loff_t *ppos) | 1274 | size_t count, loff_t *ppos) |
1266 | 1275 | ||
1267 | { | 1276 | { |
1268 | char *page; | 1277 | char *page = NULL; |
1269 | ssize_t ret; | 1278 | ssize_t ret; |
1270 | int new_value; | 1279 | int new_value; |
1271 | 1280 | ||
1272 | if (count >= PAGE_SIZE) { | 1281 | ret = task_has_security(current, SECURITY__SETSECPARAM); |
1273 | ret = -ENOMEM; | 1282 | if (ret) |
1274 | goto out; | 1283 | goto out; |
1275 | } | ||
1276 | 1284 | ||
1277 | if (*ppos != 0) { | 1285 | ret = -ENOMEM; |
1278 | /* No partial writes. */ | 1286 | if (count >= PAGE_SIZE) |
1279 | ret = -EINVAL; | ||
1280 | goto out; | 1287 | goto out; |
1281 | } | ||
1282 | 1288 | ||
1289 | /* No partial writes. */ | ||
1290 | ret = -EINVAL; | ||
1291 | if (*ppos != 0) | ||
1292 | goto out; | ||
1293 | |||
1294 | ret = -ENOMEM; | ||
1283 | page = (char *)get_zeroed_page(GFP_KERNEL); | 1295 | page = (char *)get_zeroed_page(GFP_KERNEL); |
1284 | if (!page) { | 1296 | if (!page) |
1285 | ret = -ENOMEM; | ||
1286 | goto out; | 1297 | goto out; |
1287 | } | ||
1288 | 1298 | ||
1289 | if (copy_from_user(page, buf, count)) { | 1299 | ret = -EFAULT; |
1290 | ret = -EFAULT; | 1300 | if (copy_from_user(page, buf, count)) |
1291 | goto out_free; | 1301 | goto out; |
1292 | } | ||
1293 | 1302 | ||
1294 | if (sscanf(page, "%u", &new_value) != 1) { | 1303 | ret = -EINVAL; |
1295 | ret = -EINVAL; | 1304 | if (sscanf(page, "%u", &new_value) != 1) |
1296 | goto out; | 1305 | goto out; |
1297 | } | ||
1298 | 1306 | ||
1299 | if (new_value != avc_cache_threshold) { | 1307 | avc_cache_threshold = new_value; |
1300 | ret = task_has_security(current, SECURITY__SETSECPARAM); | 1308 | |
1301 | if (ret) | ||
1302 | goto out_free; | ||
1303 | avc_cache_threshold = new_value; | ||
1304 | } | ||
1305 | ret = count; | 1309 | ret = count; |
1306 | out_free: | ||
1307 | free_page((unsigned long)page); | ||
1308 | out: | 1310 | out: |
1311 | free_page((unsigned long)page); | ||
1309 | return ret; | 1312 | return ret; |
1310 | } | 1313 | } |
1311 | 1314 | ||
@@ -1313,19 +1316,18 @@ static ssize_t sel_read_avc_hash_stats(struct file *filp, char __user *buf, | |||
1313 | size_t count, loff_t *ppos) | 1316 | size_t count, loff_t *ppos) |
1314 | { | 1317 | { |
1315 | char *page; | 1318 | char *page; |
1316 | ssize_t ret = 0; | 1319 | ssize_t length; |
1317 | 1320 | ||
1318 | page = (char *)__get_free_page(GFP_KERNEL); | 1321 | page = (char *)__get_free_page(GFP_KERNEL); |
1319 | if (!page) { | 1322 | if (!page) |
1320 | ret = -ENOMEM; | 1323 | return -ENOMEM; |
1321 | goto out; | 1324 | |
1322 | } | 1325 | length = avc_get_hash_stats(page); |
1323 | ret = avc_get_hash_stats(page); | 1326 | if (length >= 0) |
1324 | if (ret >= 0) | 1327 | length = simple_read_from_buffer(buf, count, ppos, page, length); |
1325 | ret = simple_read_from_buffer(buf, count, ppos, page, ret); | ||
1326 | free_page((unsigned long)page); | 1328 | free_page((unsigned long)page); |
1327 | out: | 1329 | |
1328 | return ret; | 1330 | return length; |
1329 | } | 1331 | } |
1330 | 1332 | ||
1331 | static const struct file_operations sel_avc_cache_threshold_ops = { | 1333 | static const struct file_operations sel_avc_cache_threshold_ops = { |
@@ -1407,7 +1409,7 @@ static const struct file_operations sel_avc_cache_stats_ops = { | |||
1407 | 1409 | ||
1408 | static int sel_make_avc_files(struct dentry *dir) | 1410 | static int sel_make_avc_files(struct dentry *dir) |
1409 | { | 1411 | { |
1410 | int i, ret = 0; | 1412 | int i; |
1411 | static struct tree_descr files[] = { | 1413 | static struct tree_descr files[] = { |
1412 | { "cache_threshold", | 1414 | { "cache_threshold", |
1413 | &sel_avc_cache_threshold_ops, S_IRUGO|S_IWUSR }, | 1415 | &sel_avc_cache_threshold_ops, S_IRUGO|S_IWUSR }, |
@@ -1422,22 +1424,19 @@ static int sel_make_avc_files(struct dentry *dir) | |||
1422 | struct dentry *dentry; | 1424 | struct dentry *dentry; |
1423 | 1425 | ||
1424 | dentry = d_alloc_name(dir, files[i].name); | 1426 | dentry = d_alloc_name(dir, files[i].name); |
1425 | if (!dentry) { | 1427 | if (!dentry) |
1426 | ret = -ENOMEM; | 1428 | return -ENOMEM; |
1427 | goto out; | ||
1428 | } | ||
1429 | 1429 | ||
1430 | inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode); | 1430 | inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode); |
1431 | if (!inode) { | 1431 | if (!inode) |
1432 | ret = -ENOMEM; | 1432 | return -ENOMEM; |
1433 | goto out; | 1433 | |
1434 | } | ||
1435 | inode->i_fop = files[i].ops; | 1434 | inode->i_fop = files[i].ops; |
1436 | inode->i_ino = ++sel_last_ino; | 1435 | inode->i_ino = ++sel_last_ino; |
1437 | d_add(dentry, inode); | 1436 | d_add(dentry, inode); |
1438 | } | 1437 | } |
1439 | out: | 1438 | |
1440 | return ret; | 1439 | return 0; |
1441 | } | 1440 | } |
1442 | 1441 | ||
1443 | static ssize_t sel_read_initcon(struct file *file, char __user *buf, | 1442 | static ssize_t sel_read_initcon(struct file *file, char __user *buf, |
@@ -1451,7 +1450,7 @@ static ssize_t sel_read_initcon(struct file *file, char __user *buf, | |||
1451 | inode = file->f_path.dentry->d_inode; | 1450 | inode = file->f_path.dentry->d_inode; |
1452 | sid = inode->i_ino&SEL_INO_MASK; | 1451 | sid = inode->i_ino&SEL_INO_MASK; |
1453 | ret = security_sid_to_context(sid, &con, &len); | 1452 | ret = security_sid_to_context(sid, &con, &len); |
1454 | if (ret < 0) | 1453 | if (ret) |
1455 | return ret; | 1454 | return ret; |
1456 | 1455 | ||
1457 | ret = simple_read_from_buffer(buf, count, ppos, con, len); | 1456 | ret = simple_read_from_buffer(buf, count, ppos, con, len); |
@@ -1466,28 +1465,25 @@ static const struct file_operations sel_initcon_ops = { | |||
1466 | 1465 | ||
1467 | static int sel_make_initcon_files(struct dentry *dir) | 1466 | static int sel_make_initcon_files(struct dentry *dir) |
1468 | { | 1467 | { |
1469 | int i, ret = 0; | 1468 | int i; |
1470 | 1469 | ||
1471 | for (i = 1; i <= SECINITSID_NUM; i++) { | 1470 | for (i = 1; i <= SECINITSID_NUM; i++) { |
1472 | struct inode *inode; | 1471 | struct inode *inode; |
1473 | struct dentry *dentry; | 1472 | struct dentry *dentry; |
1474 | dentry = d_alloc_name(dir, security_get_initial_sid_context(i)); | 1473 | dentry = d_alloc_name(dir, security_get_initial_sid_context(i)); |
1475 | if (!dentry) { | 1474 | if (!dentry) |
1476 | ret = -ENOMEM; | 1475 | return -ENOMEM; |
1477 | goto out; | ||
1478 | } | ||
1479 | 1476 | ||
1480 | inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO); | 1477 | inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO); |
1481 | if (!inode) { | 1478 | if (!inode) |
1482 | ret = -ENOMEM; | 1479 | return -ENOMEM; |
1483 | goto out; | 1480 | |
1484 | } | ||
1485 | inode->i_fop = &sel_initcon_ops; | 1481 | inode->i_fop = &sel_initcon_ops; |
1486 | inode->i_ino = i|SEL_INITCON_INO_OFFSET; | 1482 | inode->i_ino = i|SEL_INITCON_INO_OFFSET; |
1487 | d_add(dentry, inode); | 1483 | d_add(dentry, inode); |
1488 | } | 1484 | } |
1489 | out: | 1485 | |
1490 | return ret; | 1486 | return 0; |
1491 | } | 1487 | } |
1492 | 1488 | ||
1493 | static inline unsigned int sel_div(unsigned long a, unsigned long b) | 1489 | static inline unsigned int sel_div(unsigned long a, unsigned long b) |
@@ -1523,15 +1519,13 @@ static ssize_t sel_read_class(struct file *file, char __user *buf, | |||
1523 | unsigned long ino = file->f_path.dentry->d_inode->i_ino; | 1519 | unsigned long ino = file->f_path.dentry->d_inode->i_ino; |
1524 | 1520 | ||
1525 | page = (char *)__get_free_page(GFP_KERNEL); | 1521 | page = (char *)__get_free_page(GFP_KERNEL); |
1526 | if (!page) { | 1522 | if (!page) |
1527 | rc = -ENOMEM; | 1523 | return -ENOMEM; |
1528 | goto out; | ||
1529 | } | ||
1530 | 1524 | ||
1531 | len = snprintf(page, PAGE_SIZE, "%d", sel_ino_to_class(ino)); | 1525 | len = snprintf(page, PAGE_SIZE, "%d", sel_ino_to_class(ino)); |
1532 | rc = simple_read_from_buffer(buf, count, ppos, page, len); | 1526 | rc = simple_read_from_buffer(buf, count, ppos, page, len); |
1533 | free_page((unsigned long)page); | 1527 | free_page((unsigned long)page); |
1534 | out: | 1528 | |
1535 | return rc; | 1529 | return rc; |
1536 | } | 1530 | } |
1537 | 1531 | ||
@@ -1548,15 +1542,13 @@ static ssize_t sel_read_perm(struct file *file, char __user *buf, | |||
1548 | unsigned long ino = file->f_path.dentry->d_inode->i_ino; | 1542 | unsigned long ino = file->f_path.dentry->d_inode->i_ino; |
1549 | 1543 | ||
1550 | page = (char *)__get_free_page(GFP_KERNEL); | 1544 | page = (char *)__get_free_page(GFP_KERNEL); |
1551 | if (!page) { | 1545 | if (!page) |
1552 | rc = -ENOMEM; | 1546 | return -ENOMEM; |
1553 | goto out; | ||
1554 | } | ||
1555 | 1547 | ||
1556 | len = snprintf(page, PAGE_SIZE, "%d", sel_ino_to_perm(ino)); | 1548 | len = snprintf(page, PAGE_SIZE, "%d", sel_ino_to_perm(ino)); |
1557 | rc = simple_read_from_buffer(buf, count, ppos, page, len); | 1549 | rc = simple_read_from_buffer(buf, count, ppos, page, len); |
1558 | free_page((unsigned long)page); | 1550 | free_page((unsigned long)page); |
1559 | out: | 1551 | |
1560 | return rc; | 1552 | return rc; |
1561 | } | 1553 | } |
1562 | 1554 | ||
@@ -1587,39 +1579,37 @@ static const struct file_operations sel_policycap_ops = { | |||
1587 | static int sel_make_perm_files(char *objclass, int classvalue, | 1579 | static int sel_make_perm_files(char *objclass, int classvalue, |
1588 | struct dentry *dir) | 1580 | struct dentry *dir) |
1589 | { | 1581 | { |
1590 | int i, rc = 0, nperms; | 1582 | int i, rc, nperms; |
1591 | char **perms; | 1583 | char **perms; |
1592 | 1584 | ||
1593 | rc = security_get_permissions(objclass, &perms, &nperms); | 1585 | rc = security_get_permissions(objclass, &perms, &nperms); |
1594 | if (rc) | 1586 | if (rc) |
1595 | goto out; | 1587 | return rc; |
1596 | 1588 | ||
1597 | for (i = 0; i < nperms; i++) { | 1589 | for (i = 0; i < nperms; i++) { |
1598 | struct inode *inode; | 1590 | struct inode *inode; |
1599 | struct dentry *dentry; | 1591 | struct dentry *dentry; |
1600 | 1592 | ||
1593 | rc = -ENOMEM; | ||
1601 | dentry = d_alloc_name(dir, perms[i]); | 1594 | dentry = d_alloc_name(dir, perms[i]); |
1602 | if (!dentry) { | 1595 | if (!dentry) |
1603 | rc = -ENOMEM; | 1596 | goto out; |
1604 | goto out1; | ||
1605 | } | ||
1606 | 1597 | ||
1598 | rc = -ENOMEM; | ||
1607 | inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO); | 1599 | inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO); |
1608 | if (!inode) { | 1600 | if (!inode) |
1609 | rc = -ENOMEM; | 1601 | goto out; |
1610 | goto out1; | 1602 | |
1611 | } | ||
1612 | inode->i_fop = &sel_perm_ops; | 1603 | inode->i_fop = &sel_perm_ops; |
1613 | /* i+1 since perm values are 1-indexed */ | 1604 | /* i+1 since perm values are 1-indexed */ |
1614 | inode->i_ino = sel_perm_to_ino(classvalue, i + 1); | 1605 | inode->i_ino = sel_perm_to_ino(classvalue, i + 1); |
1615 | d_add(dentry, inode); | 1606 | d_add(dentry, inode); |
1616 | } | 1607 | } |
1617 | 1608 | rc = 0; | |
1618 | out1: | 1609 | out: |
1619 | for (i = 0; i < nperms; i++) | 1610 | for (i = 0; i < nperms; i++) |
1620 | kfree(perms[i]); | 1611 | kfree(perms[i]); |
1621 | kfree(perms); | 1612 | kfree(perms); |
1622 | out: | ||
1623 | return rc; | 1613 | return rc; |
1624 | } | 1614 | } |
1625 | 1615 | ||
@@ -1631,34 +1621,27 @@ static int sel_make_class_dir_entries(char *classname, int index, | |||
1631 | int rc; | 1621 | int rc; |
1632 | 1622 | ||
1633 | dentry = d_alloc_name(dir, "index"); | 1623 | dentry = d_alloc_name(dir, "index"); |
1634 | if (!dentry) { | 1624 | if (!dentry) |
1635 | rc = -ENOMEM; | 1625 | return -ENOMEM; |
1636 | goto out; | ||
1637 | } | ||
1638 | 1626 | ||
1639 | inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO); | 1627 | inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO); |
1640 | if (!inode) { | 1628 | if (!inode) |
1641 | rc = -ENOMEM; | 1629 | return -ENOMEM; |
1642 | goto out; | ||
1643 | } | ||
1644 | 1630 | ||
1645 | inode->i_fop = &sel_class_ops; | 1631 | inode->i_fop = &sel_class_ops; |
1646 | inode->i_ino = sel_class_to_ino(index); | 1632 | inode->i_ino = sel_class_to_ino(index); |
1647 | d_add(dentry, inode); | 1633 | d_add(dentry, inode); |
1648 | 1634 | ||
1649 | dentry = d_alloc_name(dir, "perms"); | 1635 | dentry = d_alloc_name(dir, "perms"); |
1650 | if (!dentry) { | 1636 | if (!dentry) |
1651 | rc = -ENOMEM; | 1637 | return -ENOMEM; |
1652 | goto out; | ||
1653 | } | ||
1654 | 1638 | ||
1655 | rc = sel_make_dir(dir->d_inode, dentry, &last_class_ino); | 1639 | rc = sel_make_dir(dir->d_inode, dentry, &last_class_ino); |
1656 | if (rc) | 1640 | if (rc) |
1657 | goto out; | 1641 | return rc; |
1658 | 1642 | ||
1659 | rc = sel_make_perm_files(classname, index, dentry); | 1643 | rc = sel_make_perm_files(classname, index, dentry); |
1660 | 1644 | ||
1661 | out: | ||
1662 | return rc; | 1645 | return rc; |
1663 | } | 1646 | } |
1664 | 1647 | ||
@@ -1688,15 +1671,15 @@ static void sel_remove_classes(void) | |||
1688 | 1671 | ||
1689 | static int sel_make_classes(void) | 1672 | static int sel_make_classes(void) |
1690 | { | 1673 | { |
1691 | int rc = 0, nclasses, i; | 1674 | int rc, nclasses, i; |
1692 | char **classes; | 1675 | char **classes; |
1693 | 1676 | ||
1694 | /* delete any existing entries */ | 1677 | /* delete any existing entries */ |
1695 | sel_remove_classes(); | 1678 | sel_remove_classes(); |
1696 | 1679 | ||
1697 | rc = security_get_classes(&classes, &nclasses); | 1680 | rc = security_get_classes(&classes, &nclasses); |
1698 | if (rc < 0) | 1681 | if (rc) |
1699 | goto out; | 1682 | return rc; |
1700 | 1683 | ||
1701 | /* +2 since classes are 1-indexed */ | 1684 | /* +2 since classes are 1-indexed */ |
1702 | last_class_ino = sel_class_to_ino(nclasses + 2); | 1685 | last_class_ino = sel_class_to_ino(nclasses + 2); |
@@ -1704,29 +1687,27 @@ static int sel_make_classes(void) | |||
1704 | for (i = 0; i < nclasses; i++) { | 1687 | for (i = 0; i < nclasses; i++) { |
1705 | struct dentry *class_name_dir; | 1688 | struct dentry *class_name_dir; |
1706 | 1689 | ||
1690 | rc = -ENOMEM; | ||
1707 | class_name_dir = d_alloc_name(class_dir, classes[i]); | 1691 | class_name_dir = d_alloc_name(class_dir, classes[i]); |
1708 | if (!class_name_dir) { | 1692 | if (!class_name_dir) |
1709 | rc = -ENOMEM; | 1693 | goto out; |
1710 | goto out1; | ||
1711 | } | ||
1712 | 1694 | ||
1713 | rc = sel_make_dir(class_dir->d_inode, class_name_dir, | 1695 | rc = sel_make_dir(class_dir->d_inode, class_name_dir, |
1714 | &last_class_ino); | 1696 | &last_class_ino); |
1715 | if (rc) | 1697 | if (rc) |
1716 | goto out1; | 1698 | goto out; |
1717 | 1699 | ||
1718 | /* i+1 since class values are 1-indexed */ | 1700 | /* i+1 since class values are 1-indexed */ |
1719 | rc = sel_make_class_dir_entries(classes[i], i + 1, | 1701 | rc = sel_make_class_dir_entries(classes[i], i + 1, |
1720 | class_name_dir); | 1702 | class_name_dir); |
1721 | if (rc) | 1703 | if (rc) |
1722 | goto out1; | 1704 | goto out; |
1723 | } | 1705 | } |
1724 | 1706 | rc = 0; | |
1725 | out1: | 1707 | out: |
1726 | for (i = 0; i < nclasses; i++) | 1708 | for (i = 0; i < nclasses; i++) |
1727 | kfree(classes[i]); | 1709 | kfree(classes[i]); |
1728 | kfree(classes); | 1710 | kfree(classes); |
1729 | out: | ||
1730 | return rc; | 1711 | return rc; |
1731 | } | 1712 | } |
1732 | 1713 | ||
@@ -1763,14 +1744,12 @@ static int sel_make_policycap(void) | |||
1763 | static int sel_make_dir(struct inode *dir, struct dentry *dentry, | 1744 | static int sel_make_dir(struct inode *dir, struct dentry *dentry, |
1764 | unsigned long *ino) | 1745 | unsigned long *ino) |
1765 | { | 1746 | { |
1766 | int ret = 0; | ||
1767 | struct inode *inode; | 1747 | struct inode *inode; |
1768 | 1748 | ||
1769 | inode = sel_make_inode(dir->i_sb, S_IFDIR | S_IRUGO | S_IXUGO); | 1749 | inode = sel_make_inode(dir->i_sb, S_IFDIR | S_IRUGO | S_IXUGO); |
1770 | if (!inode) { | 1750 | if (!inode) |
1771 | ret = -ENOMEM; | 1751 | return -ENOMEM; |
1772 | goto out; | 1752 | |
1773 | } | ||
1774 | inode->i_op = &simple_dir_inode_operations; | 1753 | inode->i_op = &simple_dir_inode_operations; |
1775 | inode->i_fop = &simple_dir_operations; | 1754 | inode->i_fop = &simple_dir_operations; |
1776 | inode->i_ino = ++(*ino); | 1755 | inode->i_ino = ++(*ino); |
@@ -1779,8 +1758,8 @@ static int sel_make_dir(struct inode *dir, struct dentry *dentry, | |||
1779 | d_add(dentry, inode); | 1758 | d_add(dentry, inode); |
1780 | /* bump link count on parent directory, too */ | 1759 | /* bump link count on parent directory, too */ |
1781 | inc_nlink(dir); | 1760 | inc_nlink(dir); |
1782 | out: | 1761 | |
1783 | return ret; | 1762 | return 0; |
1784 | } | 1763 | } |
1785 | 1764 | ||
1786 | static int sel_fill_super(struct super_block *sb, void *data, int silent) | 1765 | static int sel_fill_super(struct super_block *sb, void *data, int silent) |
@@ -1816,11 +1795,10 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) | |||
1816 | 1795 | ||
1817 | root_inode = sb->s_root->d_inode; | 1796 | root_inode = sb->s_root->d_inode; |
1818 | 1797 | ||
1798 | ret = -ENOMEM; | ||
1819 | dentry = d_alloc_name(sb->s_root, BOOL_DIR_NAME); | 1799 | dentry = d_alloc_name(sb->s_root, BOOL_DIR_NAME); |
1820 | if (!dentry) { | 1800 | if (!dentry) |
1821 | ret = -ENOMEM; | ||
1822 | goto err; | 1801 | goto err; |
1823 | } | ||
1824 | 1802 | ||
1825 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); | 1803 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); |
1826 | if (ret) | 1804 | if (ret) |
@@ -1828,17 +1806,16 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) | |||
1828 | 1806 | ||
1829 | bool_dir = dentry; | 1807 | bool_dir = dentry; |
1830 | 1808 | ||
1809 | ret = -ENOMEM; | ||
1831 | dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME); | 1810 | dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME); |
1832 | if (!dentry) { | 1811 | if (!dentry) |
1833 | ret = -ENOMEM; | ||
1834 | goto err; | 1812 | goto err; |
1835 | } | ||
1836 | 1813 | ||
1814 | ret = -ENOMEM; | ||
1837 | inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO); | 1815 | inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO); |
1838 | if (!inode) { | 1816 | if (!inode) |
1839 | ret = -ENOMEM; | ||
1840 | goto err; | 1817 | goto err; |
1841 | } | 1818 | |
1842 | inode->i_ino = ++sel_last_ino; | 1819 | inode->i_ino = ++sel_last_ino; |
1843 | isec = (struct inode_security_struct *)inode->i_security; | 1820 | isec = (struct inode_security_struct *)inode->i_security; |
1844 | isec->sid = SECINITSID_DEVNULL; | 1821 | isec->sid = SECINITSID_DEVNULL; |
@@ -1849,11 +1826,10 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) | |||
1849 | d_add(dentry, inode); | 1826 | d_add(dentry, inode); |
1850 | selinux_null = dentry; | 1827 | selinux_null = dentry; |
1851 | 1828 | ||
1829 | ret = -ENOMEM; | ||
1852 | dentry = d_alloc_name(sb->s_root, "avc"); | 1830 | dentry = d_alloc_name(sb->s_root, "avc"); |
1853 | if (!dentry) { | 1831 | if (!dentry) |
1854 | ret = -ENOMEM; | ||
1855 | goto err; | 1832 | goto err; |
1856 | } | ||
1857 | 1833 | ||
1858 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); | 1834 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); |
1859 | if (ret) | 1835 | if (ret) |
@@ -1863,11 +1839,10 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) | |||
1863 | if (ret) | 1839 | if (ret) |
1864 | goto err; | 1840 | goto err; |
1865 | 1841 | ||
1842 | ret = -ENOMEM; | ||
1866 | dentry = d_alloc_name(sb->s_root, "initial_contexts"); | 1843 | dentry = d_alloc_name(sb->s_root, "initial_contexts"); |
1867 | if (!dentry) { | 1844 | if (!dentry) |
1868 | ret = -ENOMEM; | ||
1869 | goto err; | 1845 | goto err; |
1870 | } | ||
1871 | 1846 | ||
1872 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); | 1847 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); |
1873 | if (ret) | 1848 | if (ret) |
@@ -1877,11 +1852,10 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) | |||
1877 | if (ret) | 1852 | if (ret) |
1878 | goto err; | 1853 | goto err; |
1879 | 1854 | ||
1855 | ret = -ENOMEM; | ||
1880 | dentry = d_alloc_name(sb->s_root, "class"); | 1856 | dentry = d_alloc_name(sb->s_root, "class"); |
1881 | if (!dentry) { | 1857 | if (!dentry) |
1882 | ret = -ENOMEM; | ||
1883 | goto err; | 1858 | goto err; |
1884 | } | ||
1885 | 1859 | ||
1886 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); | 1860 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); |
1887 | if (ret) | 1861 | if (ret) |
@@ -1889,11 +1863,10 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) | |||
1889 | 1863 | ||
1890 | class_dir = dentry; | 1864 | class_dir = dentry; |
1891 | 1865 | ||
1866 | ret = -ENOMEM; | ||
1892 | dentry = d_alloc_name(sb->s_root, "policy_capabilities"); | 1867 | dentry = d_alloc_name(sb->s_root, "policy_capabilities"); |
1893 | if (!dentry) { | 1868 | if (!dentry) |
1894 | ret = -ENOMEM; | ||
1895 | goto err; | 1869 | goto err; |
1896 | } | ||
1897 | 1870 | ||
1898 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); | 1871 | ret = sel_make_dir(root_inode, dentry, &sel_last_ino); |
1899 | if (ret) | 1872 | if (ret) |
@@ -1901,12 +1874,11 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) | |||
1901 | 1874 | ||
1902 | policycap_dir = dentry; | 1875 | policycap_dir = dentry; |
1903 | 1876 | ||
1904 | out: | 1877 | return 0; |
1905 | return ret; | ||
1906 | err: | 1878 | err: |
1907 | printk(KERN_ERR "SELinux: %s: failed while creating inodes\n", | 1879 | printk(KERN_ERR "SELinux: %s: failed while creating inodes\n", |
1908 | __func__); | 1880 | __func__); |
1909 | goto out; | 1881 | return ret; |
1910 | } | 1882 | } |
1911 | 1883 | ||
1912 | static struct dentry *sel_mount(struct file_system_type *fs_type, | 1884 | static struct dentry *sel_mount(struct file_system_type *fs_type, |
@@ -1930,14 +1902,16 @@ static int __init init_sel_fs(void) | |||
1930 | if (!selinux_enabled) | 1902 | if (!selinux_enabled) |
1931 | return 0; | 1903 | return 0; |
1932 | err = register_filesystem(&sel_fs_type); | 1904 | err = register_filesystem(&sel_fs_type); |
1933 | if (!err) { | 1905 | if (err) |
1934 | selinuxfs_mount = kern_mount(&sel_fs_type); | 1906 | return err; |
1935 | if (IS_ERR(selinuxfs_mount)) { | 1907 | |
1936 | printk(KERN_ERR "selinuxfs: could not mount!\n"); | 1908 | selinuxfs_mount = kern_mount(&sel_fs_type); |
1937 | err = PTR_ERR(selinuxfs_mount); | 1909 | if (IS_ERR(selinuxfs_mount)) { |
1938 | selinuxfs_mount = NULL; | 1910 | printk(KERN_ERR "selinuxfs: could not mount!\n"); |
1939 | } | 1911 | err = PTR_ERR(selinuxfs_mount); |
1912 | selinuxfs_mount = NULL; | ||
1940 | } | 1913 | } |
1914 | |||
1941 | return err; | 1915 | return err; |
1942 | } | 1916 | } |
1943 | 1917 | ||