Received: by 2002:ac0:a591:0:0:0:0:0 with SMTP id m17-v6csp1418031imm; Thu, 5 Jul 2018 23:02:37 -0700 (PDT) X-Google-Smtp-Source: AAOMgpcb1yKEoFP+y/unGZqsoR9OaFVgyZ0y2CKR+MIOY6sK4TB1Fp02715+XTqHr5K0EF2lL37r X-Received: by 2002:a17:902:292b:: with SMTP id g40-v6mr9106060plb.273.1530856957593; Thu, 05 Jul 2018 23:02:37 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1530856957; cv=none; d=google.com; s=arc-20160816; b=oMltg8LQ0xsXkT9hqN+4xXc4g+1BcwMLQdVpSnq7vujH7wdkyOni2NiEfppt+CjXtO e3jMuSLZA8TzshgHiV3Py7gnd2mZME38jsqB4KfkJre1L5lvnKNDKU56Okd2lZAyLouF 881oGWrYcaNxCLU/ne2unbtRurGQsMjrE6I1XeQU7OusImevfGgglkzxVOcI3/bmW4Va XyKwEZewAt8sTVeX8woUkps8Oombe3b3TUlzkCjrLnXemV1Sym7Z6zr30iZIj8zmyvSx hmwxHzod07dvIQ2EU35hYM84M+kY/QfWNsQ8+vUTIVi5w85ozEVnCL1aBP/JYXBiLZvq i5Zg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:references :in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=Ti1Ig2guql6mlCJeLgFQCOHz/cwRWBKif+fDYmgIrK8=; b=gWeGa5PFLmPJaIFVfCTJ1cNnOBJDWglMCrtqmVdb1+N08IMoA41/pHb/Q61U/GBW+i WxXYks3/W5ojOe5kV4O3cArgDQmdjb9blsNddDC9jO3UMiPMjoETMcjSBb4xL4ZKUWOU pJSHjxoHf+5IF1C/BFzc/MLeLn7m+SVmZ0gi14poH0VxrQ2y5SPoORHDmYqWRp8D9YPJ u1o7YMQko6ftdPhST4mO0I8+OGctVF4XMaBaVi/v9S0Ava84Avb5+66LbpdXwvnao2Xo c0k+U3gD+OVn6I9LMV3oanaLSIq23A/YIg3nPqpXMEPgCNoOo51TfIHt9JBfsGtleR6o k1yw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id a67-v6si8069076pfb.348.2018.07.05.23.02.23; Thu, 05 Jul 2018 23:02:37 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934265AbeGFGB0 (ORCPT + 99 others); Fri, 6 Jul 2018 02:01:26 -0400 Received: from mail.linuxfoundation.org ([140.211.169.12]:33094 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933878AbeGFFus (ORCPT ); Fri, 6 Jul 2018 01:50:48 -0400 Received: from localhost (D57D388D.static.ziggozakelijk.nl [213.125.56.141]) by mail.linuxfoundation.org (Postfix) with ESMTPSA id 0C0AD86A; Fri, 6 Jul 2018 05:50:47 +0000 (UTC) From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Pablo Neira Ayuso Subject: [PATCH 4.14 27/61] netfilter: nf_tables: bogus EBUSY in chain deletions Date: Fri, 6 Jul 2018 07:46:51 +0200 Message-Id: <20180706054713.378287311@linuxfoundation.org> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180706054712.332416244@linuxfoundation.org> References: <20180706054712.332416244@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.14-stable review patch. If anyone has any objections, please let me know. ------------------ From: Pablo Neira Ayuso commit bb7b40aecbf778c0c83a5bd62b0f03ca9f49a618 upstream. When removing a rule that jumps to chain and such chain in the same batch, this bogusly hits EBUSY. Add activate and deactivate operations to expression that can be called from the preparation and the commit/abort phases. Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- include/net/netfilter/nf_tables.h | 5 ++++ net/netfilter/nf_tables_api.c | 46 ++++++++++++++++++++++++++++++++++---- net/netfilter/nft_immediate.c | 15 +++++++++--- 3 files changed, 59 insertions(+), 7 deletions(-) --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -177,6 +177,7 @@ struct nft_data_desc { int nft_data_init(const struct nft_ctx *ctx, struct nft_data *data, unsigned int size, struct nft_data_desc *desc, const struct nlattr *nla); +void nft_data_hold(const struct nft_data *data, enum nft_data_types type); void nft_data_release(const struct nft_data *data, enum nft_data_types type); int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data, enum nft_data_types type, unsigned int len); @@ -731,6 +732,10 @@ struct nft_expr_ops { int (*init)(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nlattr * const tb[]); + void (*activate)(const struct nft_ctx *ctx, + const struct nft_expr *expr); + void (*deactivate)(const struct nft_ctx *ctx, + const struct nft_expr *expr); void (*destroy)(const struct nft_ctx *ctx, const struct nft_expr *expr); int (*dump)(struct sk_buff *skb, --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -220,6 +220,34 @@ static int nft_delchain(struct nft_ctx * return err; } +static void nft_rule_expr_activate(const struct nft_ctx *ctx, + struct nft_rule *rule) +{ + struct nft_expr *expr; + + expr = nft_expr_first(rule); + while (expr != nft_expr_last(rule) && expr->ops) { + if (expr->ops->activate) + expr->ops->activate(ctx, expr); + + expr = nft_expr_next(expr); + } +} + +static void nft_rule_expr_deactivate(const struct nft_ctx *ctx, + struct nft_rule *rule) +{ + struct nft_expr *expr; + + expr = nft_expr_first(rule); + while (expr != nft_expr_last(rule) && expr->ops) { + if (expr->ops->deactivate) + expr->ops->deactivate(ctx, expr); + + expr = nft_expr_next(expr); + } +} + static int nf_tables_delrule_deactivate(struct nft_ctx *ctx, struct nft_rule *rule) { @@ -265,6 +293,7 @@ static int nft_delrule(struct nft_ctx *c nft_trans_destroy(trans); return err; } + nft_rule_expr_deactivate(ctx, rule); return 0; } @@ -2218,6 +2247,13 @@ static void nf_tables_rule_destroy(const kfree(rule); } +static void nf_tables_rule_release(const struct nft_ctx *ctx, + struct nft_rule *rule) +{ + nft_rule_expr_deactivate(ctx, rule); + nf_tables_rule_destroy(ctx, rule); +} + #define NFT_RULE_MAXEXPRS 128 static struct nft_expr_info *info; @@ -2385,7 +2421,7 @@ static int nf_tables_newrule(struct net return 0; err2: - nf_tables_rule_destroy(&ctx, rule); + nf_tables_rule_release(&ctx, rule); err1: for (i = 0; i < n; i++) { if (info[i].ops != NULL) @@ -4054,7 +4090,7 @@ static int nf_tables_newsetelem(struct n * NFT_GOTO verdicts. This function must be called on active data objects * from the second phase of the commit protocol. */ -static void nft_data_hold(const struct nft_data *data, enum nft_data_types type) +void nft_data_hold(const struct nft_data *data, enum nft_data_types type) { if (type == NFT_DATA_VERDICT) { switch (data->verdict.code) { @@ -5221,10 +5257,12 @@ static int nf_tables_abort(struct net *n case NFT_MSG_NEWRULE: trans->ctx.chain->use--; list_del_rcu(&nft_trans_rule(trans)->list); + nft_rule_expr_deactivate(&trans->ctx, nft_trans_rule(trans)); break; case NFT_MSG_DELRULE: trans->ctx.chain->use++; nft_clear(trans->ctx.net, nft_trans_rule(trans)); + nft_rule_expr_activate(&trans->ctx, nft_trans_rule(trans)); nft_trans_destroy(trans); break; case NFT_MSG_NEWSET: @@ -5798,7 +5836,7 @@ int __nft_release_basechain(struct nft_c list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) { list_del(&rule->list); ctx->chain->use--; - nf_tables_rule_destroy(ctx, rule); + nf_tables_rule_release(ctx, rule); } list_del(&ctx->chain->list); ctx->table->use--; @@ -5832,7 +5870,7 @@ static void __nft_release_afinfo(struct list_for_each_entry_safe(rule, nr, &chain->rules, list) { list_del(&rule->list); chain->use--; - nf_tables_rule_destroy(&ctx, rule); + nf_tables_rule_release(&ctx, rule); } } list_for_each_entry_safe(set, ns, &table->sets, list) { --- a/net/netfilter/nft_immediate.c +++ b/net/netfilter/nft_immediate.c @@ -69,8 +69,16 @@ err1: return err; } -static void nft_immediate_destroy(const struct nft_ctx *ctx, - const struct nft_expr *expr) +static void nft_immediate_activate(const struct nft_ctx *ctx, + const struct nft_expr *expr) +{ + const struct nft_immediate_expr *priv = nft_expr_priv(expr); + + return nft_data_hold(&priv->data, nft_dreg_to_type(priv->dreg)); +} + +static void nft_immediate_deactivate(const struct nft_ctx *ctx, + const struct nft_expr *expr) { const struct nft_immediate_expr *priv = nft_expr_priv(expr); @@ -108,7 +116,8 @@ static const struct nft_expr_ops nft_imm .size = NFT_EXPR_SIZE(sizeof(struct nft_immediate_expr)), .eval = nft_immediate_eval, .init = nft_immediate_init, - .destroy = nft_immediate_destroy, + .activate = nft_immediate_activate, + .deactivate = nft_immediate_deactivate, .dump = nft_immediate_dump, .validate = nft_immediate_validate, };