* [PATCH nf,v2 1/2] netfilter: ctnetlink: reject expectation deletions on unconfirmed conntrack @ 2026-07-29 11:35 Pablo Neira Ayuso 2026-07-29 11:35 ` [PATCH nf,v2 2/2] netfilter: nf_conntrack: move expectation hlist_head on ct extension realloc Pablo Neira Ayuso 2026-07-29 12:38 ` [PATCH nf,v2 1/2] netfilter: ctnetlink: reject expectation deletions on unconfirmed conntrack Pablo Neira Ayuso 0 siblings, 2 replies; 3+ messages in thread From: Pablo Neira Ayuso @ 2026-07-29 11:35 UTC (permalink / raw) To: netfilter-devel ctnetlink allows to reach expectations that refer to unconfirmed conntrack. The ct extension area of unconfirmed conntrack could be reallocated while the packet is in transit. While holding the spinlock, check if the master conntrack is unconfirmed. The existing expectation spinlock ensures that the master conntrack is still alive because nf_ct_remove_expectations() tears down all expectations on conntrack removal. So, while holding the spinlock, the lifetime of the expectations is attached to the master conntrack. Fixes: ecfab2c9fe55 [NETFILTER]: nf_conntrack: introduce extension infrastructure Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> --- v2: new in this series, to address sashiko report. net/netfilter/nf_conntrack_expect.c | 3 +++ net/netfilter/nf_conntrack_netlink.c | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 8a3b9e33e94f..7694deaa5b12 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -620,6 +620,9 @@ void nf_ct_expect_iterate_net(struct net *net, if (!net_eq(nf_ct_exp_net(exp), net)) continue; + if (!nf_ct_is_confirmed(exp->master)) + continue; + if (iter(exp, data)) nf_ct_unlink_expect_report(exp, portid, report); } diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 31cbb1b55b9e..b58f51372849 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -3442,6 +3442,12 @@ static int ctnetlink_del_expect(struct sk_buff *skb, } } + if (!nf_ct_is_confirmed(exp->master)) { + nf_ct_expect_put(exp); + spin_unlock_bh(&nf_conntrack_expect_lock); + return -EBUSY; + } + /* after list removal, usage count == 1 */ nf_ct_unlink_expect_report(exp, NETLINK_CB(skb).portid, nlmsg_report(info->nlh)); -- 2.47.3 ^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH nf,v2 2/2] netfilter: nf_conntrack: move expectation hlist_head on ct extension realloc 2026-07-29 11:35 [PATCH nf,v2 1/2] netfilter: ctnetlink: reject expectation deletions on unconfirmed conntrack Pablo Neira Ayuso @ 2026-07-29 11:35 ` Pablo Neira Ayuso 2026-07-29 12:38 ` [PATCH nf,v2 1/2] netfilter: ctnetlink: reject expectation deletions on unconfirmed conntrack Pablo Neira Ayuso 1 sibling, 0 replies; 3+ messages in thread From: Pablo Neira Ayuso @ 2026-07-29 11:35 UTC (permalink / raw) To: netfilter-devel Commit 7c9664351980 ("netfilter: move nat hlist_head to nf_conn") moved the nat hlist_head to nf_conn and it removes the .move callback for ct extensions. This commit description already points to the same problem that is being addressed for expectations by this patch: 1. ... 2. When reallocation of extension area occurs we need to fixup the bysource hash head via hlist_replace_rcu. This means that the .pprev pointer of the first expectation might refer to a stale hlist_head after reallocation. This bug is now easier to trigger since the introduction of the commit 857b46027d6f ("netfilter: nft_ct: add ct expectations support") which allows to create expectations before the ct extension area have been fully set up for unconfirmed conntracks. This patch uses hlist_move_list() because this conntrack is unconfirmed, ie. not yet in the hashes, and it is neither visible to the conntrack garbage collector nor ctnetlink. Fixes: 857b46027d6f ("netfilter: nft_ct: add ct expectations support") Reported-by: Jaeyeong Lee <iostreampy@proton.me> Link: https://patch.msgid.link/20260715144755.00ea7dfcd9f@proton.me Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> --- v2: no changes. net/netfilter/nf_conntrack_extend.c | 33 ++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c index 0da105e1ded9..ea7795a2461f 100644 --- a/net/netfilter/nf_conntrack_extend.c +++ b/net/netfilter/nf_conntrack_extend.c @@ -87,9 +87,34 @@ static __always_inline unsigned int total_extension_size(void) ; } +static void nf_ct_ext_helper_save(struct nf_conn *ct, + struct hlist_head *expectations) +{ + struct nf_conn_help *help; + + help = nf_ct_ext_find(ct, NF_CT_EXT_HELPER); + if (!help) + return; + + hlist_move_list(&help->expectations, expectations); +} + +static void nf_ct_ext_helper_restore(struct nf_conn *ct, + struct hlist_head *expectations) +{ + struct nf_conn_help *help; + + help = nf_ct_ext_find(ct, NF_CT_EXT_HELPER); + if (!help) + return; + + hlist_move_list(expectations, &help->expectations); +} + void *nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp) { unsigned int newlen, newoff, oldlen, alloc; + HLIST_HEAD(expectations); struct nf_ct_ext *new; /* Conntrack must not be confirmed to avoid races on reallocation. */ @@ -108,13 +133,17 @@ void *nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp) oldlen = sizeof(*new); } + nf_ct_ext_helper_save(ct, &expectations); + newoff = ALIGN(oldlen, __alignof__(struct nf_ct_ext)); newlen = newoff + nf_ct_ext_type_len[id]; alloc = max(newlen, NF_CT_EXT_PREALLOC); new = krealloc(ct->ext, alloc, gfp); - if (!new) + if (!new) { + nf_ct_ext_helper_restore(ct, &expectations); return NULL; + } if (!ct->ext) memset(new->offset, 0, sizeof(new->offset)); @@ -124,6 +153,8 @@ void *nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp) memset((void *)new + newoff, 0, newlen - newoff); ct->ext = new; + nf_ct_ext_helper_restore(ct, &expectations); + return (void *)new + newoff; } EXPORT_SYMBOL(nf_ct_ext_add); -- 2.47.3 ^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH nf,v2 1/2] netfilter: ctnetlink: reject expectation deletions on unconfirmed conntrack 2026-07-29 11:35 [PATCH nf,v2 1/2] netfilter: ctnetlink: reject expectation deletions on unconfirmed conntrack Pablo Neira Ayuso 2026-07-29 11:35 ` [PATCH nf,v2 2/2] netfilter: nf_conntrack: move expectation hlist_head on ct extension realloc Pablo Neira Ayuso @ 2026-07-29 12:38 ` Pablo Neira Ayuso 1 sibling, 0 replies; 3+ messages in thread From: Pablo Neira Ayuso @ 2026-07-29 12:38 UTC (permalink / raw) To: netfilter-devel On Wed, Jul 29, 2026 at 01:35:47PM +0200, Pablo Neira Ayuso wrote: > ctnetlink allows to reach expectations that refer to unconfirmed > conntrack. The ct extension area of unconfirmed conntrack could be > reallocated while the packet is in transit. > > While holding the spinlock, check if the master conntrack is > unconfirmed. The existing expectation spinlock ensures that the master > conntrack is still alive because nf_ct_remove_expectations() tears down > all expectations on conntrack removal. So, while holding the spinlock, > the lifetime of the expectations is attached to the master conntrack. Scratch this series, I'm not tackling the issue from the right angle. Will follow up asap. ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-07-29 12:38 UTC | newest] Thread overview: 3+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-29 11:35 [PATCH nf,v2 1/2] netfilter: ctnetlink: reject expectation deletions on unconfirmed conntrack Pablo Neira Ayuso 2026-07-29 11:35 ` [PATCH nf,v2 2/2] netfilter: nf_conntrack: move expectation hlist_head on ct extension realloc Pablo Neira Ayuso 2026-07-29 12:38 ` [PATCH nf,v2 1/2] netfilter: ctnetlink: reject expectation deletions on unconfirmed conntrack Pablo Neira Ayuso
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox