On Sat, Mar 7, 2026 at 4:52 AM xietangxin <[email protected]> wrote: > > A UAF issue occurs when the virtio_net driver is configured with napi_tx=N > and the device's IFF_XMIT_DST_RELEASE flag is cleared > (e.g., during the configuration of tc route filter rules). > > When IFF_XMIT_DST_RELEASE is removed from the net_device, the network stack > expects the driver to hold the reference to skb->dst until the packet > is fully transmitted and freed. In virtio_net with napi_tx=N, > skbs may remain in the virtio transmit ring for an extended period. > > If the network namespace is destroyed while these skbs are still pending, > the corresponding dst_ops structure has freed. When a subsequent packet > is transmitted, free_old_xmit() is triggered to clean up old skbs. > It then calls dst_release() on the skb associated with the stale dst_entry. > Since the dst_ops (referenced by the dst_entry) has already been freed, > a UAF kernel paging request occurs. > > fix it by adds skb_dst_drop(skb) in start_xmit to explicitly release > the dst reference before the skb is queued in virtio_net. > > Call Trace: > Unable to handle kernel paging request at virtual address ffff80007e150000 > CPU: 2 UID: 0 PID: 6236 Comm: ping Kdump: loaded Not tainted 7.0.0-rc1+ #6 > PREEMPT > ... > percpu_counter_add_batch+0x3c/0x158 lib/percpu_counter.c:98 (P) > dst_release+0xe0/0x110 net/core/dst.c:177 > skb_release_head_state+0xe8/0x108 net/core/skbuff.c:1177 > sk_skb_reason_drop+0x54/0x2d8 net/core/skbuff.c:1255 > dev_kfree_skb_any_reason+0x64/0x78 net/core/dev.c:3469 > napi_consume_skb+0x1c4/0x3a0 net/core/skbuff.c:1527 > __free_old_xmit+0x164/0x230 drivers/net/virtio_net.c:611 [virtio_net] > free_old_xmit drivers/net/virtio_net.c:1081 [virtio_net] > start_xmit+0x7c/0x530 drivers/net/virtio_net.c:3329 [virtio_net] > ... > > Reproduction Steps: > NETDEV="enp3s0" > > config_qdisc_route_filter() { > tc qdisc del dev $NETDEV root > tc qdisc add dev $NETDEV root handle 1: prio > tc filter add dev $NETDEV parent 1:0 protocol ip prio 100 route to 100 > flowid 1:1 > ip route add 192.168.1.100/32 dev $NETDEV realm 100 > } > > test_ns() { > ip netns add testns > ip link set $NETDEV netns testns > ip netns exec testns ifconfig $NETDEV 10.0.32.46/24 > ip netns exec testns ping -c 1 10.0.32.1 > ip netns del testns > } > > config_qdisc_route_filter > > test_ns > sleep 2 > test_ns > > Signed-off-by: xietangxin <[email protected]> > --- > drivers/net/virtio_net.c | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c > index 72d6a9c6a..5b13a61b3 100644 > --- a/drivers/net/virtio_net.c > +++ b/drivers/net/virtio_net.c > @@ -3351,6 +3351,7 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, > struct net_device *dev) > /* Don't wait up for transmitted skbs to be freed. */ > if (!use_napi) { > skb_orphan(skb); > + skb_dst_drop(skb); > nf_reset_ct(skb); > }
This probably could skb_release_head_state() at this point. Thanks.

