From: Florian Westphal <fw@strlen.de>
To: Pablo Neira Ayuso <pablo@netfilter.org>
Cc: netfilter-devel@vger.kernel.org
Subject: Re: [PATCH nf] netfilter: conntrack: add dead flag to helpers
Date: Wed, 13 May 2026 12:05:02 +0200 [thread overview]
Message-ID: <agRMzvHgYCblnbrO@strlen.de> (raw)
In-Reply-To: <20260512205823.803476-1-pablo@netfilter.org>
Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> Add a new NF_CT_HELPER_F_DEAD helper flag to notify the packet path that
> this helper is going away. Thus, helpers are effectively disabled and no
> new expectations are created while removing the expectations created by
> this helper as well as unhelping the existing conntrack entries.
>
> Add the check for NF_CT_HELPER_F_DEAD in the packet path to:
> - Conntrack confirmation path which invokes the helper callback.
> - Propagation of helper to conntrack via expectation.
> - OVS ct helper invocation.
>
> Fixes: 12f7a505331e ("netfilter: add user-space connection tracking helper infrastructure")
> Reported-by: Florian Westphal <fw@strlen.de>
> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
> ---
> include/net/netfilter/nf_conntrack_helper.h | 6 ++++++
> net/netfilter/nf_conntrack_core.c | 2 +-
> net/netfilter/nf_conntrack_helper.c | 5 ++++-
> net/netfilter/nf_conntrack_ovs.c | 3 +++
> net/netfilter/nf_conntrack_proto.c | 2 +-
> 5 files changed, 15 insertions(+), 3 deletions(-)
>
> diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h
> index de2f956abf34..1faa42efe42e 100644
> --- a/include/net/netfilter/nf_conntrack_helper.h
> +++ b/include/net/netfilter/nf_conntrack_helper.h
> @@ -25,6 +25,7 @@ struct module;
> enum nf_ct_helper_flags {
> NF_CT_HELPER_F_USERSPACE = (1 << 0),
> NF_CT_HELPER_F_CONFIGURED = (1 << 1),
> + NF_CT_HELPER_F_DEAD = (1 << 2),
> };
>
> #define NF_CT_HELPER_NAME_LEN 16
> @@ -63,6 +64,11 @@ struct nf_conntrack_helper {
> char nat_mod_name[NF_CT_HELPER_NAME_LEN];
> };
>
> +static inline bool nf_ct_helper_alive(const struct nf_conntrack_helper *helper)
> +{
> + return likely(!(helper->flags & NF_CT_HELPER_F_DEAD));
> +}
> +
> /* Must be kept in sync with the classes defined by helpers */
> #define NF_CT_MAX_EXPECT_CLASSES 4
>
> diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
> index 8ba5b22a1eef..d54da6babcfe 100644
> --- a/net/netfilter/nf_conntrack_core.c
> +++ b/net/netfilter/nf_conntrack_core.c
> @@ -1818,7 +1818,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
> /* exp->master safe, refcnt bumped in nf_ct_find_expectation */
> ct->master = exp->master;
> assign_helper = rcu_dereference(exp->assign_helper);
> - if (assign_helper) {
> + if (assign_helper && nf_ct_helper_alive(assign_helper)) {
At this time, the new ct isn't in any hash. As-is, I don't think this
will guarantee such nfct canot escape. See below.
> help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
> if (help)
> rcu_assign_pointer(help->helper, assign_helper);
> diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
> index b594cd244fe1..b3752ccca75e 100644
> --- a/net/netfilter/nf_conntrack_helper.c
> +++ b/net/netfilter/nf_conntrack_helper.c
> @@ -415,8 +415,11 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
> nf_ct_helper_count--;
> mutex_unlock(&nf_ct_helper_mutex);
>
> + me->flags |= NF_CT_HELPER_F_DEAD;
> +
Does this need to be toggled while under lock?
I don't think synchronize_rcu() is a barrier.
Also, it looks like this can be racing with nfnl_cthelper_update().
We probably need to add some new lock, or reuse existing one like
nf_ct_helper_mutex, or expectation spinlock.
> /* Make sure every nothing is still using the helper unless its a
> - * connection in the hash.
> + * connection in the hash, no more expectations are created after
> + * this rcu grace period.
> */
> synchronize_rcu();
... that makes things wait until we leave rcu protection.
I think we should also drop nfqueued packets here to make sure
they can't be reinjected.
Also, should __nf_ct_expect_check() also call nf_ct_helper_alive()
and refuse insertion of such exp into the table?
That would give following unreg sequence:
1. Unlink from hash
2. set flag -> prevent concurrent nf_ct_expect_related() from
adding more expectations to the exp table
3. synchronize_rcu() -> all skbs that had this helper have
left RCU protection
4. nf_ct_expect_iterate_destroy() removes all not-yet-found
exp entries from table
5. nf_ct_iterate_destroy() -> clear exp from nf_conn's that are
*in conntrack table*
That still means we could have a NEW conntrack queued via nfqueue.
I think we also need to toss nfqueued packets after step 3) and
need to refuse queueing to userspace if the flag is set (-> drop).
We could have several nfqueue back to back:
-t mangle -A PREROUTING -j NFQUEUE
-t mangle -A FORWARD -j NFQUEUE
... and each synchronize_rcu() might advance skb to next
'queue' instead of nf_confirm().
But I think that this a good direction, I think its better than my
rather destructive temporarily-block-all-exps idea.
next prev parent reply other threads:[~2026-05-13 10:05 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-12 20:58 [PATCH nf] netfilter: conntrack: add dead flag to helpers Pablo Neira Ayuso
2026-05-13 10:05 ` Florian Westphal [this message]
2026-05-13 15:29 ` Pablo Neira Ayuso
2026-05-13 15:38 ` Pablo Neira Ayuso
2026-05-13 15:52 ` Pablo Neira Ayuso
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=agRMzvHgYCblnbrO@strlen.de \
--to=fw@strlen.de \
--cc=netfilter-devel@vger.kernel.org \
--cc=pablo@netfilter.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox