diff options
Diffstat (limited to 'backport-CVE-2024-11053-pre1.patch')
-rw-r--r-- | backport-CVE-2024-11053-pre1.patch | 453 |
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 + |