Commit Graph
392 Commits
Author SHA1 Message Date
Andrew Tridgell 861bfa0812 daemon: bound the pre-transfer handshake with a timeout
rsyncd.conf(5) says of "timeout": "Using this parameter you can ensure that
rsync won't wait on a dead client forever."  That did not hold before a module
was known.  set_io_timeout() ran at the very end of rsync_module(), so the
greeting, authentication and the whole argument list were read with no I/O
timeout at all -- a peer could stall at any of them and the child waited
indefinitely.  Measured: 20 connections sending "@RSYNCD: 31.0" with no newline
were all still alive well past timeout=5, and only went away when the client
hung up.

The consequence is worse than an idle process.  claim_connection() runs BEFORE
auth_server(), so naming a module is enough to take a slot: an attacker with no
credentials could occupy every "max connections" slot of an authenticated
module and hold them for as long as it kept the sockets open, with the
documented control unable to recover them.  It costs the attacker nothing --
five stalled children measured 0 CPU ticks over 5s -- so this is descriptor and
slot exhaustion, not load.

Bound the handshake at min(configured, 60s).  "timeout" is a Locals parameter,
so lp_timeout(-1) reads the global section -- the same -1 idiom start_daemon()
already uses for lp_reverse_lookup().

Both halves of that minimum matter.  "timeout" DEFAULTS TO 0, so honouring only
the configured value would leave the daemon most exposed to this -- one whose
administrator never set a timeout -- exactly as pinnable as before.  And capping
matters because an operator who sets "timeout = 86400" for slow links is asking
for patience during a TRANSFER, not for a stranger to hold a pre-auth slot for a
day.  The pre-module phase has no legitimate reason to take even a minute.

The bound is retired the moment the module is known, which is what lets the
configured value still govern the transfer.  That retirement is load-bearing:
the per-module test only ever LOWERS the timeout (`lp_timeout(module_id) <
io_timeout`), so leaving the handshake bound in place would silently clamp a
module that asked for more -- "timeout = 300" would get 60.  It is cleared
before that test runs, and only when io_timeout is still the value we armed,
since the client's own --timeout is parsed in between and must win on its own
terms.  Verified: with no global timeout and "timeout = 120" in the module, a
connection idles past 75s rather than being dropped at 60.

Applied only for a real socket daemon (am_daemon > 0): an rsh-run daemon has no
listener to exhaust.

Verified end to end with max connections = 2 and timeout = 5: with two stalled
unauthenticated connections holding both slots, a legitimate client is refused
during the timeout window and served once it elapses.  Before this change it was
refused both times.

Reported by Chamal De Silva.  Not a regression -- 3.2.7 behaves the same way.

An idle timeout alone is not enough, which the review of the first version of
this change made concrete: safe_read() consults it only when poll() TIMES OUT,
so a peer sending a byte more often than allowed_lull (timeout/2) is never
checked at all.  Measured: one byte every 20s held the handshake open for 182s
against a 60s bound, keeping its max-connections slot the whole time -- the
reported attack, merely with the attacker typing.

Non-positive configured values are treated as "use the built-in bound":
"timeout" is parsed with atoi(), so "timeout = -1" would otherwise reach
set_io_timeout() (which reads it as no timeout) and alarm() (which would take it
as a huge unsigned count), disabling the very bound it looks like it configures.

The client's own --timeout is no longer inferred by comparing values, which could
not distinguish it from an identical armed value: io_timeout is zeroed before
parse_arguments(), so anything non-zero afterwards came from the client.

So the bound is absolute and lives in the READ PATH, next to the idle timeout
it complements: safe_read() caps each poll() at whatever is left of it and
gives up when it expires, so it is re-checked on every iteration and a peer
that keeps typing cannot outrun it.

