summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorPaolo Abeni <pabeni@redhat.com>2025-12-18 13:55:01 +0100
committerPaolo Abeni <pabeni@redhat.com>2025-12-18 13:55:01 +0100
commit3e82accd3e9c35acfc68e44e12b37e5fd350c768 (patch)
tree66df313498771397eb1586bf2a6471e6e8e7adb3 /net
parent78a47532ab4d0beebb13e67c4ef97b3fe9f56be0 (diff)
parentfec7b0795548b43e2c3c46e3143c34ef6070341c (diff)
Merge tag 'nf-25-12-16' of https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
Florian Westphal says: ==================== netfilter: updates for net The following patchset contains Netfilter fixes for *net*: 1) Jozsef Kadlecsik is retiring. Fortunately Jozsef will still keep an eye on ipset patches. 2) remove a bogus direction check from nat core, this caused spurious flakes in the 'reverse clash' selftest, from myself. 3) nf_tables doesn't need to do chain validation on register store, from Pablo Neira Ayuso. 4) nf_tables shouldn't revisit chains during ruleset (graph) validation if possible. Both 3 and 4 were slated for -next initially but there are now two independent reports of people hitting soft lockup errors during ruleset validation, so it makes no sense anymore to route this via -next given this is -stable material. From myself. 5) call cond_resched() in a more frequently visited place during nf_tables chain validation, this wasn't possible earlier due to rcu read lock, but nowadays its not held anymore during set walks. 6) Don't fail conntrack packetdrill test with HZ=100 kernels. netfilter pull request nf-25-12-16 * tag 'nf-25-12-16' of https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf: selftests: netfilter: packetdrill: avoid failure on HZ=100 kernel netfilter: nf_tables: avoid softlockup warnings in nft_chain_validate netfilter: nf_tables: avoid chain re-validation if possible netfilter: nf_tables: remove redundant chain validation on register store netfilter: nf_nat: remove bogus direction check MAINTAINERS: Remove Jozsef Kadlecsik from MAINTAINERS file ==================== Link: https://patch.msgid.link/20251216190904.14507-1-fw@strlen.de Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/nf_nat_core.c14
-rw-r--r--net/netfilter/nf_tables_api.c84
2 files changed, 68 insertions, 30 deletions
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c
index 78a61dac4ade..e6b24586d2fe 100644
--- a/net/netfilter/nf_nat_core.c
+++ b/net/netfilter/nf_nat_core.c
@@ -294,25 +294,13 @@ nf_nat_used_tuple_new(const struct nf_conntrack_tuple *tuple,
ct = nf_ct_tuplehash_to_ctrack(thash);
- /* NB: IP_CT_DIR_ORIGINAL should be impossible because
- * nf_nat_used_tuple() handles origin collisions.
- *
- * Handle remote chance other CPU confirmed its ct right after.
- */
- if (thash->tuple.dst.dir != IP_CT_DIR_REPLY)
- goto out;
-
/* clashing connection subject to NAT? Retry with new tuple. */
if (READ_ONCE(ct->status) & uses_nat)
goto out;
if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
- &ignored_ct->tuplehash[IP_CT_DIR_REPLY].tuple) &&
- nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple,
- &ignored_ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple)) {
+ &ignored_ct->tuplehash[IP_CT_DIR_REPLY].tuple))
taken = false;
- goto out;
- }
out:
nf_ct_put(ct);
return taken;
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index f3de2f9bbebf..618af6e90773 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -123,6 +123,29 @@ static void nft_validate_state_update(struct nft_table *table, u8 new_validate_s
table->validate_state = new_validate_state;
}
+
+static bool nft_chain_vstate_valid(const struct nft_ctx *ctx,
+ const struct nft_chain *chain)
+{
+ const struct nft_base_chain *base_chain;
+ enum nft_chain_types type;
+ u8 hooknum;
+
+ if (WARN_ON_ONCE(!nft_is_base_chain(ctx->chain)))
+ return false;
+
+ base_chain = nft_base_chain(ctx->chain);
+ hooknum = base_chain->ops.hooknum;
+ type = base_chain->type->type;
+
+ /* chain is already validated for this call depth */
+ if (chain->vstate.depth >= ctx->level &&
+ chain->vstate.hook_mask[type] & BIT(hooknum))
+ return true;
+
+ return false;
+}
+
static void nf_tables_trans_destroy_work(struct work_struct *w);
static void nft_trans_gc_work(struct work_struct *work);
@@ -4079,6 +4102,29 @@ static void nf_tables_rule_release(const struct nft_ctx *ctx, struct nft_rule *r
nf_tables_rule_destroy(ctx, rule);
}
+static void nft_chain_vstate_update(const struct nft_ctx *ctx, struct nft_chain *chain)
+{
+ const struct nft_base_chain *base_chain;
+ enum nft_chain_types type;
+ u8 hooknum;
+
+ /* ctx->chain must hold the calling base chain. */
+ if (WARN_ON_ONCE(!nft_is_base_chain(ctx->chain))) {
+ memset(&chain->vstate, 0, sizeof(chain->vstate));
+ return;
+ }
+
+ base_chain = nft_base_chain(ctx->chain);
+ hooknum = base_chain->ops.hooknum;
+ type = base_chain->type->type;
+
+ BUILD_BUG_ON(BIT(NF_INET_NUMHOOKS) > U8_MAX);
+
+ chain->vstate.hook_mask[type] |= BIT(hooknum);
+ if (chain->vstate.depth < ctx->level)
+ chain->vstate.depth = ctx->level;
+}
+
/** nft_chain_validate - loop detection and hook validation
*
* @ctx: context containing call depth and base chain
@@ -4088,15 +4134,25 @@ static void nf_tables_rule_release(const struct nft_ctx *ctx, struct nft_rule *r
* and set lookups until either the jump limit is hit or all reachable
* chains have been validated.
*/
-int nft_chain_validate(const struct nft_ctx *ctx, const struct nft_chain *chain)
+int nft_chain_validate(const struct nft_ctx *ctx, struct nft_chain *chain)
{
struct nft_expr *expr, *last;
struct nft_rule *rule;
int err;
+ BUILD_BUG_ON(NFT_JUMP_STACK_SIZE > 255);
if (ctx->level == NFT_JUMP_STACK_SIZE)
return -EMLINK;
+ if (ctx->level > 0) {
+ /* jumps to base chains are not allowed. */
+ if (nft_is_base_chain(chain))
+ return -ELOOP;
+
+ if (nft_chain_vstate_valid(ctx, chain))
+ return 0;
+ }
+
list_for_each_entry(rule, &chain->rules, list) {
if (fatal_signal_pending(current))
return -EINTR;
@@ -4115,8 +4171,11 @@ int nft_chain_validate(const struct nft_ctx *ctx, const struct nft_chain *chain)
if (err < 0)
return err;
}
+
+ cond_resched();
}
+ nft_chain_vstate_update(ctx, chain);
return 0;
}
EXPORT_SYMBOL_GPL(nft_chain_validate);
@@ -4128,7 +4187,7 @@ static int nft_table_validate(struct net *net, const struct nft_table *table)
.net = net,
.family = table->family,
};
- int err;
+ int err = 0;
list_for_each_entry(chain, &table->chains, list) {
if (!nft_is_base_chain(chain))
@@ -4137,12 +4196,14 @@ static int nft_table_validate(struct net *net, const struct nft_table *table)
ctx.chain = chain;
err = nft_chain_validate(&ctx, chain);
if (err < 0)
- return err;
-
- cond_resched();
+ goto err;
}
- return 0;
+err:
+ list_for_each_entry(chain, &table->chains, list)
+ memset(&chain->vstate, 0, sizeof(chain->vstate));
+
+ return err;
}
int nft_setelem_validate(const struct nft_ctx *ctx, struct nft_set *set,
@@ -11676,21 +11737,10 @@ static int nft_validate_register_store(const struct nft_ctx *ctx,
enum nft_data_types type,
unsigned int len)
{
- int err;
-
switch (reg) {
case NFT_REG_VERDICT:
if (type != NFT_DATA_VERDICT)
return -EINVAL;
-
- if (data != NULL &&
- (data->verdict.code == NFT_GOTO ||
- data->verdict.code == NFT_JUMP)) {
- err = nft_chain_validate(ctx, data->verdict.chain);
- if (err < 0)
- return err;
- }
-
break;
default:
if (type != NFT_DATA_VALUE)