From f4aeb4189958cf9b2b6d134fd42b89bc9a3c401f Mon Sep 17 00:00:00 2001 From: Tobias Stoeckmann Date: Wed, 10 Aug 2016 19:09:34 +0200 Subject: [PATCH] Fix stack overflow with way too many cookies * src/cookies.c (cookie_header): Use heap instead of stack. * src/http.c (request_send): Likewise. If wget has to handle an insanely large amount of cookies (~700,000 on 32 bit systems or ~530,000 on 64 bit systems), the stack is not large enough to hold these pointers, leading to undefined behaviour according to POSIX; expect a segmentation fault in real life. ;) Signed-off-by: Tobias Stoeckmann --- bootstrap.conf | 1 + src/cookies.c | 14 +++++++++----- src/http.c | 5 +++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/bootstrap.conf b/bootstrap.conf index a20d8da8..2b225b72 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -84,6 +84,7 @@ snprintf socket spawn-pipe stdbool +stdint strcase strerror_r-posix strptime diff --git a/src/cookies.c b/src/cookies.c index 81ecfa57..767b2849 100644 --- a/src/cookies.c +++ b/src/cookies.c @@ -45,6 +45,7 @@ as that of the covered work. */ #include "wget.h" +#include #include #include #include @@ -1018,7 +1019,7 @@ cookie_header (struct cookie_jar *jar, const char *host, struct cookie *cookie; struct weighed_cookie *outgoing; - int count, i, ocnt; + size_t count, i, ocnt; char *result; int result_size, pos; PREPEND_SLASH (path); /* see cookie_handle_set_cookie */ @@ -1032,7 +1033,7 @@ cookie_header (struct cookie_jar *jar, const char *host, chain_count = find_chains_of_host (jar, host, chains); /* No cookies for this host. */ - if (!chain_count) + if (chain_count <= 0) return NULL; cookies_now = time (NULL); @@ -1043,7 +1044,7 @@ cookie_header (struct cookie_jar *jar, const char *host, /* Count the number of matching cookies. */ count = 0; - for (i = 0; i < chain_count; i++) + for (i = 0; i < (unsigned) chain_count; i++) for (cookie = chains[i]; cookie; cookie = cookie->next) if (cookie_matches_url (cookie, host, port, path, secflag, NULL)) ++count; @@ -1051,12 +1052,14 @@ cookie_header (struct cookie_jar *jar, const char *host, return NULL; /* no cookies matched */ /* Allocate the array. */ - outgoing = alloca_array (struct weighed_cookie, count); + if (count > SIZE_MAX / sizeof (struct weighed_cookie)) + return NULL; /* unable to process so many cookies */ + outgoing = xmalloc (count * sizeof (struct weighed_cookie)); /* Fill the array with all the matching cookies from the chains that match HOST. */ ocnt = 0; - for (i = 0; i < chain_count; i++) + for (i = 0; i < (unsigned) chain_count; i++) for (cookie = chains[i]; cookie; cookie = cookie->next) { int pg; @@ -1111,6 +1114,7 @@ cookie_header (struct cookie_jar *jar, const char *host, } } result[pos++] = '\0'; + xfree (outgoing); assert (pos == result_size); return result; } diff --git a/src/http.c b/src/http.c index 1091121b..56b8669d 100644 --- a/src/http.c +++ b/src/http.c @@ -344,7 +344,7 @@ request_send (const struct request *req, int fd, FILE *warc_tmp) /* "\r\n\0" */ size += 3; - p = request_string = alloca_array (char, size); + p = request_string = xmalloc (size); /* Generate the request. */ @@ -379,8 +379,9 @@ request_send (const struct request *req, int fd, FILE *warc_tmp) /* Write a copy of the data to the WARC record. */ int warc_tmp_written = fwrite (request_string, 1, size - 1, warc_tmp); if (warc_tmp_written != size - 1) - return -2; + write_error = -2; } + xfree (request_string); return write_error; }