aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2025-10-22 14:49:25 +0000
committerMark Johnston <markj@FreeBSD.org>2025-10-22 15:49:11 +0000
commitdf888c8f41f633be3aacecdd357ebaad62aa11bd (patch)
treea2f3e607b0edd1eb62552016076170eb23ef0cbe
parent6e4767672a21f89c070d351d62a8d75629fd077d (diff)
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)
-rw-r--r--sys/netinet/in_pcb.c34
1 files 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)];