]> 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.
 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)
   /* Get greeting.  */
   err = ftp_response (csock, &respline);
   if (err != FTPOK)
-    {
-      xfree (respline);
-      return err;
-    }
+    return err;
   if (*respline != '2')
     {
       xfree (respline);
   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;
 }
 
   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.
 
 /* 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)
 {
 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 {
 }
 
 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.
 
    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 *
 
    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 */
 
   char *hunk = xmalloc (bufsize);
   int tail = 0;                        /* tail position in HUNK */
 
+  assert (maxsize >= bufsize);
+
   while (1)
     {
       const char *end;
   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;
        }
          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
       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)
        {
 
       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.
    In the former case errno indicates the error condition, and in the
 
    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)
 {
 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
 }
 \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));
 
 
 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 **,
 char *fd_read_line PARAMS ((int));
 
 uerr_t retrieve_url PARAMS ((const char *, char **, char **,