PT-2026-116814 · Linux · Linux
CVE-2026-98595
·
Published
2026-10-18
·
Updated
2026-10-18
None
No severity ratings or metrics are available. When they are, we'll update the corresponding info on the page.
In the Linux kernel, the following vulnerability has been resolved:
udp: remove a disconnected socket from the 4-tuple hash table
A UDP socket bound to a specific address and port keeps its entry in the
4-tuple hash table after it is disconnected:
sk binds to 127.0.0.1:21001
sk connects to 127.0.0.2:20001 // filed in the 4-tuple table
sk disconnects, connect(AF UNSPEC) // still filed, peer now 0.0.0.0:0
udp disconnect() takes a socket out of that table only as a side effect
of ->rehash() or ->unhash(), and it skips ->rehash() when
SOCK BINDADDR LOCK is set and ->unhash() when SOCK BINDPORT LOCK is set.
commit 6996a2d2d0a6 ("udp: Unhash auto-bound connected sk from 4-tuple hash
table when disconnected.") fixed the same end state for a wildcard-bound
socket, by a path this one does not take.
The entry is counted whether or not anything hits it. hash4 cnt on the
hash2 slot stays raised for as long as the socket lives, so udp has hash4()
keeps sending every packet for that address and port through the 4-tuple
lookup first.
On IPv6 it can also be hit. udp disconnect() does not clear sk v6 daddr,
so udp v6 rehash() files the entry under the peer the socket was connected
to with a zero dport, and inet6 match() compares that same
field: a datagram from the former peer with a zero source port matches,
and source port zero is accepted on receive. On IPv4 the peer is cleared,
so a match would need a zero source address as well, which the routing
layer rejects as martian. The stale sk v6 daddr is a separate defect, not
addressed here; removing the entry closes this path either way.
The entry can also be relocated. udp disconnect() clears sk bound dev if,
so a subsequent SO BINDTODEVICE calls ->rehash(), and because the receive
address is still specific udp lib rehash() moves the entry instead of
removing it, into the bucket that (rcv saddr, num, 0, 0) hashes to -- a
pure function of the address and port, so every socket reaching this state
on one address and port collects in one bucket. The bucket cannot be chosen
from outside, as udp ehashfn() is seeded with a per-boot secret. This last
one became reachable only with commit 644f9108f3a5 ("udp: Make rehash4
independent in udp lib rehash()"), which moved the hash4 handling out of a
branch a disconnected socket does not take; the stale entry itself dates
from the commit in Fixes.
Take the socket out of the table before udp disconnect() runs, while it
still matches how it was filed. This also reaches the wildcard case ahead
of udp lib rehash()'s udp unhash4() branch, leaving that branch unreachable
from udp disconnect(); removing it belongs in net-next. udp disconnect()
and udp abort() are the only UDP entries into udp disconnect(), which is
shared with raw, ping and l2tp sockets that are not struct udp sock:
ping prot.obj size is sizeof(struct inet sock), so udp hashed4() on one
would read past the allocation.
Found an issue in the description? Have something to add? Feel free to write us 👾
Related Identifiers
Affected Products
Linux