diff options
Diffstat (limited to 'security/apparmor/policy.c')
| -rw-r--r-- | security/apparmor/policy.c | 24 | 
1 files changed, 23 insertions, 1 deletions
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index cf5fd220309..813200384d9 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -724,6 +724,8 @@ fail:   */  static void free_profile(struct aa_profile *profile)  { +	struct aa_profile *p; +  	AA_DEBUG("%s(%p)\n", __func__, profile);  	if (!profile) @@ -751,7 +753,27 @@ static void free_profile(struct aa_profile *profile)  	aa_put_dfa(profile->xmatch);  	aa_put_dfa(profile->policy.dfa); -	aa_put_profile(profile->replacedby); +	/* put the profile reference for replacedby, but not via +	 * put_profile(kref_put). +	 * replacedby can form a long chain that can result in cascading +	 * frees that blows the stack because kref_put makes a nested fn +	 * call (it looks like recursion, with free_profile calling +	 * free_profile) for each profile in the chain lp#1056078. +	 */ +	for (p = profile->replacedby; p; ) { +		if (atomic_dec_and_test(&p->base.count.refcount)) { +			/* no more refs on p, grab its replacedby */ +			struct aa_profile *next = p->replacedby; +			/* break the chain */ +			p->replacedby = NULL; +			/* now free p, chain is broken */ +			free_profile(p); + +			/* follow up with next profile in the chain */ +			p = next; +		} else +			break; +	}  	kzfree(profile);  }  |