Re: [PATCH net] xfrm: add missing rcu_read_lock(), skb_dst_force() and dev_hold() for xfrm_trans_reinject()
Steffen Klassert <[email protected]>
| Newsgroups | org.kernel.vger.netdev |
|---|---|
| Message-ID | <[email protected]> |
On Fri, Aug 07, 2026 at 05:15:33PM +0000, Eric Dumazet wrote:
> syzbot reported a suspicious RCU usage warning in ip6_pkt_drop():
>
> WARNING: suspicious RCU usage in ip6_pkt_drop
> include/net/addrconf.h:389 suspicious rcu_dereference_check() usage!
>
> Call Trace:
> __in6_dev_get_safely include/net/addrconf.h:389 [inline]
> ip6_pkt_drop+0x596/0x610 net/ipv6/route.c:4620
> ip6_pkt_discard+0x1c/0x30 net/ipv6/route.c:4651
> xfrm_trans_reinject+0x324/0x630 net/xfrm/xfrm_input.c:806
> process_one_work kernel/workqueue.c:3322 [inline]
> process_scheduled_works+0xa8e/0x14e0 kernel/workqueue.c:3405
> worker_thread+0xa47/0xfb0 kernel/workqueue.c:3486
>
> When commit 4f4920669d21 ("xfrm: Reinject transport-mode packets through
> workqueue") converted xfrm_trans_reinject from a tasklet to a workqueue,
> the reinjection loop ceased running in softirq context. Workqueue workers
> run in process context where local_bh_disable() does not enter an RCU
> read-side critical section under CONFIG_PREEMPT_RCU.
>
> Because finish callbacks (such as ip6_rcv_finish) expect to run under an
> RCU read lock (performing route lookups, l3mdev lookups, and accessing
> RCU-protected data structures), invoking them in workqueue context without
> rcu_read_lock() triggers RCU lockdep warnings.
>
> Furthermore, packets queued to the workqueue via xfrm_trans_queue_net()
> may carry non-refcounted (noref) dst entries (e.g. from ip_route_input_noref).
> Additionally, on netdevice unregistration, dst_dev_put() replaces dst->dev
> with blackhole_netdev, so dst entries do not keep skb->dev alive while
> queued in the workqueue.
>
> Fix these issues by:
> 1. Calling skb_dst_force(skb) in xfrm_trans_queue_net() while still in the
> caller's RCU section to ensure dst is reference-counted before queuing.
> 2. Holding a reference on skb->dev via dev_hold()/dev_put() across workqueue
> deferral so skb->dev remains valid during finish() callback processing.
> 3. Acquiring rcu_read_lock() around the finish callback invocation loop in
> xfrm_trans_reinject().
>
> Fixes: 4f4920669d21 ("xfrm: Reinject transport-mode packets through workqueue")
> Reported-by: syzbot <[email protected]>
> Signed-off-by: Eric Dumazet <[email protected]>
> Cc: Steffen Klassert <[email protected]>
> Cc: Liu Jian <[email protected]>
Now applied to the ipsec tree, thanks a lot Eric!