mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-06-08 14:15:46 -04:00
socketpair_tcp() fakes a connected socket pair via a loopback TCP self-connect (socket -> bind 127.0.0.1:0 -> listen -> connect -> accept), used by sock_exec() for RSYNC_CONNECT_PROG. Its comment has long promised that "nobody else can attach to the socket, or if they do that this function fails", but nothing actually verified it: the code accept()ed whatever connection arrived first without checking it was the one our own connect() made. Between listen() and accept() the ephemeral loopback port is connectable by any local user. With backlog 1 a same-host attacker who races a connection in before our connect() lands could have their socket returned by accept(), handing them one end of the rsync protocol stream. The exposure is small (loopback only, random ephemeral port, sub-millisecond window, local users only), but the promised guarantee was simply not enforced. Enforce it: after the connection is established, require that the peer address of the accepted end (fd[0]) equals the local address of our connecting end (fd[1]), and that both are 127.0.0.1. A hijacked connection has a different source port and is rejected (errno EPERM, fail closed). The legitimate self-connect always matches, so there is no behaviour change for the normal path. Verified: rebuilds clean with -Wall -W; the full testsuite still passes in both transports (pipe `make check` 57/3, `runtests.py --use-tcp` 59/1) -- the pipe transport exercises this code path on every daemon test. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
23 KiB
23 KiB