BUG/MEDIUM: sock: bound the recvmsg() length when receiving old sockets
sock_get_old_sockets() sizes tmpbuf from the number of FDs announced by the
old process, but passes a fixed iov_len of MAX_SEND_FD entries to every
recvmsg() and loops as long as fewer FDs than announced were received,
without ever comparing curoff to the size of the allocation. A peer
announcing a single FD (4118 bytes allocated) and then streaming plain data
with no SCM_RIGHTS makes the kernel write up to 252*4118 bytes per recvmsg()
past the end of the buffer, and the loop never ends. Reproduced with a fake
old process: glibc aborts on "free(): invalid next size" after ~320 kB. Only
the peer of the -x transfer socket can do this, so it is not reachable from
the network, but it happens before privileges are dropped.
Let's clamp each recvmsg() to the room really left in the allocation and
abort the transfer when the peer sends more. Legitimate transfers are
unaffected, they use at most 1+255+1+255+4 bytes per FD.
This has been there since commit
f73629d23 ("MINOR: global: Add an option to
get the old listening sockets.") in 1.8, which already sized tmpbuf on fd_nb
and the iovec on MAX_SEND_FD. It may be backported to all stable versions.
Reported-by: Claude (ANT-2026-Q363CKEH)