[PATCH net 1/1] net: Don't deliver IPv6 packets to IPv4 sockets

Shihuang Liu <[email protected]>
Newsgroups org.kernel.vger.netdev,org.kernel.vger.bpf,org.kernel.vger.linux-kernel,org.kernel.vger.stable
Message-ID <[email protected]>
bpf_sk_assign() allows a TC ingress program to attach an arbitrary
hashed socket to an skb, without checking that the socket family
matches the packet's network layer. As a result, an IPv6 UDP packet
can be assigned to an AF_INET UDP socket: udpv6_rcv() steals the
socket via inet6_steal_sock(), which also lacks a family check, and
queues the IPv6 skb on the AF_INET socket.

recvmsg() on that socket then runs the IPv4 udp_recvmsg(), which
interprets the IPv6 skb control block as IPv4 IP options. When
IP_RETOPTS is enabled on the target socket, __ip_options_echo()
copies up to 153 bytes of attacker-controlled data from the IPv6
Destination Options extension header into the 40-byte option-data
area of the stack-allocated optbuf in ip_cmsg_recv_retopts():

    BUG: KASAN: stack-out-of-bounds in __ip_options_echo
    Write of size 153
    ...
    __ip_options_echo
    ip_cmsg_recv_offset
    udp_recvmsg

Reject sockets whose family is not AF_INET6 in inet6_steal_sock().
An IPv6 packet can never be legitimately delivered to an AF_INET
socket, so drop the stolen socket and return NULL, letting the
callers continue with the regular IPv6 lookup. When the socket is
refcounted, release it with sock_gen_put(), the same type-safe
helper sock_pfree() and sock_edemux() use, so the release stays
correct no matter which kind of socket a future BPF helper allows
to be assigned. This covers both the UDPv6 and TCPv6 receive
paths. The opposite direction, an IPv4 packet assigned to a
dual-stack AF_INET6 socket, remains allowed since that is a
supported configuration.

Fixes: cf7fbe660f2d ("bpf: Add socket assign support")
Cc: [email protected]
Assisted-by: GLM:GLM-5.3
Signed-off-by: Shihuang Liu <[email protected]>
---
 include/net/inet6_hashtables.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h
index 2cc5d416bbb5..b39e59efac8d 100644
--- a/include/net/inet6_hashtables.h
+++ b/include/net/inet6_hashtables.h
@@ -115,6 +115,12 @@ struct sock *inet6_steal_sock(struct net *net, struct sk_buff *skb, int doff,
 	if (!sk)
 		return NULL;
 
+	if (unlikely(sk->sk_family != AF_INET6)) {
+		if (*refcounted)
+			sock_gen_put(sk);
+		return NULL;
+	}
+
 	if (!prefetched || !sk_fullsock(sk))
 		return sk;
 
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.