git: 90e14aa082d3 - releng/13.5 - inpcb: Ignore SO_REUSEPORT_LB on connected sockets

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Wed, 22 Oct 2025 15:53:35 UTC
The branch releng/13.5 has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=90e14aa082d3f90c8a805dc0394e1db851859835

commit 90e14aa082d3f90c8a805dc0394e1db851859835
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2025-10-22 14:49:25 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2025-10-22 15:52:57 +0000

    inpcb: Ignore SO_REUSEPORT_LB on connected sockets
    
    While TCP disallows connect()ing a socket with SO_REUSEPORT_LB, UDP does
    not.  As a result, a connected UDP socket can be placed in the lbgroup
    hash and thus receive datagrams from sources other than the connected
    host.
    
    Reported by:    Amit Klein <amit.klein@mail.huji.ac.il>
    Reported by:    Omer Ben Simhon <omer.bensimhon@mail.huji.ac.il>
    Reviewed by:    glebius
    Approved by:    so
    Security:       FreeBSD-SA-25:09.netinet
    Security:       CVE-2025-24934
    
    (cherry picked from commit 320ad3dec5ff1b37f6907a47961c18b9d77e6a53)
    (cherry picked from commit df888c8f41f633be3aacecdd357ebaad62aa11bd)
---
 sys/netinet/in_pcb.c | 34 +++++++++++++++++++++++++---------
 1 file changed, 25 insertions(+), 9 deletions(-)

diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index 03315344a455..a6fd5feddf9e 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -2668,6 +2668,7 @@ in_pcbinshash_internal(struct inpcb *inp, struct mbuf *m)
 	struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
 	struct inpcbport *phd;
 	u_int32_t hashkey_faddr;
+	bool connected;
 
 	INP_WLOCK_ASSERT(inp);
 	INP_HASH_WLOCK_ASSERT(pcbinfo);
@@ -2676,11 +2677,15 @@ in_pcbinshash_internal(struct inpcb *inp, struct mbuf *m)
 	    ("in_pcbinshash: INP_INHASHLIST"));
 
 #ifdef INET6
-	if (inp->inp_vflag & INP_IPV6)
+	if (inp->inp_vflag & INP_IPV6) {
 		hashkey_faddr = INP6_PCBHASHKEY(&inp->in6p_faddr);
-	else
+		connected = !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr);
+	} else
 #endif
-	hashkey_faddr = inp->inp_faddr.s_addr;
+	{
+		hashkey_faddr = inp->inp_faddr.s_addr;
+		connected = inp->inp_faddr.s_addr != INADDR_ANY;
+	}
 
 	pcbhash = &pcbinfo->ipi_hashbase[INP_PCBHASH(hashkey_faddr,
 		 inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)];
@@ -2689,10 +2694,12 @@ in_pcbinshash_internal(struct inpcb *inp, struct mbuf *m)
 	    INP_PCBPORTHASH(inp->inp_lport, pcbinfo->ipi_porthashmask)];
 
 	/*
-	 * Add entry to load balance group.
-	 * Only do this if SO_REUSEPORT_LB is set.
+	 * Ignore SO_REUSEPORT_LB if the socket is connected.  Really this case
+	 * should be an error, but for UDP sockets it is not, and some
+	 * applications erroneously set it on connected UDP sockets, so we can't
+	 * change this without breaking compatibility.
 	 */
-	if ((inp->inp_flags2 & INP_REUSEPORT_LB) != 0) {
+	if (!connected && (inp->inp_flags2 & INP_REUSEPORT_LB) != 0) {
 		int error = in_pcbinslbgrouphash(inp, M_NODOM);
 		if (error != 0)
 			return (error);
@@ -2761,6 +2768,7 @@ in_pcbrehash_mbuf(struct inpcb *inp, struct mbuf *m)
 	struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
 	struct inpcbhead *head;
 	u_int32_t hashkey_faddr;
+	bool connected;
 
 	INP_WLOCK_ASSERT(inp);
 	INP_HASH_WLOCK_ASSERT(pcbinfo);
@@ -2769,11 +2777,19 @@ in_pcbrehash_mbuf(struct inpcb *inp, struct mbuf *m)
 	    ("in_pcbrehash: !INP_INHASHLIST"));
 
 #ifdef INET6
-	if (inp->inp_vflag & INP_IPV6)
+	if (inp->inp_vflag & INP_IPV6) {
 		hashkey_faddr = INP6_PCBHASHKEY(&inp->in6p_faddr);
-	else
+		connected = !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr);
+	} else
 #endif
-	hashkey_faddr = inp->inp_faddr.s_addr;
+	{
+		hashkey_faddr = inp->inp_faddr.s_addr;
+		connected = inp->inp_faddr.s_addr != INADDR_ANY;
+	}
+
+	/* See the comment in in_pcbinshash(). */
+	if (connected && (inp->inp_flags2 & INP_REUSEPORT_LB) != 0)
+		in_pcbremlbgrouphash(inp);
 
 	head = &pcbinfo->ipi_hashbase[INP_PCBHASH(hashkey_faddr,
 		inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)];