From patchwork Wed Sep 26 15:59:34 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tim Gardner X-Patchwork-Id: 187111 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from chlorine.canonical.com (chlorine.canonical.com [91.189.94.204]) by ozlabs.org (Postfix) with ESMTP id 248D62C0090 for ; Thu, 27 Sep 2012 01:59:54 +1000 (EST) Received: from localhost ([127.0.0.1] helo=chlorine.canonical.com) by chlorine.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1TGtyz-0007ou-QF; Wed, 26 Sep 2012 15:57:06 +0000 Received: from mail.tpi.com ([70.99.223.143]) by chlorine.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1TGtyw-0007lj-LF for kernel-team@lists.ubuntu.com; Wed, 26 Sep 2012 15:57:03 +0000 Received: from salmon.rtg.net (mail.tpi.com [70.99.223.143]) by mail.tpi.com (Postfix) with ESMTP id EEE1132CDB7 for ; Wed, 26 Sep 2012 08:59:23 -0700 (PDT) Received: by salmon.rtg.net (Postfix, from userid 1000) id 2C18920BC3; Wed, 26 Sep 2012 09:59:35 -0600 (MDT) From: Tim Gardner To: kernel-team@lists.ubuntu.com Subject: [PATCH Precise SRU] UBUNTU SAUCE: apparmor: fix IRQ stack overflow Date: Wed, 26 Sep 2012 09:59:34 -0600 Message-Id: <1348675174-95879-1-git-send-email-tim.gardner@canonical.com> X-Mailer: git-send-email 1.7.9.5 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.13 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: kernel-team-bounces@lists.ubuntu.com Errors-To: kernel-team-bounces@lists.ubuntu.com From: John Johansen BugLink: http://bugs.launchpad.net/bugs/1056078 Profile replacement can cause a long chain of profiles to build up that get freed in a cascading chain of free_profile calls. Because free_profile is being called via aa_put_profile (and hence kref_put) each profile free is done via what amounts to recursion. That is free_profile indirectly calls free_profile on the next profile in the chain via aa_put_profile. Break this recursion by directly walking the chain, and as long as a profile is being freed because it has no more references continue on to the next profile. This results in at most 2 levels of free_profile being called. Signed-off-by: John Johansen Signed-off-by: Tim Gardner Acked-by: Colin Ian King --- security/apparmor/policy.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 4a5e1b5..93faca0 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) @@ -752,7 +754,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, but not via put_profile/kref_put + * replacedby can form a long chain that can result in cascading + * frees that blows the stack lp#1056078. The long chain creation + * should be addressed in profile replacement. + * This just addresses recursion of free_profile causing the + * stack to blow. + */ + 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); }