It is deliberately NOT alarm()/SIGALRM.  Three earlier attempts used one and
each regressed something: fork() clears pending alarms, so the "post-xfer exec"
parent -- which waits for the ENTIRE transfer -- kept the deadline and _exit()ed
mid-transfer, skipping the hook and releasing the max-connections fcntl lock
while the transfer child ran on; "pre-xfer exec" and the name converter are
operator scripts that may legitimately outlast any handshake bound; and the
cancellation sat inside an exec-environment compile guard, so a build without
setenv/putenv kept it armed through the transfer.  A deadline consulted only
where the daemon is already blocked reading a peer has none of those hazards.

It is also kept entirely separate from io_timeout, which is an idle timeout the
module or client may set.  Mixing them clamped a module asking for more than the
bound ("timeout = 300" became 60) and leaked the handshake value into the
transfer.  Verified: module 300 stays 300, and a client --timeout=7 still wins.

Armed for each peer-driven phase and cleared between them: at the start of the
handshake, tightened by the module's own timeout once the module is known and
its slot claimed, cleared across the hook/fork setup, re-armed before
"@RSYNCD: OK" so it spans BOTH read_args() calls including secluded args, and
cleared before the transfer.

That argument-read coverage is the part that matters most.  auth_server()
returns immediately when a module sets no "auth users", so on an ANONYMOUS
module nothing is authenticated: without a bound there, a peer could claim the
slot, take the OK, and trickle an unterminated argument line forever.  Measured:
still open after 150s before, closed at 60s after.

(cherry picked from commit 4d7c243ca6)
2026-08-02 21:33:25 +10:00
Andrew Tridgell a3d8ecc312 io: describe the timeout guards in terms of poll(), not select()
The MSG_IO_TIMEOUT cap and set_io_timeout()'s negative/overflow guards
were written when these loops used select(), and their comments explain
the danger as a tight select()-EINVAL spin on a negative tv_sec.

Under poll() the failure mode inverts: the timeout is a millisecond count
where a negative value means "wait forever", so a wrapped allowed_lull
hangs the process instead of spinning it.  The guards are still needed and
unchanged -- only their stated reason was wrong, and a rationale that no
longer matches the code is what gets a guard removed later.

poll_timeout_ms() clamps the value too, so the guards are now belt and
braces; noted so neither looks redundant on its own.

(cherry picked from commit d5cce08503)
2026-08-02 21:33:25 +10:00
Stuart Inglis 4cfdb22863 io/socket: address review of the poll() conversion
Follow-up to the FD_SETSIZE fix, covering the points raised in review.

Negative/overflowing I/O timeouts.  set_io_timeout() could produce a negative
select_timeout (a peer-supplied MSG_IO_TIMEOUT value was applied unchecked),
and every wait now passes select_timeout * 1000 to poll(), where a negative
millisecond count means "wait forever" -- so a hostile or buggy peer could
stall the other side and bypass keepalives entirely.  select() used to reject
that with EINVAL, which kept the loop and check_timeout() running.  Clamp a
negative argument to 0, compute allowed_lull without overflowing near INT_MAX
(secs / 2 + secs % 2), ignore a non-positive MSG_IO_TIMEOUT value, and funnel
all three waits through poll_timeout_ms(), which keeps the count positive and
bounded.

The daemon accept loop had the same fd_set overflow.  start_accept_loop() still
stored listening sockets in an fd_set, so a daemon started with enough
descriptors already open got listener fds >= FD_SETSIZE and hit the same
undefined behaviour at startup -- verified: with the old code a transfer
through such a daemon yields nothing, with this change it succeeds.  Converted
it to poll() as well.

Readiness testing.  Treating any non-zero revents as ordinary readiness was
wrong: poll() reports POLLERR/POLLHUP/POLLNVAL unrequested, and an invalid fd
shows up as POLLNVAL on a successful poll() rather than -1/EBADF, which left
the EBADF branches dead and let an invalid ff_forward_fd reach
forward_filesfrom_data() (where EBADF reads as EOF).  Use role-specific masks
(POLL_RD_BITS / POLL_WR_BITS), handle POLLNVAL explicitly in all three loops,
and request POLLPRI so select()'s old exception set is not silently dropped.

