]> sjero.net Git - wget/commitdiff
[svn] Limit the maximum amount of memory allocated by fd_read_hunk and its
authorhniksic <devnull@localhost>
Sat, 19 Mar 2005 17:35:15 +0000 (09:35 -0800)
committerhniksic <devnull@localhost>
Sat, 19 Mar 2005 17:35:15 +0000 (09:35 -0800)
callers.  Don't allocate more than 64k bytes on headers; don't allocate
more than 4k bytes on a single line.

src/ChangeLog
src/ftp-basic.c
src/http.c
src/retr.c
src/retr.h

index 2bc2c55792f20459620d95958dba9c2308b2dec7..67059694594e2b865ce00de6ad00362751c76f21 100644 (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>
 
        * wget.h: Include options.h after wgint has been defined.
index 5960ade619ad4c49a873fe21982f2f9c93fc6b08..5d32aadc626a5447e368793820940fbe1fd89f0b 100644 (file)
@@ -123,10 +123,7 @@ ftp_login (int csock, const char *acc, const char *pass)
   /* Get greeting.  */
   err = ftp_response (csock, &respline);
   if (err != FTPOK)
-    {
-      xfree (respline);
-      return err;
-    }
+    return err;
   if (*respline != '2')
     {
       xfree (respline);
index 646a031e4e7c9ad4d164de321dd1597dd6ccc415..c77a93af58ff24c3983ab0ec357b65c5000841a4 100644 (file)
@@ -432,6 +432,13 @@ response_head_terminator (const char *hunk, int oldlen, int peeklen)
   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
    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 *
 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 {
index ef142bceb881330b03ee450f11a7b2b0b7bd6aff..978fb7284036960cc0dc3dc2605e8b7d90644d0f 100644 (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
    process is retried until all data arrives safely.
 
-   BUFSIZE is the size of the initial buffer expected to read all the
-   data in the typical case.
+   SIZEHINT is the buffer size sufficient to hold all the data in the
+   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
    functions -- see fd_read_line as a simple example.  */
 
 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);
   int tail = 0;                        /* tail position in HUNK */
 
+  assert (maxsize >= bufsize);
+
   while (1)
     {
       const char *end;
@@ -400,7 +405,7 @@ fd_read_hunk (int fd, hunk_terminator_t hunk_terminator, int bufsize)
          xfree (hunk);
          return NULL;
        }
-      end = hunk_terminator (hunk, tail, pklen);
+      end = terminator (hunk, tail, pklen);
       if (end)
        {
          /* 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)
        {
+         /* Double the buffer size, but refuse to allocate more than
+            MAXSIZE bytes.  */
+         if (maxsize && bufsize >= maxsize)
+           {
+             xfree (hunk);
+             errno = ENOMEM;
+             return NULL;
+           }
          bufsize <<= 1;
+         if (maxsize && bufsize > maxsize)
+           bufsize = maxsize;
          hunk = xrealloc (hunk, bufsize);
        }
     }
@@ -474,8 +489,14 @@ line_terminator (const char *hunk, int oldlen, int peeklen)
   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
-   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.
    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 *
 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);
 }
 \f
 /* Return a printed representation of the download rate, as
index fa90ea9523f9fc10636c3b2045d537c36d7e987f..6f896d97c8f720905c2099193433f39a2748879b 100644 (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));
 
-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));
 
 uerr_t retrieve_url PARAMS ((const char *, char **, char **,