1
0
mirror of https://github.com/moparisthebest/wget synced 2024-07-03 16:38:41 -04:00

[svn] Limit the maximum amount of memory allocated by fd_read_hunk and its

callers.  Don't allocate more than 64k bytes on headers; don't allocate
more than 4k bytes on a single line.
This commit is contained in:
hniksic 2005-03-19 09:35:15 -08:00
parent b90b20763b
commit 72ce32e8ab
5 changed files with 53 additions and 12 deletions

View File

@ -1,3 +1,18 @@
2005-03-17 Hrvoje Niksic <hniksic@xemacs.org>
* ftp-basic.c (ftp_login): Don't free the string if ftp_response
returned an error status because the line didn't get allocated in
the first place.
2005-03-15 Hrvoje Niksic <hniksic@xemacs.org>
* http.c (read_http_response_head): Limit the response size to 64k
bytes.
* retr.c (fd_read_hunk): Accept a MAXSIZE argument that limits the
number of bytes the function is allowed to allocate.
(fd_read_line): Limit the line to 4096 bytes.
2005-03-12 Hrvoje Niksic <hniksic@xemacs.org> 2005-03-12 Hrvoje Niksic <hniksic@xemacs.org>
* wget.h: Include options.h after wgint has been defined. * wget.h: Include options.h after wgint has been defined.

View File

@ -123,10 +123,7 @@ ftp_login (int csock, const char *acc, const char *pass)
/* Get greeting. */ /* Get greeting. */
err = ftp_response (csock, &respline); err = ftp_response (csock, &respline);
if (err != FTPOK) if (err != FTPOK)
{ return err;
xfree (respline);
return err;
}
if (*respline != '2') if (*respline != '2')
{ {
xfree (respline); xfree (respline);

View File

@ -432,6 +432,13 @@ response_head_terminator (const char *hunk, int oldlen, int peeklen)
return NULL; return NULL;
} }
/* The maximum size of a single HTTP response we care to read. This
is not meant to impose an arbitrary limit, but to protect the user
from Wget slurping up available memory upon encountering malicious
or buggy server output. Define it to 0 to remove the limit. */
#define HTTP_RESPONSE_MAX_SIZE 65536
/* Read the HTTP request head from FD and return it. The error /* Read the HTTP request head from FD and return it. The error
conditions are the same as with fd_read_hunk. conditions are the same as with fd_read_hunk.
@ -443,7 +450,8 @@ response_head_terminator (const char *hunk, int oldlen, int peeklen)
static char * static char *
read_http_response_head (int fd) read_http_response_head (int fd)
{ {
return fd_read_hunk (fd, response_head_terminator, 512); return fd_read_hunk (fd, response_head_terminator, 512,
HTTP_RESPONSE_MAX_SIZE);
} }
struct response { struct response {

View File

@ -375,18 +375,23 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
a read. If the read returns a different amount of data, the a read. If the read returns a different amount of data, the
process is retried until all data arrives safely. process is retried until all data arrives safely.
BUFSIZE is the size of the initial buffer expected to read all the SIZEHINT is the buffer size sufficient to hold all the data in the
data in the typical case. typical case (it is used as the initial buffer size). MAXSIZE is
the maximum amount of memory this function is allowed to allocate,
or 0 if no upper limit is to be enforced.
This function should be used as a building block for other This function should be used as a building block for other
functions -- see fd_read_line as a simple example. */ functions -- see fd_read_line as a simple example. */
char * char *
fd_read_hunk (int fd, hunk_terminator_t hunk_terminator, int bufsize) fd_read_hunk (int fd, hunk_terminator_t terminator, long sizehint, long maxsize)
{ {
long bufsize = sizehint;
char *hunk = xmalloc (bufsize); char *hunk = xmalloc (bufsize);
int tail = 0; /* tail position in HUNK */ int tail = 0; /* tail position in HUNK */
assert (maxsize >= bufsize);
while (1) while (1)
{ {
const char *end; const char *end;
@ -400,7 +405,7 @@ fd_read_hunk (int fd, hunk_terminator_t hunk_terminator, int bufsize)
xfree (hunk); xfree (hunk);
return NULL; return NULL;
} }
end = hunk_terminator (hunk, tail, pklen); end = terminator (hunk, tail, pklen);
if (end) if (end)
{ {
/* The data contains the terminator: we'll drain the data up /* The data contains the terminator: we'll drain the data up
@ -458,7 +463,17 @@ fd_read_hunk (int fd, hunk_terminator_t hunk_terminator, int bufsize)
if (tail == bufsize - 1) if (tail == bufsize - 1)
{ {
/* Double the buffer size, but refuse to allocate more than
MAXSIZE bytes. */
if (maxsize && bufsize >= maxsize)
{
xfree (hunk);
errno = ENOMEM;
return NULL;
}
bufsize <<= 1; bufsize <<= 1;
if (maxsize && bufsize > maxsize)
bufsize = maxsize;
hunk = xrealloc (hunk, bufsize); hunk = xrealloc (hunk, bufsize);
} }
} }
@ -474,8 +489,14 @@ line_terminator (const char *hunk, int oldlen, int peeklen)
return NULL; return NULL;
} }
/* The maximum size of the single line we agree to accept. This is
not meant to impose an arbitrary limit, but to protect the user
from Wget slurping up available memory upon encountering malicious
or buggy server output. Define it to 0 to remove the limit. */
#define FD_READ_LINE_MAX 4096
/* Read one line from FD and return it. The line is allocated using /* Read one line from FD and return it. The line is allocated using
malloc. malloc, but is never larger than FD_READ_LINE_MAX.
If an error occurs, or if no data can be read, NULL is returned. If an error occurs, or if no data can be read, NULL is returned.
In the former case errno indicates the error condition, and in the In the former case errno indicates the error condition, and in the
@ -484,7 +505,7 @@ line_terminator (const char *hunk, int oldlen, int peeklen)
char * char *
fd_read_line (int fd) fd_read_line (int fd)
{ {
return fd_read_hunk (fd, line_terminator, 128); return fd_read_hunk (fd, line_terminator, 128, FD_READ_LINE_MAX);
} }
/* Return a printed representation of the download rate, as /* Return a printed representation of the download rate, as

View File

@ -41,7 +41,7 @@ int fd_read_body PARAMS ((int, FILE *, wgint, wgint, wgint *, wgint *, double *,
typedef const char *(*hunk_terminator_t) PARAMS ((const char *, int, int)); typedef const char *(*hunk_terminator_t) PARAMS ((const char *, int, int));
char *fd_read_hunk PARAMS ((int, hunk_terminator_t, int)); char *fd_read_hunk PARAMS ((int, hunk_terminator_t, long, long));
char *fd_read_line PARAMS ((int)); char *fd_read_line PARAMS ((int));
uerr_t retrieve_url PARAMS ((const char *, char **, char **, uerr_t retrieve_url PARAMS ((const char *, char **, char **,