summaryrefslogtreecommitdiffstats
path: root/security/apparmor/policy.c
diff options
context:
space:
mode:
authorAlexander Graf <agraf@suse.de>2012-10-31 13:36:18 +0100
committerAlexander Graf <agraf@suse.de>2012-10-31 13:36:18 +0100
commit0588000eac9ba4178cebade437da3b28e8fad48f (patch)
tree697e514a0a0193f17a54f372dd18c5cd3927e154 /security/apparmor/policy.c
parent8b5869ad85f703ffeb25e656eab826f6b85b984c (diff)
parent81c52c56e2b43589091ee29038bcf793d3f184ab (diff)
Merge commit 'origin/queue' into for-queue
Conflicts: arch/powerpc/include/asm/Kbuild arch/powerpc/include/uapi/asm/Kbuild
Diffstat (limited to 'security/apparmor/policy.c')
-rw-r--r--security/apparmor/policy.c24
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);
}