Blame SOURCES/0071-curl-7.29.0-CVE-2019-5482.patch

a8283e
From fe9b4ce23f82a3b2564123bbc3c674cc07a04f2b Mon Sep 17 00:00:00 2001
a8283e
From: Thomas Vegas <>
a8283e
Date: Sat, 31 Aug 2019 16:59:56 +0200
a8283e
Subject: [PATCH 1/2] tftp: return error when packet is too small for options
a8283e
a8283e
Upstream-commit: 82f3ba3806a34fe94dcf9e5c9b88deda6679ca1b
a8283e
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
a8283e
---
a8283e
 lib/tftp.c | 76 +++++++++++++++++++++++++++++++++---------------------
a8283e
 1 file changed, 46 insertions(+), 30 deletions(-)
a8283e
a8283e
diff --git a/lib/tftp.c b/lib/tftp.c
a8283e
index 022648a..8ab9d71 100644
a8283e
--- a/lib/tftp.c
a8283e
+++ b/lib/tftp.c
a8283e
@@ -405,13 +405,14 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state,
a8283e
   return CURLE_OK;
a8283e
 }
a8283e
 
a8283e
-static size_t tftp_option_add(tftp_state_data_t *state, size_t csize,
a8283e
-                              char *buf, const char *option)
a8283e
+static CURLcode tftp_option_add(tftp_state_data_t *state, size_t *csize,
a8283e
+                                char *buf, const char *option)
a8283e
 {
a8283e
-  if(( strlen(option) + csize + 1 ) > (size_t)state->blksize)
a8283e
-    return 0;
a8283e
+  if(( strlen(option) + *csize + 1) > (size_t)state->blksize)
a8283e
+    return CURLE_TFTP_ILLEGAL;
a8283e
   strcpy(buf, option);
a8283e
-  return( strlen(option) + 1 );
a8283e
+  *csize += strlen(option) + 1;
a8283e
+  return CURLE_OK;
a8283e
 }
a8283e
 
a8283e
 static CURLcode tftp_connect_for_tx(tftp_state_data_t *state,
a8283e
@@ -498,31 +499,46 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
a8283e
     sbytes = 4 + strlen(filename) + strlen(mode);
a8283e
 
a8283e
     /* add tsize option */
a8283e
-    if(data->set.upload && (data->set.infilesize != -1))
a8283e
-      snprintf( buf, sizeof(buf), "%" FORMAT_OFF_T, data->set.infilesize );
a8283e
-    else
a8283e
-      strcpy(buf, "0"); /* the destination is large enough */
a8283e
-
a8283e
-    sbytes += tftp_option_add(state, sbytes,
a8283e
-                              (char *)state->spacket.data+sbytes,
a8283e
-                              TFTP_OPTION_TSIZE);
a8283e
-    sbytes += tftp_option_add(state, sbytes,
a8283e
-                              (char *)state->spacket.data+sbytes, buf);
a8283e
-    /* add blksize option */
a8283e
-    snprintf( buf, sizeof(buf), "%d", state->requested_blksize );
a8283e
-    sbytes += tftp_option_add(state, sbytes,
a8283e
-                              (char *)state->spacket.data+sbytes,
a8283e
-                              TFTP_OPTION_BLKSIZE);
a8283e
-    sbytes += tftp_option_add(state, sbytes,
a8283e
-                              (char *)state->spacket.data+sbytes, buf );
a8283e
-
a8283e
-    /* add timeout option */
a8283e
-    snprintf( buf, sizeof(buf), "%d", state->retry_time);
a8283e
-    sbytes += tftp_option_add(state, sbytes,
a8283e
-                              (char *)state->spacket.data+sbytes,
a8283e
-                              TFTP_OPTION_INTERVAL);
a8283e
-    sbytes += tftp_option_add(state, sbytes,
a8283e
-                              (char *)state->spacket.data+sbytes, buf );
a8283e
+    {
a8283e
+      CURLcode result;
a8283e
+      if(data->set.upload && (data->set.infilesize != -1))
a8283e
+        snprintf( buf, sizeof(buf), "%" FORMAT_OFF_T, data->set.infilesize );
a8283e
+      else
a8283e
+        strcpy(buf, "0"); /* the destination is large enough */
a8283e
+
a8283e
+      result = tftp_option_add(state, &sbytes,
a8283e
+                               (char *)state->spacket.data + sbytes,
a8283e
+                               TFTP_OPTION_TSIZE);
a8283e
+      if(result == CURLE_OK)
a8283e
+        result = tftp_option_add(state, &sbytes,
a8283e
+                                 (char *)state->spacket.data + sbytes, buf);
a8283e
+
a8283e
+      /* add blksize option */
a8283e
+      snprintf(buf, sizeof(buf), "%d", state->requested_blksize);
a8283e
+      if(result == CURLE_OK)
a8283e
+        result = tftp_option_add(state, &sbytes,
a8283e
+                                 (char *)state->spacket.data + sbytes,
a8283e
+                                 TFTP_OPTION_BLKSIZE);
a8283e
+      if(result == CURLE_OK)
a8283e
+        result = tftp_option_add(state, &sbytes,
a8283e
+                                 (char *)state->spacket.data + sbytes, buf);
a8283e
+
a8283e
+      /* add timeout option */
a8283e
+      snprintf(buf, sizeof(buf), "%d", state->retry_time);
a8283e
+      if(result == CURLE_OK)
a8283e
+        result = tftp_option_add(state, &sbytes,
a8283e
+                                 (char *)state->spacket.data + sbytes,
a8283e
+                                 TFTP_OPTION_INTERVAL);
a8283e
+      if(result == CURLE_OK)
a8283e
+        result = tftp_option_add(state, &sbytes,
a8283e
+                                 (char *)state->spacket.data + sbytes, buf);
a8283e
+
a8283e
+      if(result != CURLE_OK) {
a8283e
+        failf(data, "TFTP buffer too small for options");
a8283e
+        free(filename);
a8283e
+        return CURLE_TFTP_ILLEGAL;
a8283e
+      }
a8283e
+    }
a8283e
 
a8283e
     /* the typecase for the 3rd argument is mostly for systems that do
a8283e
        not have a size_t argument, like older unixes that want an 'int' */
a8283e
-- 
a8283e
2.20.1
a8283e
a8283e
a8283e
From ea5ca5f9ee1a4588061fc8b5a10c5b65fb68a0cd Mon Sep 17 00:00:00 2001
a8283e
From: Thomas Vegas <>
a8283e
Date: Sat, 31 Aug 2019 17:30:51 +0200
a8283e
Subject: [PATCH 2/2] tftp: Alloc maximum blksize, and use default unless OACK
a8283e
 is received
a8283e
a8283e
Fixes potential buffer overflow from 'recvfrom()', should the server
a8283e
return an OACK without blksize.
a8283e
a8283e
Bug: https://curl.haxx.se/docs/CVE-2019-5482.html
a8283e
CVE-2019-5482
a8283e
a8283e
Upstream-commit: facb0e4662415b5f28163e853dc6742ac5fafb3d
a8283e
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
a8283e
---
a8283e
 lib/tftp.c | 12 +++++++++---
a8283e
 1 file changed, 9 insertions(+), 3 deletions(-)
a8283e
a8283e
diff --git a/lib/tftp.c b/lib/tftp.c
a8283e
index 8ab9d71..af3b288 100644
a8283e
--- a/lib/tftp.c
a8283e
+++ b/lib/tftp.c
a8283e
@@ -961,6 +961,7 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done)
a8283e
   CURLcode code;
