summaryrefslogtreecommitdiff
path: root/backport-CVE-2024-11053-pre1.patch
diff options
context:
space:
mode:
Diffstat (limited to 'backport-CVE-2024-11053-pre1.patch')
-rw-r--r--backport-CVE-2024-11053-pre1.patch453
1 files changed, 453 insertions, 0 deletions
diff --git a/backport-CVE-2024-11053-pre1.patch b/backport-CVE-2024-11053-pre1.patch
new file mode 100644
index 0000000..1a55294
--- /dev/null
+++ b/backport-CVE-2024-11053-pre1.patch
@@ -0,0 +1,453 @@
+From 142ac257b3242459b284020c59f1902b9687a954 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Tue, 6 Feb 2024 10:15:52 +0100
+Subject: [PATCH] lib: convert Curl_get_line to use dynbuf
+
+Create the line in a dynbuf. Aborts the reading of the file on
+errors. Avoids having to always allocate maximum amount from the
+start. Avoids direct malloc.
+
+Closes #12846
+
+Conflict:context adapt
+Reference:https://github.com/curl/curl/commit/142ac257b3242459b284020c59f1902b9687a954
+---
+ lib/altsvc.c | 18 +++-------
+ lib/cookie.c | 29 ++++------------
+ lib/curl_get_line.c | 55 +++++++++++++----------------
+ lib/curl_get_line.h | 7 ++--
+ lib/hsts.c | 17 +++------
+ lib/netrc.c | 10 ++++--
+ tests/unit/unit3200.c | 80 ++++++++++++++++++++++++-------------------
+ 7 files changed, 96 insertions(+), 120 deletions(-)
+
+diff --git a/lib/altsvc.c b/lib/altsvc.c
+index e9f62bf0e..c12d7bda1 100644
+--- a/lib/altsvc.c
++++ b/lib/altsvc.c
+@@ -209,7 +209,6 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, char *line)
+ static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file)
+ {
+ CURLcode result = CURLE_OK;
+- char *line = NULL;
+ FILE *fp;
+
+ /* we need a private copy of the file name so that the altsvc cache file
+@@ -221,11 +220,10 @@ static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file)
+
+ fp = fopen(file, FOPEN_READTEXT);
+ if(fp) {
+- line = malloc(MAX_ALTSVC_LINE);
+- if(!line)
+- goto fail;
+- while(Curl_get_line(line, MAX_ALTSVC_LINE, fp)) {
+- char *lineptr = line;
++ struct dynbuf buf;
++ Curl_dyn_init(&buf, MAX_ALTSVC_LINE);
++ while(Curl_get_line(&buf, fp)) {
++ char *lineptr = Curl_dyn_ptr(&buf);
+ while(*lineptr && ISBLANK(*lineptr))
+ lineptr++;
+ if(*lineptr == '#')
+@@ -234,16 +232,10 @@ static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file)
+
+ altsvc_add(asi, lineptr);
+ }
+- free(line); /* free the line buffer */
++ Curl_dyn_free(&buf); /* free the line buffer */
+ fclose(fp);
+ }
+ return result;
+-
+-fail:
+- Curl_safefree(asi->filename);
+- free(line);
+- fclose(fp);
+- return CURLE_OUT_OF_MEMORY;
+ }
+
+ /*
+diff --git a/lib/cookie.c b/lib/cookie.c
+index dc319b611..d10dd572b 100644
+--- a/lib/cookie.c
++++ b/lib/cookie.c
+@@ -1205,7 +1205,6 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
+ bool newsession)
+ {
+ struct CookieInfo *c;
+- char *line = NULL;
+ FILE *handle = NULL;
+
+ if(!inc) {
+@@ -1241,16 +1240,14 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
+
+ c->running = FALSE; /* this is not running, this is init */
+ if(fp) {
+-
+- line = malloc(MAX_COOKIE_LINE);
+- if(!line)
+- goto fail;
+- while(Curl_get_line(line, MAX_COOKIE_LINE, fp)) {
+- char *lineptr = line;
++ struct dynbuf buf;
++ Curl_dyn_init(&buf, MAX_COOKIE_LINE);
++ while(Curl_get_line(&buf, fp)) {
++ char *lineptr = Curl_dyn_ptr(&buf);
+ bool headerline = FALSE;
+- if(checkprefix("Set-Cookie:", line)) {
++ if(checkprefix("Set-Cookie:", lineptr)) {
+ /* This is a cookie line, get it! */
+- lineptr = &line[11];
++ lineptr += 11;
+ headerline = TRUE;
+ while(*lineptr && ISBLANK(*lineptr))
+ lineptr++;
+@@ -1258,7 +1255,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
+
+ Curl_cookie_add(data, c, headerline, TRUE, lineptr, NULL, NULL, TRUE);
+ }
+- free(line); /* free the line buffer */
++ Curl_dyn_free(&buf); /* free the line buffer */
+
+ /*
+ * Remove expired cookies from the hash. We must make sure to run this
+@@ -1274,18 +1271,6 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
+ c->running = TRUE; /* now, we're running */
+
+ return c;
+-
+-fail:
+- free(line);
+- /*
+- * Only clean up if we allocated it here, as the original could still be in
+- * use by a share handle.
+- */
+- if(!inc)
+- Curl_cookie_cleanup(c);
+- if(handle)
+- fclose(handle);
+- return NULL; /* out of memory */
+ }
+
+ /*
+diff --git a/lib/curl_get_line.c b/lib/curl_get_line.c
+index 686abe751..100207331 100644
+--- a/lib/curl_get_line.c
++++ b/lib/curl_get_line.c
+@@ -33,14 +33,16 @@
+ #include "memdebug.h"
+
+ /*
+- * Curl_get_line() makes sure to only return complete whole lines that fit in
+- * 'len' bytes and end with a newline.
++ * Curl_get_line() makes sure to only return complete whole lines that end
++ * newlines.
+ */
+-char *Curl_get_line(char *buf, int len, FILE *input)
++int Curl_get_line(struct dynbuf *buf, FILE *input)
+ {
+- bool partial = FALSE;
++ CURLcode result;
++ char buffer[128];
++ Curl_dyn_reset(buf);
+ while(1) {
+- char *b = fgets(buf, len, input);
++ char *b = fgets(buffer, sizeof(buffer), input);
+
+ if(b) {
+ size_t rlen = strlen(b);
+@@ -48,39 +50,28 @@ char *Curl_get_line(char *buf, int len, FILE *input)
+ if(!rlen)
+ break;
+
+- if(b[rlen-1] == '\n') {
+- /* b is \n terminated */
+- if(partial) {
+- partial = FALSE;
+- continue;
+- }
+- return b;
+- }
+- else if(feof(input)) {
+- if(partial)
+- /* Line is already too large to return, ignore rest */
+- break;
++ result = Curl_dyn_addn(buf, b, rlen);
++ if(result)
++ /* too long line or out of memory */
++ return 0; /* error */
+
+- if(rlen + 1 < (size_t) len) {
+- /* b is EOF terminated, insert missing \n */
+- b[rlen] = '\n';
+- b[rlen + 1] = '\0';
+- return b;
+- }
+- else
+- /* Maximum buffersize reached + EOF
+- * This line is impossible to add a \n to so we'll ignore it
+- */
+- break;
++ else if(b[rlen-1] == '\n')
++ /* end of the line */
++ return 1; /* all good */
++
++ else if(feof(input)) {
++ /* append a newline */
++ result = Curl_dyn_addn(buf, "\n", 1);
++ if(result)
++ /* too long line or out of memory */
++ return 0; /* error */
++ return 1; /* all good */
+ }
+- else
+- /* Maximum buffersize reached */
+- partial = TRUE;
+ }
+ else
+ break;
+ }
+- return NULL;
++ return 0;
+ }
+
+ #endif /* if not disabled */
+diff --git a/lib/curl_get_line.h b/lib/curl_get_line.h
+index 0ff32c5c2..7907cde88 100644
+--- a/lib/curl_get_line.h
++++ b/lib/curl_get_line.h
+@@ -24,8 +24,9 @@
+ *
+ ***************************************************************************/
+
+-/* get_line() makes sure to only return complete whole lines that fit in 'len'
+- * bytes and end with a newline. */
+-char *Curl_get_line(char *buf, int len, FILE *input);
++#include "dynbuf.h"
++
++/* Curl_get_line() returns complete lines that end with a newline. */
++int Curl_get_line(struct dynbuf *buf, FILE *input);
+
+ #endif /* HEADER_CURL_GET_LINE_H */
+diff --git a/lib/hsts.c b/lib/hsts.c
+index 8725a35c1..607755e6b 100644
+--- a/lib/hsts.c
++++ b/lib/hsts.c
+@@ -511,7 +511,6 @@ static CURLcode hsts_pull(struct Curl_easy *data, struct hsts *h)
+ static CURLcode hsts_load(struct hsts *h, const char *file)
+ {
+ CURLcode result = CURLE_OK;
+- char *line = NULL;
+ FILE *fp;
+
+ /* we need a private copy of the file name so that the hsts cache file
+@@ -523,11 +522,10 @@ static CURLcode hsts_load(struct hsts *h, const char *file)
+
+ fp = fopen(file, FOPEN_READTEXT);
+ if(fp) {
+- line = malloc(MAX_HSTS_LINE);
+- if(!line)
+- goto fail;
+- while(Curl_get_line(line, MAX_HSTS_LINE, fp)) {
+- char *lineptr = line;
++ struct dynbuf buf;
++ Curl_dyn_init(&buf, MAX_HSTS_LINE);
++ while(Curl_get_line(&buf, fp)) {
++ char *lineptr = Curl_dyn_ptr(&buf);
+ while(*lineptr && ISBLANK(*lineptr))
+ lineptr++;
+ if(*lineptr == '#')
+@@ -536,15 +534,10 @@ static CURLcode hsts_load(struct hsts *h, const char *file)
+
+ hsts_add(h, lineptr);
+ }
+- free(line); /* free the line buffer */
++ Curl_dyn_free(&buf); /* free the line buffer */
+ fclose(fp);
+ }
+ return result;
+-
+-fail:
+- Curl_safefree(h->filename);
+- fclose(fp);
+- return CURLE_OUT_OF_MEMORY;
+ }
+
+ /*
+diff --git a/lib/netrc.c b/lib/netrc.c
+index 038c6dca6..cd2a2844e 100644
+--- a/lib/netrc.c
++++ b/lib/netrc.c
+@@ -53,6 +53,8 @@ enum host_lookup_state {
+ #define NETRC_FAILED -1
+ #define NETRC_SUCCESS 0
+
++#define MAX_NETRC_LINE 4096
++
+ /*
+ * Returns zero on success.
+ */
+@@ -80,13 +82,14 @@ static int parsenetrc(const char *host,
+ file = fopen(netrcfile, FOPEN_READTEXT);
+ if(file) {
+ bool done = FALSE;
+- char netrcbuffer[4096];
+- int netrcbuffsize = (int)sizeof(netrcbuffer);
++ struct dynbuf buf;
++ Curl_dyn_init(&buf, MAX_NETRC_LINE);
+
+- while(!done && Curl_get_line(netrcbuffer, netrcbuffsize, file)) {
++ while(!done && Curl_get_line(&buf, file)) {
+ char *tok;
+ char *tok_end;
+ bool quoted;
++ char *netrcbuffer = Curl_dyn_ptr(&buf);
+ if(state == MACDEF) {
+ if((netrcbuffer[0] == '\n') || (netrcbuffer[0] == '\r'))
+ state = NOTHING;
+@@ -245,6 +248,7 @@ static int parsenetrc(const char *host,
+ } /* while Curl_get_line() */
+
+ out:
++ Curl_dyn_free(&buf);
+ if(!retcode) {
+ /* success */
+ if(login_alloc) {
+diff --git a/tests/unit/unit3200.c b/tests/unit/unit3200.c
+index 0544bcc93..6f508ce07 100644
+--- a/tests/unit/unit3200.c
++++ b/tests/unit/unit3200.c
+@@ -69,7 +69,7 @@ static const char *filecontents[] = {
+ "LINE1\n"
+ C4096 "SOME EXTRA TEXT",
+
+- /* First and third line should be read */
++ /* Only first should be read */
+ "LINE1\n"
+ C4096 "SOME EXTRA TEXT\n"
+ "LINE3\n",
+@@ -84,11 +84,13 @@ static const char *filecontents[] = {
+
+ UNITTEST_START
+ size_t i;
++ int rc = 0;
+ for(i = 0; i < NUMTESTS; i++) {
+ FILE *fp;
+- char buf[4096];
++ struct dynbuf buf;
+ int len = 4096;
+ char *line;
++ Curl_dyn_init(&buf, len);
+
+ fp = fopen(arg, "wb");
+ abort_unless(fp != NULL, "Cannot open testfile");
+@@ -101,65 +103,73 @@ UNITTEST_START
+ fprintf(stderr, "Test %zd...", i);
+ switch(i) {
+ case 0:
+- line = Curl_get_line(buf, len, fp);
++ rc = Curl_get_line(&buf, fp);
++ line = Curl_dyn_ptr(&buf);
+ fail_unless(line && !strcmp("LINE1\n", line),
+- "First line failed (1)");
+- line = Curl_get_line(buf, len, fp);
++ "First line failed (1)");
++ rc = Curl_get_line(&buf, fp);
++ line = Curl_dyn_ptr(&buf);
+ fail_unless(line && !strcmp("LINE2 NEWLINE\n", line),
+- "Second line failed (1)");
+- line = Curl_get_line(buf, len, fp);
+- abort_unless(line == NULL, "Missed EOF (1)");
++ "Second line failed (1)");
++ rc = Curl_get_line(&buf, fp);
++ abort_unless(!Curl_dyn_len(&buf), "Missed EOF (1)");
+ break;
+ case 1:
+- line = Curl_get_line(buf, len, fp);
++ rc = Curl_get_line(&buf, fp);
++ line = Curl_dyn_ptr(&buf);
+ fail_unless(line && !strcmp("LINE1\n", line),
+- "First line failed (2)");
+- line = Curl_get_line(buf, len, fp);
++ "First line failed (2)");
++ rc = Curl_get_line(&buf, fp);
++ line = Curl_dyn_ptr(&buf);
+ fail_unless(line && !strcmp("LINE2 NONEWLINE\n", line),
+- "Second line failed (2)");
+- line = Curl_get_line(buf, len, fp);
+- abort_unless(line == NULL, "Missed EOF (2)");
++ "Second line failed (2)");
++ rc = Curl_get_line(&buf, fp);
++ abort_unless(!Curl_dyn_len(&buf), "Missed EOF (2)");
+ break;
+ case 2:
+- line = Curl_get_line(buf, len, fp);
++ rc = Curl_get_line(&buf, fp);
++ line = Curl_dyn_ptr(&buf);
+ fail_unless(line && !strcmp("LINE1\n", line),
+- "First line failed (3)");
+- line = Curl_get_line(buf, len, fp);
+- fail_unless(line == NULL,
+- "Did not detect max read on EOF (3)");
++ "First line failed (3)");
++ rc = Curl_get_line(&buf, fp);
++ fail_unless(!Curl_dyn_len(&buf),
++ "Did not detect max read on EOF (3)");
+ break;
+ case 3:
+- line = Curl_get_line(buf, len, fp);
++ rc = Curl_get_line(&buf, fp);
++ line = Curl_dyn_ptr(&buf);
+ fail_unless(line && !strcmp("LINE1\n", line),
+- "First line failed (4)");
+- line = Curl_get_line(buf, len, fp);
+- fail_unless(line == NULL,
+- "Did not ignore partial on EOF (4)");
++ "First line failed (4)");
++ rc = Curl_get_line(&buf, fp);
++ fail_unless(!Curl_dyn_len(&buf),
++ "Did not ignore partial on EOF (4)");
+ break;
+ case 4:
+- line = Curl_get_line(buf, len, fp);
++ rc = Curl_get_line(&buf, fp);
++ line = Curl_dyn_ptr(&buf);
+ fail_unless(line && !strcmp("LINE1\n", line),
+- "First line failed (5)");
+- line = Curl_get_line(buf, len, fp);
+- fail_unless(line && !strcmp("LINE3\n", line),
+- "Third line failed (5)");
+- line = Curl_get_line(buf, len, fp);
+- abort_unless(line == NULL, "Missed EOF (5)");
++ "First line failed (5)");
++ rc = Curl_get_line(&buf, fp);
++ fail_unless(!Curl_dyn_len(&buf),
++ "Did not bail out on too long line");
+ break;
+ case 5:
+- line = Curl_get_line(buf, len, fp);
++ rc = Curl_get_line(&buf, fp);
++ line = Curl_dyn_ptr(&buf);
+ fail_unless(line && !strcmp("LINE1\x1aTEST\n", line),
+- "Missed/Misinterpreted ^Z (6)");
+- line = Curl_get_line(buf, len, fp);
+- abort_unless(line == NULL, "Missed EOF (6)");
++ "Missed/Misinterpreted ^Z (6)");
++ rc = Curl_get_line(&buf, fp);
++ abort_unless(!Curl_dyn_len(&buf), "Missed EOF (6)");
+ break;
+ default:
+ abort_unless(1, "Unknown case");
+ break;
+ }
++ Curl_dyn_free(&buf);
+ fclose(fp);
+ fprintf(stderr, "OK\n");
+ }
++ return rc;
+ UNITTEST_STOP
+
+ #else
+--
+2.33.0
+