Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security

Pull apparmor bugfix from James Morris.

Fix a possibly unbounded recursion by iterating over the entries instead.

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
  apparmor: fix IRQ stack overflow during free_profile
This commit is contained in:
Linus Torvalds 2012-10-24 16:58:20 -07:00
commit 206aa6a6c5
1 changed files with 23 additions and 1 deletions

View File

@ -724,6 +724,8 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat)
*/ */
static void free_profile(struct aa_profile *profile) static void free_profile(struct aa_profile *profile)
{ {
struct aa_profile *p;
AA_DEBUG("%s(%p)\n", __func__, profile); AA_DEBUG("%s(%p)\n", __func__, profile);
if (!profile) if (!profile)
@ -751,7 +753,27 @@ static void free_profile(struct aa_profile *profile)
aa_put_dfa(profile->xmatch); aa_put_dfa(profile->xmatch);
aa_put_dfa(profile->policy.dfa); 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); kzfree(profile);
} }