mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: netdev-bot+sashiko@kernel.org
To: i.maximets@ovn.org
Cc: netdev@vger.kernel.org, pablo@netfilter.org, fw@strlen.de,
	phil@nwl.cc, davem@davemloft.net, edumazet@google.com,
	kuba@kernel.org, pabeni@redhat.com, horms@kernel.org,
	aconole@redhat.com, echaudro@redhat.com, jhs@mojatatu.com,
	jiri@resnulli.us, lucien.xin@gmail.com,
	marcelo.leitner@gmail.com, netfilter-devel@vger.kernel.org,
	coreteam@netfilter.org, linux-kernel@vger.kernel.org,
	dev@openvswitch.org, stable@vger.kernel.org
Subject: Re: [PATCH net 4/6] net/sched: act_ct: avoid modifying shared unconfirmed ct entry
Date: Tue, 22 Sep 2026 14:58:40 +0000	[thread overview]
Message-ID: <179008912095.2160803.9187949237353089190@kernel.org> (raw)
In-Reply-To: <20260921145655.3167436-5-i.maximets@ovn.org>

Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider.

Critical: 0 · High: 0 · Medium: 1 (1) · Low: 0

If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).

- [Medium] tcf_ct_act() now discards an unconfirmed conntrack entry
  purely because its refcount is >1, without checking whether the…

Pre-existing issues:
- [Medium] At this commit, tcf_ct_act() still calls nf_ct_helper()
  (net/sched/act_ct.c:1106) before the commit block that grows the…

--

net/sched: act_ct: avoid modifying shared unconfirmed ct entry

tcf_ct_act() now resets the skb conntrack association when the cached entry
is unconfirmed and its refcount shows it is shared with another skb, so that
a commit or nat pass cannot grow the extension area of an entry another
clone still points into.  The nat flag is also hoisted into a local
variable.

> diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c
> index 55f3521edb4c9..e72143d36b119 100644
> --- a/net/sched/act_ct.c
> +++ b/net/sched/act_ct.c

[ ... ]

