diff options
Diffstat (limited to 'backport-Duplicate-argv-data-before-poptFreeContext.patch')
-rw-r--r-- | backport-Duplicate-argv-data-before-poptFreeContext.patch | 630 |
1 files changed, 630 insertions, 0 deletions
diff --git a/backport-Duplicate-argv-data-before-poptFreeContext.patch b/backport-Duplicate-argv-data-before-poptFreeContext.patch new file mode 100644 index 0000000..fb80795 --- /dev/null +++ b/backport-Duplicate-argv-data-before-poptFreeContext.patch @@ -0,0 +1,630 @@ +From a2bd5eb03e299de04e63eb469ce3d3d3f092942f Mon Sep 17 00:00:00 2001 +From: Wayne Davison <wayne@opencoder.net> +Date: Tue, 22 Nov 2022 21:00:04 -0800 +Subject: [PATCH] Duplicate argv data before poptFreeContext(). + +Reference:https://github.com/RsyncProject/rsync/commit/8990ad96de881f7332d16d32485f9d8b841a87d2 +Conflict:NA +--- + main.c | 13 ----- + options.c | 160 ++++++++++++++++++++++++++++++------------------------ + 2 files changed, 90 insertions(+), 83 deletions(-) + +diff --git a/main.c b/main.c +index 9ebfbea..5f9a7a9 100644 +--- a/main.c ++++ b/main.c +@@ -1372,15 +1372,6 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[]) + return MAX(exit_code, exit_code2); + } + +-static void dup_argv(char *argv[]) +-{ +- int i; +- +- for (i = 0; argv[i]; i++) +- argv[i] = strdup(argv[i]); +-} +- +- + /* Start a client for either type of remote connection. Work out + * whether the arguments request a remote shell or rsyncd connection, + * and call the appropriate connection function, then run_client. +@@ -1396,10 +1387,6 @@ static int start_client(int argc, char *argv[]) + int ret; + pid_t pid; + +- /* Don't clobber argv[] so that ps(1) can still show the right +- * command line. */ +- dup_argv(argv); +- + if (!read_batch) { /* for read_batch, NO source is specified */ + char *path = check_for_hostspec(argv[0], &shell_machine, &rsync_port); + if (path) { /* source is remote */ +diff --git a/options.c b/options.c +index 4feeb7e..62558ef 100644 +--- a/options.c ++++ b/options.c +@@ -200,6 +200,7 @@ int remote_option_cnt = 0; + const char **remote_options = NULL; + const char *checksum_choice = NULL; + const char *compress_choice = NULL; ++static const char *empty_argv[1]; + + int quiet = 0; + int output_motd = 1; +@@ -1345,7 +1346,7 @@ char *alt_dest_opt(int type) + **/ + int parse_arguments(int *argc_p, const char ***argv_p) + { +- static poptContext pc; ++ poptContext pc; + const char *arg, **argv = *argv_p; + int argc = *argc_p; + int opt, want_dest_type; +@@ -1365,10 +1366,6 @@ int parse_arguments(int *argc_p, const char ***argv_p) + + /* TODO: Call poptReadDefaultConfig; handle errors. */ + +- /* The context leaks in case of an error, but if there's a +- * problem we always exit anyhow. */ +- if (pc) +- poptFreeContext(pc); + pc = poptGetContext(RSYNC_NAME, argc, argv, long_options, 0); + if (!am_server) { + poptReadDefaultConfig(pc, 0); +@@ -1411,7 +1408,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + strlcpy(err_buf, + "Attempt to hack rsync thwarted!\n", + sizeof err_buf); +- return 0; ++ goto cleanup; + } + #ifdef ICONV_OPTION + iconv_opt = NULL; +@@ -1457,7 +1454,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + if (tmpdir && strlen(tmpdir) >= MAXPATHLEN - 10) { + snprintf(err_buf, sizeof err_buf, + "the --temp-dir path is WAY too long.\n"); +- return 0; ++ goto cleanup; + } + + if (!daemon_opt) { +@@ -1467,8 +1464,16 @@ int parse_arguments(int *argc_p, const char ***argv_p) + exit_cleanup(RERR_SYNTAX); + } + +- *argv_p = argv = poptGetArgs(pc); +- *argc_p = argc = count_args(argv); ++ argv = poptGetArgs(pc); ++ argc = count_args(argv); ++ if (!argc) { ++ *argv_p = empty_argv; ++ *argc_p = 0; ++ } else if (poptDupArgv(argc, argv, argc_p, argv_p) != 0) ++ out_of_memory("parse_arguments"); ++ argv = *argv_p; ++ poptFreeContext(pc); ++ + am_starting_up = 0; + daemon_opt = 0; + am_daemon = 1; +@@ -1523,7 +1528,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + case 'a': + if (refused_archive_part) { + create_refuse_error(refused_archive_part); +- return 0; ++ goto cleanup; + } + if (!recurse) /* preserve recurse == 2 */ + recurse = 1; +@@ -1593,7 +1598,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + case 'P': + if (refused_partial || refused_progress) { + create_refuse_error(refused_partial ? refused_partial : refused_progress); +- return 0; ++ goto cleanup; + } + do_progress = 1; + keep_partial = 1; +@@ -1628,7 +1633,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + if (*arg != '-') { + snprintf(err_buf, sizeof err_buf, + "Remote option must start with a dash: %s\n", arg); +- return 0; ++ goto cleanup; + } + if (remote_option_cnt+2 >= remote_option_alloc) { + remote_option_alloc += 16; +@@ -1670,27 +1675,27 @@ int parse_arguments(int *argc_p, const char ***argv_p) + ssize_t size; + arg = poptGetOptArg(pc); + if ((size = parse_size_arg(arg, 'b', "block-size", 0, max_blength, False)) < 0) +- return 0; ++ goto cleanup; + block_size = (int32)size; + break; + } + + case OPT_MAX_SIZE: + if ((max_size = parse_size_arg(max_size_arg, 'b', "max-size", 0, -1, False)) < 0) +- return 0; ++ goto cleanup; + max_size_arg = strdup(do_big_num(max_size, 0, NULL)); + break; + + case OPT_MIN_SIZE: + if ((min_size = parse_size_arg(min_size_arg, 'b', "min-size", 0, -1, False)) < 0) +- return 0; ++ goto cleanup; + min_size_arg = strdup(do_big_num(min_size, 0, NULL)); + break; + + case OPT_BWLIMIT: { + ssize_t size = parse_size_arg(bwlimit_arg, 'K', "bwlimit", 512, -1, True); + if (size < 0) +- return 0; ++ goto cleanup; + bwlimit_arg = strdup(do_big_num(size, 0, NULL)); + bwlimit = (size + 512) / 1024; + break; +@@ -1719,7 +1724,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + snprintf(err_buf, sizeof err_buf, + "ERROR: the %s option conflicts with the %s option\n", + alt_dest_opt(want_dest_type), alt_dest_opt(0)); +- return 0; ++ goto cleanup; + } + alt_dest_type = want_dest_type; + +@@ -1727,7 +1732,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + snprintf(err_buf, sizeof err_buf, + "ERROR: at most %d %s args may be specified\n", + MAX_BASIS_DIRS, alt_dest_opt(0)); +- return 0; ++ goto cleanup; + } + /* We defer sanitizing this arg until we know what + * our destination directory is going to be. */ +@@ -1740,7 +1745,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + snprintf(err_buf, sizeof err_buf, + "Invalid argument passed to --chmod (%s)\n", + arg); +- return 0; ++ goto cleanup; + } + break; + +@@ -1759,11 +1764,11 @@ int parse_arguments(int *argc_p, const char ***argv_p) + if (usermap_via_chown) { + snprintf(err_buf, sizeof err_buf, + "--usermap conflicts with prior --chown.\n"); +- return 0; ++ goto cleanup; + } + snprintf(err_buf, sizeof err_buf, + "You can only specify --usermap once.\n"); +- return 0; ++ goto cleanup; + } + usermap = (char *)poptGetOptArg(pc); + usermap_via_chown = False; +@@ -1775,11 +1780,11 @@ int parse_arguments(int *argc_p, const char ***argv_p) + if (groupmap_via_chown) { + snprintf(err_buf, sizeof err_buf, + "--groupmap conflicts with prior --chown.\n"); +- return 0; ++ goto cleanup; + } + snprintf(err_buf, sizeof err_buf, + "You can only specify --groupmap once.\n"); +- return 0; ++ goto cleanup; + } + groupmap = (char *)poptGetOptArg(pc); + groupmap_via_chown = False; +@@ -1798,11 +1803,11 @@ int parse_arguments(int *argc_p, const char ***argv_p) + if (!usermap_via_chown) { + snprintf(err_buf, sizeof err_buf, + "--chown conflicts with prior --usermap.\n"); +- return 0; ++ goto cleanup; + } + snprintf(err_buf, sizeof err_buf, + "You can only specify a user-affecting --chown once.\n"); +- return 0; ++ goto cleanup; + } + if (asprintf(&usermap, "*:%.*s", len, chown) < 0) + out_of_memory("parse_arguments"); +@@ -1814,11 +1819,11 @@ int parse_arguments(int *argc_p, const char ***argv_p) + if (!groupmap_via_chown) { + snprintf(err_buf, sizeof err_buf, + "--chown conflicts with prior --groupmap.\n"); +- return 0; ++ goto cleanup; + } + snprintf(err_buf, sizeof err_buf, + "You can only specify a group-affecting --chown once.\n"); +- return 0; ++ goto cleanup; + } + if (asprintf(&groupmap, "*:%s", arg) < 0) + out_of_memory("parse_arguments"); +@@ -1846,7 +1851,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + snprintf(err_buf,sizeof(err_buf), + "ACLs are not supported on this %s\n", + am_server ? "server" : "client"); +- return 0; ++ goto cleanup; + #endif + + case 'X': +@@ -1857,7 +1862,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + snprintf(err_buf,sizeof(err_buf), + "extended attributes are not supported on this %s\n", + am_server ? "server" : "client"); +- return 0; ++ goto cleanup; + #endif + + case OPT_STOP_AFTER: { +@@ -1866,7 +1871,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + stop_at_utime = time(NULL); + if ((val = atol(arg) * 60) <= 0 || LONG_MAX - val < stop_at_utime || (long)(time_t)val != val) { + snprintf(err_buf, sizeof err_buf, "invalid --stop-after value: %s\n", arg); +- return 0; ++ goto cleanup; + } + stop_at_utime += val; + break; +@@ -1877,11 +1882,11 @@ int parse_arguments(int *argc_p, const char ***argv_p) + arg = poptGetOptArg(pc); + if ((stop_at_utime = parse_time(arg)) == (time_t)-1) { + snprintf(err_buf, sizeof err_buf, "invalid --stop-at format: %s\n", arg); +- return 0; ++ goto cleanup; + } + if (stop_at_utime <= time(NULL)) { + snprintf(err_buf, sizeof err_buf, "--stop-at time is not in the future: %s\n", arg); +- return 0; ++ goto cleanup; + } + break; + #endif +@@ -1899,7 +1904,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + else { + snprintf(err_buf, sizeof err_buf, + "--stderr mode \"%s\" is not one of errors, all, or client\n", arg); +- return 0; ++ goto cleanup; + } + saw_stderr_opt = 1; + break; +@@ -1910,13 +1915,13 @@ int parse_arguments(int *argc_p, const char ***argv_p) + * turned this option off. */ + if (opt >= OPT_REFUSED_BASE) { + create_refuse_error(opt); +- return 0; ++ goto cleanup; + } + snprintf(err_buf, sizeof err_buf, "%s%s: %s\n", + am_server ? "on remote machine: " : "", + poptBadOption(pc, POPT_BADOPTION_NOALIAS), + poptStrerror(opt)); +- return 0; ++ goto cleanup; + } + } + +@@ -1936,7 +1941,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + if (max_alloc_arg) { + ssize_t size = parse_size_arg(max_alloc_arg, 'B', "max-alloc", 1024*1024, -1, True); + if (size < 0) +- return 0; ++ goto cleanup; + max_alloc = size; + } + +@@ -1950,7 +1955,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + if (protect_args > 0) { + snprintf(err_buf, sizeof err_buf, + "--protect-args conflicts with --old-args.\n"); +- return 0; ++ goto cleanup; + } + protect_args = 0; + } +@@ -1995,7 +2000,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + do_compression = CPRES_AUTO; + if (do_compression && refused_compress) { + create_refuse_error(refused_compress); +- return 0; ++ goto cleanup; + } + } + +@@ -2020,7 +2025,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + default: + snprintf(err_buf, sizeof err_buf, + "Invalid --outbuf setting -- specify N, L, or B.\n"); +- return 0; ++ goto cleanup; + } + setvbuf(stdout, (char *)NULL, mode, 0); + } +@@ -2048,7 +2053,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + } + if (refused_no_iconv && !iconv_opt) { + create_refuse_error(refused_no_iconv); +- return 0; ++ goto cleanup; + } + #endif + +@@ -2059,18 +2064,30 @@ int parse_arguments(int *argc_p, const char ***argv_p) + if (orig_protect_args == 2 && am_server) + protect_args = orig_protect_args; + +- if (protect_args == 1 && am_server) ++ if (protect_args == 1 && am_server) { ++ poptFreeContext(pc); + return 1; ++ } + +- *argv_p = argv = poptGetArgs(pc); +- *argc_p = argc = count_args(argv); ++ /* Because popt 1.19 has started to free the returned args data, we now ++ * make a copy of the array and then do an immediate cleanup. */ ++ argv = poptGetArgs(pc); ++ argc = count_args(argv); ++ if (!argc) { ++ *argv_p = empty_argv; ++ *argc_p = 0; ++ } else if (poptDupArgv(argc, argv, argc_p, argv_p) != 0) ++ out_of_memory("parse_arguments"); ++ argv = *argv_p; ++ poptFreeContext(pc); ++ pc = NULL; + + #ifndef SUPPORT_LINKS + if (preserve_links && !am_sender) { + snprintf(err_buf, sizeof err_buf, + "symlinks are not supported on this %s\n", + am_server ? "server" : "client"); +- return 0; ++ goto cleanup; + } + #endif + +@@ -2079,7 +2096,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + snprintf(err_buf, sizeof err_buf, + "hard links are not supported on this %s\n", + am_server ? "server" : "client"); +- return 0; ++ goto cleanup; + } + #endif + +@@ -2087,20 +2104,20 @@ int parse_arguments(int *argc_p, const char ***argv_p) + if (am_root < 0 && preserve_xattrs > 1) { + snprintf(err_buf, sizeof err_buf, + "--fake-super conflicts with -XX\n"); +- return 0; ++ goto cleanup; + } + #else + if (am_root < 0) { + snprintf(err_buf, sizeof err_buf, + "--fake-super requires an rsync with extended attributes enabled\n"); +- return 0; ++ goto cleanup; + } + #endif + + if (write_batch && read_batch) { + snprintf(err_buf, sizeof err_buf, + "--write-batch and --read-batch can not be used together\n"); +- return 0; ++ goto cleanup; + } + if (write_batch > 0 || read_batch) { + if (am_server) { +@@ -2119,25 +2136,25 @@ int parse_arguments(int *argc_p, const char ***argv_p) + if (read_batch && files_from) { + snprintf(err_buf, sizeof err_buf, + "--read-batch cannot be used with --files-from\n"); +- return 0; ++ goto cleanup; + } + if (read_batch && remove_source_files) { + snprintf(err_buf, sizeof err_buf, + "--read-batch cannot be used with --remove-%s-files\n", + remove_source_files == 1 ? "source" : "sent"); +- return 0; ++ goto cleanup; + } + if (batch_name && strlen(batch_name) > MAX_BATCH_NAME_LEN) { + snprintf(err_buf, sizeof err_buf, + "the batch-file name must be %d characters or less.\n", + MAX_BATCH_NAME_LEN); +- return 0; ++ goto cleanup; + } + + if (tmpdir && strlen(tmpdir) >= MAXPATHLEN - 10) { + snprintf(err_buf, sizeof err_buf, + "the --temp-dir path is WAY too long.\n"); +- return 0; ++ goto cleanup; + } + + if (max_delete < 0 && max_delete != INT_MIN) { +@@ -2171,7 +2188,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + if (delete_before + !!delete_during + delete_after > 1) { + snprintf(err_buf, sizeof err_buf, + "You may not combine multiple --delete-WHEN options.\n"); +- return 0; ++ goto cleanup; + } + if (delete_before || delete_during || delete_after) + delete_mode = 1; +@@ -2182,7 +2199,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + delete_during = 1; + else { + create_refuse_error(refused_delete_before); +- return 0; ++ goto cleanup; + } + } else if (refused_delete_during) + delete_before = 1; +@@ -2191,14 +2208,14 @@ int parse_arguments(int *argc_p, const char ***argv_p) + if (!xfer_dirs && delete_mode) { + snprintf(err_buf, sizeof err_buf, + "--delete does not work without --recursive (-r) or --dirs (-d).\n"); +- return 0; ++ goto cleanup; + } + + if (missing_args == 3) /* simplify if both options were specified */ + missing_args = 2; + if (refused_delete && (delete_mode || missing_args == 2)) { + create_refuse_error(refused_delete); +- return 0; ++ goto cleanup; + } + + if (remove_source_files) { +@@ -2207,7 +2224,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + * options. */ + if (refused_delete && am_sender) { + create_refuse_error(refused_delete); +- return 0; ++ goto cleanup; + } + need_messages_from_generator = 1; + } +@@ -2261,7 +2278,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + snprintf(err_buf, sizeof err_buf, + "--suffix cannot contain slashes: %s\n", + backup_suffix); +- return 0; ++ goto cleanup; + } + if (backup_dir) { + size_t len; +@@ -2274,7 +2291,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + if (len > sizeof backup_dir_buf - 128) { + snprintf(err_buf, sizeof err_buf, + "the --backup-dir path is WAY too long.\n"); +- return 0; ++ goto cleanup; + } + backup_dir_len = (int)len; + if (!backup_dir_len) { +@@ -2293,7 +2310,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + "--suffix cannot be empty %s\n", backup_dir_len < 0 + ? "when --backup-dir is the same as the dest dir" + : "without a --backup-dir"); +- return 0; ++ goto cleanup; + } else if (make_backups && delete_mode && !delete_excluded && !am_server) { + snprintf(backup_dir_buf, sizeof backup_dir_buf, + "P *%s", backup_suffix); +@@ -2362,11 +2379,11 @@ int parse_arguments(int *argc_p, const char ***argv_p) + if (whole_file > 0) { + snprintf(err_buf, sizeof err_buf, + "--append cannot be used with --whole-file\n"); +- return 0; ++ goto cleanup; + } + if (refused_inplace) { + create_refuse_error(refused_inplace); +- return 0; ++ goto cleanup; + } + inplace = 1; + } +@@ -2374,7 +2391,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + if (write_devices) { + if (refused_inplace) { + create_refuse_error(refused_inplace); +- return 0; ++ goto cleanup; + } + inplace = 1; + } +@@ -2389,13 +2406,13 @@ int parse_arguments(int *argc_p, const char ***argv_p) + "--%s cannot be used with --%s\n", + append_mode ? "append" : "inplace", + delay_updates ? "delay-updates" : "partial-dir"); +- return 0; ++ goto cleanup; + } + /* --inplace implies --partial for refusal purposes, but we + * clear the keep_partial flag for internal logic purposes. */ + if (refused_partial) { + create_refuse_error(refused_partial); +- return 0; ++ goto cleanup; + } + keep_partial = 0; + #else +@@ -2403,7 +2420,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + "--%s is not supported on this %s\n", + append_mode ? "append" : "inplace", + am_server ? "server" : "client"); +- return 0; ++ goto cleanup; + #endif + } else { + if (keep_partial && !partial_dir && !am_server) { +@@ -2417,7 +2434,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + partial_dir = NULL; + if (!partial_dir && refused_partial) { + create_refuse_error(refused_partial); +- return 0; ++ goto cleanup; + } + keep_partial = 1; + } +@@ -2438,14 +2455,14 @@ int parse_arguments(int *argc_p, const char ***argv_p) + if (am_server) { + snprintf(err_buf, sizeof err_buf, + "The --files-from sent to the server cannot specify a host.\n"); +- return 0; ++ goto cleanup; + } + files_from = p; + filesfrom_host = h; + if (strcmp(files_from, "-") == 0) { + snprintf(err_buf, sizeof err_buf, + "Invalid --files-from remote filename\n"); +- return 0; ++ goto cleanup; + } + } else { + if (sanitize_paths) +@@ -2464,7 +2481,7 @@ int parse_arguments(int *argc_p, const char ***argv_p) + snprintf(err_buf, sizeof err_buf, + "failed to open files-from file %s: %s\n", + files_from, strerror(errno)); +- return 0; ++ goto cleanup; + } + } + } +@@ -2481,6 +2498,9 @@ int parse_arguments(int *argc_p, const char ***argv_p) + options_rejected: + snprintf(err_buf, sizeof err_buf, + "Your options have been rejected by the server.\n"); ++ cleanup: ++ if (pc) ++ poptFreeContext(pc); + return 0; + } + +-- +2.33.0 + |