diff options
Diffstat (limited to 'security/selinux/avc.c')
| -rw-r--r-- | security/selinux/avc.c | 70 | 
1 files changed, 41 insertions, 29 deletions
| diff --git a/security/selinux/avc.c b/security/selinux/avc.c index dca1c22d9276..6989472d0957 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -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_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; +	return slow_avc_audit(ssid, tsid, tclass, +		requested, audited, denied, +		avd, a, flags);  }  /** | 