> @@ -998,6 +998,7 @@ TC_INDIRECT_SCOPE int tcf_ct_act(struct sk_buff *skb, const struct tc_action *a,
>  	retval = p->action;
>  	commit = p->ct_action & TCA_CT_ACT_COMMIT;
>  	clear = p->ct_action & TCA_CT_ACT_CLEAR;
> +	nat = p->ct_action & TCA_CT_ACT_NAT;
>  	tmpl = p->tmpl;
>  
>  	tcf_lastuse_update(&c->tcf_tm);
> @@ -1046,6 +1047,19 @@ TC_INDIRECT_SCOPE int tcf_ct_act(struct sk_buff *skb, const struct tc_action *a,
>  	 * different zone.
>  	 */
>  	cached = tcf_ct_skb_nfct_cached(net, skb, p);
> +
> +	/* If the ct entry is not confirmed and shared with some other skb,
> +	 * e.g., a cloned one, we can't just modify it with a commit or nat
> +	 * as we must not modify the extension set.  Reset.
> +	 */
> +	if (cached && (commit || nat)) {
> +		ct = nf_ct_get(skb, &ctinfo);
> +		if (ct && !nf_ct_is_confirmed(ct) && nf_ct_shared(ct)) {
> +			nf_reset_ct(skb);
> +			cached = false;
> +		}
> +	}
> +

[Severity: Medium]
Can this drop NAT state that was already applied to the packet?

The condition keys off nf_ct_shared(ct), i.e. refcount > 1, and not off
whether the sharing skb will ever be re-processed by conntrack.  act_ct
permits nat without commit, and in that case
tcf_ct_act_nat()->nf_ct_nat() (net/netfilter/nf_nat_ovs.c) already
installs the binding and translates the headers on the unconfirmed entry:

net/netfilter/nf_nat_ovs.c:nf_ct_nat() {
	...
	/* Add NAT extension if not confirmed yet. */
	if (!nf_ct_is_confirmed(ct) && !nf_ct_nat_ext_add(ct))
		return NF_DROP;   /* Can't NAT. */
	...
	err = nf_ct_nat_execute(skb, ct, ctinfo, action, range, maniptype);
}

If the skb is then cloned by a path that keeps the nfct reference, and a
later filter runs "action ct zone N commit" on the original, the new block
sees cached && commit with an unconfirmed, shared entry, calls
nf_reset_ct(skb) and sets cached = false.  nf_conntrack_in() then re-tracks
the already translated packet, so the entry that gets committed carries the
post-NAT tuple as its ORIGINAL tuple and no matching binding, and reply
traffic is no longer reverse translated.  Before this change the cached,
NAT'ed unconfirmed entry was simply committed.

One note on the trigger: act_mirred and AF_PACKET taps do not produce this
sharing, since both clear the association on the clone:

net/sched/act_mirred.c:tcf_mirred_to_dev() {
	/* All mirred/redirected skbs should clear previous ct info */
	nf_reset_ct(skb_to_send);
}

net/packet/af_packet.c:packet_rcv() {
	/* drop conntrack reference */
	nf_reset_ct(skb);
}

Bridge flood/multicast delivery does keep it, though -
net/bridge/br_forward.c:deliver_clone() calls skb_clone() with no
nf_reset_ct(), so __nf_copy() raises ct_general.use on the clone.

Would it be worth mentioning in the changelog that the reset also fires
when the second pass does commit?  The changelog currently only argues
about the "without commit" case:

    This, however, doesn't really change the picture for sensible
    networking cases as there should be no need to run the same packet
    twice (before and after the clone) through conntrack without packet
    header or zone changes and without commit.

[Severity: Medium]
This is a pre-existing ordering problem and is not introduced by this
patch, but it is worth flagging for backports since the new guard does not
cover it.

At this commit tcf_ct_act() still runs the helper before the commit block
grows the extension area of an unconfirmed entry:

net/sched/act_ct.c:tcf_ct_act() {
	...
	if (nf_ct_is_confirmed(ct) ? ((!cached && !skip_add) || add_helper) : commit) {
		err = nf_ct_helper(skb, ct, ctinfo, family);
		if (err != NF_ACCEPT)
			goto nf_error;
	}

	if (commit) {
		tcf_ct_act_set_mark(ct, p->mark, p->mark_mask);
		tcf_ct_act_set_labels(ct, p->labels, p->labels_mask);

		if (!nf_ct_is_confirmed(ct))
			nf_conn_act_ct_ext_add(skb, ct, ctinfo);
	...
}

A helper that inserts an expectation links exp->lnode into a list head that
lives inside ct->ext:

net/netfilter/nf_conntrack_expect.c:nf_ct_expect_insert() {
	hlist_add_head_rcu(&exp->lnode, &master_help->expectations);
}

and the following nf_ct_ext_add(NF_CT_EXT_ACT_CT) relocates that memory:

net/netfilter/nf_conntrack_extend.c:nf_ct_ext_add() {
	new = krealloc(old, alloc, gfp);
}

leaving exp->lnode.pprev pointing into the freed block, which is written
through when the expectation is unlinked via nf_ct_remove_expectations().

The new reset only fires for cached entries with refcount > 1, so an entry
that was just tracked (cached == false), or the replacement entry created
after the reset, still follows the helper-then-realloc sequence with a
single skb reference.

The later patch in this series ("net/sched: act_ct: fix helper UAF due to
extensions realloc") moves nf_ct_helper() after the
nf_conn_act_ct_ext_add() block with the comment "This has to be done after
all the extensions are already added.", so the ordering is resolved within
the series.  Given the stable tag here, should the two patches be marked so
that backporters take the reordering change together with this one?

[ ... ]

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260921145655.3167436-1-i.maximets%40ovn.org

  reply	other threads:[~2026-09-22 14:58 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-21 14:55 [PATCH net 0/6] ovs, net/sched: fixes for UAF after conntrack extension realloc Ilya Maximets
2026-09-21 14:55 ` [PATCH net 1/6] net: openvswitch: conntrack: avoid modifying shared unconfirmed ct entry Ilya Maximets
2026-09-22 14:58   ` netdev-bot+sashiko
2026-09-22 15:27     ` Ilya Maximets
2026-09-22 15:26   ` Aaron Conole
2026-09-21 14:55 ` [PATCH net 2/6] net: openvswitch: conntrack: remove 'add_helper' dead code Ilya Maximets
2026-09-22 14:58   ` netdev-bot+sashiko
2026-09-22 15:29     ` Ilya Maximets
2026-09-22 15:26   ` Aaron Conole
2026-09-21 14:55 ` [PATCH net 3/6] net: openvswitch: conntrack: fix helper UAF due to extensions realloc Ilya Maximets
2026-09-22 14:58   ` netdev-bot+sashiko
2026-09-22 15:43     ` Ilya Maximets
2026-09-22 15:26   ` Aaron Conole
2026-09-21 14:55 ` [PATCH net 4/6] net/sched: act_ct: avoid modifying shared unconfirmed ct entry Ilya Maximets
2026-09-22 14:58   ` netdev-bot+sashiko [this message]
2026-09-22 15:52     ` Ilya Maximets
2026-09-22 15:27   ` Aaron Conole
2026-09-22 20:42   ` Xin Long
2026-09-22 21:34   ` Jamal Hadi Salim
2026-09-21 14:55 ` [PATCH net 5/6] net/sched: act_ct: remove 'add_helper' dead code Ilya Maximets
2026-09-22 15:27   ` Aaron Conole
2026-09-22 20:43   ` Xin Long
2026-09-22 21:35   ` Jamal Hadi Salim
2026-09-21 14:55 ` [PATCH net 6/6] net/sched: act_ct: fix helper UAF due to extensions realloc Ilya Maximets
2026-09-22 14:58   ` netdev-bot+sashiko
2026-09-22 15:54     ` Ilya Maximets
2026-09-22 20:43   ` Xin Long
2026-09-22 21:36   ` Jamal Hadi Salim
2026-09-23 12:35   ` Aaron Conole
2026-09-24  1:21 ` [PATCH net 0/6] ovs, net/sched: fixes for UAF after conntrack extension realloc Jakub Kicinski

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=179008912095.2160803.9187949237353089190@kernel.org \
    --to=netdev-bot+sashiko@kernel.org \
    --cc=aconole@redhat.com \
    --cc=coreteam@netfilter.org \
    --cc=davem@davemloft.net \
    --cc=dev@openvswitch.org \
    --cc=echaudro@redhat.com \
    --cc=edumazet@google.com \
    --cc=fw@strlen.de \
    --cc=horms@kernel.org \
    --cc=i.maximets@ovn.org \
    --cc=jhs@mojatatu.com \
    --cc=jiri@resnulli.us \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lucien.xin@gmail.com \
    --cc=marcelo.leitner@gmail.com \
    --cc=netdev@vger.kernel.org \
    --cc=netfilter-devel@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=pablo@netfilter.org \
    --cc=phil@nwl.cc \
    --cc=stable@vger.kernel.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

all inboxes | Powered by JetHome®