aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--security/selinux/avc.c52
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 */
753static 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
762static 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;