Blob Blame History Raw
From 680f72e4b9a72abe924cc3b3f0b10819a38a423c Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Mon, 24 Apr 2017 15:33:57 +0200
Subject: [PATCH 1/6] http: use private user:password output buffer

Don't clobber the receive buffer.

Upstream-commit: 94460878cc634b590a7282e3fe60ceafb62d141a
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/http.c | 28 +++++++++++++++++-----------
 1 file changed, 17 insertions(+), 11 deletions(-)

diff --git a/lib/http.c b/lib/http.c
index bd48831..553cfe8 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -285,6 +285,7 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy)
   const char *user;
   const char *pwd;
   CURLcode result;
+  char *out;
 
   if(proxy) {
     userp = &conn->allocptr.proxyuserpwd;
@@ -297,27 +298,32 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy)
     pwd = conn->passwd;
   }
 
-  snprintf(data->state.buffer, CURL_BUFSIZE(data->set.buffer_size),
-           "%s:%s", user, pwd);
+  out = aprintf("%s:%s", user, pwd);
+  if(!out)
+    return CURLE_OUT_OF_MEMORY;
 
-  result = Curl_base64_encode(data,
-                              data->state.buffer, strlen(data->state.buffer),
-                              &authorization, &size);
+  result = Curl_base64_encode(data, out, strlen(out), &authorization, &size);
   if(result)
-    return result;
+    goto fail;
 
-  if(!authorization)
-    return CURLE_REMOTE_ACCESS_DENIED;
+  if(!authorization) {
+    result = CURLE_REMOTE_ACCESS_DENIED;
+    goto fail;
+  }
 
   free(*userp);
   *userp = aprintf("%sAuthorization: Basic %s\r\n",
                    proxy ? "Proxy-" : "",
                    authorization);
   free(authorization);
-  if(!*userp)
-    return CURLE_OUT_OF_MEMORY;
+  if(!*userp) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto fail;
+  }
 
-  return CURLE_OK;
+  fail:
+  free(out);
+  return result;
 }
 
 /* pickoneauth() selects the most favourable authentication method from the
-- 
2.14.3


From b296481dc5e24a57ad5e3c3edf8473a04af0f52b Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Mon, 24 Apr 2017 16:05:46 +0200
Subject: [PATCH 2/6] ftp: use private buffer for temp storage, not receive
 buffer

Upstream-commit: 349789e645a306a6ee467ef90a57f6cc306ca92e
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/ftp.c | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/lib/ftp.c b/lib/ftp.c
index cab3699..fa8a29b 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -2101,17 +2101,17 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
       /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
          last .sss part is optional and means fractions of a second */
       int year, month, day, hour, minute, second;