A bidirectional fd is no longer entered twice.  A direct daemon connection uses
one fd for both directions; it now occupies a single pollfd row with OR-ed
events instead of two rows carrying different masks, which also avoids the
Cygwin < 3.3.6 duplicate-entry readiness bug.

poll() is now a declared requirement: configure.ac checks for poll.h and
poll(), failing with a clear message rather than leaving it implicit.

The test no longer hardcodes FD_SETSIZE (1024 on glibc but 65536 on 64-bit
Solaris, where it would have opened too few fds and passed vacuously); it asks
the C library for the real value via a small compiled probe and skips if that
is unavailable.  Its description now also covers the fortified-libc case, where
the pre-fix result is an abort rather than a hang.

(cherry picked from commit 7ef165dd45)

(cherry picked from commit bf3a11cf24)
2026-08-02 21:33:25 +10:00
Stuart Inglis 75bafbf11d io: use poll() instead of select() to avoid an FD_SETSIZE hang (issue #231)
rsync's I/O loops (safe_read, safe_write, and the main perform_io
multiplexer) waited for readiness with select() and fd_set bitmaps. An
fd_set can only represent descriptors below FD_SETSIZE (1024 with glibc).

When rsync is started with many descriptors already open -- e.g. inherited
from a parent process that leaked fds, a high "ulimit -n", or a busy daemon
-- its own socket and pipe fds get allocated at or above 1024. FD_SET() and
FD_ISSET() then index past the end of the fixed-size fd_set, which is
undefined behavior: select() reports the fd as ready, but FD_ISSET() reads
the out-of-bounds bit as 0, so the read or write never happens and rsync
spins at 100% CPU forever with no progress. This is the long-standing
"rsync hangs at 100% CPU on large systems" report, and it matches the
MemorySanitizer use-of-uninitialized-value seen in perform_io.

Convert the three loops to poll(), which identifies descriptors by value in
a small array and has no FD_SETSIZE ceiling, so a high-numbered fd works
fine. rsync only ever waits on a handful of fds (at most three in
perform_io: in_fd, out_fd, and the files-from forward fd), so poll() is as
fast as -- or faster than -- select() here; the select()-vs-poll() cost gap
only appears when watching thousands of descriptors, which rsync never
does. The remaining select(0, ...) call is a pure timed sleep with no fds
and is unaffected.

The conversion is behavior-preserving: the same max_fd bookkeeping decides
when there is nothing to wait on, the per-fd readiness checks map to the
matching pollfd revents, and the timeout is the same (now expressed in
milliseconds).

testsuite/highfd-hang_test.py reproduces the hang deterministically by
opening enough inheritable dummy fds to push rsync's descriptors past
FD_SETSIZE before an ordinary transfer; it hangs (caught by a timeout) on
the select() code and passes instantly with poll().

(cherry picked from commit 4a751a2ceb)

(cherry picked from commit 44fdf0bc43)
2026-08-02 21:33:25 +10:00
Codex 84cfcce27e receiver: do not acknowledge batch-only files as installed
(cherry picked from commit c0e6948d0f)
2026-08-02 21:23:59 +10:00
Andrew Tridgell 2989988526 io: make set_io_timeout() arithmetic overflow-safe
io_timeout can reach INT_MAX -- from an operator --timeout (options.c parses it
as a plain int, unbounded and even negative) or a peer's MSG_IO_TIMEOUT (now
also capped at 86400 in read_a_msg).  Several signed computations then misbehave:

 * allowed_lull = (io_timeout + 1) / 2 overflows to a negative allowed_lull /
   select_timeout; select() then returns EINVAL on the negative tv_sec, which
   isn't EBADF, so the read loop spins at 100% CPU forever (io_timeout ~= 68
   years never fires check_timeout), plus a keepalive flood.  Compute
   ceil(io_timeout/2) in a wider type so "+ 1" cannot overflow.

 * the generator and sender derive an int loop-check limit as allowed_lull * 5
   (generator.c, sender.c), which overflows for a large allowed_lull.  Cap
   allowed_lull so that product stays in range -- invisible to real use, as
   allowed_lull is the keep-alive half-interval and INT_MAX/5 seconds is over
   13 years.

 * a negative --timeout drove allowed_lull / select_timeout negative the same
   way; treat secs < 0 as "no timeout" up front.

