mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
net: tap: set skb->dev before parsing virtio net header in tap_get_user_xdp()
The commit4f61f133f3("net: tap: NULL pointer derefence in dev_parse_header_protocol when skb->dev is null") fixed a crash in tap_get_user() by assigning skb->dev before calling tun_vnet_hdr_to_skb(). This is required because virtio_net_hdr_to_skb() may invoke dev_parse_header_protocol(), which dereferences skb->dev. Without the assignment, a NULL pointer dereference can occur. However, tap_get_user_xdp() still parses the virtio-net header before assigning skb->dev. When the vhost TX path passes an XDP buffer containing a GSO virtio-net header but the protocol is set to zero on purpose, tun_vnet_hdr_to_skb() can reach dev_parse_header_protocol() while skb->dev is still NULL, resulting in a crash. Fix this by looking up the tap device and assigning skb->dev before calling tun_vnet_hdr_to_skb(), matching the ordering already used in tap_get_user(). Preserve the existing RCU read-side critical section across dev_queue_xmit(). Fixes:924a9bc362("net: check if protocol extracted by virtio_net_hdr_set_proto is correct") Cc: stable@vger.kernel.org Signed-off-by: Dongli Zhang <dongli.zhang@oracle.com> Reviewed-by: Willem de Bruijn <willemb@google.com> Acked-by: Michael S. Tsirkin <mst@redhat.com> Link: https://patch.msgid.link/20260802224612.264563-1-dongli.zhang@oracle.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
f803c08639
commit
3874892dd2
|
|
@ -1074,10 +1074,21 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp)
|
|||
skb_reset_mac_header(skb);
|
||||
skb->protocol = eth_hdr(skb)->h_proto;
|
||||
|
||||
rcu_read_lock();
|
||||
tap = rcu_dereference(q->tap);
|
||||
if (!tap) {
|
||||
kfree_skb(skb);
|
||||
rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
skb->dev = tap->dev;
|
||||
|
||||
if (vnet_hdr_len) {
|
||||
err = tun_vnet_hdr_to_skb(q->flags, skb, gso);
|
||||
if (err)
|
||||
if (err) {
|
||||
rcu_read_unlock();
|
||||
goto err_kfree;
|
||||
}
|
||||
}
|
||||
|
||||
/* Move network header to the right position for VLAN tagged packets */
|
||||
|
|
@ -1085,15 +1096,8 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp)
|
|||
vlan_get_protocol_and_depth(skb, skb->protocol, &depth) != 0)
|
||||
skb_set_network_header(skb, depth);
|
||||
|
||||
rcu_read_lock();
|
||||
tap = rcu_dereference(q->tap);
|
||||
if (tap) {
|
||||
skb->dev = tap->dev;
|
||||
skb_probe_transport_header(skb);
|
||||
dev_queue_xmit(skb);
|
||||
} else {
|
||||
kfree_skb(skb);
|
||||
}
|
||||
skb_probe_transport_header(skb);
|
||||
dev_queue_xmit(skb);
|
||||
rcu_read_unlock();
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user