-      char *buf = data->state.buffer;
-      if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
+      if(6 == sscanf(&data->state.buffer[4], "%04d%02d%02d%02d%02d%02d",
                      &year, &month, &day, &hour, &minute, &second)) {
         /* we have a time, reformat it */
+        char timebuf[24];
         time_t secs=time(NULL);
-        /* using the good old yacc/bison yuck */
-        snprintf(buf, CURL_BUFSIZE(conn->data->set.buffer_size),
+
+        snprintf(timebuf, sizeof(timebuf),
                  "%04d%02d%02d %02d:%02d:%02d GMT",
                  year, month, day, hour, minute, second);
         /* now, convert this into a time() value: */
-        data->info.filetime = (long)curl_getdate(buf, &secs);
+        data->info.filetime = (long)curl_getdate(timebuf, &secs);
       }
 
 #ifdef CURL_FTP_HTTPSTYLE_HEAD
@@ -2122,6 +2122,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
          ftpc->file &&
          data->set.get_filetime &&
          (data->info.filetime>=0) ) {
+        char headerbuf[128];
         time_t filetime = (time_t)data->info.filetime;
         struct tm buffer;
         const struct tm *tm = &buffer;
@@ -2131,7 +2132,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
           return result;
 
         /* format: "Tue, 15 Nov 1994 12:45:26" */
-        snprintf(buf, BUFSIZE-1,
+        snprintf(headerbuf, sizeof(headerbuf),
                  "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
                  Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
                  tm->tm_mday,
@@ -2140,7 +2141,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
                  tm->tm_hour,
                  tm->tm_min,
                  tm->tm_sec);
-        result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
+        result = Curl_client_write(conn, CLIENTWRITE_BOTH, headerbuf, 0);
         if(result)
           return result;
       } /* end of a ridiculous amount of conditionals */
@@ -2318,9 +2319,10 @@ static CURLcode ftp_state_size_resp(struct connectdata *conn,
   if(instate == FTP_SIZE) {
 #ifdef CURL_FTP_HTTPSTYLE_HEAD
     if(-1 != filesize) {
-      snprintf(buf, CURL_BUFSIZE(data->set.buffer_size),
+      char clbuf[128];
+      snprintf(clbuf, sizeof(clbuf),
                "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
-      result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
+      result = Curl_client_write(conn, CLIENTWRITE_BOTH, clbuf, 0);
       if(result)
         return result;
     }
@@ -2421,7 +2423,6 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
   CURLcode result = CURLE_OK;
   struct Curl_easy *data = conn->data;
   struct FTP *ftp = data->req.protop;
-  char *buf = data->state.buffer;
 
   if((ftpcode == 150) || (ftpcode == 125)) {
 
@@ -2465,6 +2466,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
        *
        * Example D above makes this parsing a little tricky */
       char *bytes;
+      char *buf = data->state.buffer;
       bytes=strstr(buf, " bytes");
       if(bytes--) {
         long in=(long)(bytes-buf);
-- 
2.14.3


From eff37c35be39bd7671bfc99b2035a99bf5396ff1 Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Tue, 25 Apr 2017 00:09:22 +0200
Subject: [PATCH 3/6] CURLOPT_BUFFERSIZE: 1024 bytes is now the minimum size

The buffer is needed to receive FTP, HTTP CONNECT responses etc so
already at this size things risk breaking and smaller is certainly not
wise.

Upstream-commit: c2ddc12d6086b522703c8b80a72ab791680f1a28
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/url.c     | 15 +++++++++------
 lib/urldata.h |  1 +
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/lib/url.c b/lib/url.c
index 93a6447..c248507 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -2283,15 +2283,17 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
      * The application kindly asks for a differently sized receive buffer.
      * If it seems reasonable, we'll use it.
      */
-    data->set.buffer_size = va_arg(param, long);
+    arg = va_arg(param, long);
 
-    if(data->set.buffer_size > MAX_BUFSIZE)
-      data->set.buffer_size = MAX_BUFSIZE; /* huge internal default */
-    else if(data->set.buffer_size < 1)
-      data->set.buffer_size = BUFSIZE;
+    if(arg > MAX_BUFSIZE)
+      arg = MAX_BUFSIZE; /* huge internal default */
+    else if(arg < 1)
+      arg = BUFSIZE;
+    else if(arg < MIN_BUFSIZE)
+      arg = BUFSIZE;
 
     /* Resize only if larger than default buffer size. */
-    if(data->set.buffer_size > BUFSIZE) {
+    if(arg > BUFSIZE) {
       data->state.buffer = realloc(data->state.buffer,
                                    data->set.buffer_size + 1);
       if(!data->state.buffer) {
@@ -2299,6 +2301,7 @@ CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
         result = CURLE_OUT_OF_MEMORY;
       }
     }
+    data->set.buffer_size = arg;
 
     break;
 
diff --git a/lib/urldata.h b/lib/urldata.h
index 2b9f951..d8d9b35 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -205,6 +205,7 @@
 #define BUFSIZE CURL_MAX_WRITE_SIZE
 #undef MAX_BUFSIZE
 #define MAX_BUFSIZE CURL_MAX_READ_SIZE
+#define MIN_BUFSIZE 1024
 #define CURL_BUFSIZE(x) ((x)?(x):(BUFSIZE))
 
 /* Initial size of the buffer to store headers in, it'll be enlarged in case
-- 
2.14.3


From 71ffc3a5b6cfefae49c16857de8746e4f0741e11 Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Tue, 25 Apr 2017 00:15:28 +0200
Subject: [PATCH 4/6] file: use private buffer for C-L output

... instead of clobbering the download buffer.

Upstream-commit: 7c312f84ea930d89c0f0f774b50032c4f9ae30e4
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/file.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/lib/file.c b/lib/file.c
index e90902c..302076d 100644
--- a/lib/file.c
+++ b/lib/file.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -476,9 +476,10 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
     time_t filetime;
     struct tm buffer;
     const struct tm *tm = &buffer;
-    snprintf(buf, CURL_BUFSIZE(data->set.buffer_size),
+    char header[80];
+    snprintf(header, sizeof(header),
              "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", expected_size);
-    result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
+    result = Curl_client_write(conn, CLIENTWRITE_BOTH, header, 0);
     if(result)
       return result;
 
@@ -493,7 +494,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
       return result;
 
     /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
-    snprintf(buf, BUFSIZE-1,
+    snprintf(header, sizeof(header),
              "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
              Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
              tm->tm_mday,
-- 
2.14.3


From 9ef22a7e4ab98008f545fe59246c30594ca106de Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Tue, 25 Apr 2017 00:16:10 +0200
Subject: [PATCH 5/6] buffer_size: make sure it always has the correct size

Removes the need for CURL_BUFSIZE

Upstream-commit: f535f4f5fc6cbdce1aec5a3481cec37369dca468
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/easy.c    | 2 +-
 lib/ftp.c     | 2 +-
 lib/telnet.c  | 2 +-
 lib/url.c     | 1 +
 lib/urldata.h | 1 -
 5 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/lib/easy.c b/lib/easy.c
index bed94a4..97d393e 100644
--- a/lib/easy.c
+++ b/lib/easy.c
@@ -871,7 +871,7 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
    * the likeliness of us forgetting to init a buffer here in the future.
    */
   outcurl->set.buffer_size = data->set.buffer_size;
-  outcurl->state.buffer = malloc(CURL_BUFSIZE(outcurl->set.buffer_size) + 1);
+  outcurl->state.buffer = malloc(outcurl->set.buffer_size + 1);
   if(!outcurl->state.buffer)
     goto fail;
 
diff --git a/lib/ftp.c b/lib/ftp.c
index fa8a29b..388cbbc 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -2825,7 +2825,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
     case FTP_PWD:
       if(ftpcode == 257) {
         char *ptr=&data->state.buffer[4];  /* start on the first letter */
-        const size_t buf_size = CURL_BUFSIZE(data->set.buffer_size);
+        const size_t buf_size = data->set.buffer_size;
         char *dir;
         char *store;
         bool entry_extracted = FALSE;
diff --git a/lib/telnet.c b/lib/telnet.c
index 162cab7..7e54e07 100644
--- a/lib/telnet.c
+++ b/lib/telnet.c
@@ -1416,7 +1416,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
 
   /* Keep on listening and act on events */
   while(keepon) {
-    const DWORD buf_size = (DWORD)CURL_BUFSIZE(data->set.buffer_size);
+    const DWORD buf_size = (DWORD)data->set.buffer_size;
     waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
     switch(waitret) {
     case WAIT_TIMEOUT:
diff --git a/lib/url.c b/lib/url.c
index c248507..81c5017 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -610,6 +610,7 @@ CURLcode Curl_init_userdefined(struct UserDefined *set)
 
   set->expect_100_timeout = 1000L; /* Wait for a second by default. */
   set->sep_headers = TRUE; /* separated header lists by default */
+  set->buffer_size = BUFSIZE;
 
   Curl_http2_init_userset(set);
   return result;
diff --git a/lib/urldata.h b/lib/urldata.h
index d8d9b35..cd09f5a 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -206,7 +206,6 @@
 #undef MAX_BUFSIZE
 #define MAX_BUFSIZE CURL_MAX_READ_SIZE
 #define MIN_BUFSIZE 1024
-#define CURL_BUFSIZE(x) ((x)?(x):(BUFSIZE))
 
 /* Initial size of the buffer to store headers in, it'll be enlarged in case
    of need. */
-- 
2.14.3


From c6721356b97629ac8fd9089139073938ba530403 Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Thu, 8 Mar 2018 10:33:16 +0100
Subject: [PATCH 6/6] readwrite: make sure excess reads don't go beyond buffer
 end

CVE-2018-1000122
Bug: https://curl.haxx.se/docs/adv_2018-b047.html

Detected by OSS-fuzz

Upstream-commit: d52dc4760f6d9ca1937eefa2093058a952465128
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 lib/transfer.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/lib/transfer.c b/lib/transfer.c
index a577bf7..62cf36b 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -791,10 +791,15 @@ static CURLcode readwrite_data(struct Curl_easy *data,
 
     } /* if(!header and data to read) */
 
-    if(conn->handler->readwrite &&
-       (excess > 0 && !conn->bits.stream_was_rewound)) {
+    if(conn->handler->readwrite && excess && !conn->bits.stream_was_rewound) {
       /* Parse the excess data */
       k->str += nread;
+
+      if(&k->str[excess] > &k->buf[data->set.buffer_size]) {
+        /* the excess amount was too excessive(!), make sure
+           it doesn't read out of buffer */
+        excess = &k->buf[data->set.buffer_size] - k->str;
+      }
       nread = (ssize_t)excess;
 
       result = conn->handler->readwrite(data, conn, &nread, &readmore);
-- 
2.14.3