Re: RFC: nftables does not allow to delete a rule twice

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Phil,

On Thu, Feb 14, 2019 at 06:21:04PM +0100, Phil Sutter wrote:
> Hi Pablo,
> 
> Originating from a problem with ebtables-nft user-defined chain
> policies, I made up the following use-case:
> 
> | # iptables-nft -A FORWARD -j ACCEPT
> | # iptables-nft-restore --noflush <<EOF
> | *filter
> | -D FORWARD -j ACCEPT
> | -F
> | COMMIT
> | EOF
> | iptables-restore v1.8.2 (nf_tables): 
> | line 3: RULE_FLUSH failed (No such file or directory): rule in chain FORWARD
> 
> In case anyone reading this is not aware of it: In nftables, flushing a
> chain works by sending NFT_MSG_DELRULE message with just table and chain
> defined, no rule handle or position.
> 
> The problem is that delete command in batch removes the rule, flush
> command then tries to delete the same rule again. Kernel returns -ENOENT
> in nf_tables_delrule_deactivate().
> 
> The above use-case works with legacy iptables.
> 
> Question is if I have to work around this in userspace or if we should
> make nf_tables_delrule_deactivate() return 0 even if given rule is not
> active? Downside is that second option would cause double deletion of
> same rule within a single batch to succeed.

>From the flush path, we can skip requests for deletion of rules that
have been already deleted, ie. we add no transaction since there is
already one in place.
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 5a92f23f179f..efc79422a8c7 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -288,11 +288,14 @@ static struct nft_trans *nft_trans_rule_add(struct nft_ctx *ctx, int msg_type,
 	return trans;
 }
 
-static int nft_delrule(struct nft_ctx *ctx, struct nft_rule *rule)
+static int nft_delrule(struct nft_ctx *ctx, struct nft_rule *rule, bool flush)
 {
 	struct nft_trans *trans;
 	int err;
 
+	if (flush && !nft_is_active_next(ctx->net, rule))
+		return 0;
+
 	trans = nft_trans_rule_add(ctx, NFT_MSG_DELRULE, rule);
 	if (trans == NULL)
 		return -ENOMEM;
@@ -313,7 +316,7 @@ static int nft_delrule_by_chain(struct nft_ctx *ctx)
 	int err;
 
 	list_for_each_entry(rule, &ctx->chain->rules, list) {
-		err = nft_delrule(ctx, rule);
+		err = nft_delrule(ctx, rule, true);
 		if (err < 0)
 			return err;
 	}
@@ -1906,7 +1909,7 @@ static int nf_tables_delchain(struct net *net, struct sock *nlsk,
 			continue;
 		use--;
 
-		err = nft_delrule(&ctx, rule);
+		err = nft_delrule(&ctx, rule, true);
 		if (err < 0)
 			return err;
 	}
@@ -2707,7 +2710,7 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
 			err = -ENOMEM;
 			goto err2;
 		}
-		err = nft_delrule(&ctx, old_rule);
+		err = nft_delrule(&ctx, old_rule, false);
 		if (err < 0) {
 			nft_trans_destroy(trans);
 			goto err2;
@@ -2804,7 +2807,7 @@ static int nf_tables_delrule(struct net *net, struct sock *nlsk,
 				return PTR_ERR(rule);
 			}
 
-			err = nft_delrule(&ctx, rule);
+			err = nft_delrule(&ctx, rule, false);
 		} else if (nla[NFTA_RULE_ID]) {
 			rule = nft_rule_lookup_byid(net, nla[NFTA_RULE_ID]);
 			if (IS_ERR(rule)) {
@@ -2812,7 +2815,7 @@ static int nf_tables_delrule(struct net *net, struct sock *nlsk,
 				return PTR_ERR(rule);
 			}
 
-			err = nft_delrule(&ctx, rule);
+			err = nft_delrule(&ctx, rule, false);
 		} else {
 			err = nft_delrule_by_chain(&ctx);
 		}

[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux