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
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index cf5fd22..8132003 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -724,6 +724,8 @@
  */
 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 @@
 	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);
 }