diff options
Diffstat (limited to 'main/squid/CVE-2019-12528.patch')
-rw-r--r-- | main/squid/CVE-2019-12528.patch | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/main/squid/CVE-2019-12528.patch b/main/squid/CVE-2019-12528.patch new file mode 100644 index 00000000000..67a307273ef --- /dev/null +++ b/main/squid/CVE-2019-12528.patch @@ -0,0 +1,169 @@ +commit 8cdb18ca1829a0b7faa1c9e472604ed0e7e105ac +Author: Christos Tsantilas <christos@chtsanti.net> +Date: 2019-12-20 07:29:58 +0000 + + Fix FTP buffers handling (#521) + + Fix the parsing of the received listing from FTP services. + Also relaxed size/filename grammar used for DOS listings: Tolerate + multiple spaces between the size and the filename. + + This is a Measurement Factory project + +diff --git a/src/clients/FtpGateway.cc b/src/clients/FtpGateway.cc +index 2e50ad9..5bac13b 100644 +--- a/src/clients/FtpGateway.cc ++++ b/src/clients/FtpGateway.cc +@@ -539,8 +539,10 @@ ftpListParseParts(const char *buf, struct Ftp::GatewayFlags flags) + { + ftpListParts *p = NULL; + char *t = NULL; +- const char *ct = NULL; +- char *tokens[MAX_TOKENS]; ++ struct FtpLineToken { ++ char *token = NULL; ///< token image copied from the received line ++ size_t pos = 0; ///< token offset on the received line ++ } tokens[MAX_TOKENS]; + int i; + int n_tokens; + static char tbuf[128]; +@@ -581,7 +583,8 @@ ftpListParseParts(const char *buf, struct Ftp::GatewayFlags flags) + } + + for (t = strtok(xbuf, w_space); t && n_tokens < MAX_TOKENS; t = strtok(NULL, w_space)) { +- tokens[n_tokens] = xstrdup(t); ++ tokens[n_tokens].token = xstrdup(t); ++ tokens[n_tokens].pos = t - xbuf; + ++n_tokens; + } + +@@ -589,10 +592,10 @@ ftpListParseParts(const char *buf, struct Ftp::GatewayFlags flags) + + /* locate the Month field */ + for (i = 3; i < n_tokens - 2; ++i) { +- char *size = tokens[i - 1]; +- char *month = tokens[i]; +- char *day = tokens[i + 1]; +- char *year = tokens[i + 2]; ++ const char *size = tokens[i - 1].token; ++ char *month = tokens[i].token; ++ char *day = tokens[i + 1].token; ++ char *year = tokens[i + 2].token; + + if (!is_month(month)) + continue; +@@ -606,23 +609,27 @@ ftpListParseParts(const char *buf, struct Ftp::GatewayFlags flags) + if (regexec(&scan_ftp_time, year, 0, NULL, 0) != 0) /* Yr | hh:mm */ + continue; + +- snprintf(tbuf, 128, "%s %2s %5s", +- month, day, year); ++ const char *copyFrom = buf + tokens[i].pos; + +- if (!strstr(buf, tbuf)) +- snprintf(tbuf, 128, "%s %2s %-5s", +- month, day, year); ++ // "MMM DD [ YYYY|hh:mm]" with at most two spaces between DD and YYYY ++ int dateSize = snprintf(tbuf, sizeof(tbuf), "%s %2s %5s", month, day, year); ++ bool isTypeA = (dateSize == 12) && (strncmp(copyFrom, tbuf, dateSize) == 0); + +- char const *copyFrom = NULL; ++ // "MMM DD [YYYY|hh:mm]" with one space between DD and YYYY ++ dateSize = snprintf(tbuf, sizeof(tbuf), "%s %2s %-5s", month, day, year); ++ bool isTypeB = (dateSize == 12 || dateSize == 11) && (strncmp(copyFrom, tbuf, dateSize) == 0); + +- if ((copyFrom = strstr(buf, tbuf))) { +- p->type = *tokens[0]; ++ // TODO: replace isTypeA and isTypeB with a regex. ++ if (isTypeA || isTypeB) { ++ p->type = *tokens[0].token; + p->size = strtoll(size, NULL, 10); ++ const int finalDateSize = snprintf(tbuf, sizeof(tbuf), "%s %2s %5s", month, day, year); ++ assert(finalDateSize >= 0); + p->date = xstrdup(tbuf); + ++ // point after tokens[i+2] : ++ copyFrom = buf + tokens[i + 2].pos + strlen(tokens[i + 2].token); + if (flags.skip_whitespace) { +- copyFrom += strlen(tbuf); +- + while (strchr(w_space, *copyFrom)) + ++copyFrom; + } else { +@@ -634,7 +641,6 @@ ftpListParseParts(const char *buf, struct Ftp::GatewayFlags flags) + * Assuming a single space between date and filename + * suggested by: Nathan.Bailey@cc.monash.edu.au and + * Mike Battersby <mike@starbug.bofh.asn.au> */ +- copyFrom += strlen(tbuf); + if (strchr(w_space, *copyFrom)) + ++copyFrom; + } +@@ -654,45 +660,36 @@ ftpListParseParts(const char *buf, struct Ftp::GatewayFlags flags) + + /* try it as a DOS listing, 04-05-70 09:33PM ... */ + if (n_tokens > 3 && +- regexec(&scan_ftp_dosdate, tokens[0], 0, NULL, 0) == 0 && +- regexec(&scan_ftp_dostime, tokens[1], 0, NULL, 0) == 0) { +- if (!strcasecmp(tokens[2], "<dir>")) { ++ regexec(&scan_ftp_dosdate, tokens[0].token, 0, NULL, 0) == 0 && ++ regexec(&scan_ftp_dostime, tokens[1].token, 0, NULL, 0) == 0) { ++ if (!strcasecmp(tokens[2].token, "<dir>")) { + p->type = 'd'; + } else { + p->type = '-'; +- p->size = strtoll(tokens[2], NULL, 10); ++ p->size = strtoll(tokens[2].token, NULL, 10); + } + +- snprintf(tbuf, 128, "%s %s", tokens[0], tokens[1]); ++ snprintf(tbuf, sizeof(tbuf), "%s %s", tokens[0].token, tokens[1].token); + p->date = xstrdup(tbuf); + + if (p->type == 'd') { +- /* Directory.. name begins with first printable after <dir> */ +- ct = strstr(buf, tokens[2]); +- ct += strlen(tokens[2]); +- +- while (xisspace(*ct)) +- ++ct; +- +- if (!*ct) +- ct = NULL; ++ // Directory.. name begins with first printable after <dir> ++ // Because of the "n_tokens > 3", the next printable after <dir> ++ // is stored at token[3]. No need for more checks here. + } else { +- /* A file. Name begins after size, with a space in between */ +- snprintf(tbuf, 128, " %s %s", tokens[2], tokens[3]); +- ct = strstr(buf, tbuf); +- +- if (ct) { +- ct += strlen(tokens[2]) + 2; +- } ++ // A file. Name begins after size, with a space in between. ++ // Also a space should exist before size. ++ // But there is not needed to be very strict with spaces. ++ // The name is stored at token[3], take it from here. + } + +- p->name = xstrdup(ct ? ct : tokens[3]); ++ p->name = xstrdup(tokens[3].token); + goto found; + } + + /* Try EPLF format; carson@lehman.com */ + if (buf[0] == '+') { +- ct = buf + 1; ++ const char *ct = buf + 1; + p->type = 0; + + while (ct && *ct) { +@@ -763,7 +760,7 @@ blank: + found: + + for (i = 0; i < n_tokens; ++i) +- xfree(tokens[i]); ++ xfree(tokens[i].token); + + if (!p->name) + ftpListPartsFree(&p); /* cleanup */ |