aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-03-31 10:58:08 -0700
committerGerrit Code Review <gerrit@cyanogenmod.org>2015-11-09 06:36:32 -0800
commit0829ab05e113d5b52dfa4c8de94eb7bfffdf72bb (patch)
tree511c0aa902389558518d77efbbdb545682facfa6 /security
parentda5606533e0bebb408b7e6df68caea46d387598e (diff)
downloadkernel_samsung_smdk4412-0829ab05e113d5b52dfa4c8de94eb7bfffdf72bb.zip
kernel_samsung_smdk4412-0829ab05e113d5b52dfa4c8de94eb7bfffdf72bb.tar.gz
kernel_samsung_smdk4412-0829ab05e113d5b52dfa4c8de94eb7bfffdf72bb.tar.bz2
selinux: don't inline slow-path code into avc_has_perm_noaudit()
The selinux AVC paths remain some of the hottest (and deepest) codepaths at filename lookup time, and we make it worse by having the slow path cases take up I$ and stack space even when they don't trigger. Gcc tends to always want to inline functions that are just called once - never mind that this might make for slower and worse code in the caller. So this tries to improve on it a bit by making the slow-path cases explicitly separate functions that are marked noinline, causing gcc to at least no longer allocate stack space for them unless they are actually called. It also seems to help register allocation a tiny bit, since gcc now doesn't take the slow case code into account. Uninlining the slow path may also allow us to inline the remaining hot path into the one caller that actually matters: avc_has_perm_flags(). I'll have to look at that separately, but both avc_audit() and avc_has_perm_noaudit() are now small and lean enough that inlining them may make sense. Change-Id: Ibc0563b84cbbde9afca15af78e957917a4f72bc6 Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'security')
-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 e759527..799b0f9 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -741,6 +741,41 @@ int avc_ss_reset(u32 seqno)
return rc;
}
+/*
+ * Slow-path helper function for avc_has_perm_noaudit,
+ * when the avc_node lookup fails. We get called with
+ * the RCU read lock held, and need to return with it
+ * still held, but drop if for the security compute.
+ *
+ * Don't inline this, since it's the slow-path and just
+ * results in a bigger stack frame.
+ */
+static noinline struct avc_node *avc_compute_av(u32 ssid, u32 tsid,
+ u16 tclass, struct av_decision *avd)
+{
+ rcu_read_unlock();
+ security_compute_av(ssid, tsid, tclass, avd);
+ rcu_read_lock();
+ return avc_insert(ssid, tsid, tclass, avd);
+}
+
+static noinline int avc_denied(u32 ssid, u32 tsid,
+ u16 tclass, u32 requested,
+ unsigned flags,
+ struct av_decision *avd)
+{
+ if (flags & AVC_STRICT)
+ return -EACCES;
+
+ if (selinux_enforcing && !(avd->flags & AVD_FLAGS_PERMISSIVE))
+ return -EACCES;
+
+ avc_update_node(AVC_CALLBACK_GRANT, requested, ssid,
+ tsid, tclass, avd->seqno);
+ return 0;
+}
+
+
/**
* avc_has_perm_noaudit - Check permissions but perform no auditing.
* @ssid: source security identifier
@@ -776,26 +811,15 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
node = avc_lookup(ssid, tsid, tclass);
if (unlikely(!node)) {
- rcu_read_unlock();
- security_compute_av(ssid, tsid, tclass, avd);
- rcu_read_lock();
- node = avc_insert(ssid, tsid, tclass, avd);
+ node = avc_compute_av(ssid, tsid, tclass, avd);
} else {
memcpy(avd, &node->ae.avd, sizeof(*avd));
avd = &node->ae.avd;
}
denied = requested & ~(avd->allowed);
-
- if (denied) {
- if (flags & AVC_STRICT)
- rc = -EACCES;
- else if (!selinux_enforcing || (avd->flags & AVD_FLAGS_PERMISSIVE))
- avc_update_node(AVC_CALLBACK_GRANT, requested, ssid,
- tsid, tclass, avd->seqno);
- else
- rc = -EACCES;
- }
+ if (unlikely(denied))
+ rc = avc_denied(ssid, tsid, tclass, requested, flags, avd);
rcu_read_unlock();
return rc;