* [PATCH nf,v1 1/4] netfilter: ctnetlink: do not allow to reset helper on existing conntrack
@ 2026-06-23 5:46 Pablo Neira Ayuso
2026-06-23 5:46 ` [PATCH nf,v1 2/4] netfilter: nf_conntrack_expect: store master_tuple in expectation Pablo Neira Ayuso
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Pablo Neira Ayuso @ 2026-06-23 5:46 UTC (permalink / raw)
To: netfilter-devel
This feature allows to reset a helper for an existing conntrack, but it
is not safe. This requires a synchronized_rcu() call after resetting the
helper, which is going to be expensive for a large batch of conntrack
entries. This also needs to call to the .destroy callback to release the
GRE/PPTP mappings to fix it.
This feature antedates the creation of the conntrack-tools and I cannot
find a good use-case for this. Given that I cannot find any user in the
netfilter.org userspace tree, I prefer to remove this feature.
Fixes: c1d10adb4a52 ("[NETFILTER]: Add ctnetlink port for nf_conntrack")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v1: resend to let sashiko pick in with this batch.
net/netfilter/nf_conntrack_netlink.c | 13 -------------
1 file changed, 13 deletions(-)
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 4e78d2482989..cb38ef42e9e6 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1953,19 +1953,6 @@ static int ctnetlink_change_helper(struct nf_conn *ct,
return err;
}
- if (!strcmp(helpname, "") && help) {
- helper = rcu_dereference(help->helper);
- if (helper) {
- /* we had a helper before ... */
- nf_ct_remove_expectations(ct);
- RCU_INIT_POINTER(help->helper, NULL);
- if (refcount_dec_and_test(&helper->ct_refcnt))
- kfree_rcu(helper, rcu);
- }
- rcu_read_unlock();
- return 0;
- }
-
helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct),
nf_ct_protonum(ct));
if (helper == NULL) {
--
2.47.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH nf,v1 2/4] netfilter: nf_conntrack_expect: store master_tuple in expectation
2026-06-23 5:46 [PATCH nf,v1 1/4] netfilter: ctnetlink: do not allow to reset helper on existing conntrack Pablo Neira Ayuso
@ 2026-06-23 5:46 ` Pablo Neira Ayuso
2026-06-23 5:46 ` [PATCH nf,v1 3/4] netfilter: nf_conntrack_expect: run expectation eviction with no helper Pablo Neira Ayuso
2026-06-23 5:46 ` [PATCH nf,v1 4/4] netfilter: nf_conntrack_helper: cap maximum number of expectation at helper registration Pablo Neira Ayuso
2 siblings, 0 replies; 4+ messages in thread
From: Pablo Neira Ayuso @ 2026-06-23 5:46 UTC (permalink / raw)
To: netfilter-devel
Store master conntrack tuple in the expectation since exp->master might
refer to a different conntrack when accessed from rcu read side lock
area due to typesafe rcu rules.
Fixes: 02a3231b6d82 ("netfilter: nf_conntrack_expect: store netns and zone in expectation")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v1: resend to let sashiko pick in with this batch.
include/net/netfilter/nf_conntrack_expect.h | 1 +
net/netfilter/nf_conntrack_broadcast.c | 1 +
net/netfilter/nf_conntrack_expect.c | 2 ++
net/netfilter/nf_conntrack_netlink.c | 10 ++++------
4 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
index be4a120d549e..c024345c9bd8 100644
--- a/include/net/netfilter/nf_conntrack_expect.h
+++ b/include/net/netfilter/nf_conntrack_expect.h
@@ -26,6 +26,7 @@ struct nf_conntrack_expect {
possible_net_t net;
/* We expect this tuple, with the following mask */
+ struct nf_conntrack_tuple master_tuple;
struct nf_conntrack_tuple tuple;
struct nf_conntrack_tuple_mask mask;
diff --git a/net/netfilter/nf_conntrack_broadcast.c b/net/netfilter/nf_conntrack_broadcast.c
index 400119b6320e..bf78828c7549 100644
--- a/net/netfilter/nf_conntrack_broadcast.c
+++ b/net/netfilter/nf_conntrack_broadcast.c
@@ -62,6 +62,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb,
if (exp == NULL)
goto out;
+ exp->master_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
helper = rcu_dereference(help->helper);
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 49e18eda037e..9454913e1b33 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -355,6 +355,8 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
exp->tuple.src.l3num = family;
exp->tuple.dst.protonum = proto;
+ exp->master_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
+
if (saddr) {
memcpy(&exp->tuple.src.u3, saddr, len);
if (sizeof(exp->tuple.src.u3) > len)
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index cb38ef42e9e6..4217715d42dc 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -3002,7 +3002,6 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
const struct nf_conntrack_expect *exp)
{
__s32 timeout = (__s32)(READ_ONCE(exp->timeout) - nfct_time_stamp) / HZ;
- struct nf_conn *master = exp->master;
struct nf_conntrack_helper *helper;
#if IS_ENABLED(CONFIG_NF_NAT)
struct nlattr *nest_parms;
@@ -3017,9 +3016,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
goto nla_put_failure;
if (ctnetlink_exp_dump_mask(skb, &exp->tuple, &exp->mask) < 0)
goto nla_put_failure;
- if (ctnetlink_exp_dump_tuple(skb,
- &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
- CTA_EXPECT_MASTER) < 0)
+ if (ctnetlink_exp_dump_tuple(skb, &exp->master_tuple, CTA_EXPECT_MASTER) < 0)
goto nla_put_failure;
#if IS_ENABLED(CONFIG_NF_NAT)
@@ -3032,9 +3029,9 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
if (nla_put_be32(skb, CTA_EXPECT_NAT_DIR, htonl(exp->dir)))
goto nla_put_failure;
- nat_tuple.src.l3num = nf_ct_l3num(master);
+ nat_tuple.src.l3num = exp->master_tuple.src.l3num;
nat_tuple.src.u3 = exp->saved_addr;
- nat_tuple.dst.protonum = nf_ct_protonum(master);
+ nat_tuple.dst.protonum = exp->master_tuple.dst.protonum;
nat_tuple.src.u = exp->saved_proto;
if (ctnetlink_exp_dump_tuple(skb, &nat_tuple,
@@ -3576,6 +3573,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
#endif
rcu_assign_pointer(exp->helper, helper);
rcu_assign_pointer(exp->assign_helper, assign_helper);
+ exp->master_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
exp->tuple = *tuple;
exp->mask.src.u3 = mask->src.u3;
exp->mask.src.u.all = mask->src.u.all;
--
2.47.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH nf,v1 3/4] netfilter: nf_conntrack_expect: run expectation eviction with no helper
2026-06-23 5:46 [PATCH nf,v1 1/4] netfilter: ctnetlink: do not allow to reset helper on existing conntrack Pablo Neira Ayuso
2026-06-23 5:46 ` [PATCH nf,v1 2/4] netfilter: nf_conntrack_expect: store master_tuple in expectation Pablo Neira Ayuso
@ 2026-06-23 5:46 ` Pablo Neira Ayuso
2026-06-23 5:46 ` [PATCH nf,v1 4/4] netfilter: nf_conntrack_helper: cap maximum number of expectation at helper registration Pablo Neira Ayuso
2 siblings, 0 replies; 4+ messages in thread
From: Pablo Neira Ayuso @ 2026-06-23 5:46 UTC (permalink / raw)
To: netfilter-devel
Run expectation eviction if no helper is specified to deal with the
nft_ct expectation support.
Cap the maximum expectation limit per master conntrack to
NF_CT_EXPECT_MAX_CNT (255).
Fixes: 857b46027d6f ("netfilter: nft_ct: add ct expectations support")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v1: resend to let sashiko pick in with this batch.
net/netfilter/nf_conntrack_expect.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 9454913e1b33..113bb1cb1683 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -499,6 +499,13 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect,
if (p->max_expected &&
master_help->expecting[expect->class] >= p->max_expected)
evict_oldest_expect(master_help, expect, p);
+ } else {
+ const struct nf_conntrack_expect_policy default_exp_policy = {
+ .max_expected = NF_CT_EXPECT_MAX_CNT,
+ };
+
+ if (master_help->expecting[expect->class] >= default_exp_policy.max_expected)
+ evict_oldest_expect(master_help, expect, &default_exp_policy);
}
cnet = nf_ct_pernet(net);
--
2.47.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH nf,v1 4/4] netfilter: nf_conntrack_helper: cap maximum number of expectation at helper registration
2026-06-23 5:46 [PATCH nf,v1 1/4] netfilter: ctnetlink: do not allow to reset helper on existing conntrack Pablo Neira Ayuso
2026-06-23 5:46 ` [PATCH nf,v1 2/4] netfilter: nf_conntrack_expect: store master_tuple in expectation Pablo Neira Ayuso
2026-06-23 5:46 ` [PATCH nf,v1 3/4] netfilter: nf_conntrack_expect: run expectation eviction with no helper Pablo Neira Ayuso
@ 2026-06-23 5:46 ` Pablo Neira Ayuso
2 siblings, 0 replies; 4+ messages in thread
From: Pablo Neira Ayuso @ 2026-06-23 5:46 UTC (permalink / raw)
To: netfilter-devel
On helper registration, the maximum number of expectations cannot go over
NF_CT_EXPECT_MAX_CNT (255), but zero can be specified then
nf_conntrack_expect_max applies. Turn zero into NF_CT_EXPECT_MAX_CNT
otherwise, expectation LRU eviction on insertion is disabled.
Moreover, expand this sanity check all expectation classes.
This max_expecy policy is only tunable since userspace helpers are
available, set Fixes: tag to the commit that adds such infrastructure.
Remove the check for p->max_expected given this field must always
be non-zero after this patch.
Fixes: 12f7a505331e ("netfilter: add user-space connection tracking helper infrastructure")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v1: resend to let sashiko pick in with this batch.
net/netfilter/nf_conntrack_expect.c | 3 +--
net/netfilter/nf_conntrack_helper.c | 9 +++++++--
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 113bb1cb1683..38630c5e006f 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -496,8 +496,7 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect,
lockdep_is_held(&nf_conntrack_expect_lock));
if (helper) {
p = &helper->expect_policy[expect->class];
- if (p->max_expected &&
- master_help->expecting[expect->class] >= p->max_expected)
+ if (master_help->expecting[expect->class] >= p->max_expected)
evict_oldest_expect(master_help, expect, p);
} else {
const struct nf_conntrack_expect_policy default_exp_policy = {
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index 8b94001c2430..a7fffe26b830 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -374,8 +374,13 @@ int __nf_conntrack_helper_register(struct nf_conntrack_helper *me)
if (!nf_ct_helper_hash)
return -ENOENT;
- if (me->expect_policy->max_expected > NF_CT_EXPECT_MAX_CNT)
- return -EINVAL;
+ for (i = 0; i < me->expect_class_max; i++) {
+ if (!me->expect_policy[i].max_expected)
+ me->expect_policy[i].max_expected = NF_CT_EXPECT_MAX_CNT;
+
+ if (me->expect_policy[i].max_expected > NF_CT_EXPECT_MAX_CNT)
+ return -EINVAL;
+ }
mutex_lock(&nf_ct_helper_mutex);
for (i = 0; i < nf_ct_helper_hsize; i++) {
--
2.47.3
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-06-23 5:46 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-23 5:46 [PATCH nf,v1 1/4] netfilter: ctnetlink: do not allow to reset helper on existing conntrack Pablo Neira Ayuso
2026-06-23 5:46 ` [PATCH nf,v1 2/4] netfilter: nf_conntrack_expect: store master_tuple in expectation Pablo Neira Ayuso
2026-06-23 5:46 ` [PATCH nf,v1 3/4] netfilter: nf_conntrack_expect: run expectation eviction with no helper Pablo Neira Ayuso
2026-06-23 5:46 ` [PATCH nf,v1 4/4] netfilter: nf_conntrack_helper: cap maximum number of expectation at helper registration Pablo Neira Ayuso
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.