[PATCH] net/packet: zero-pad spkt_device and preserve sa.origlen across MSG_PEEK

From: Hui Peng

Date: Sat Sep 19 2026 - 17:53:41 EST


Fix two issues in net/packet/af_packet.c:

1. In packet_rcv_spkt(), use strscpy_pad() instead of strscpy() when
populating spkt->spkt_device so trailing bytes after dev->name's NUL
terminator in the 14-byte buffer are zeroed.
2. In packet_recvmsg(), PACKET_SKB_CB(skb)->sa.origlen aliases
sll->sll_family and sll->sll_protocol inside the union. Overwriting
sll->sll_family and sll->sll_protocol in PACKET_SKB_CB(skb) directly
clobbers sa.origlen for subsequent recvmsg(MSG_PEEK | MSG_TRUNC) calls
on the same skb. Instead, write sll_family and sll_protocol into the
destination msg->msg_name buffer after copying PACKET_SKB_CB(skb)->sa.

Fixes: 2472d7613bd3 ("net: packet: use sockaddr_ll fields as storage for skb original length in recvmsg path")
Assisted-by: LLM
Signed-off-by: Hui Peng <benquike@xxxxxxxxx>
---
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 50cae32ae269..15def2d16806 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1918,7 +1918,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev,
*/

spkt->spkt_family = dev->type;
- strscpy(spkt->spkt_device, dev->name, sizeof(spkt->spkt_device));
+ strscpy_pad(spkt->spkt_device, dev->name, sizeof(spkt->spkt_device));
spkt->spkt_protocol = skb->protocol;

/*
@@ -3510,15 +3510,8 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
if (err)
goto out_free;

- if (sock->type != SOCK_PACKET) {
- struct sockaddr_ll *sll = &PACKET_SKB_CB(skb)->sa.ll;
-
- /* Original length was stored in sockaddr_ll fields */
+ if (sock->type != SOCK_PACKET)
origlen = PACKET_SKB_CB(skb)->sa.origlen;
- sll->sll_family = AF_PACKET;
- sll->sll_protocol = (sock->type == SOCK_DGRAM) ?
- vlan_get_protocol_dgram(skb) : skb->protocol;
- }

sock_recv_cmsgs(msg, sk, skb);

@@ -3552,6 +3545,13 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
msg->msg_namelen = copy_len;
}
memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa, copy_len);
+ if (sock->type != SOCK_PACKET) {
+ struct sockaddr_ll *u_sll = msg->msg_name;
+
+ u_sll->sll_family = AF_PACKET;
+ u_sll->sll_protocol = (sock->type == SOCK_DGRAM) ?
+ vlan_get_protocol_dgram(skb) : skb->protocol;
+ }
}

if (packet_sock_flag(pkt_sk(sk), PACKET_SOCK_AUXDATA)) {