security: optimize avc_audit() common path
[linux-2.6.git] / security / selinux / avc.c
index 3d2715f..6989472 100644 (file)
@@ -457,6 +457,42 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
                           ad->selinux_audit_data.tclass);
 }
 
+/* This is the slow part of avc audit with big stack footprint */
+static noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
+               u32 requested, u32 audited, u32 denied,
+               struct av_decision *avd, struct common_audit_data *a,
+               unsigned flags)
+{
+       struct common_audit_data stack_data;
+
+       if (!a) {
+               a = &stack_data;
+               COMMON_AUDIT_DATA_INIT(a, NONE);
+       }
+
+       /*
+        * When in a RCU walk do the audit on the RCU retry.  This is because
+        * the collection of the dname in an inode audit message is not RCU
+        * safe.  Note this may drop some audits when the situation changes
+        * during retry. However this is logically just as if the operation
+        * happened a little later.
+        */
+       if ((a->type == LSM_AUDIT_DATA_INODE) &&
+           (flags & MAY_NOT_BLOCK))
+               return -ECHILD;
+
+       a->selinux_audit_data.tclass = tclass;
+       a->selinux_audit_data.requested = requested;
+       a->selinux_audit_data.ssid = ssid;
+       a->selinux_audit_data.tsid = tsid;
+       a->selinux_audit_data.audited = audited;
+       a->selinux_audit_data.denied = denied;
+       a->lsm_pre_audit = avc_audit_pre_callback;
+       a->lsm_post_audit = avc_audit_post_callback;
+       common_lsm_audit(a);
+       return 0;
+}
+
 /**
  * avc_audit - Audit the granting or denial of permissions.
  * @ssid: source security identifier
@@ -482,10 +518,9 @@ int avc_audit(u32 ssid, u32 tsid,
               struct av_decision *avd, int result, struct common_audit_data *a,
               unsigned flags)
 {
-       struct common_audit_data stack_data;
        u32 denied, audited;
        denied = requested & ~avd->allowed;
-       if (denied) {
+       if (unlikely(denied)) {
                audited = denied & avd->auditdeny;
                /*
                 * a->selinux_audit_data.auditdeny is TRICKY!  Setting a bit in
@@ -511,35 +546,12 @@ int avc_audit(u32 ssid, u32 tsid,
                audited = denied = requested;
        else
                audited = requested & avd->auditallow;
-       if (!audited)
+       if (likely(!audited))
                return 0;
 
-       if (!a) {
-               a = &stack_data;
-               COMMON_AUDIT_DATA_INIT(a, NONE);
-       }
-
-       /*
-        * When in a RCU walk do the audit on the RCU retry.  This is because
-        * the collection of the dname in an inode audit message is not RCU
-        * safe.  Note this may drop some audits when the situation changes
-        * during retry. However this is logically just as if the operation
-        * happened a little later.
-        */
-       if ((a->type == LSM_AUDIT_DATA_FS) &&
-           (flags & IPERM_FLAG_RCU))
-               return -ECHILD;
-
-       a->selinux_audit_data.tclass = tclass;
-       a->selinux_audit_data.requested = requested;
-       a->selinux_audit_data.ssid = ssid;
-       a->selinux_audit_data.tsid = tsid;
-       a->selinux_audit_data.audited = audited;
-       a->selinux_audit_data.denied = denied;
-       a->lsm_pre_audit = avc_audit_pre_callback;
-       a->lsm_post_audit = avc_audit_post_callback;
-       common_lsm_audit(a);
-       return 0;
+       return slow_avc_audit(ssid, tsid, tclass,
+               requested, audited, denied,
+               avd, a, flags);
 }
 
 /**
@@ -752,10 +764,9 @@ int avc_ss_reset(u32 seqno)
 int avc_has_perm_noaudit(u32 ssid, u32 tsid,
                         u16 tclass, u32 requested,
                         unsigned flags,
-                        struct av_decision *in_avd)
+                        struct av_decision *avd)
 {
        struct avc_node *node;
-       struct av_decision avd_entry, *avd;
        int rc = 0;
        u32 denied;
 
@@ -766,18 +777,11 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
        node = avc_lookup(ssid, tsid, tclass);
        if (unlikely(!node)) {
                rcu_read_unlock();
-
-               if (in_avd)
-                       avd = in_avd;
-               else
-                       avd = &avd_entry;
-
                security_compute_av(ssid, tsid, tclass, avd);
                rcu_read_lock();
                node = avc_insert(ssid, tsid, tclass, avd);
        } else {
-               if (in_avd)
-                       memcpy(in_avd, &node->ae.avd, sizeof(*in_avd));
+               memcpy(avd, &node->ae.avd, sizeof(*avd));
                avd = &node->ae.avd;
        }