summaryrefslogtreecommitdiff
path: root/security/selinux/avc.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux/avc.c')
-rw-r--r--security/selinux/avc.c101
1 files changed, 64 insertions, 37 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 6989472d0957..8ee42b2a5f19 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -436,9 +436,9 @@ static void avc_audit_pre_callback(struct audit_buffer *ab, void *a)
{
struct common_audit_data *ad = a;
audit_log_format(ab, "avc: %s ",
- ad->selinux_audit_data.denied ? "denied" : "granted");
- avc_dump_av(ab, ad->selinux_audit_data.tclass,
- ad->selinux_audit_data.audited);
+ ad->selinux_audit_data->slad->denied ? "denied" : "granted");
+ avc_dump_av(ab, ad->selinux_audit_data->slad->tclass,
+ ad->selinux_audit_data->slad->audited);
audit_log_format(ab, " for ");
}
@@ -452,22 +452,25 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
{
struct common_audit_data *ad = a;
audit_log_format(ab, " ");
- avc_dump_query(ab, ad->selinux_audit_data.ssid,
- ad->selinux_audit_data.tsid,
- ad->selinux_audit_data.tclass);
+ avc_dump_query(ab, ad->selinux_audit_data->slad->ssid,
+ ad->selinux_audit_data->slad->tsid,
+ ad->selinux_audit_data->slad->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,
+ struct common_audit_data *a,
unsigned flags)
{
struct common_audit_data stack_data;
+ struct selinux_audit_data sad = {0,};
+ struct selinux_late_audit_data slad;
if (!a) {
a = &stack_data;
COMMON_AUDIT_DATA_INIT(a, NONE);
+ a->selinux_audit_data = &sad;
}
/*
@@ -481,15 +484,15 @@ static noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
(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);
+ slad.tclass = tclass;
+ slad.requested = requested;
+ slad.ssid = ssid;
+ slad.tsid = tsid;
+ slad.audited = audited;
+ slad.denied = denied;
+
+ a->selinux_audit_data->slad = &slad;
+ common_lsm_audit(a, avc_audit_pre_callback, avc_audit_post_callback);
return 0;
}
@@ -513,7 +516,7 @@ static noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
* be performed under a lock, to allow the lock to be released
* before calling the auditing code.
*/
-int avc_audit(u32 ssid, u32 tsid,
+inline int avc_audit(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct av_decision *avd, int result, struct common_audit_data *a,
unsigned flags)
@@ -523,7 +526,7 @@ int avc_audit(u32 ssid, u32 tsid,
if (unlikely(denied)) {
audited = denied & avd->auditdeny;
/*
- * a->selinux_audit_data.auditdeny is TRICKY! Setting a bit in
+ * a->selinux_audit_data->auditdeny is TRICKY! Setting a bit in
* this field means that ANY denials should NOT be audited if
* the policy contains an explicit dontaudit rule for that
* permission. Take notice that this is unrelated to the
@@ -532,15 +535,15 @@ int avc_audit(u32 ssid, u32 tsid,
*
* denied == READ
* avd.auditdeny & ACCESS == 0 (not set means explicit rule)
- * selinux_audit_data.auditdeny & ACCESS == 1
+ * selinux_audit_data->auditdeny & ACCESS == 1
*
* We will NOT audit the denial even though the denied
* permission was READ and the auditdeny checks were for
* ACCESS
*/
if (a &&
- a->selinux_audit_data.auditdeny &&
- !(a->selinux_audit_data.auditdeny & avd->auditdeny))
+ a->selinux_audit_data->auditdeny &&
+ !(a->selinux_audit_data->auditdeny & avd->auditdeny))
audited = 0;
} else if (result)
audited = denied = requested;
@@ -551,7 +554,7 @@ int avc_audit(u32 ssid, u32 tsid,
return slow_avc_audit(ssid, tsid, tclass,
requested, audited, denied,
- avd, a, flags);
+ a, flags);
}
/**
@@ -741,6 +744,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
@@ -761,7 +799,7 @@ int avc_ss_reset(u32 seqno)
* auditing, e.g. in cases where a lock must be held for the check but
* should be released for the auditing.
*/
-int avc_has_perm_noaudit(u32 ssid, u32 tsid,
+inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
unsigned flags,
struct av_decision *avd)
@@ -776,26 +814,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;