Netdev List
 help / color / mirror / Atom feed
* [PATCH net] xfrm: retry inexact policy lookup after node reinsertion
@ 2026-08-24 15:20 Chengfeng Ye
  2026-09-03  7:32 ` Steffen Klassert
  0 siblings, 1 reply; 3+ messages in thread
From: Chengfeng Ye @ 2026-08-24 15:20 UTC (permalink / raw)
  To: Steffen Klassert, Herbert Xu, David S . Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, Florian Westphal
  Cc: netdev, linux-kernel, Chengfeng Ye, stable

When a newly inserted inexact policy covers multiple existing nodes,
xfrm_policy_inexact_node_merge() removes each policy from the old node with
hlist_del_rcu(). xfrm_policy_inexact_list_reinsert() then immediately adds
the same bydst node to another hlist. hlist_del_rcu() leaves ->next intact
for readers already at the removed entry, but the add overwrites it before
an RCU grace period.

This permits the following interleaving:

  CPU 0                                  CPU 1
  -----                                  -----
  reach policy P in the old hlist
                                         delete P from the old hlist
                                         add P to the new hlist
  follow P->next into the new hlist

The lookup can then skip a matching policy and make an incorrect IPsec
decision.

During concurrent policy insertion and route lookup, KCSAN reported:

  BUG: KCSAN: data-race in __xfrm_policy_link / xfrm_lookup_with_ifid
  write to ... by task 92 on cpu 0:
    __xfrm_policy_link
    xfrm_policy_insert
    xfrm_add_policy
  read to ... by task 91 on cpu 1:
    xfrm_lookup_with_ifid
    xfrm_lookup_route
    ip_route_output_flow

The per-bin sequence counter already brackets inexact tree changes,
including node merges. Snapshot it before candidate discovery and retry
after evaluating all candidate lists if it changed. This rejects results
from any traversal overlapping reinsertion while leaving stable lookup
order and locking unchanged.

Fixes: 9cf545ebd591 ("xfrm: policy: store inexact policies in a tree ordered by destination address")
Cc: stable@vger.kernel.org
Signed-off-by: Chengfeng Ye <nicoyip.dev@gmail.com>
---
 net/xfrm/xfrm_policy.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 932a313b9460..5d4e863863df 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2157,6 +2157,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
 	struct xfrm_pol_inexact_bin *bin;
 	struct xfrm_policy *pol, *ret;
 	struct hlist_head *chain;
+	unsigned int inexact_sequence;
 	unsigned int sequence;
 	int err;
 
@@ -2191,12 +2192,18 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
 		goto skip_inexact;
 
 	bin = xfrm_policy_inexact_lookup_rcu(net, type, family, dir, if_id);
-	if (!bin || !xfrm_policy_find_inexact_candidates(&cand, bin, saddr,
-							 daddr))
+	if (!bin)
+		goto skip_inexact;
+
+	inexact_sequence = read_seqcount_begin(&bin->count);
+	if (!xfrm_policy_find_inexact_candidates(&cand, bin, saddr, daddr))
 		goto skip_inexact;
 
 	pol = xfrm_policy_eval_candidates(&cand, ret, fl, type,
 					  family, if_id);
+	if (read_seqcount_retry(&bin->count, inexact_sequence))
+		goto retry;
+
 	if (pol) {
 		ret = pol;
 		if (IS_ERR(pol))
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH net] xfrm: retry inexact policy lookup after node reinsertion
  2026-08-24 15:20 [PATCH net] xfrm: retry inexact policy lookup after node reinsertion Chengfeng Ye
@ 2026-09-03  7:32 ` Steffen Klassert
  2026-09-03 11:52   ` Chengfeng Ye
  0 siblings, 1 reply; 3+ messages in thread
From: Steffen Klassert @ 2026-09-03  7:32 UTC (permalink / raw)
  To: Chengfeng Ye
  Cc: Herbert Xu, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Florian Westphal, netdev, linux-kernel,
	stable

This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
---
--- Patch [1]: [PATCH net] xfrm: retry inexact policy lookup after node reinsertion ---
commit 55045c9b49d306c47b0ee8e568d224e0bca94a3c
Author: Chengfeng Ye <nicoyip.dev@gmail.com>

xfrm: retry inexact policy lookup after node reinsertion

This adds a snapshot of the per-bin sequence counter around inexact
candidate discovery and evaluation in xfrm_policy_lookup_bytype(), and
retries the whole lookup if the counter changed.  The stated goal is to
reject lookups that overlap the bydst hlist hop done during node merge and
reinsertion.

No Link: tags are present in the commit header.

> During concurrent policy insertion and route lookup, KCSAN reported:
>
>   BUG: KCSAN: data-race in __xfrm_policy_link / xfrm_lookup_with_ifid
>   write to ... by task 92 on cpu 0:
>     __xfrm_policy_link
>     xfrm_policy_insert
>     xfrm_add_policy
>   read to ... by task 91 on cpu 1:
>     xfrm_lookup_with_ifid
>     xfrm_lookup_route
>     ip_route_output_flow

Discovered by: opus-5 · Missed by: sonnet-5, gpt-5-6-sol, sashiko-gemini · Confirmed by: gpt-5-6-sol
Can this KCSAN report come from the code the patch changes?

__xfrm_policy_link() in net/xfrm/xfrm_policy.c only does this:

	switch (dir) {
	case XFRM_POLICY_IN:
	case XFRM_POLICY_FWD:
	case XFRM_POLICY_OUT:
		pol->pos = xfrm_gen_pos(net);
		break;
	}

	list_add(&pol->walk.all, &net->xfrm.policy_all);
	WRITE_ONCE(net->xfrm.policy_count[dir], net->xfrm.policy_count[dir] + 1);
	xfrm_pol_hold(pol);

The only one of those locations that xfrm_lookup_with_ifid() touches is
policy_count, and it reads it marked:

	if (!if_id && ((dst_orig->flags & DST_NOXFRM) ||
		       !READ_ONCE(net->xfrm.policy_count[XFRM_POLICY_OUT])))
		goto nopol;

Documentation/dev-tools/kcsan.rst states that if all concurrent accesses to
a variable are properly marked, KCSAN will never trigger a watchpoint and
therefore never report the accesses.  Both sides here are marked, so how
was this pair reported?

The write side the changelog describes in prose is a different one: the
bydst hop in xfrm_policy_inexact_node_merge():

	hlist_for_each_entry(tmp, &v->hhead, bydst) {
		tmp->bydst_reinsert = true;
		hlist_del_rcu(&tmp->bydst);
	}

	xfrm_policy_inexact_list_reinsert(net, n, family);

That path is reached via xfrm_policy_inexact_insert_node(), not via
__xfrm_policy_link(), and it also uses only marked writes
(hlist_del_rcu(), hlist_add_head_rcu(), hlist_add_behind_rcu()) against a
reader using hlist_for_each_entry_rcu().  So that pair would not be
reported by KCSAN either, which suggests the hazard being fixed is a
logical list-hop ordering problem between correctly marked RCU accesses
rather than a data race.

Could the changelog be reworded to describe the ordering problem directly,
and either drop the KCSAN splat or replace it with a report that actually
corresponds to the accesses this patch guards?  With Cc: stable in place,
the quoted evidence is what backporters will use to judge the fix.

> diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
> index 932a313b9460a..5d4e863863dfe 100644
> --- a/net/xfrm/xfrm_policy.c
> +++ b/net/xfrm/xfrm_policy.c

[ ... ]

> @@ -2191,12 +2192,18 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
>  		goto skip_inexact;
>
>  	bin = xfrm_policy_inexact_lookup_rcu(net, type, family, dir, if_id);
> -	if (!bin || !xfrm_policy_find_inexact_candidates(&cand, bin, saddr,
> -							 daddr))
> +	if (!bin)
> +		goto skip_inexact;
> +
> +	inexact_sequence = read_seqcount_begin(&bin->count);
> +	if (!xfrm_policy_find_inexact_candidates(&cand, bin, saddr, daddr))
>  		goto skip_inexact;
>
>  	pol = xfrm_policy_eval_candidates(&cand, ret, fl, type,
>  					  family, if_id);
> +	if (read_seqcount_retry(&bin->count, inexact_sequence))
> +		goto retry;
> +

Discovered by: opus-5 · Missed by: sonnet-5, gpt-5-6-sol, sashiko-gemini · Confirmed by: gpt-5-6-sol
Related to the above: this retry can only observe mutations that are
bracketed by write_seqcount_begin(&bin->count).  The chain updates done by
xfrm_policy_insert_list() and __xfrm_policy_unlink(), and the counter
update in __xfrm_policy_link() named in the quoted splat, do not run inside
any bin->count write section.

So even taken at face value, would this new read_seqcount_retry() have any
effect on the __xfrm_policy_link() versus xfrm_lookup_with_ifid() pair
quoted in the changelog?

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH net] xfrm: retry inexact policy lookup after node reinsertion
  2026-09-03  7:32 ` Steffen Klassert
