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.
This commit is contained in:
Wayne Davison
2022-09-19 22:37:29 -07:00
parent 77d762ced8
commit 97e02bf21a
4 changed files with 82 additions and 39 deletions

13
NEWS.md
View File

@@ -8,6 +8,9 @@
- When rsync gets an unpack error on an ACL, mention the filename.
- Avoid oversetting sanitize_paths when a daemon is serving "/" (even if
"use chroot" is false).
### ENHANCEMENTS:
- Added negotiated daemon-auth support that allows a stronger checksum digest
@@ -32,6 +35,11 @@
converted. Newer rsync versions will provide more complete info than older
versions.
- The [`use chroot`](#rsyncd.conf) daemon parameter now defaults to "unset" so
that rsync can test if chrooting works and decide to proceed with a sanitized
copy if chroot is not supported (e.g., for a non-root daemon). Explicitly
setting it to true or false (on or off) behaves the same way as before.
### PACKAGING RELATED:
- The checksum code now uses openssl's EVP methods, which gets rid of various
@@ -49,6 +57,11 @@
configured path in the OPENSSL_CONF environment variable (when the variable
is not already set). This will enable openssl's MD4 code for rsync to use.
- The packager may wish to include an explicit "use chroot = true" in the top
section of the /etc/rsyncd.conf file if the daemon is being installed to run
as the root user (though rsync should behave the same even with the value
unset, a little extra paranoia doesn't hurt).
------------------------------------------------------------------------------
# NEWS for rsync 3.2.6 (9 Sep 2022)

View File

@@ -701,7 +701,7 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
int set_uid;
char *p, *err_msg = NULL;
char *name = lp_name(i);
int use_chroot = lp_use_chroot(i);
int use_chroot = lp_use_chroot(i); /* might be 1 (yes), 0 (no), or -1 (unset) */
int ret, pre_exec_arg_fd = -1, pre_exec_error_fd = -1;
int save_munge_symlinks;
pid_t pre_exec_pid = 0;
@@ -826,6 +826,20 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
io_printf(f_out, "@ERROR: no path setting.\n");
return -1;
}
if (use_chroot < 0) {
if (strstr(module_dir, "/./") != NULL)
use_chroot = 1; /* The module is expecting a chroot inner & outer path. */
else if (chroot("/") < 0) {
rprintf(FLOG, "chroot test failed: %s. "
"Switching 'use chroot' from unset to no.\n",
strerror(errno));
use_chroot = 0;
} else {
if (chdir("/") < 0)
rsyserr(FLOG, errno, "chdir(\"/\") failed");
use_chroot = 1;
}
}
if (use_chroot) {
if ((p = strstr(module_dir, "/./")) != NULL) {
*p = '\0'; /* Temporary... */
@@ -962,20 +976,8 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
}
if (use_chroot) {
/*
* XXX: The 'use chroot' flag is a fairly reliable
* source of confusion, because it fails under two
* important circumstances: running as non-root,
* running on Win32 (or possibly others). On the
* other hand, if you are running as root, then it
* might be better to always use chroot.
*
* So, perhaps if we can't chroot we should just issue
* a warning, unless a "require chroot" flag is set,
* in which case we fail.
*/
if (chroot(module_chdir)) {
rsyserr(FLOG, errno, "chroot %s failed", module_chdir);
rsyserr(FLOG, errno, "chroot(\"%s\") failed", module_chdir);
io_printf(f_out, "@ERROR: chroot failed\n");
return -1;
}
@@ -984,7 +986,7 @@ static int rsync_module(int f_in, int f_out, int i, const char *addr, const char
if (!change_dir(module_chdir, CD_NORMAL))
return path_failure(f_out, module_chdir, True);
if (module_dirlen || (!use_chroot && !*lp_daemon_chroot()))
if (module_dirlen)
sanitize_paths = 1;
if ((munge_symlinks = lp_munge_symlinks(module_id)) < 0)
@@ -1299,8 +1301,12 @@ int start_daemon(int f_in, int f_out)
p = lp_daemon_chroot();
if (*p) {
log_init(0); /* Make use we've initialized syslog before chrooting. */
if (chroot(p) < 0 || chdir("/") < 0) {
rsyserr(FLOG, errno, "daemon chroot %s failed", p);
if (chroot(p) < 0) {
rsyserr(FLOG, errno, "daemon chroot(\"%s\") failed", p);
return -1;
}
if (chdir("/") < 0) {
rsyserr(FLOG, errno, "daemon chdir(\"/\") failed");
return -1;
}
}

View File

@@ -60,9 +60,9 @@ BOOL read_only True
BOOL reverse_lookup True
BOOL strict_modes True
BOOL transfer_logging False
BOOL use_chroot True
BOOL write_only False
BOOL3 munge_symlinks Unset
BOOL3 numeric_ids Unset
BOOL3 open_noatime Unset
BOOL3 use_chroot Unset

View File

@@ -164,6 +164,16 @@ the values of parameters. See the GLOBAL PARAMETERS section for more details.
available in this module. You must specify this parameter for each module
in `rsyncd.conf`.
If the value contains a "/./" element then the path will be divided at that
point into a chroot dir and an inner-chroot subdir. If [`use chroot`](#)
is set to false, though, the extraneous dot dir is just cleaned out of the
path. An example of this idiom is:
> path = /var/rsync/./module1
This will (when chrooting) chroot to "/var/rsync" and set the inside-chroot
path to "/module1".
You may base the path's value off of an environment variable by surrounding
the variable name with percent signs. You can even reference a variable
that is set by rsync when the user connects. For example, this would use
@@ -187,29 +197,43 @@ the values of parameters. See the GLOBAL PARAMETERS section for more details.
path, and of complicating the preservation of users and groups by name (see
below).
As an additional safety feature, you can specify a dot-dir in the module's
"[path](#)" to indicate the point where the chroot should occur. This allows
rsync to run in a chroot with a non-"/" path for the top of the transfer
hierarchy. Doing this guards against unintended library loading (since
those absolute paths will not be inside the transfer hierarchy unless you
have used an unwise pathname), and lets you setup libraries for the chroot
that are outside of the transfer. For example, specifying
"/var/rsync/./module1" will chroot to the "/var/rsync" directory and set
the inside-chroot path to "/module1". If you had omitted the dot-dir, the
chroot would have used the whole path, and the inside-chroot path would
have been "/".
If `use chroot` is not set, it defaults to trying to enable a chroot but
allows the daemon to continue (after logging a warning) if it fails. The
one exception to this is when a module's [`path`](#) has a "/./" chroot
divider in it -- this causes an unset value to be treated as true for that
module.
When both "use chroot" and "[daemon chroot](#)" are false, OR the inside-chroot
path of "use chroot" is not "/", rsync will: (1) munge symlinks by default
for security reasons (see "[munge symlinks](#)" for a way to turn this off, but
only if you trust your users), (2) substitute leading slashes in absolute
paths with the module's path (so that options such as `--backup-dir`,
`--compare-dest`, etc. interpret an absolute path as rooted in the module's
"[path](#)" dir), and (3) trim ".." path elements from args if rsync believes
they would escape the module hierarchy. The default for "use chroot" is
true, and is the safer choice (especially if the module is not read-only).
Prior to rsync 3.2.7, the default value was "true". The new default makes
it easier to setup an rsync daemon as a non-root user or to run a daemon on
a system where chroot fails. Explicitly setting the value to true in the
rsyncd.conf file will always require the chroot to succeed.
When this parameter is enabled *and* the "[name converter](#)" parameter is
It is also possible to specify a dot-dir in the module's "[path](#)" to
indicate that you want to chdir to the earlier part of the path and then
serve files from inside the latter part of the path (with default
sanitizing and symlink munging). This can be useful if you need some
library dirs inside the chroot (typically for uid & gid lookups) but don't
want to put the lib dir into the top of the served path (even though they
can be hidden with an [`exclude`](#) directive). However, a better choice
for a modern rsync setup is to use a [`name converter`](#)" and try to
avoid inner lib dirs altogether. See also the [`daemon chroot`](#)
parameter, which causes rsync to chroot into its own chroot area before
doing any path-related chrooting.
If the daemon is serving the "/" dir (either directly or due to being
chrooted to the module's path), rsync does not do any extra path sanitizing
or (default) munging. When it has to limit access to a particular subdir
(either due to chroot being disabled or having an inside-chroot path set),
rsync will munge symlinks (by default) and sanitize paths. Those that
dislike munged symlinks (and really, really trust their users to not break
out of the subdir) can disable the symlink munging via the "[munge
symlinks](#)" parameter. Sanitizing paths trims ".." path elements from
args that rsync believes would escape the module hierarchy, and also
substitutes leading slashes in absolute paths with the module's path (so
that options such as `--backup-dir` & `--compare-dest` interpret an
absolute path as rooted in the module's "[path](#)" dir).
When a chroot is in effect *and* the "[name converter](#)" parameter is
*not* set, the "[numeric ids](#)" parameter will default to being enabled
(disabling name lookups). This means that if you manually setup
name-lookup libraries in your chroot (instead of using a name converter)