create_rsync_argv(): Allocate correctly sized arg array.
authorAndre Noll <maan@tuebingen.mpg.de>
Tue, 3 Sep 2019 09:09:14 +0000 (11:09 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Tue, 3 Sep 2019 09:09:14 +0000 (11:09 +0200)
In the calculation of the length of the argv array we did not take
into account that --source-dir may be given multiple times. This can
result in an invalid write at the end of the allocated space.

dss.c

diff --git a/dss.c b/dss.c
index f8bbb99..b6a3d3e 100644 (file)
--- a/dss.c
+++ b/dss.c
@@ -1386,7 +1386,7 @@ out:
 static void create_rsync_argv(char ***argv, int64_t *num)
 {
        char *logname;
-       int i = 0, j, N = OPT_GIVEN(DSS, RSYNC_OPTION);
+       int i = 0, j, N;
        struct snapshot_list sl;
        static bool seeded;
 
@@ -1395,7 +1395,13 @@ static void create_rsync_argv(char ***argv, int64_t *num)
        name_of_reference_snapshot = name_of_newest_complete_snapshot(&sl);
        free_snapshot_list(&sl);
 
-       *argv = dss_malloc((15 + N) * sizeof(char *));
+       /*
+        * We specify up to 6 arguments, one argument per given rsync option
+        * and one argument per given source dir. We also need space for the
+        * terminating NULL pointer.
+        */
+       N = OPT_GIVEN(DSS, RSYNC_OPTION) + OPT_GIVEN(DSS, SOURCE_DIR);
+       *argv = dss_malloc((7 + N) * sizeof(char *));
        (*argv)[i++] = dss_strdup("rsync");
        (*argv)[i++] = dss_strdup("-a");
        (*argv)[i++] = dss_strdup("--delete");
@@ -1407,7 +1413,7 @@ static void create_rsync_argv(char ***argv, int64_t *num)
                DSS_NOTICE_LOG(("adding --checksum to rsync options\n"));
                (*argv)[i++] = dss_strdup("--checksum");
        }
-       for (j = 0; j < N; j++)
+       for (j = 0; j < OPT_GIVEN(DSS, RSYNC_OPTION); j++)
                (*argv)[i++] = dss_strdup(lls_string_val(j,
                        OPT_RESULT(DSS, RSYNC_OPTION)));
        if (name_of_reference_snapshot) {
@@ -1417,9 +1423,8 @@ static void create_rsync_argv(char ***argv, int64_t *num)
        } else
                DSS_INFO_LOG(("no suitable reference snapshot found\n"));
        logname = dss_logname();
-       N = OPT_GIVEN(DSS, SOURCE_DIR);
        if (use_rsync_locally(logname)) {
-               for (j = 0; j < N; j++)
+               for (j = 0; j < OPT_GIVEN(DSS, SOURCE_DIR); j++)
                        (*argv)[i++] = dss_strdup(lls_string_val(j,
                                OPT_RESULT(DSS, SOURCE_DIR)));
        } else {
@@ -1436,7 +1441,7 @@ static void create_rsync_argv(char ***argv, int64_t *num)
                 * directory on the destination match the source. To preserve
                 * the old behaviour, we thus have to special-case N=1.
                 */
-               for (j = 0; j < N; j++) {
+               for (j = 0; j < OPT_GIVEN(DSS, SOURCE_DIR); j++) {
                        (*argv)[i++] = make_message("%s@%s:%s%s",
                                OPT_GIVEN(DSS, REMOTE_USER)?
                                        OPT_STRING_VAL(DSS, REMOTE_USER) : logname,