Received: by 2002:a05:6a10:f347:0:0:0:0 with SMTP id d7csp9440261pxu; Mon, 28 Dec 2020 16:37:39 -0800 (PST) X-Google-Smtp-Source: ABdhPJyqfZMJnpbrZa88890jL2zqlYpmz3Tp/CmeoblxcNryU/85GtuQsarC03x1MRk50GVM3N4s X-Received: by 2002:a05:6402:d09:: with SMTP id eb9mr43653357edb.71.1609202259013; Mon, 28 Dec 2020 16:37:39 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1609202259; cv=none; d=google.com; s=arc-20160816; b=WH3hkCZmSrIrmkK8rlUbgPRtKCM2YNZL1KIsKvj+TdO4S2b40nYNGsUcBsEC2wZlVK ESSc3C1kscMXD9Kd/uTuW9Y7VjyZbsescNJduRVPt+NjL43bMhoOsoIz2RRDSkhcGg8Y Rkg7mtlPeqVDQ8HYCrGHqIIUXec+TY3kzZNbrzR+8t4q1FAqVi5NLchEtsgXbDFpvTWV ZL571JjfR7yBTiYyjpgXVzcGtNW9yQC+4FlY/+WxvVXTO/SVxfcpO9agvzxW5XMdpqMB 2sNJDwCoISCJoF34J4mViTgEqY1RN47NeFKdXGAwjrDCOCdOUG4HewWCBoR9SKt8w+v7 I1vw== 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=KIBTpZuDUW9x9jMqtEoYGdeEYPO6J2G6WzgjKP9eu3I=; b=xRJWTGf2YDBkZ+Bd/otJ1R/9iE/xPjMlE+28M0wPAOI+Es8slg8s6j7MjZfIUJvNMi 8rKAYSixW8yM/n0aMqXFsjcbqNf8UKA2yUK2Uefwilo6J3faxI+kWWiisTw7ac9sc5rv DgmHymQlasCWLRcRMR2yeDX6FZbDmbWnfT6GP3lOE5yDzYqH2dX9eYLRNiiejH/eQhay 2rF7KDO5ZqpwV2LPJfnG4aOOsSzCyXc15wBNcIvBaJifsIsaE68HEaVPd3uXBJ1Ai0/P YZgNmAgH7uYVFOFhZpXuM8dsQYEhLTD90vSQeAphS/RTJfPZvXynHQQIfcPGW1OFj0FL hU0A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=E+cCtl0L; 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 y24si19696928eju.410.2020.12.28.16.37.17; Mon, 28 Dec 2020 16:37:39 -0800 (PST) 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=E+cCtl0L; 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 S2393052AbgL1Pw2 (ORCPT + 99 others); Mon, 28 Dec 2020 10:52:28 -0500 Received: from mail.kernel.org ([198.145.29.99]:38366 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2391199AbgL1NiE (ORCPT ); Mon, 28 Dec 2020 08:38:04 -0500 Received: by mail.kernel.org (Postfix) with ESMTPSA id 0637321D94; Mon, 28 Dec 2020 13:37:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1609162643; bh=pWFcgJnEpPRBx3+LSSh3e7Tj68NxMszCxzBSFJwjvT4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=E+cCtl0L1F2sWsNWtnx21OcrphCQNlaXWSWDER0Icpijhc+oGNFUBQdM1kNXNVgBy 23Lb8zuY4iOzIhCZiLJ1bs14XVp0yybfL1WQbiybVKK7ALuWHz78dopfe2Xoyp7HOl 36CPDoyTx9VllpsLxCdKeIKVoFfb7Az0YZC8MszY= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Pablo Neira Ayso , Florian Westphal , Sasha Levin Subject: [PATCH 5.4 023/453] netfilter: nft_compat: make sure xtables destructors have run Date: Mon, 28 Dec 2020 13:44:19 +0100 Message-Id: <20201228124938.370882595@linuxfoundation.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20201228124937.240114599@linuxfoundation.org> References: <20201228124937.240114599@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 [ Upstream commit ffe8923f109b7ea92c0842c89e61300eefa11c94 ] Pablo Neira found that after recent update of xt_IDLETIMER the iptables-nft tests sometimes show an error. He tracked this down to the delayed cleanup used by nf_tables core: del rule (transaction A) add rule (transaction B) Its possible that by time transaction B (both in same netns) runs, the xt target destructor has not been invoked yet. For native nft expressions this is no problem because all expressions that have such side effects make sure these are handled from the commit phase, rather than async cleanup. For nft_compat however this isn't true. Instead of forcing synchronous behaviour for nft_compat, keep track of the number of outstanding destructor calls. When we attempt to create a new expression, flush the cleanup worker to make sure destructors have completed. With lots of help from Pablo Neira. Reported-by: Pablo Neira Ayso Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin --- include/net/netfilter/nf_tables.h | 2 ++ net/netfilter/nf_tables_api.c | 10 +++++++-- net/netfilter/nft_compat.c | 36 +++++++++++++++++++++++++++---- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index a576bcbba2fcc..6a6fcd10d3185 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -1462,4 +1462,6 @@ void nft_chain_filter_fini(void); void __init nft_chain_route_init(void); void nft_chain_route_fini(void); + +void nf_tables_trans_destroy_flush_work(void); #endif /* _NET_NF_TABLES_H */ diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 459b7c0547115..7753d6f1467c9 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -6605,6 +6605,12 @@ static void nf_tables_trans_destroy_work(struct work_struct *w) } } +void nf_tables_trans_destroy_flush_work(void) +{ + flush_work(&trans_destroy_work); +} +EXPORT_SYMBOL_GPL(nf_tables_trans_destroy_flush_work); + static int nf_tables_commit_chain_prepare(struct net *net, struct nft_chain *chain) { struct nft_rule *rule; @@ -6776,9 +6782,9 @@ static void nf_tables_commit_release(struct net *net) spin_unlock(&nf_tables_destroy_list_lock); nf_tables_module_autoload_cleanup(net); - mutex_unlock(&net->nft.commit_mutex); - schedule_work(&trans_destroy_work); + + mutex_unlock(&net->nft.commit_mutex); } static int nf_tables_commit(struct net *net, struct sk_buff *skb) diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c index f9adca62ccb3d..0e3e0ff805812 100644 --- a/net/netfilter/nft_compat.c +++ b/net/netfilter/nft_compat.c @@ -27,6 +27,8 @@ struct nft_xt_match_priv { void *info; }; +static refcount_t nft_compat_pending_destroy = REFCOUNT_INIT(1); + static int nft_compat_chain_validate_dependency(const struct nft_ctx *ctx, const char *tablename) { @@ -236,6 +238,15 @@ nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr, nft_target_set_tgchk_param(&par, ctx, target, info, &e, proto, inv); + /* xtables matches or targets can have side effects, e.g. + * creation/destruction of /proc files. + * The xt ->destroy functions are run asynchronously from + * work queue. If we have pending invocations we thus + * need to wait for those to finish. + */ + if (refcount_read(&nft_compat_pending_destroy) > 1) + nf_tables_trans_destroy_flush_work(); + ret = xt_check_target(&par, size, proto, inv); if (ret < 0) return ret; @@ -247,6 +258,13 @@ nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr, return 0; } +static void __nft_mt_tg_destroy(struct module *me, const struct nft_expr *expr) +{ + refcount_dec(&nft_compat_pending_destroy); + module_put(me); + kfree(expr->ops); +} + static void nft_target_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) { @@ -262,8 +280,7 @@ nft_target_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) if (par.target->destroy != NULL) par.target->destroy(&par); - module_put(me); - kfree(expr->ops); + __nft_mt_tg_destroy(me, expr); } static int nft_extension_dump_info(struct sk_buff *skb, int attr, @@ -494,8 +511,7 @@ __nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr, if (par.match->destroy != NULL) par.match->destroy(&par); - module_put(me); - kfree(expr->ops); + __nft_mt_tg_destroy(me, expr); } static void @@ -700,6 +716,14 @@ static const struct nfnetlink_subsystem nfnl_compat_subsys = { static struct nft_expr_type nft_match_type; +static void nft_mt_tg_deactivate(const struct nft_ctx *ctx, + const struct nft_expr *expr, + enum nft_trans_phase phase) +{ + if (phase == NFT_TRANS_COMMIT) + refcount_inc(&nft_compat_pending_destroy); +} + static const struct nft_expr_ops * nft_match_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[]) @@ -738,6 +762,7 @@ nft_match_select_ops(const struct nft_ctx *ctx, ops->type = &nft_match_type; ops->eval = nft_match_eval; ops->init = nft_match_init; + ops->deactivate = nft_mt_tg_deactivate, ops->destroy = nft_match_destroy; ops->dump = nft_match_dump; ops->validate = nft_match_validate; @@ -828,6 +853,7 @@ nft_target_select_ops(const struct nft_ctx *ctx, ops->size = NFT_EXPR_SIZE(XT_ALIGN(target->targetsize)); ops->init = nft_target_init; ops->destroy = nft_target_destroy; + ops->deactivate = nft_mt_tg_deactivate, ops->dump = nft_target_dump; ops->validate = nft_target_validate; ops->data = target; @@ -891,6 +917,8 @@ static void __exit nft_compat_module_exit(void) nfnetlink_subsys_unregister(&nfnl_compat_subsys); nft_unregister_expr(&nft_target_type); nft_unregister_expr(&nft_match_type); + + WARN_ON_ONCE(refcount_read(&nft_compat_pending_destroy) != 1); } MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFT_COMPAT); -- 2.27.0