The overflows are undefined behaviour, so plain -O2 gcc/clang happen to keep
select_timeout at 60, but -fwrapv / -fno-strict-overflow (common hardening) wrap
to the spin and -ftrapv aborts.

Reported by z3r0s.
2026-07-24 16:39:13 +10:00
Gogs 00e09a3eba io: cap MSG_IO_TIMEOUT value to prevent signed integer overflow
A malicious server can send MSG_IO_TIMEOUT with val near INT_MAX
(0x7FFFFFFF). The existing val <= 0 guard prevents timeout disabling,
but a large positive value passes through to set_io_timeout() where
(io_timeout + 1) / 2 overflows signed int, wrapping allowed_lull and
select_timeout negative. Every subsequent select() returns EINVAL
immediately, trapping the client in a tight CPU loop.

Cap the accepted timeout at 86400 seconds (24 hours), which is well
above any practical timeout and avoids the overflow in set_io_timeout().

Reported-by: z3r0s <https://github.com/z3r0s6>
2026-07-24 16:39:13 +10:00
Leonid Bugaev 60671e3db2 Mask incoming MSG_IO_ERROR to defined bits only
A peer-supplied MSG_IO_ERROR value was OR'd into the local io_error
without masking, allowing a malicious peer to set arbitrary bits that
propagate to exit codes and get re-forwarded to other peers.

Fix: mask the incoming value with IOERR_VALID_MASK (IOERR_GENERAL |
IOERR_VANISHED | IOERR_DEL_LIMIT) before OR'ing.

Test: testsuite/ki62-io-error-mask_test.py
2026-07-20 14:18:19 +10:00
Andrew Tridgell b3e558d1ba io, main: make the SIGUSR2 handler async-signal-safe
sigusr2_handler called output_summary() (rprintf/vsnprintf/fwrite/iconv/malloc)
and close_all() (fstat/shutdown/close) directly from signal context before
_exit().  SIGUSR2 is sent by the generator/parent to tell the receiver child to
print its summary and exit; if it interrupted the receiver while it was inside
malloc/stdio, the handler re-entered those and could deadlock or corrupt.

The handler now only sets a flag (got_sigusr2, a volatile sig_atomic_t); the
actual summary + shutdown moves to receive_sigusr2(), run from a safe point in
the receiver's post-transfer wait paths:
 - the perform_io() flag checks (next to got_kill_signal);
 - the safe_read()/safe_write() loops (which a --read-batch / --write-batch fd
   uses without going through perform_io);
 - the whine_about_eof() kluge loop, where the receiver waits out the race of
   the sender dying before the kill-signal arrives -- this loop polls for the
   signal, so without the flag check it slept the full 10s and then errored with
   RERR_STREAMIO instead of exiting cleanly;
 - the trailing `while (!got_sigusr2) msleep()` loop in do_recv().

(Leonid Bugaev May-2026 re-audit, KI-14.)
2026-06-27 18:18:53 +10:00
Andrew Tridgell 63fbf31890 io: reject a non-positive MSG_IO_TIMEOUT from the peer
A peer may use MSG_IO_TIMEOUT only to ask us to adopt a SHORTER I/O timeout
(a stricter cap).  A crafted server sending val <= 0 would instead zero the
client's --timeout via set_io_timeout(0), disabling it entirely and letting the
server hang the client indefinitely.  Ignore a non-positive value.

