From patchwork Wed May 15 13:02:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrea Righi X-Patchwork-Id: 1100037 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 453vr758K3z9sBV; Wed, 15 May 2019 23:03:35 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1hQtZE-0000C7-3b; Wed, 15 May 2019 13:03:32 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:128) (Exim 4.86_2) (envelope-from ) id 1hQtZB-0000Ar-6t for kernel-team@lists.ubuntu.com; Wed, 15 May 2019 13:03:29 +0000 Received: from mail-wr1-f71.google.com ([209.85.221.71]) by youngberry.canonical.com with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1hQtZA-0006Qe-Ml for kernel-team@lists.ubuntu.com; Wed, 15 May 2019 13:03:28 +0000 Received: by mail-wr1-f71.google.com with SMTP id p3so1109008wrw.0 for ; Wed, 15 May 2019 06:03:28 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=u+a/sMZD10CpVLdr8zZZ2GKWu3d1vvnahStxClEqsd0=; b=I/IGVxLOCczI8+y1Q+gtjw6+MJFH14lG1duYF5fiDwV6ptyp2RWn7d6U0kzNOEJTvD pwZs7Q1B6eL2ES8ZR5t/H1ls9GE87+L7yIGpZLz/ntIyAJDNpU9AMoyJAq3dgdo/fVSq 7aJ+/DJZJKX+944QV8r2SoTp7WNzIRdOZAVrAAngWVozPia7t7RTSyR7E+k8U9OHBfJQ cihYebrXOR7wSwqW0I2u/mKK8ekRXqNhuMEIu9NiW5tddKzvLaXSYmXDdVhARA5o2ZZc ogqDmNuVI9gIvCQx94iOiueFo3bNXPxi3p5IcbAHUZDOz29h4bHTfIkl6lGZOmLe8XLA cv4A== X-Gm-Message-State: APjAAAX97A6r78TEpsVR0M43kiW+T1V/f6DYlCy/0a049CHA9UCvkv8c vHYGQ72i91sWgSIeBi41i6HWLP8PMM8fAvF+YOSSdztA9rvnS2OwkPRSIBy2rtfJLzhU+1lWvOx B1f/WkkTbbt3XtRJ4+oTW4yBsNNUA2mCpHxAsceXxbQ== X-Received: by 2002:adf:e711:: with SMTP id c17mr3512554wrm.227.1557925407665; Wed, 15 May 2019 06:03:27 -0700 (PDT) X-Google-Smtp-Source: APXvYqzUkaKGHsvOu75tM1Og/VVUW4Ft7MAtLl69KvcHCTAVIqQC3KfTuv3vqd6fUa5sorCmyWq9Lg== X-Received: by 2002:adf:e711:: with SMTP id c17mr3512539wrm.227.1557925407493; Wed, 15 May 2019 06:03:27 -0700 (PDT) Received: from localhost.localdomain (host157-126-dynamic.32-79-r.retail.telecomitalia.it. [79.32.126.157]) by smtp.gmail.com with ESMTPSA id i17sm2430564wrr.46.2019.05.15.06.03.22 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 15 May 2019 06:03:23 -0700 (PDT) From: Andrea Righi To: kernel-team@lists.ubuntu.com Subject: [SRU][B][PATCH 4/7] net_sched: fix a race condition in tcindex_destroy() Date: Wed, 15 May 2019 15:02:38 +0200 Message-Id: <20190515130242.6942-5-andrea.righi@canonical.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190515130242.6942-1-andrea.righi@canonical.com> References: <20190515130242.6942-1-andrea.righi@canonical.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Cong Wang Buglink: https://bugs.launchpad.net/bugs/1825942 tcindex_destroy() invokes tcindex_destroy_element() via a walker to delete each filter result in its perfect hash table, and tcindex_destroy_element() calls tcindex_delete() which schedules tcf RCU works to do the final deletion work. Unfortunately this races with the RCU callback __tcindex_destroy(), which could lead to use-after-free as reported by Adrian. Fix this by migrating this RCU callback to tcf RCU work too, as that workqueue is ordered, we will not have use-after-free. Note, we don't need to hold netns refcnt because we don't call tcf_exts_destroy() here. Fixes: 27ce4f05e2ab ("net_sched: use tcf_queue_work() in tcindex filter") Reported-by: Adrian Cc: Ben Hutchings Cc: Jamal Hadi Salim Cc: Jiri Pirko Signed-off-by: Cong Wang Signed-off-by: David S. Miller (cherry picked from commit 8015d93ebd27484418d4952284fd02172fa4b0b2) Signed-off-by: Andrea Righi --- net/sched/cls_tcindex.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c index 752ac4bd9028..5d89ca5c76cd 100644 --- a/net/sched/cls_tcindex.c +++ b/net/sched/cls_tcindex.c @@ -48,7 +48,7 @@ struct tcindex_data { u32 hash; /* hash table size; 0 if undefined */ u32 alloc_hash; /* allocated size */ u32 fall_through; /* 0: only classify if explicit match */ - struct rcu_head rcu; + struct rcu_work rwork; }; static inline int tcindex_filter_is_set(struct tcindex_filter_result *r) @@ -228,9 +228,11 @@ static int tcindex_destroy_element(struct tcf_proto *tp, return tcindex_delete(tp, arg, &last); } -static void __tcindex_destroy(struct rcu_head *head) +static void tcindex_destroy_work(struct work_struct *work) { - struct tcindex_data *p = container_of(head, struct tcindex_data, rcu); + struct tcindex_data *p = container_of(to_rcu_work(work), + struct tcindex_data, + rwork); kfree(p->perfect); kfree(p->h); @@ -257,9 +259,11 @@ static int tcindex_filter_result_init(struct tcindex_filter_result *r) return tcf_exts_init(&r->exts, TCA_TCINDEX_ACT, TCA_TCINDEX_POLICE); } -static void __tcindex_partial_destroy(struct rcu_head *head) +static void tcindex_partial_destroy_work(struct work_struct *work) { - struct tcindex_data *p = container_of(head, struct tcindex_data, rcu); + struct tcindex_data *p = container_of(to_rcu_work(work), + struct tcindex_data, + rwork); kfree(p->perfect); kfree(p); @@ -476,7 +480,7 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, } if (oldp) - call_rcu(&oldp->rcu, __tcindex_partial_destroy); + tcf_queue_work(&oldp->rwork, tcindex_partial_destroy_work); return 0; errout_alloc: @@ -566,7 +570,7 @@ static void tcindex_destroy(struct tcf_proto *tp) walker.fn = tcindex_destroy_element; tcindex_walk(tp, &walker); - call_rcu(&p->rcu, __tcindex_destroy); + tcf_queue_work(&p->rwork, tcindex_destroy_work); }