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

CVE-2026-98595

Affected Products

Linux