From: Wayne Davison Date: Tue, 9 Aug 2022 18:45:56 +0000 (-0700) Subject: Add `--trust-sender` option. X-Git-Tag: v3.2.5~11 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cff8f044776c5143a5b270969d4bb0f1fea8b017;p=thirdparty%2Frsync.git Add `--trust-sender` option. --- diff --git a/NEWS.md b/NEWS.md index 0c212da9..5394b1a9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -17,6 +17,9 @@ ### BUG FIXES: +- Fixed the handling of filenames specified with backslash-quoted wildcards + when the default remote-arg-escaping is enabled. + - Fixed the configure check for signed char that was causing a host that defaults to unsigned characters to generate bogus rolling checksums. This made rsync send mostly literal data for a copy instead of finding matching @@ -26,6 +29,11 @@ - Lots of manpage improvements, including an attempt to better describe how include/exclude filters work. +### ENHANCEMENTS: + +- The [`--trust-sender`](rsync.1#opt) option was added as a way to bypass the + extra file-list safety checking (should that be required). + ### PACKAGING RELATED: - The build date that goes into the manpages is now based on the developer's diff --git a/exclude.c b/exclude.c index d36a105e..da25661b 100644 --- a/exclude.c +++ b/exclude.c @@ -33,18 +33,15 @@ extern int recurse; extern int local_server; extern int prune_empty_dirs; extern int ignore_perishable; -extern int old_style_args; extern int relative_paths; extern int delete_mode; extern int delete_excluded; extern int cvs_exclude; extern int sanitize_paths; extern int protocol_version; -extern int read_batch; -extern int list_only; +extern int trust_sender_args; extern int module_id; -extern char *filesfrom_host; extern char curr_dir[MAXPATHLEN]; extern unsigned int curr_dir_len; extern unsigned int module_dirlen; @@ -55,6 +52,7 @@ filter_rule_list daemon_filter_list = { .debug_type = " [daemon]" }; filter_rule_list implied_filter_list = { .debug_type = " [implied]" }; int saw_xattr_filter = 0; +int trust_sender_args = 0; int trust_sender_filter = 0; /* Need room enough for ":MODS " prefix plus some room to grow. */ @@ -377,7 +375,7 @@ void add_implied_include(const char *arg, int skip_daemon_module) int slash_cnt = 1; /* We know we're adding a leading slash. */ const char *cp; char *p; - if (am_server || old_style_args || list_only || read_batch || filesfrom_host != NULL) + if (trust_sender_args) return; if (partial_string_len) { arg_len = strlen(arg); diff --git a/main.c b/main.c index 6721ceb7..9ebfbea7 100644 --- a/main.c +++ b/main.c @@ -89,7 +89,6 @@ extern int backup_dir_len; extern int basis_dir_cnt; extern int default_af_hint; extern int stdout_format_has_i; -extern int trust_sender_filter; extern struct stats stats; extern char *stdout_format; extern char *logfile_format; @@ -636,7 +635,6 @@ static pid_t do_cmd(char *cmd, char *machine, char *user, char **remote_argv, in #ifdef ICONV_CONST setup_iconv(); #endif - trust_sender_filter = 1; } else if (local_server) { /* If the user didn't request --[no-]whole-file, force * it on, but only if we're not batch processing. */ diff --git a/options.c b/options.c index e7a9fcae..4feeb7e0 100644 --- a/options.c +++ b/options.c @@ -27,6 +27,8 @@ extern int module_id; extern int local_server; extern int sanitize_paths; +extern int trust_sender_args; +extern int trust_sender_filter; extern unsigned int module_dirlen; extern filter_rule_list filter_list; extern filter_rule_list daemon_filter_list; @@ -64,6 +66,7 @@ int preserve_atimes = 0; int preserve_crtimes = 0; int omit_dir_times = 0; int omit_link_times = 0; +int trust_sender = 0; int update_only = 0; int open_noatime = 0; int cvs_exclude = 0; @@ -788,6 +791,7 @@ static struct poptOption long_options[] = { {"protect-args", 's', POPT_ARG_VAL, &protect_args, 1, 0, 0}, {"no-protect-args", 0, POPT_ARG_VAL, &protect_args, 0, 0, 0}, {"no-s", 0, POPT_ARG_VAL, &protect_args, 0, 0, 0}, + {"trust-sender", 0, POPT_ARG_VAL, &trust_sender, 1, 0, 0}, {"numeric-ids", 0, POPT_ARG_VAL, &numeric_ids, 1, 0, 0 }, {"no-numeric-ids", 0, POPT_ARG_VAL, &numeric_ids, 0, 0, 0 }, {"usermap", 0, POPT_ARG_STRING, 0, OPT_USERMAP, 0, 0 }, @@ -2465,6 +2469,11 @@ int parse_arguments(int *argc_p, const char ***argv_p) } } + if (trust_sender || am_server || read_batch) + trust_sender_args = trust_sender_filter = 1; + else if (old_style_args || filesfrom_host != NULL) + trust_sender_args = 1; + am_starting_up = 0; return 1; @@ -2499,7 +2508,7 @@ char *safe_arg(const char *opt, const char *arg) char *ret; if (!protect_args && old_style_args < 2 && (!old_style_args || (!is_filename_arg && opt != SPLIT_ARG_WHEN_OLD))) { const char *f; - if (!old_style_args && *arg == '~' && (relative_paths || !strchr(arg, '/'))) { + if (!trust_sender_args && *arg == '~' && (relative_paths || !strchr(arg, '/'))) { extras++; escape_leading_tilde = 1; } diff --git a/rsync.1.md b/rsync.1.md index 0c27df4c..72675594 100644 --- a/rsync.1.md +++ b/rsync.1.md @@ -193,6 +193,8 @@ Dedicate a "host1-files" dir to the remote content: > rsync -aiv host1:dir1 ~/host1-files +See the [`--trust-sender`](#opt) option for additional details. + ## ADVANCED USAGE The syntax for requesting multiple files from a remote host is done by @@ -463,6 +465,7 @@ has its own detailed description later in this manpage. --from0, -0 all *-from/filter files are delimited by 0s --old-args disable the modern arg-protection idiom --protect-args, -s no space-splitting; wildcard chars only +--trust-sender trust the remote sender's file list --copy-as=USER[:GROUP] specify user & optional group for the copy --address=ADDRESS bind address for outgoing socket to daemon --port=PORT specify double-colon alternate port number @@ -536,7 +539,8 @@ option has a short variant). The parameter may need to be quoted in some manner for it to survive the shell's command-line parsing. Also keep in mind that a leading tilde (`~`) in a pathname is substituted by your shell, so make sure that you separate the -option name from the pathname using a space if you want the shell to expand it. +option name from the pathname using a space if you want the local shell to +expand it. [comment]: # (Some markup below uses a literal non-breakable space when a backtick string) [comment]: # (needs to contain a space since markdown strips spaces from the start/end) @@ -1908,8 +1912,8 @@ option name from the pathname using a space if you want the shell to expand it. A rule can still apply to both sides even with this option specified if the rule is given both the sender & receiver modifer letters (e.g., `-f'-sr foo'`). Receiver-side protect/risk rules can also be explicitly specified - to limit the deletions. This is saves you from having to edit a bunch of - `-f'- foo'` rules into `-f'-s foo'` or `-f'H foo'` rules (not to mention + to limit the deletions. This saves you from having to edit a bunch of + `-f'- foo'` rules into `-f'-s foo'` (aka `-f'H foo'`) rules (not to mention the corresponding includes). See the [FILTER RULES](#) section for more information. See @@ -2408,6 +2412,38 @@ option name from the pathname using a space if you want the shell to expand it. Note that this option is incompatible with the use of the restricted rsync script (`rrsync`) since it hides options from the script's inspection. +0. `--trust-sender` + + Disable the extra validation of the file list from a remote sender (this + safety feature was added in 3.2.5). This should only be done if you trust + the sender to not try to do something malicious, which should be the case + if they're running a stock rsync. + + Normally when pulling files from a remote rsync, the client runs 2 extra + validation checks: + + - Verify that additional arg items didn't get added at the top of the + transfer. + - Verify that none of the items in the file list should have been excluded. + + Note that various options can turn off one or both of these checks if the + option interferes with the validation. For instance: + + - Using a per-directory filter file reads filter rules that only the server + knows about, so the filter checking is disabled. + - Using the [`--old-args`](#opt) option allows the sender to manipulate the + requested args, so the arg checking is disabled. + - Reading the files-from list from the server side means that the client + doesn't know the arg list, so the arg checking is disabled. + - Using [`--read-batch`](#opt) disables both checks since the batch file's + contents will have been verified when it was created. + + This option may help an under-powered client server if the extra pattern + matching is slowing things down on a huge transfer. It can also be used + to work around a bug in the verification logic, possibly after using the + [`--list-only`](#opt) option combined with [`--trust-sender`](#opt) to look + over the full file list. + 0. `--copy-as=USER[:GROUP]` This option instructs rsync to use the USER and (if specified after a @@ -3444,8 +3480,8 @@ option name from the pathname using a space if you want the shell to expand it. include the destination. CAUTION: keep in mind that a source arg with a wild-card is expanded by the - shell into multiple args, so it is never safe to try to list such an arg - without using this option. For example: + shell into multiple args, so it is never safe to try to specify a single + wild-card arg to try to infer this option. A safe example is: > rsync -av --list-only foo* dest/ @@ -3790,7 +3826,7 @@ different ways. We will first cover the basics of how include & exclude rules affect what files are transferred, ignoring any deletion side-effects. Filter rules mainly affect the contents of directories that rsync is "recursing" into, but they can -also affect a top-level item in the transfer that were specified as a argument. +also affect a top-level item in the transfer that was specified as a argument. The default for any unmatched file/dir is for it to be included in the transfer, which puts the file/dir into the sender's file list. The use of an @@ -3919,7 +3955,7 @@ You have your choice of using either short or long RULE names, as described below. If you use a short-named rule, the ',' separating the RULE from the MODIFIERS is optional. The PATTERN or FILENAME that follows (when present) must come after either a single space or an underscore (\_). Any additional -spaces and/or undeerscore are considered to be a part of the pattern name. +spaces and/or underscores are considered to be a part of the pattern name. Here are the available rule prefixes: 0. `exclude, '-'` specifies an exclude pattern that (by default) is both a @@ -3929,10 +3965,8 @@ Here are the available rule prefixes: 0. `merge, '.'` specifies a merge-file on the client side to read for more rules. 0. `dir-merge, ':'` specifies a per-directory merge-file. Using this kind of - filter rule requires that you trust the sending side's filter checking, and - thus it disables the receiver's verification of the file-list names against - the filter rules (since only the sender can know for sure if it obeyed all - the filter rules when some are per-dir merged from the sender's files). + filter rule requires that you trust the sending side's filter checking, so + it has the side-effect mentioned under the [`--trust-sender`](#opt) option. 0. `hide, 'H'` specifies a pattern for hiding files from the transfer. Equivalent to a sender-only exclude, so `-f'H foo'` could also be specified as `-f'-s foo'`. @@ -3969,15 +4003,15 @@ The matching rules for the pattern argument take several forms: - If a pattern contains a `/` (not counting a trailing slash) or a "`**`" (which can match a slash), then the pattern is matched against the full pathname, including any leading directories within the transfer. If the - pattern doesn't contain a `/` or a "`**`", then it is matched only against - the final component of the filename or pathname. For example, `foo` means - that the final path component must be "foo" while `foo/bar` would match the - last 2 elements of the path (as long as both elements are within the - transfer). + pattern doesn't contain a (non-trailing) `/` or a "`**`", then it is matched + only against the final component of the filename or pathname. For example, + `foo` means that the final path component must be "foo" while `foo/bar` would + match the last 2 elements of the path (as long as both elements are within + the transfer). - A pattern that ends with a `/` only matches a directory, not a regular file, symlink, or device. - A pattern that starts with a `/` is anchored to the start of the transfer - path instead of the end. For example, `/foo` or `/foo/bar` match only + path instead of the end. For example, `/foo/**` or `/foo/bar/**` match only leading elements in the path. If the rule is read from a per-directory filter file, the transfer path being matched will begin at the level of the filter file instead of the top of the transfer. See the section on @@ -4010,11 +4044,11 @@ Here are some examples of exclude/include matching: - Option `-f'- /foo'` would exclude a file (or directory) named foo in the transfer-root directory - Option `-f'- foo/'` would exclude any directory named foo -- Option `-f'- /foo/*/bar'` would exclude any file/dir named bar which is at - two levels below a directory named foo, which must be at the root of the - transfer -- Option `-f'- /foo/**/bar'` would exclude any file/dir named bar two or more - levels below a directory named foo, which must be at the root of the transfer +- Option `-f'- foo/*/bar'` would exclude any file/dir named bar which is at two + levels below a directory named foo (if foo is in the transfer) +- Option `-f'- /foo/**/bar'` would exclude any file/dir named bar that was two + or more levels below the top-level directory named foo (exclude /foo/bar in a + separate rule, if desired) - Options `-f'+ */' -f'+ *.c' -f'- *'` would include all directories and .c source files but nothing else - Options `-f'+ foo/' -f'+ foo/bar.c' -f'- *'` would include only the foo