@ 2026-09-03 11:52   ` Chengfeng Ye
  0 siblings, 0 replies; 3+ messages in thread
From: Chengfeng Ye @ 2026-09-03 11:52 UTC (permalink / raw)
  To: Steffen Klassert
  Cc: Herbert Xu, David S . Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Florian Westphal, netdev, linux-kernel,
	stable

On Thu, Sep 3, 2026 at 3:32 PM Steffen Klassert
<steffen.klassert@secunet.com> wrote:
>
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> ---
> --- Patch [1]: [PATCH net] xfrm: retry inexact policy lookup after node reinsertion ---
> commit 55045c9b49d306c47b0ee8e568d224e0bca94a3c
> Author: Chengfeng Ye <nicoyip.dev@gmail.com>
>
> xfrm: retry inexact policy lookup after node reinsertion
>
> This adds a snapshot of the per-bin sequence counter around inexact
> candidate discovery and evaluation in xfrm_policy_lookup_bytype(), and
> retries the whole lookup if the counter changed.  The stated goal is to
> reject lookups that overlap the bydst hlist hop done during node merge and
> reinsertion.
>
> No Link: tags are present in the commit header.
>
> > During concurrent policy insertion and route lookup, KCSAN reported:
> >
> >   BUG: KCSAN: data-race in __xfrm_policy_link / xfrm_lookup_with_ifid
> >   write to ... by task 92 on cpu 0:
> >     __xfrm_policy_link
> >     xfrm_policy_insert
> >     xfrm_add_policy
> >   read to ... by task 91 on cpu 1:
> >     xfrm_lookup_with_ifid
> >     xfrm_lookup_route
> >     ip_route_output_flow
>
> Discovered by: opus-5 · Missed by: sonnet-5, gpt-5-6-sol, sashiko-gemini · Confirmed by: gpt-5-6-sol
> Can this KCSAN report come from the code the patch changes?
>
> __xfrm_policy_link() in net/xfrm/xfrm_policy.c only does this:
>
>         switch (dir) {
>         case XFRM_POLICY_IN:
>         case XFRM_POLICY_FWD:
>         case XFRM_POLICY_OUT:
>                 pol->pos = xfrm_gen_pos(net);
>                 break;
>         }
>
>         list_add(&pol->walk.all, &net->xfrm.policy_all);
>         WRITE_ONCE(net->xfrm.policy_count[dir], net->xfrm.policy_count[dir] + 1);
>         xfrm_pol_hold(pol);
>
> The only one of those locations that xfrm_lookup_with_ifid() touches is
> policy_count, and it reads it marked:
>
>         if (!if_id && ((dst_orig->flags & DST_NOXFRM) ||
>                        !READ_ONCE(net->xfrm.policy_count[XFRM_POLICY_OUT])))
>                 goto nopol;
>
> Documentation/dev-tools/kcsan.rst states that if all concurrent accesses to
> a variable are properly marked, KCSAN will never trigger a watchpoint and
> therefore never report the accesses.  Both sides here are marked, so how
> was this pair reported?
>
> The write side the changelog describes in prose is a different one: the
> bydst hop in xfrm_policy_inexact_node_merge():
>
>         hlist_for_each_entry(tmp, &v->hhead, bydst) {
>                 tmp->bydst_reinsert = true;
>                 hlist_del_rcu(&tmp->bydst);
>         }
>
>         xfrm_policy_inexact_list_reinsert(net, n, family);
>
> That path is reached via xfrm_policy_inexact_insert_node(), not via
> __xfrm_policy_link(), and it also uses only marked writes
> (hlist_del_rcu(), hlist_add_head_rcu(), hlist_add_behind_rcu()) against a
> reader using hlist_for_each_entry_rcu().  So that pair would not be
> reported by KCSAN either, which suggests the hazard being fixed is a
> logical list-hop ordering problem between correctly marked RCU accesses
> rather than a data race.
>
> Could the changelog be reworded to describe the ordering problem directly,
> and either drop the KCSAN splat or replace it with a report that actually
> corresponds to the accesses this patch guards?  With Cc: stable in place,
> the quoted evidence is what backporters will use to judge the fix.
>
> > diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
> > index 932a313b9460a..5d4e863863dfe 100644
> > --- a/net/xfrm/xfrm_policy.c
> > +++ b/net/xfrm/xfrm_policy.c
>
> [ ... ]
>
> > @@ -2191,12 +2192,18 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
> >               goto skip_inexact;
> >
> >       bin = xfrm_policy_inexact_lookup_rcu(net, type, family, dir, if_id);
> > -     if (!bin || !xfrm_policy_find_inexact_candidates(&cand, bin, saddr,
> > -                                                      daddr))
> > +     if (!bin)
> > +             goto skip_inexact;
> > +
> > +     inexact_sequence = read_seqcount_begin(&bin->count);
> > +     if (!xfrm_policy_find_inexact_candidates(&cand, bin, saddr, daddr))
> >               goto skip_inexact;
> >
> >       pol = xfrm_policy_eval_candidates(&cand, ret, fl, type,
> >                                         family, if_id);
> > +     if (read_seqcount_retry(&bin->count, inexact_sequence))
> > +             goto retry;
> > +
>
> Discovered by: opus-5 · Missed by: sonnet-5, gpt-5-6-sol, sashiko-gemini · Confirmed by: gpt-5-6-sol
> Related to the above: this retry can only observe mutations that are
> bracketed by write_seqcount_begin(&bin->count).  The chain updates done by
> xfrm_policy_insert_list() and __xfrm_policy_unlink(), and the counter
> update in __xfrm_policy_link() named in the quoted splat, do not run inside
> any bin->count write section.
>
> So even taken at face value, would this new read_seqcount_retry() have any
> effect on the __xfrm_policy_link() versus xfrm_lookup_with_ifid() pair
> quoted in the changelog?


Hi Steffen,

The review is correct. While generating the changelog I mistakenly
pointed the agent to the KCSAN report triggered for the data race
already fixed by 66817a979426, and I'm sorry for the mistake. I will
send a v2 to correct the changelog.

Best regards,
Chengfeng

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-09-03 11:52 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-24 15:20 [PATCH net] xfrm: retry inexact policy lookup after node reinsertion Chengfeng Ye
2026-09-03  7:32 ` Steffen Klassert
2026-09-03 11:52   ` Chengfeng Ye

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox