Commit Graph
41 Commits
Author SHA1 Message Date
Andrew Tridgell 346c31037f daemon: refuse '!', '~' and braces in a hook expansion too
The refused set was built from the characters that obviously execute
something, and missed three that a SECOND shell acts on:

  '!' negates in command position.  A hook written as an access check --
      `pre-xfer exec = sh -c '%RSYNC_USER_NAME% false'` -- becomes
      `! false`, reports success, and serves the transfer.  An
      authenticated user named "!" turns a denial into an approval, which
      is precisely the case the fail-closed comment above exists for.
  '~' is tilde-expanded, so ~root becomes /root.
  '{' and '}' brace-expand in bash and zsh.

None of them execute anything on their own, which is how a set built from
the obvious metacharacters came to miss them.  That is also the standing
weakness of the approach: this is a deny-list, and the two rounds of
review it took to find '!' are the argument for eventually inverting it.

The documentation is corrected with it -- it claimed every shell-active
character was refused, which this disproves -- and now lists the set.
Each listed character is pinned by the test, which needed its module
paths to EXIST first: a missing path fails the transfer on its own, so
checking the exit status alone passed whether or not the character was
refused.  Removing any single character from the set now fails the test.

(cherry picked from commit f704aa4aed)
2026-08-02 21:33:25 +10:00
Andrew Tridgell 838513e96d rsyncd.conf: document that the hook metacharacter refusal covers your own values
Refusing a shell-active %VAR% in an exec hook is a real usability cost
and it is not confined to hostile input: the check runs on every
%RSYNC_*% value, so a module whose path holds a space cannot be
interpolated into a hook at all.  `path = /srv/My Backups` with a command
mentioning %RSYNC_MODULE_PATH% refuses every transfer of that module,
with no attacker involved.

That is deliberate rather than an oversight.  rsync escapes a
substitution for the quoting context it sits in, which is right for the
one shell that runs the command and wrong for a command that starts a
second one -- `sh -c '... %RSYNC_USER_NAME% ...'` hands the inner shell a
bare value, where "touc?" is glob-expanded against /usr/bin and chooses
the command rather than being data for it.  Escaping for an unknown
number of passes is not possible, so the value is refused instead.  Nor
can the check exempt operator-supplied values: `path` may itself be
templated from a peer one (`path = /home/%RSYNC_USER_NAME%`), and once
both are inside the same string rsync cannot tell them apart.

Say so in the manual, and give the way out: the same names are exported
to the command, so $RSYNC_MODULE_PATH inside a script is unrestricted.

The test pins both halves, since a documented behaviour with no oracle
drifts.  Both are fault-injected: narrowing the refused set back makes
the interpolated half pass when the manual says it must not, and dropping
the RSYNC_MODULE_PATH export fails the workaround half.

(cherry picked from commit 5bf9940de4)
2026-08-02 21:33:25 +10:00
Andrew TridgellandGreg Kroah-Hartman cd82ef3782 compat: assign metadata ndx after batch flags; pick own preferred name
Move the uid/gid/acls/xattrs *_ndx assignments past check_batch_flags():
a mismatched-flag batch otherwise wrote F_XATTR(file) at offset 0 of
every file_struct, clobbering file->dirname. parse_negotiate_str() no
longer short-circuits on am_server, so each side picks its own #1 mutual
digest/checksum/compress choice rather than deferring to the peer's
order; man pages updated to match.

Co-authored-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2026-06-22 09:21:59 +10:00
Andrew Tridgell 4a7594a96f docs: NEWS, README and man pages for the 3.5.0 security backport
Document --insecure-links, clarify in rsyncd.conf(5) that exclude=/filter is a
name-based filter and not a symlink boundary, and record the backported fixes.
2026-06-21 18:25:28 +10:00
Andrew Tridgell 846887d5c2 daemon: add an "auth digest" floor to refuse weak negotiated auth digests
The daemon picks the challenge-response auth digest from the client's
negotiation, or -- for a peer that sends no digest list (any rsync before
3.2.0, including the openrsync that ships with macOS) -- falls back to md5
(protocol >= 30) or md4.  The negotiation is unauthenticated, so an on-path
attacker can also rewrite it to force md5/md4 between two modern peers.  A
captured (challenge, response) pair is then far cheaper to brute-force
offline against a weak digest, recovering a guessable shared secret.

Add a per-module (or global) "auth digest = NAME" parameter.  After the
digest is negotiated, auth_server() refuses the connection (before issuing
the challenge) when the negotiated digest is weaker than NAME, comparing by
position in the strongest-first valid_auth_checksums list.  Because the
check is on the resolved digest, it also catches the md5/md4 fallback, so an
old or list-omitting client cannot slip under the floor.  A floor naming a
digest this build lacks is fail-closed.  Default off, preserving
compatibility with older clients.

Documented in rsyncd.conf(5) and SECURITY.md.  The test covers the strong-
client accept, the unknown-floor fail-closed, and -- with a bundled old
static rsync -- the real md5-downgrade refusal (plus a no-floor control).

(cherry picked from commit 1ba7951c; backport drops the SECURITY.md policy
section, which is 3.5.0-specific, and the _test.py, which the stable harness
does not run.)
2026-06-15 15:24:42 +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
Wayne Davison 5510255f12 Tweak maintainer messaging. 2024-04-08 13:16:12 -07:00
Christian Hesse 35f5a21a16 hint that a proxy can handle plain and ssl stream at the same time 2024-04-07 09:25:46 +10:00
Wayne Davison ae3e13ba99 Update github links. 2024-04-06 10:33:42 -07:00
Grant Gardner a47ae6fad9 typo in rsyncd.conf.5.md 2024-04-06 09:53:47 +11:00
Wayne Davison 48252c3c2b A couple manpage links. 2022-11-23 07:59:12 -08:00
Wayne Davison 5b67ff2a86 Improve [global] module documentation. 2022-11-22 22:55:52 -08:00
Wayne Davison 4d44bf122d A few more doc tweaks & comment tweaks. 2022-09-30 12:34:58 -07:00
Wayne Davison 97e02bf21a Some "use chroot" improvements.
- The sanitize_paths variable was set too often. It only needs to be set
  when the "inner" path is not "/".  This change avoids sanitizing &
  munging things for a path=/ module just because chroot is off.
- The default for "use chroot" is now "unset" instead of "true".  When
  unset it checks if chrooting works, and if not, it proceeds with a
  sanitized copy instead of totally failing to work.  This makes it
  easier to setup a non-root rsync daemon, for instance.  It will have
  no effect on a typical Linux root-run daemon where the default will
  continue to use chroot (because chrooting works).  A config file can
  explicitly set "use chroot = true | false" to force the choice.
- Try to improve the "use chroot" manpage.
2022-09-20 00:08:16 -07:00
Wayne Davison 0a09df2c5e Rename --protect-args to --secluded-args. 2022-08-23 14:56:23 -07:00
Wayne Davison b38780f3fd Some proxy improvements (mainly). 2022-06-19 11:42:25 -07:00
Wayne Davison 8aa465117f Add new & improved --copy-devices option. 2022-03-27 14:04:59 -07:00
Wayne Davison 96ed4b47b9 Some word fixes. 2022-03-26 08:58:51 -07:00
Wayne Davison d07272d631 More man page and NEWS improvements.
- Add link targets for all option choices, not just the first one.
- Tweak cross-link arg format.
- Add more links, including some in the latest NEWS.
- Split out a few numbered lists.
2022-01-16 10:47:36 -08:00
Wayne Davison 76dc7d0a76 It's OK to capitalize rsync at the start of a sentence. 2022-01-15 21:44:26 -08:00
Wayne Davison 995ce7198b Man page improvments, including html cross-links. 2022-01-15 16:31:54 -08:00
Wayne Davison e841944b47 Change manpage headings in html to use h2 tags with an id target. 2022-01-12 16:43:22 -08:00
Wayne Davison c11467af36 Some compression improvements.
The compression level of the first file in the transfer no longer sets
the level for all files that follow it.  Document that per-file level
switching has no current effect (except for a global "dont compress = *"
rule in the daemon).
2021-12-31 12:21:13 -08:00
Wayne Davison ec8a05f653 Some packaging improvements. 2021-10-10 09:28:24 -07:00
Wayne Davison 7e07a32504 Add the name converter daemon parameter.
This is based on the long-standing patch but with the protocol changed
to just use newlines as delimiters instead of null chars (since names
should not contain a newline AND it makes it easier to write a helper
script).  Lots of other small improvements and a better default value
for "numeric ids" when using "use chroot" with "name converter".
2020-07-17 10:30:59 -07:00
Wayne Davison 2f13049600 Add "@netgroup" names to host matching. 2020-07-12 19:16:57 -07:00
Wayne Davison 565cde84a7 Don't turn off the user's open-noatime unless the module is forcing the value. 2020-07-04 10:28:38 -07:00
Paul Slootman f0e670b4c6 Add "open noatime" module option to rsyncd.conf 2020-07-04 09:30:35 -07:00
Wayne Davison b1a8b09c21 Some man page changes. 2020-06-26 11:27:27 -07:00
Christian Hesse 39a083b16b Add missing semicolon in man page
All nginx configuration directives end in semicolon.
2020-06-24 17:54:47 -07:00
Wayne Davison 6a9adabfbb Mention the early-input on stdin. 2020-06-21 20:25:51 -07:00
Wayne Davison b0ab07cdac Some README and man page tweaks. 2020-06-20 20:31:52 -07:00
Wayne Davison d80da9e674 A few small tweaks. 2020-06-15 15:04:08 -07:00
Wayne Davison 1fa38546a0 Document how to setup rsyncd behind a TLS proxy. 2020-06-15 11:36:24 -07:00
Wayne Davison 249e28c75a Rename "haproxy header" to "proxy protocol". 2020-06-15 11:33:23 -07:00
Wayne Davison 43a939e3f2 Improve some md files. 2020-06-14 15:29:45 -07:00
Wayne Davison b040825b86 Improve the haproxy header docs. 2020-06-11 15:23:35 -07:00
Wayne Davison cff0764b7f Add haproxy header parameter to rsync daemon 2020-06-11 14:22:25 -07:00
Wayne Davison a3377921eb Add early exec daemon parameter.
Inspired by Ciprian Dorin Craciun's `bootstrap exec` patch.
2020-06-10 21:38:37 -07:00
Wayne Davison 03fc62ad2f More man processing improvements
- Support the commonmark library in addition to cmarkgfm.
- Remove github-flavor from the markup.
- A few more html style improvements.
2020-06-09 17:02:41 -07:00
Wayne Davison 53fae55652 Change man page src format from yodl to markdown.
This removes the yodl dependency, which is sometimes hard to track down.
Instead, this uses a python3 script that leverages the cmarkgfm library
to turn the source file into html.  Then, the script parses the html in
order to turn the tag stream into a nroff stream using a simple state
machine. While it's doing that it also implements one added format rule
that turns an ordinal list that starts at 0 into a description list
(since markdown doesn't have an easy description list idiom).
2020-06-08 21:03:42 -07:00