(Leonid Bugaev May-2026 re-audit, KI-47; pre-existing since 2009.)
2026-06-27 18:17:30 +10:00
Andrew TridgellandGreg Kroah-Hartman 4da4a7ce1e io/xattrs/rsync-ssl: EOF-sentinel guard, xattr ndx guard, gnutls CA refusal
io.c only treats a short read as the EOF sentinel when the fd is still
open; xattrs.c never stores a -1 from find_matching_xattr() and guards
ndx < 0 in set_xattr; rsync-ssl refuses the gnutls backend without
RSYNC_SSL_CA_CERT.

Co-authored-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2026-06-22 09:21:59 +10:00
Andrew Tridgell ff544c6920 io: defer in_multiplexed=1 in the other write-side read_a_msg cases
The run4 0002 fix deferred the in_multiplexed re-arm past the call-out only for
MSG_NOOP and MSG_IO_ERROR (the two fuzzed tags), but the same anti-pattern --
re-arming the re-entry guard before a write-side call-out that can reach
perform_io() -> read_a_msg() -- remained in the sibling cases (Codex review).
Defer it past the call-out in those too:

  - MSG_NO_SEND (!am_generator -> send_msg_int): exploitable at a daemon sender,
    the same stack-exhaustion recursion as MSG_NOOP.
  - MSG_DELETED (!am_generator -> log_delete -> send_msg when am_server): same.
  - MSG_DELETED (am_generator -> send_msg): not currently exploitable (the
    generator is not am_sender, so send_msg doesn't perform_io), deferred for
    uniformity.

MSG_SUCCESS/MSG_REDO are left as-is: successful_send() returns early unless
--remove-source-files and does not reach send_msg()->perform_io(), and the
generator-status path runs only in the (non-am_sender) generator.

(cherry picked from commit f4f1905f5cfd83bd10d4db3b734da34cc43d33b0)
2026-06-15 17:47:45 +10:00
Andrew Tridgell ffc91be590 io: ensure argv has room for the trailing NULL in read_args
After the '.' separator, read_args delegates argv growth to
glob_expand_module() -> glob_expand()/glob_match(), each of which reserves
glob.argc+1 slots -- room for the entry being added but not for the trailing
NULL that read_args writes after the loop.  A daemon client can send a single
post-dot request line whose " mod/" splits land argc on exactly maxargs
(initially MAX_ARGS=1000, then any ENSURE_MEMSPACE doubling boundary), so the
'argv[argc] = NULL' at the end is an 8-byte NULL write one slot past the argv
heap allocation.  Reachable from an unauthenticated client; runs after
chroot/setuid in rsync_module so the corruption is in the privilege-dropped
per-connection child.

Ensure the +1 slot before the store.  The pre-dot growth check at
'argc == maxargs-1' already leaves the slot but never fires once dot_pos is set.

(cherry picked from commit ec4f7a03c42e93a48fce20d0b7667235564f9248)
2026-06-15 17:15:28 +10:00
Andrew Tridgell e3986e768f io: defer in_multiplexed=1 past MSG_NOOP/MSG_IO_ERROR call-outs
read_a_msg() sets iobuf.in_multiplexed = -1 on entry so that any perform_io()
reached while the message body is being consumed will not re-enter read_a_msg()
(IN_MULTIPLEXED_AND_READY tests > 0). The MSG_NOOP and MSG_IO_ERROR handlers
reset it to 1 *before* calling maybe_send_keepalive() / send_msg_int(), both of
which can hit perform_io(PIO_NEED_MSGROOM). With more frames already buffered
(iobuf.in.len > 512), perform_io() then loops back into read_a_msg() -- each
frame stacks a fresh BIGPATHBUFLEN local, so a hostile peer that floods MSG_NOOP
at a daemon sender (or MSG_IO_ERROR at a daemon receiver child) exhausts the
stack.

Move the reset after the call-out so the guard stays armed across the write-side
flush.  The outer caller continues draining input once we return.

(cherry picked from commit 5d2794fca309dd558f68b21bff6d3e9728e58237)
2026-06-15 17:15:28 +10:00
Andrew Tridgell 6e00a3b867 daemon: bound argument lists + proxy-protocol peer/length hardening
- io: bound daemon argument lists so a malicious daemon client cannot grow
   argv without limit (DoS);
 - socket: bound the PROXY CONNECT request and proxy response header lines;
 - daemon: require a trusted-proxy host list for "proxy protocol = true"
   (reject untrusted proxy peers, fail-closed), and warn at startup when the
   trusted-proxy list is unset so the fail-closed behaviour is not silent.

Tests: daemon-argv-limit, proxy-connect-request-too-long,
proxy-response-header-too-long, proxy-protocol-trusted-peer.
2026-06-15 15:24:42 +10:00
Andrew Tridgell 6365fe750b io: reject malformed wire indices and zero-length checksum blocks
Backport of the 3.5.0 wire-input validation:
 - reject an out-of-range file index from the wire in read_ndx();
 - reject a zero-length checksum block.

Test: checksum-zero-blocklen.
2026-06-12 15:55:30 +10:00
Andrew Tridgell ce4c0cfb48 daemon: un-backslash escaped option args (#829)
Without --secluded-args, the client's safe_arg() backslash-escapes shell
and wildcard chars in option values before sending them to the server, so
--chown's --usermap=*:user is transmitted as --usermap=\*:user.  Over ssh a
remote shell removes the backslashes before rsync parses the args, but a
daemon has no shell and read_args() stored option args verbatim -- so the
receiver saw the literal "\*", the usermap/groupmap wildcard never matched,
and the module's configured uid/gid won instead.  A regression from the
secluded-args hardening; rsync 3.2.3 (protocol 31) worked.

Un-backslash option args in read_args() on the daemon's first
(non-protected) read, mirroring what the ssh-side shell does.  File args
after the dot are already handled by glob_expand(); the protected (NUL,
already-unescaped) re-read and the server's stdin read pass unescape=0 so
their raw args are left untouched.

Thanks to @elcamlost for the report (#829).

Fixes: #829
(cherry picked from commit 8dc5fd1408)
2026-06-07 18:47:07 +10:00
Andrew TridgellandClaude Opus 4.7 ddd7b59a4f defence-in-depth: bound wire-supplied counts and lengths
Multiple receiver-side fields read from the wire were trusted
without upper-bound checks. A hostile peer could either request
extreme allocations (DoS via --max-alloc) or, on platforms where
read_varint returned a negative value, push ~SIZE_MAX through the
size_t conversion to wrap downstream length checks.

Introduce read_int_bounded(), read_varint_bounded() and
read_varint_size() in io.c so wire-derived integer ranges are
checked at the read site rather than scattered across each
caller, with RERR_PROTOCOL on out-of-range input.

Apply the bounded primitives to:
  - sum->count (checksum count -- previously could overflow
    (size_t)count * xfer_sum_len on 32-bit with raised max-alloc)
  - xattrs: count, name_len, datum_len, plus rel_pos overflow
    detect to stop chain wrapping the num accumulator
  - acls: ida-entry count
  - flist: file mode S_IFMT validation, modtime_nsec range check
  - delete-stat counters in main: per-summand cap so the total
    can't overflow a signed 32-bit accumulator

Reporters include Joshua Rogers (checksum-count overflow finding).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 08:20:48 +10:00
Andrew TridgellandClaude Opus 4.7 5564c88150 receiver: add parent_ndx<0 guard, mirroring 797e17f
Commit 797e17f ("fixed an invalid access to files array") added a
parent_ndx < 0 guard to send_files() in sender.c, but the visually-
identical block in recv_files() in receiver.c was not updated. A
malicious rsync:// server can therefore drive any connecting client
into the same out-of-bounds dir_flist->files[-1] read followed by a
file_struct dereference in f_name() one line later.

Reach: protocol-30+ default (inc_recurse) makes flist.c:2745 set
parent_ndx = -1 on the first received flist when the sender omits a
leading "." entry; rsync.c flist_for_ndx() does not reject ndx == 0
in that state because the range check evaluates 0 < 0 = false; and
read_ndx_and_attrs() only validates ndx with the ITEM_TRANSFER bit
set, so iflags=ITEM_IS_NEW (or any other non-transfer iflag word)
bypasses the check.

Apply the same guard receiver-side. Confirmed: the same PoC (a
minimal Python rsyncd that handshakes with CF_INC_RECURSE, sends a
no-leading-"." flist, and emits ndx=0 with ITEM_IS_NEW) crashes
unpatched 3.4.2 with SEGV_MAPERR si_addr=0x4101a-class in the
receiver child; with this guard it exits cleanly with code 2
(RERR_PROTOCOL).

The attack surface delta over the sender variant is large:
the original was malicious-client -> daemon, this is
malicious-server -> any rsync client doing a normal rsync://
or remote-shell pull.

Reported by Pratham Gupta (alchemy1729).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 08:20:48 +10:00
Holger Hoffstätte 6994fdf50e Fix glibc-2.43 constness warnings
Glibc 2.43 added C23 const-preserving overloads to various string functions,
which change the return type depending on the constness of the argument(s).
Currently this leads to warnings from calls to strtok() or strchr().
Fix this by properly declaring the respective variable types.

Signed-off-by: Holger Hoffstätte <holger@applied-asynchrony.com>
2026-05-07 06:35:39 +10:00
Wayne Davison 0902b52f66 Some checksum buffer fixes.
- Put sum2_array into sum_struct to hold an array of sum2 checksums
  that are each xfer_sum_len bytes.
- Remove sum2 buf from sum_buf.
- Add macro sum2_at() to access each sum2 array element.
- Throw an error if a sums header has an s2length larger than
  xfer_sum_len.
2024-10-29 23:06:34 -07:00
Wayne Davison fdf5e577f5 Read a 4-byte mtime as unsigned (old-protocol).
When conversing with a protocol 29 or earlier rsync, the modtime values
are arriving as 4-byte integers.  This change interprets these short
values as unsigned integers, allowing the time that can be conveyed to
range from 1-Jan-1970 to 7-Feb-2106 instead of the signed range of
13-Dec-1901 to 19-Jan-2038.  Given that we are fast approaching 2038,
any old-protocol transfers will be better served using the unsigned
range rather than the signed.

It is important to keep in mind that protocol 30 & 31 convey the full
8-byte mtime value (plus nanoseconds), allowing for a huge span of time
that is not affected by this change.
2022-10-02 09:54:54 -07:00
Wayne Davison 5183c0d6f0 Add safety check for local --remove-source-files.
A local_server copy now includes the dev+ino info from the destination
file so that the sender can make sure that it is not going to delete
the destination file.  Fixes mistakes such as:

  rsync -aiv --remove-source-files dir .
2022-08-21 10:19:23 -07:00
Wayne Davison c86763dc38 Fix handling of daemon module names in file-list verification; convert some while loops to for loops. 2022-08-09 11:37:47 -07:00
Wayne Davison 685bf58046 Handle files-from args that span 2 buffers. 2022-08-08 21:18:10 -07:00
Wayne Davison b7231c7d02 Some extra file-list safety checks. 2022-07-31 17:46:34 -07:00
Wayne Davison 10aeb75cea Add debugging comment about read_buf_(). 2022-04-11 09:50:31 -07:00
Wayne Davison 3e44bbd313 Preparing for release of 3.2.4pre1 2022-01-02 15:13:19 -08:00
Rodrigo Osorio ffbca80ca2 Time-limit options are not being checked enough (#179)
The `--stop-at`, `--stop-after`, and `--time-limit`` options should have their
limit checked when receiving and sending data, not just when receiving.
Fixes #177.
2022-01-02 14:37:27 -08:00
Wayne Davison 512acd125e Use mallinfo2, when available, and use %zd for size_t values on C99.
An exhanced version of pull request #265.
2021-12-26 14:25:53 -08:00
Wayne Davison ead44adcd3 Allow the generator's msg iobuf to get bigger too. 2021-02-25 12:28:18 -08:00
Wayne Davison f9bb8f76ee Change daemon variable & simplify some option code
- Rename daemon_over_rsh -> daemon_connection since it is also used to
  indicate if a non-rsh daemon connection is active.
- Move the daemon-over-rsh exception out of server_options() to the one
  caller that needs that behavior.
- Don't allow noop_io_until_death() to be short-circuited when talking
  to a daemon over a socket, because it can't send errors via stderr.
2020-07-25 09:36:42 -07:00
Wayne Davison 592059c8fd Improve error output for local & remote-shell xfers 2020-07-23 11:23:47 -07:00
Wayne Davison af531cf787 Add the --stop-after & --stop-at options. 2020-07-12 18:32:41 -07:00
Wayne Davison 11eb67eec9 Some memory allocation improvements
- All the memory-allocation macros now auto-check for failure and exit
   with a failure message that incudes the caller's file and lineno
   info.  This includes strdup().

 - Added the `--max-alloc=SIZE` option to be able to override the memory
   allocator's sanity-check limit.  It defaults to 1G (as before).
   Fixes bugzilla bug 12769.
2020-06-25 20:54:21 -07:00
Wayne Davison ff272503b0 Output who_am_i() info in all rsyserr() messages. 2020-06-14 15:54:42 -07:00
Wayne Davison e63ff70eae Some indentation fixes. 2020-06-13 19:15:02 -07:00
Wayne Davison 01b9bbb0f9 Avoid a deadlock due to huge amounts of verbose messages.
Allow the receiver to increase their iobuf.msg xbuf if it fills up. This
ensures that the receiver will never block trying to output a message,
and thus it will always drain the data from the sender and keep the
whole thing from clogging up.
2020-06-04 14:20:51 -07:00
Wayne Davison d619a87aa5 Avoid noop_io_until_death() if --msgs2stderr was specified. 2020-05-30 05:53:59 -07:00
Wayne Davison f60bd811e9 Use MSG_FLUSH in a couple more spots. 2020-05-28 00:41:39 -07:00
benrubson 32fe5fbc11 Correctly send last error to sender 2020-05-26 16:24:30 +02:00
Wayne Davison 87f2984df0 Improve how negotiated info affects batch files. 2020-05-25 19:19:59 -07:00
Wayne Davison 97e8c55ee8 Some minor tweaks & tidying up. 2020-05-24 22:50:51 -07:00
Wayne Davison 2f84a6bd73 Add support for negotiated checksum names. 2020-05-24 13:22:19 -07:00
Wayne Davison 55bb4dab7a Some checksum improvements
- Improve csum negotation logic.
- Define the csum names in a single structure.
- Add --debug=CSUM.
2020-05-22 17:59:12 -07:00
Wayne Davison 4f6c8c6652 Checksum negotiation & more bits for compat_flags
- Add checksum negotiation to the protocol so that we can easily add new
  checksum algorithms and each will be used when both sides support it.
- Increase the size of the compat_flags value in the protocol from a
  byte to an int.
2020-05-22 09:52:14 -07:00
Wayne Davison 6242786158 A few superficial tweaks. 2020-04-29 19:41:56 -07:00
Wayne Davison b430ceec7a Use a varint to send the file-list flags
If both sides support the "V" compatibility flag, we send the file-list
flags as a varint instead of a 1-or-2 byte value.  This upgrades the
number of reserved flag bits from 1 to 17 with very few extra bytes in
typical file-list data.
2020-04-29 18:22:52 -07:00
Wayne Davison 3e2e4b5a33 Tweak the copyright year. 2019-03-16 09:15:49 -07:00
Wayne Davison 473108ae6e Tweak copyright date. 2018-01-14 19:55:07 -08:00