From ac7bceff6f1ade9b9d885641581ca6d33b917e77 Mon Sep 17 00:00:00 2001 From: Vivian Thiebaut <81188381+vthiebaut10@users.noreply.github.com> Date: Thu, 17 Feb 2022 20:32:35 -0500 Subject: [PATCH] Fix SCP stack overflow when copying over directories (#565) --- scp.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/scp.c b/scp.c index 25f2cbd10..a47092590 100644 --- a/scp.c +++ b/scp.c @@ -1262,7 +1262,14 @@ source(int argc, char **argv) off_t i, statbytes; size_t amt, nr; int fd = -1, haderr, indx; +#ifdef WINDOWS + /* PATH_MAX is too large on Windows.*/ + /* Allocate memory dynamically for encname and buf to avoid stack overflow on recursive calls.*/ + char *last, *name, *buf = NULL, *encname = NULL; + size_t encname_len, buf_len, tmp_len; +#else char *last, *name, buf[PATH_MAX + 128], encname[PATH_MAX]; +#endif int len; for (indx = 0; indx < argc; ++indx) { @@ -1274,7 +1281,20 @@ source(int argc, char **argv) if ((fd = open(name, O_RDONLY|O_NONBLOCK, 0)) == -1) goto syserr; if (strchr(name, '\n') != NULL) { +#ifdef WINDOWS + if (!encname) { + encname_len = ((2 * len) < PATH_MAX) ? 2 * len : PATH_MAX; + encname = xmalloc(encname_len); + } + while ((tmp_len = strnvis(encname, name, encname_len, VIS_NL)) >= encname_len) { + if (tmp_len >= PATH_MAX) + break; + encname_len = tmp_len + 1; + encname = xreallocarray(encname, encname_len, sizeof(char)); + } +#else strnvis(encname, name, sizeof(encname), VIS_NL); +#endif name = encname; } if (fstat(fd, &stb) == -1) { @@ -1309,9 +1329,27 @@ syserr: run_err("%s: %s", name, strerror(errno)); goto next; } #define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) +#ifdef WINDOWS + if (!buf) + { + /*Set the initial size of buf to "strlen(last) + 20" based on multiple tests that*/ + /*inidicate that this is usually enough. If not enough, more space will be allocated below.*/ + buf_len = ((strlen(last) + 20) < PATH_MAX) ? strlen(last) + 20 : PATH_MAX; + buf = xmalloc(buf_len); + } + while ((tmp_len = snprintf(buf, buf_len, "C%04o %lld %s\n", + (u_int) (stb.st_mode & FILEMODEMASK), + (long long)stb.st_size, last)) >= buf_len) { + if (tmp_len >= PATH_MAX) + break; + buf_len = tmp_len + 1; + buf = xreallocarray(buf, buf_len, sizeof(char)); + } +#else snprintf(buf, sizeof buf, "C%04o %lld %s\n", (u_int) (stb.st_mode & FILEMODEMASK), (long long)stb.st_size, last); +#endif if (verbose_mode) fmprintf(stderr, "Sending file modes: %s", buf); (void) atomicio(vwrite, remout, buf, strlen(buf)); @@ -1363,6 +1401,12 @@ next: if (fd != -1) { if (showprogress) stop_progress_meter(); } +#ifdef WINDOWS + if (encname) + free(encname); + if (buf) + free(buf); +#endif } void @@ -1370,7 +1414,16 @@ rsource(char *name, struct stat *statp) { DIR *dirp; struct dirent *dp; +#ifndef WINDOWS char *last, *vect[1], path[PATH_MAX]; +#else + /* PATH_MAX is too large on Windows.*/ + /* Allocate memory dynamically for path to avoid stack overflow on recursive calls.*/ + char *last, *vect[1], *path; + size_t path_len = 260, len; + + path = xmalloc(path_len); +#endif if (!(dirp = opendir(name))) { run_err("%s: %s", name, strerror(errno)); @@ -1387,8 +1440,19 @@ rsource(char *name, struct stat *statp) return; } } +#ifdef WINDOWS + while ((len = snprintf(path, path_len, "D%04o %d %.1024s\n", + (u_int)(statp->st_mode & FILEMODEMASK), 0, last)) >= path_len) + { + if (len >= PATH_MAX) + break; + path_len = len + 1; + path = xreallocarray(path, path_len, sizeof(char)); + } +#else (void) snprintf(path, sizeof path, "D%04o %d %.1024s\n", (u_int) (statp->st_mode & FILEMODEMASK), 0, last); +#endif if (verbose_mode) fmprintf(stderr, "Entering directory: %s", path); (void) atomicio(vwrite, remout, path, strlen(path)); @@ -1401,14 +1465,29 @@ rsource(char *name, struct stat *statp) continue; if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue; +#ifdef WINDOWS + if (strlen(name) + 1 + strlen(dp->d_name) >= PATH_MAX - 1) { +#else if (strlen(name) + 1 + strlen(dp->d_name) >= sizeof(path) - 1) { +#endif run_err("%s/%s: name too long", name, dp->d_name); continue; } +#ifdef WINDOWS + while ((len = snprintf(path, path_len, "%s/%s", name, dp->d_name)) >= path_len) { + path_len = len + 1; + path = xreallocarray(path, path_len, sizeof(char)); + } +#else (void) snprintf(path, sizeof path, "%s/%s", name, dp->d_name); +#endif vect[0] = path; source(1, vect); } +#ifdef WINDOWS + if (path) + free(path); +#endif (void) closedir(dirp); (void) atomicio(vwrite, remout, "E\n", 2); (void) response();