Received: by 2002:a05:6a10:17d3:0:0:0:0 with SMTP id hz19csp2583052pxb; Mon, 19 Apr 2021 08:56:17 -0700 (PDT) X-Google-Smtp-Source: ABdhPJx221zMod2zLs28ZrkyQ2MwYOxNSYlICubMlDRaSaCP03C+gxwG3Sj9d64LpRBRBU8GnRPa X-Received: by 2002:a17:902:7847:b029:ea:c45a:29fc with SMTP id e7-20020a1709027847b02900eac45a29fcmr23288111pln.46.1618847777523; Mon, 19 Apr 2021 08:56:17 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1618847777; cv=none; d=google.com; s=arc-20160816; b=Z5/9iDkEEnx5MUJOUjXPHKwbwmUPibUo3hGB/ABRVjY/TXmhd9XpQCVO88iFDutBx2 j2n5Ll85LIsRs1BmPZulXXmv82zpHDq7bYeYZrVC8gUeRs/VGbMCzRHw3RaDE4AQ4GQF 65wz0CW5vdcLkWeEsSUnVsQSsCvLT3Btr07dm/o/duD6/erVq3RtHG+9j92ja3tnna7U 0qAgqDFSA5MCtvOwOtvXLb+DRteWJL1CTJ5LCXTk62Ys73jXU4rspHZfy1U+0HpmghUn cVNmZXr7KlOJheUcjBPQ+zmD2d8yRO8PRq3c5lagGV42odb+BxQ8FQPOm0JXVw99ZHhj mZig== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=9v3VWtJkIHb0TwyiNxenJoWWul+H/neJ73RPr/InwrU=; b=I+JtAtYsJHi/oNwGuYD5TUu14UYnwl8syzggitsCbv+g+81fCbVIWPm74b8gOvxAcn UAIn9UsM5H7NoG4E+qUMGa9QrP66TO+dfbNQ4phAh+lJyyJ4EuMZf7gNNBeQ3aCZbrQh VnOZByJCU44u5aMOUH4nY+amklq2JUSg6TjS54ydtZM783nFem9RF/D4gKtbi0qLSm8v JrbfBbpepBpYiX2wKNpJpfl5dy5Er0jv4gRjkwEhltf5qi9W2Mh1+fB6FGfMUECGtuwE wVJ9MdIjnZq0q18LUJzQKeBOXVGrCohRQfVguSo5ontlsRq0AcfzOQoRcbtGdLUvPiIO D3VQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=D75qu6Ao; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id f1si15719632plt.353.2021.04.19.08.56.03; Mon, 19 Apr 2021 08:56:17 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=D75qu6Ao; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241455AbhDSNhZ (ORCPT + 99 others); Mon, 19 Apr 2021 09:37:25 -0400 Received: from mail.kernel.org ([198.145.29.99]:34792 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242035AbhDSNZN (ORCPT ); Mon, 19 Apr 2021 09:25:13 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id F37F7613C0; Mon, 19 Apr 2021 13:20:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1618838419; bh=eLCoQEkiSj/MFiqR7oOJnee3Vfz/By49eeyqWjXcnnk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=D75qu6AoTnrUfKf9C5B/KbISwuV8Y0mktoHabSeCpUMxmpZpJg7rx0gtW+eZIKgmf SxQxaLKytTiIL0QbZJCs3NjtJ9Fdun1sTVr6CpLHyu7vHeNv4mm3isw6QF8uLit0ii bg6Ev7TOEpGibkIbRHYopPWE7g5aFsldDwoFLBG8= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Florian Westphal , Pablo Neira Ayuso Subject: [PATCH 5.4 52/73] netfilter: bridge: add pre_exit hooks for ebtable unregistration Date: Mon, 19 Apr 2021 15:06:43 +0200 Message-Id: <20210419130525.511359861@linuxfoundation.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210419130523.802169214@linuxfoundation.org> References: <20210419130523.802169214@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Florian Westphal commit 7ee3c61dcd28bf6e290e06ad382f13511dc790e9 upstream. Just like ip/ip6/arptables, the hooks have to be removed, then synchronize_rcu() has to be called to make sure no more packets are being processed before the ruleset data is released. Place the hook unregistration in the pre_exit hook, then call the new ebtables pre_exit function from there. Years ago, when first netns support got added for netfilter+ebtables, this used an older (now removed) netfilter hook unregister API, that did a unconditional synchronize_rcu(). Now that all is done with call_rcu, ebtable_{filter,nat,broute} pernet exit handlers may free the ebtable ruleset while packets are still in flight. This can only happens on module removal, not during netns exit. The new function expects the table name, not the table struct. This is because upcoming patch set (targeting -next) will remove all net->xt.{nat,filter,broute}_table instances, this makes it necessary to avoid external references to those member variables. The existing APIs will be converted, so follow the upcoming scheme of passing name + hook type instead. Fixes: aee12a0a3727e ("ebtables: remove nf_hook_register usage") Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- include/linux/netfilter_bridge/ebtables.h | 5 +++-- net/bridge/netfilter/ebtable_broute.c | 8 +++++++- net/bridge/netfilter/ebtable_filter.c | 8 +++++++- net/bridge/netfilter/ebtable_nat.c | 8 +++++++- net/bridge/netfilter/ebtables.c | 30 +++++++++++++++++++++++++++--- 5 files changed, 51 insertions(+), 8 deletions(-) --- a/include/linux/netfilter_bridge/ebtables.h +++ b/include/linux/netfilter_bridge/ebtables.h @@ -110,8 +110,9 @@ extern int ebt_register_table(struct net const struct ebt_table *table, const struct nf_hook_ops *ops, struct ebt_table **res); -extern void ebt_unregister_table(struct net *net, struct ebt_table *table, - const struct nf_hook_ops *); +extern void ebt_unregister_table(struct net *net, struct ebt_table *table); +void ebt_unregister_table_pre_exit(struct net *net, const char *tablename, + const struct nf_hook_ops *ops); extern unsigned int ebt_do_table(struct sk_buff *skb, const struct nf_hook_state *state, struct ebt_table *table); --- a/net/bridge/netfilter/ebtable_broute.c +++ b/net/bridge/netfilter/ebtable_broute.c @@ -105,14 +105,20 @@ static int __net_init broute_net_init(st &net->xt.broute_table); } +static void __net_exit broute_net_pre_exit(struct net *net) +{ + ebt_unregister_table_pre_exit(net, "broute", &ebt_ops_broute); +} + static void __net_exit broute_net_exit(struct net *net) { - ebt_unregister_table(net, net->xt.broute_table, &ebt_ops_broute); + ebt_unregister_table(net, net->xt.broute_table); } static struct pernet_operations broute_net_ops = { .init = broute_net_init, .exit = broute_net_exit, + .pre_exit = broute_net_pre_exit, }; static int __init ebtable_broute_init(void) --- a/net/bridge/netfilter/ebtable_filter.c +++ b/net/bridge/netfilter/ebtable_filter.c @@ -99,14 +99,20 @@ static int __net_init frame_filter_net_i &net->xt.frame_filter); } +static void __net_exit frame_filter_net_pre_exit(struct net *net) +{ + ebt_unregister_table_pre_exit(net, "filter", ebt_ops_filter); +} + static void __net_exit frame_filter_net_exit(struct net *net) { - ebt_unregister_table(net, net->xt.frame_filter, ebt_ops_filter); + ebt_unregister_table(net, net->xt.frame_filter); } static struct pernet_operations frame_filter_net_ops = { .init = frame_filter_net_init, .exit = frame_filter_net_exit, + .pre_exit = frame_filter_net_pre_exit, }; static int __init ebtable_filter_init(void) --- a/net/bridge/netfilter/ebtable_nat.c +++ b/net/bridge/netfilter/ebtable_nat.c @@ -99,14 +99,20 @@ static int __net_init frame_nat_net_init &net->xt.frame_nat); } +static void __net_exit frame_nat_net_pre_exit(struct net *net) +{ + ebt_unregister_table_pre_exit(net, "nat", ebt_ops_nat); +} + static void __net_exit frame_nat_net_exit(struct net *net) { - ebt_unregister_table(net, net->xt.frame_nat, ebt_ops_nat); + ebt_unregister_table(net, net->xt.frame_nat); } static struct pernet_operations frame_nat_net_ops = { .init = frame_nat_net_init, .exit = frame_nat_net_exit, + .pre_exit = frame_nat_net_pre_exit, }; static int __init ebtable_nat_init(void) --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -1237,10 +1237,34 @@ out: return ret; } -void ebt_unregister_table(struct net *net, struct ebt_table *table, - const struct nf_hook_ops *ops) +static struct ebt_table *__ebt_find_table(struct net *net, const char *name) +{ + struct ebt_table *t; + + mutex_lock(&ebt_mutex); + + list_for_each_entry(t, &net->xt.tables[NFPROTO_BRIDGE], list) { + if (strcmp(t->name, name) == 0) { + mutex_unlock(&ebt_mutex); + return t; + } + } + + mutex_unlock(&ebt_mutex); + return NULL; +} + +void ebt_unregister_table_pre_exit(struct net *net, const char *name, const struct nf_hook_ops *ops) +{ + struct ebt_table *table = __ebt_find_table(net, name); + + if (table) + nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks)); +} +EXPORT_SYMBOL(ebt_unregister_table_pre_exit); + +void ebt_unregister_table(struct net *net, struct ebt_table *table) { - nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks)); __ebt_unregister_table(net, table); }