IPV6_ADDRFORM can convert an IPv6 UDP socket while a native IPv6 packet is still queued for reception. The converted socket then receives the packet through udp_recvmsg(), which passes it to ip_cmsg_recv_offset() as if it were IPv4. This makes the IPv4 ancillary-data code interpret inet6_skb_parm as inet_skb_parm. In particular, IP_RETOPTS can take the IPv6 lastopt and nhoff offsets as an IPv4 option length and RR offset. A destination options header can then make __ip_options_echo() copy more than the 40-byte stack option buffer. KASAN reported a 152-byte write on 3/3 fresh v6.12.105 boots and 3/3 fresh v7.2 boots. A production-shaped v6.12.105 build instead reached a hardened-usercopy BUG followed by a fatal-exception panic on 3/3 boots. Check the network header version before parsing SOL_IP control messages. skb->protocol is not a reliable discriminator here: IPv4 multicast route cache reports can leave it unset, while software VLAN processing can change it to ETH_P_8021Q before a TX timestamp is queued. Both paths still carry an IPv4 network header and valid IP_PKTINFO. With this change the original trigger returned its payload without a control message or a target KASAN report. The no-extension and native IPv6 controls passed, and IP_PKTINFO was preserved for both the multicast route report and software VLAN TX timestamp paths. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Assisted-by: LLM Signed-off-by: Daehyeon Ko <4ncienth@gmail.com> --- Changes in v2: - Use the actual network header version instead of skb->protocol as the discriminator. - Preserve IP_PKTINFO for IPv4 multicast route cache reports and software VLAN TX timestamp error-queue skbs. - Validate both reviewer-reported paths alongside the original trigger and controls. --- net/ipv4/ip_sockglue.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index a55ef327ec932c..01d264e8f34ea1 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -174,6 +174,9 @@ void ip_cmsg_recv_offset(struct msghdr *msg, struct sock *sk, if (!flags) return; + if (unlikely(ip_hdr(skb)->version != IPVERSION)) + return; + /* Ordered by supposed usage frequency */ if (flags & IP_CMSG_PKTINFO) { ip_cmsg_recv_pktinfo(msg, skb); -- 2.54.0