diff options
-rw-r--r-- | security/selinux/avc.c | 52 |
1 files changed, 38 insertions, 14 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 6989472d0957..07620bc94e2a 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -741,6 +741,41 @@ int avc_ss_reset(u32 seqno) | |||
741 | return rc; | 741 | return rc; |
742 | } | 742 | } |
743 | 743 | ||
744 | /* | ||
745 | * Slow-path helper function for avc_has_perm_noaudit, | ||
746 | * when the avc_node lookup fails. We get called with | ||
747 | * the RCU read lock held, and need to return with it | ||
748 | * still held, but drop if for the security compute. | ||
749 | * | ||
750 | * Don't inline this, since it's the slow-path and just | ||
751 | * results in a bigger stack frame. | ||
752 | */ | ||
753 | static noinline struct avc_node *avc_compute_av(u32 ssid, u32 tsid, | ||
754 | u16 tclass, struct av_decision *avd) | ||
755 | { | ||
756 | rcu_read_unlock(); | ||
757 | security_compute_av(ssid, tsid, tclass, avd); | ||
758 | rcu_read_lock(); | ||
759 | return avc_insert(ssid, tsid, tclass, avd); | ||
760 | } | ||
761 | |||
762 | static noinline int avc_denied(u32 ssid, u32 tsid, | ||
763 | u16 tclass, u32 requested, | ||
764 | unsigned flags, | ||
765 | struct av_decision *avd) | ||
766 | { | ||
767 | if (flags & AVC_STRICT) | ||
768 | return -EACCES; | ||
769 | |||
770 | if (selinux_enforcing && !(avd->flags & AVD_FLAGS_PERMISSIVE)) | ||
771 | return -EACCES; | ||
772 | |||
773 | avc_update_node(AVC_CALLBACK_GRANT, requested, ssid, | ||
774 | tsid, tclass, avd->seqno); | ||
775 | return 0; | ||
776 | } | ||
777 | |||
778 | |||
744 | /** | 779 | /** |
745 | * avc_has_perm_noaudit - Check permissions but perform no auditing. | 780 | * avc_has_perm_noaudit - Check permissions but perform no auditing. |
746 | * @ssid: source security identifier | 781 | * @ssid: source security identifier |
@@ -776,26 +811,15 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, | |||
776 | 811 | ||
777 | node = avc_lookup(ssid, tsid, tclass); | 812 | node = avc_lookup(ssid, tsid, tclass); |
778 | if (unlikely(!node)) { | 813 | if (unlikely(!node)) { |
779 | rcu_read_unlock(); | 814 | node = avc_compute_av(ssid, tsid, tclass, avd); |
780 | security_compute_av(ssid, tsid, tclass, avd); | ||
781 | rcu_read_lock(); | ||
782 | node = avc_insert(ssid, tsid, tclass, avd); | ||
783 | } else { | 815 | } else { |
784 | memcpy(avd, &node->ae.avd, sizeof(*avd)); | 816 | memcpy(avd, &node->ae.avd, sizeof(*avd)); |
785 | avd = &node->ae.avd; | 817 | avd = &node->ae.avd; |
786 | } | 818 | } |
787 | 819 | ||
788 | denied = requested & ~(avd->allowed); | 820 | denied = requested & ~(avd->allowed); |
789 | 821 | if (unlikely(denied)) | |
790 | if (denied) { | 822 | rc = avc_denied(ssid, tsid, tclass, requested, flags, avd); |
791 | if (flags & AVC_STRICT) | ||
792 | rc = -EACCES; | ||
793 | else if (!selinux_enforcing || (avd->flags & AVD_FLAGS_PERMISSIVE)) | ||
794 | avc_update_node(AVC_CALLBACK_GRANT, requested, ssid, | ||
795 | tsid, tclass, avd->seqno); | ||
796 | else | ||
797 | rc = -EACCES; | ||
798 | } | ||
799 | 823 | ||
800 | rcu_read_unlock(); | 824 | rcu_read_unlock(); |
801 | return rc; | 825 | return rc; |