a8283e
   tftp_state_data_t *state;
a8283e
   int blksize, rc;
a8283e
+  int need_blksize;
a8283e
 
a8283e
   blksize = TFTP_BLKSIZE_DEFAULT;
a8283e
 
a8283e
@@ -979,15 +980,20 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done)
a8283e
       return CURLE_TFTP_ILLEGAL;
a8283e
   }
a8283e
 
a8283e
+  need_blksize = blksize;
a8283e
+  /* default size is the fallback when no OACK is received */
a8283e
+  if(need_blksize < TFTP_BLKSIZE_DEFAULT)
a8283e
+    need_blksize = TFTP_BLKSIZE_DEFAULT;
a8283e
+
a8283e
   if(!state->rpacket.data) {
a8283e
-    state->rpacket.data = calloc(1, blksize + 2 + 2);
a8283e
+    state->rpacket.data = calloc(1, need_blksize + 2 + 2);
a8283e
 
a8283e
     if(!state->rpacket.data)
a8283e
       return CURLE_OUT_OF_MEMORY;
a8283e
   }
a8283e
 
a8283e
   if(!state->spacket.data) {
a8283e
-    state->spacket.data = calloc(1, blksize + 2 + 2);
a8283e
+    state->spacket.data = calloc(1, need_blksize + 2 + 2);
a8283e
 
a8283e
     if(!state->spacket.data)
a8283e
       return CURLE_OUT_OF_MEMORY;
a8283e
@@ -1001,7 +1007,7 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done)
a8283e
   state->sockfd = state->conn->sock[FIRSTSOCKET];
a8283e
   state->state = TFTP_STATE_START;
a8283e
   state->error = TFTP_ERR_NONE;
a8283e
-  state->blksize = blksize;
a8283e
+  state->blksize = TFTP_BLKSIZE_DEFAULT; /* Unless updated by OACK response */
a8283e
   state->requested_blksize = blksize;
a8283e
 
a8283e
   ((struct sockaddr *)&state->local_addr)->sa_family =
a8283e
-- 
a8283e
2.20.1
a8283e