From 661aff850ec55fdd3a73904417efb303dfdab51f Mon Sep 17 00:00:00 2001 From: Armin Kuster Date: Sat, 17 Sep 2016 22:33:07 -0700 Subject: wget: Security fix CVE-2016-4971 affects wget < 1.18.0 (From OE-Core rev: 15b6586ae64f745777ba5c42f4cf055aeeed83d8) Signed-off-by: Armin Kuster Signed-off-by: Richard Purdie --- .../recipes-extended/wget/wget/CVE-2016-4971.patch | 294 +++++++++++++++++++++ ...mping-and-continue-behaviour-with-ftp-pro.patch | 108 ++++++++ meta/recipes-extended/wget/wget_1.16.3.bb | 2 + 3 files changed, 404 insertions(+) create mode 100644 meta/recipes-extended/wget/wget/CVE-2016-4971.patch create mode 100644 meta/recipes-extended/wget/wget/Fix-timestamping-and-continue-behaviour-with-ftp-pro.patch diff --git a/meta/recipes-extended/wget/wget/CVE-2016-4971.patch b/meta/recipes-extended/wget/wget/CVE-2016-4971.patch new file mode 100644 index 0000000000..62583d9b9a --- /dev/null +++ b/meta/recipes-extended/wget/wget/CVE-2016-4971.patch @@ -0,0 +1,294 @@ +From e996e322ffd42aaa051602da182d03178d0f13e1 Mon Sep 17 00:00:00 2001 +From: Giuseppe Scrivano +Date: Mon, 6 Jun 2016 21:20:24 +0200 +Subject: [PATCH] ftp: understand --trust-server-names on a HTTP->FTP redirect + +If not --trust-server-names is used, FTP will also get the destination +file name from the original url specified by the user instead of the +redirected url. Closes CVE-2016-4971. + +* src/ftp.c (ftp_get_listing): Add argument original_url. +(getftp): Likewise. +(ftp_loop_internal): Likewise. Use original_url to generate the +file name if --trust-server-names is not provided. +(ftp_retrieve_glob): Likewise. +(ftp_loop): Likewise. + +Signed-off-by: Giuseppe Scrivano + +Upstream-Status: Backport +CVE: CVE-2016-4971 +Signed-off-by: Armin Kuster + +--- + src/ftp.c | 71 +++++++++++++++++++++++++++++++++++++------------------------- + src/ftp.h | 3 ++- + src/retr.c | 3 ++- + 3 files changed, 47 insertions(+), 30 deletions(-) + +Index: wget-1.16.3/src/ftp.c +=================================================================== +--- wget-1.16.3.orig/src/ftp.c ++++ wget-1.16.3/src/ftp.c +@@ -235,14 +235,15 @@ print_length (wgint size, wgint start, b + logputs (LOG_VERBOSE, !authoritative ? _(" (unauthoritative)\n") : "\n"); + } + +-static uerr_t ftp_get_listing (struct url *, ccon *, struct fileinfo **); ++static uerr_t ftp_get_listing (struct url *, struct url *, ccon *, struct fileinfo **); + + /* Retrieves a file with denoted parameters through opening an FTP + connection to the server. It always closes the data connection, + and closes the control connection in case of error. If warc_tmp + is non-NULL, the downloaded data will be written there as well. */ + static uerr_t +-getftp (struct url *u, wgint passed_expected_bytes, wgint *qtyread, ++getftp (struct url *u, struct url *original_url, ++ wgint passed_expected_bytes, wgint *qtyread, + wgint restval, ccon *con, int count, wgint *last_expected_bytes, + FILE *warc_tmp) + { +@@ -996,7 +997,7 @@ Error in server response, closing contro + { + bool exists = false; + struct fileinfo *f; +- uerr_t _res = ftp_get_listing (u, con, &f); ++ uerr_t _res = ftp_get_listing (u, original_url, con, &f); + /* Set the DO_RETR command flag again, because it gets unset when + calling ftp_get_listing() and would otherwise cause an assertion + failure earlier on when this function gets repeatedly called +@@ -1540,8 +1541,8 @@ Error in server response, closing contro + This loop either gets commands from con, or (if ON_YOUR_OWN is + set), makes them up to retrieve the file given by the URL. */ + static uerr_t +-ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_file, +- bool force_full_retrieve) ++ftp_loop_internal (struct url *u, struct url *original_url, struct fileinfo *f, ++ ccon *con, char **local_file, bool force_full_retrieve) + { + int count, orig_lp; + wgint restval, len = 0, qtyread = 0; +@@ -1566,7 +1567,7 @@ ftp_loop_internal (struct url *u, struct + { + /* URL-derived file. Consider "-O file" name. */ + xfree (con->target); +- con->target = url_file_name (u, NULL); ++ con->target = url_file_name (opt.trustservernames || !original_url ? u : original_url, NULL); + if (!opt.output_document) + locf = con->target; + else +@@ -1684,8 +1685,8 @@ ftp_loop_internal (struct url *u, struct + + /* If we are working on a WARC record, getftp should also write + to the warc_tmp file. */ +- err = getftp (u, len, &qtyread, restval, con, count, &last_expected_bytes, +- warc_tmp); ++ err = getftp (u, original_url, len, &qtyread, restval, con, count, ++ &last_expected_bytes, warc_tmp); + + if (con->csock == -1) + con->st &= ~DONE_CWD; +@@ -1838,7 +1839,8 @@ Removing file due to --delete-after in f + /* Return the directory listing in a reusable format. The directory + is specifed in u->dir. */ + static uerr_t +-ftp_get_listing (struct url *u, ccon *con, struct fileinfo **f) ++ftp_get_listing (struct url *u, struct url *original_url, ccon *con, ++ struct fileinfo **f) + { + uerr_t err; + char *uf; /* url file name */ +@@ -1859,7 +1861,7 @@ ftp_get_listing (struct url *u, ccon *co + + con->target = xstrdup (lf); + xfree (lf); +- err = ftp_loop_internal (u, NULL, con, NULL, false); ++ err = ftp_loop_internal (u, original_url, NULL, con, NULL, false); + lf = xstrdup (con->target); + xfree (con->target); + con->target = old_target; +@@ -1882,8 +1884,9 @@ ftp_get_listing (struct url *u, ccon *co + return err; + } + +-static uerr_t ftp_retrieve_dirs (struct url *, struct fileinfo *, ccon *); +-static uerr_t ftp_retrieve_glob (struct url *, ccon *, int); ++static uerr_t ftp_retrieve_dirs (struct url *, struct url *, ++ struct fileinfo *, ccon *); ++static uerr_t ftp_retrieve_glob (struct url *, struct url *, ccon *, int); + static struct fileinfo *delelement (struct fileinfo *, struct fileinfo **); + static void freefileinfo (struct fileinfo *f); + +@@ -1895,7 +1898,8 @@ static void freefileinfo (struct fileinf + If opt.recursive is set, after all files have been retrieved, + ftp_retrieve_dirs will be called to retrieve the directories. */ + static uerr_t +-ftp_retrieve_list (struct url *u, struct fileinfo *f, ccon *con) ++ftp_retrieve_list (struct url *u, struct url *original_url, ++ struct fileinfo *f, ccon *con) + { + static int depth = 0; + uerr_t err; +@@ -2056,7 +2060,10 @@ Already have correct symlink %s -> %s\n\ + else /* opt.retr_symlinks */ + { + if (dlthis) +- err = ftp_loop_internal (u, f, con, NULL, force_full_retrieve); ++ { ++ err = ftp_loop_internal (u, original_url, f, con, NULL, ++ force_full_retrieve); ++ } + } /* opt.retr_symlinks */ + break; + case FT_DIRECTORY: +@@ -2067,7 +2074,10 @@ Already have correct symlink %s -> %s\n\ + case FT_PLAINFILE: + /* Call the retrieve loop. */ + if (dlthis) +- err = ftp_loop_internal (u, f, con, NULL, force_full_retrieve); ++ { ++ err = ftp_loop_internal (u, original_url, f, con, NULL, ++ force_full_retrieve); ++ } + break; + case FT_UNKNOWN: + logprintf (LOG_NOTQUIET, _("%s: unknown/unsupported file type.\n"), +@@ -2132,7 +2142,7 @@ Already have correct symlink %s -> %s\n\ + /* We do not want to call ftp_retrieve_dirs here */ + if (opt.recursive && + !(opt.reclevel != INFINITE_RECURSION && depth >= opt.reclevel)) +- err = ftp_retrieve_dirs (u, orig, con); ++ err = ftp_retrieve_dirs (u, original_url, orig, con); + else if (opt.recursive) + DEBUGP ((_("Will not retrieve dirs since depth is %d (max %d).\n"), + depth, opt.reclevel)); +@@ -2145,7 +2155,8 @@ Already have correct symlink %s -> %s\n\ + ftp_retrieve_glob on each directory entry. The function knows + about excluded directories. */ + static uerr_t +-ftp_retrieve_dirs (struct url *u, struct fileinfo *f, ccon *con) ++ftp_retrieve_dirs (struct url *u, struct url *original_url, ++ struct fileinfo *f, ccon *con) + { + char *container = NULL; + int container_size = 0; +@@ -2195,7 +2206,7 @@ Not descending to %s as it is excluded/n + odir = xstrdup (u->dir); /* because url_set_dir will free + u->dir. */ + url_set_dir (u, newdir); +- ftp_retrieve_glob (u, con, GLOB_GETALL); ++ ftp_retrieve_glob (u, original_url, con, GLOB_GETALL); + url_set_dir (u, odir); + xfree (odir); + +@@ -2254,14 +2265,15 @@ is_invalid_entry (struct fileinfo *f) + GLOB_GLOBALL, use globbing; if it's GLOB_GETALL, download the whole + directory. */ + static uerr_t +-ftp_retrieve_glob (struct url *u, ccon *con, int action) ++ftp_retrieve_glob (struct url *u, struct url *original_url, ++ ccon *con, int action) + { + struct fileinfo *f, *start; + uerr_t res; + + con->cmd |= LEAVE_PENDING; + +- res = ftp_get_listing (u, con, &start); ++ res = ftp_get_listing (u, original_url, con, &start); + if (res != RETROK) + return res; + /* First: weed out that do not conform the global rules given in +@@ -2357,7 +2369,7 @@ ftp_retrieve_glob (struct url *u, ccon * + if (start) + { + /* Just get everything. */ +- res = ftp_retrieve_list (u, start, con); ++ res = ftp_retrieve_list (u, original_url, start, con); + } + else + { +@@ -2373,7 +2385,7 @@ ftp_retrieve_glob (struct url *u, ccon * + { + /* Let's try retrieving it anyway. */ + con->st |= ON_YOUR_OWN; +- res = ftp_loop_internal (u, NULL, con, NULL, false); ++ res = ftp_loop_internal (u, original_url, NULL, con, NULL, false); + return res; + } + +@@ -2393,8 +2405,8 @@ ftp_retrieve_glob (struct url *u, ccon * + of URL. Inherently, its capabilities are limited on what can be + encoded into a URL. */ + uerr_t +-ftp_loop (struct url *u, char **local_file, int *dt, struct url *proxy, +- bool recursive, bool glob) ++ftp_loop (struct url *u, struct url *original_url, char **local_file, int *dt, ++ struct url *proxy, bool recursive, bool glob) + { + ccon con; /* FTP connection */ + uerr_t res; +@@ -2415,16 +2427,17 @@ ftp_loop (struct url *u, char **local_fi + if (!*u->file && !recursive) + { + struct fileinfo *f; +- res = ftp_get_listing (u, &con, &f); ++ res = ftp_get_listing (u, original_url, &con, &f); + + if (res == RETROK) + { + if (opt.htmlify && !opt.spider) + { ++ struct url *url_file = opt.trustservernames ? u : original_url; + char *filename = (opt.output_document + ? xstrdup (opt.output_document) + : (con.target ? xstrdup (con.target) +- : url_file_name (u, NULL))); ++ : url_file_name (url_file, NULL))); + res = ftp_index (filename, u, f); + if (res == FTPOK && opt.verbose) + { +@@ -2469,11 +2482,13 @@ ftp_loop (struct url *u, char **local_fi + /* ftp_retrieve_glob is a catch-all function that gets called + if we need globbing, time-stamping, recursion or preserve + permissions. Its third argument is just what we really need. */ +- res = ftp_retrieve_glob (u, &con, ++ res = ftp_retrieve_glob (u, original_url, &con, + ispattern ? GLOB_GLOBALL : GLOB_GETONE); + } + else +- res = ftp_loop_internal (u, NULL, &con, local_file, false); ++ { ++ res = ftp_loop_internal (u, original_url, NULL, &con, local_file, false); ++ } + } + if (res == FTPOK) + res = RETROK; +Index: wget-1.16.3/src/ftp.h +=================================================================== +--- wget-1.16.3.orig/src/ftp.h ++++ wget-1.16.3/src/ftp.h +@@ -150,7 +150,8 @@ enum wget_ftp_fstatus + }; + + struct fileinfo *ftp_parse_ls (const char *, const enum stype); +-uerr_t ftp_loop (struct url *, char **, int *, struct url *, bool, bool); ++uerr_t ftp_loop (struct url *, struct url *, char **, int *, struct url *, ++ bool, bool); + + uerr_t ftp_index (const char *, struct url *, struct fileinfo *); + +Index: wget-1.16.3/src/retr.c +=================================================================== +--- wget-1.16.3.orig/src/retr.c ++++ wget-1.16.3/src/retr.c +@@ -807,7 +807,8 @@ retrieve_url (struct url * orig_parsed, + if (redirection_count) + oldrec = glob = false; + +- result = ftp_loop (u, &local_file, dt, proxy_url, recursive, glob); ++ result = ftp_loop (u, orig_parsed, &local_file, dt, proxy_url, ++ recursive, glob); + recursive = oldrec; + + /* There is a possibility of having HTTP being redirected to diff --git a/meta/recipes-extended/wget/wget/Fix-timestamping-and-continue-behaviour-with-ftp-pro.patch b/meta/recipes-extended/wget/wget/Fix-timestamping-and-continue-behaviour-with-ftp-pro.patch new file mode 100644 index 0000000000..a63b6c22cc --- /dev/null +++ b/meta/recipes-extended/wget/wget/Fix-timestamping-and-continue-behaviour-with-ftp-pro.patch @@ -0,0 +1,108 @@ +From 0e6d6ca963f13e0c4d239cd9e7aea62d176da8eb Mon Sep 17 00:00:00 2001 +From: Nikolay Merinov +Date: Fri, 17 Apr 2015 23:32:30 +0500 +Subject: [PATCH] Fix timestamping and continue behaviour with ftp protocol. + +* src/ftp.c (ftp_loop_internal): Add option `force_full_retrieve' that force to +retrieve full file. +(ftp_retrieve_list): Pass `true' as `force_full_retrieve' option to +`ftp_loop_internal' if we want to download file with newer timestamp than local +copy. + +Upstream-Status: Backport +In support of CVE-2016-4971 +Signed-off-by: Armin Kuster + +--- + src/ftp.c | 21 +++++++++++++-------- + 1 file changed, 13 insertions(+), 8 deletions(-) + +Index: wget-1.16.3/src/ftp.c +=================================================================== +--- wget-1.16.3.orig/src/ftp.c ++++ wget-1.16.3/src/ftp.c +@@ -1540,7 +1540,8 @@ Error in server response, closing contro + This loop either gets commands from con, or (if ON_YOUR_OWN is + set), makes them up to retrieve the file given by the URL. */ + static uerr_t +-ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_file) ++ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con, char **local_file, ++ bool force_full_retrieve) + { + int count, orig_lp; + wgint restval, len = 0, qtyread = 0; +@@ -1642,6 +1643,8 @@ ftp_loop_internal (struct url *u, struct + /* Decide whether or not to restart. */ + if (con->cmd & DO_LIST) + restval = 0; ++ else if (force_full_retrieve) ++ restval = 0; + else if (opt.start_pos >= 0) + restval = opt.start_pos; + else if (opt.always_rest +@@ -1856,7 +1859,7 @@ ftp_get_listing (struct url *u, ccon *co + + con->target = xstrdup (lf); + xfree (lf); +- err = ftp_loop_internal (u, NULL, con, NULL); ++ err = ftp_loop_internal (u, NULL, con, NULL, false); + lf = xstrdup (con->target); + xfree (con->target); + con->target = old_target; +@@ -1901,6 +1904,7 @@ ftp_retrieve_list (struct url *u, struct + time_t tml; + bool dlthis; /* Download this (file). */ + const char *actual_target = NULL; ++ bool force_full_retrieve = false; + + /* Increase the depth. */ + ++depth; +@@ -1980,9 +1984,10 @@ ftp_retrieve_list (struct url *u, struct + Remote file no newer than local file %s -- not retrieving.\n"), quote (con->target)); + dlthis = false; + } +- else if (eq_size) ++ else if (f->tstamp > tml) + { +- /* Remote file is newer or sizes cannot be matched */ ++ /* Remote file is newer */ ++ force_full_retrieve = true; + logprintf (LOG_VERBOSE, _("\ + Remote file is newer than local file %s -- retrieving.\n\n"), + quote (con->target)); +@@ -2051,7 +2056,7 @@ Already have correct symlink %s -> %s\n\ + else /* opt.retr_symlinks */ + { + if (dlthis) +- err = ftp_loop_internal (u, f, con, NULL); ++ err = ftp_loop_internal (u, f, con, NULL, force_full_retrieve); + } /* opt.retr_symlinks */ + break; + case FT_DIRECTORY: +@@ -2062,7 +2067,7 @@ Already have correct symlink %s -> %s\n\ + case FT_PLAINFILE: + /* Call the retrieve loop. */ + if (dlthis) +- err = ftp_loop_internal (u, f, con, NULL); ++ err = ftp_loop_internal (u, f, con, NULL, force_full_retrieve); + break; + case FT_UNKNOWN: + logprintf (LOG_NOTQUIET, _("%s: unknown/unsupported file type.\n"), +@@ -2368,7 +2373,7 @@ ftp_retrieve_glob (struct url *u, ccon * + { + /* Let's try retrieving it anyway. */ + con->st |= ON_YOUR_OWN; +- res = ftp_loop_internal (u, NULL, con, NULL); ++ res = ftp_loop_internal (u, NULL, con, NULL, false); + return res; + } + +@@ -2468,7 +2473,7 @@ ftp_loop (struct url *u, char **local_fi + ispattern ? GLOB_GLOBALL : GLOB_GETONE); + } + else +- res = ftp_loop_internal (u, NULL, &con, local_file); ++ res = ftp_loop_internal (u, NULL, &con, local_file, false); + } + if (res == FTPOK) + res = RETROK; diff --git a/meta/recipes-extended/wget/wget_1.16.3.bb b/meta/recipes-extended/wget/wget_1.16.3.bb index 5c34a42dfe..0204f30dc9 100644 --- a/meta/recipes-extended/wget/wget_1.16.3.bb +++ b/meta/recipes-extended/wget/wget_1.16.3.bb @@ -1,6 +1,8 @@ SRC_URI = "${GNU_MIRROR}/wget/wget-${PV}.tar.gz \ file://fix_makefile.patch \ file://0001-Unset-need_charset_alias-when-building-for-musl.patch \ + file://Fix-timestamping-and-continue-behaviour-with-ftp-pro.patch \ + file://CVE-2016-4971.patch \ " SRC_URI[md5sum] = "f61d9011b99f824106a5d5a05dd0f63d" -- cgit v1.2.3-54-g00ecf