Package: release.debian.org Severity: normal Tags: bullseye User: release.debian....@packages.debian.org Usertags: pu X-Debbugs-Cc: c...@packages.debian.org, charlesmel...@riseup.net Control: affects -1 + src:curl
[ Reason ] Vulnerabilities were discovered and reported to Curl upstream [1][2] with the following CVE IDs: - CVE-2023-28321 - CVE-2023-28322 The description of the CVE-2023-28321 is: > An improper certificate validation vulnerability exists in curl > <v8.1.0 in the way it supports matching of wildcard patterns when > listed as "Subject Alternative Name" in TLS server certificates. curl > can be built to use its own name matching function for TLS rather than > one provided by a TLS library. This private wildcard matching function > would match IDN (International Domain Name) hosts incorrectly and > could as a result accept patterns that otherwise should mismatch. IDN > hostnames are converted to puny code before used for certificate > checks. Puny coded names always start with `xn--` and should not be > allowed to pattern match, but the wildcard check in curl could still > check for `x*`, which would match even though the IDN name most likely > contained nothing even resembling an `x`. And the description of the CVE-2023-28322 is: > An information disclosure vulnerability exists in curl <v8.1.0 when > doing HTTP(S) transfers, libcurl might erroneously use the read > callback (`CURLOPT_READFUNCTION`) to ask for data to send, even when > the `CURLOPT_POSTFIELDS` option has been set, if the same handle > previously wasused to issue a `PUT` request which used that callback. > This flaw may surprise the application and cause it to misbehave and > either send off the wrong data or use memory after free or similar in > the second transfer. The problem exists in the logic for a reused > handle when it is (expected to be) changed from a PUT to a POST. This proposed update is meant to fix those vulnerabilities. [ Impact ] As the vulnerabilities are present in bullseye's curl code, they can be exploited by malicious actors. [ Tests ] Automatic tests were executed (from the curl test suite) during build time. Everything passed after the changes were introduced. I also conducted a test to see if the CVE-2023-28321 was fixed. In order to do so, I've followed the report's reproduction steps [3] and tested in a bullseye container. The default bullseye curl version is vulnerable, but this new one is not. Unfortunately the PoC of CVE-2023-28322 was crafted using a newer version of libcurl, so I wasn't able to validate the fix of the backported patch. Also, note the fix for CVE-2023-28321 comes from CentOS and is already available there. [ Risks ] The changes for weren't big because the delta between bullseye's version and current upstream are not that large (true for CVE-2023-28322). Though they exist so I did a backport of the patch (obviously there is a chance of introducing bugs here, but we are using the tests to spot it). Also, the fix for CVE-2023-28321 is new code based on the fix applied in curl 8.1.0 done by a Red Hat engineer. So, new bugs could have been introduced. I reviewed this fix and samueloph reviewed everything (both fixes and packaging). [ Checklist ] [x] *all* changes are documented in the d/changelog [x] I reviewed all changes and I approve them [x] attach debdiff against the package in (old)stable [x] the issue is verified as fixed in unstable [ Changes ] Here is a list of the commits applied to this pu release: commit a1190a634dcca9a85f8217c71b1073825885a16e Author: Carlos Henrique Lima Melara <charlesmel...@riseup.net> Date: Sun Sep 10 15:29:53 2023 +0530 Finalize changelog for 7.74.0-1.3+deb11u9 bullseye upload commit 39155aa17df39693c2f21ef5dbb0ddf11568256f Author: Carlos Henrique Lima Melara <charlesmel...@riseup.net> Date: Fri Sep 8 19:00:25 2023 +0530 d/p/CVE-2023-28322.patch: backport patch commit 156409a45db1c739edece8fd3b3d4d78d09c82ae Author: Carlos Henrique Lima Melara <charlesmel...@riseup.net> Date: Sun Aug 13 11:01:11 2023 -0300 Import 2 new patches fixing CVES One comes from upstream and another from CentOS. CVE-2023-28321 CVE-2023-28322 [ Other info ] Links: [1] https://security-tracker.debian.org/tracker/CVE-2023-28321 [2] https://security-tracker.debian.org/tracker/CVE-2023-28322 [3] https://hackerone.com/reports/1950627 Cheers, Charles
diff -Nru curl-7.74.0/debian/changelog curl-7.74.0/debian/changelog --- curl-7.74.0/debian/changelog 2023-04-03 03:34:17.000000000 +0800 +++ curl-7.74.0/debian/changelog 2023-09-10 17:49:20.000000000 +0800 @@ -1,3 +1,14 @@ +curl (7.74.0-1.3+deb11u9) bullseye; urgency=medium + + * Team upload. + * Import 2 new patches to fix CVES: + - CVE-2023-28321: IDN wildcard match may lead to Improper Cerificate + Validation. + - CVE-2023-28322: more POST-after-PUT confusion. + * debian/patches/CVE-2023-28322.patch: backport patch. + + -- Carlos Henrique Lima Melara <charlesmel...@riseup.net> Sun, 10 Sep 2023 15:19:20 +0530 + curl (7.74.0-1.3+deb11u8) bullseye; urgency=medium * Backport upstream patches to fix 5 CVEs: diff -Nru curl-7.74.0/debian/patches/CVE-2023-28321.patch curl-7.74.0/debian/patches/CVE-2023-28321.patch --- curl-7.74.0/debian/patches/CVE-2023-28321.patch 1970-01-01 07:30:00.000000000 +0730 +++ curl-7.74.0/debian/patches/CVE-2023-28321.patch 2023-09-10 17:49:20.000000000 +0800 @@ -0,0 +1,296 @@ +From bb4d7d8d9f2ce34d3dded9b96eaf800e38b92434 Mon Sep 17 00:00:00 2001 +From: Jacek Migacz <jmig...@redhat.com> +Date: Tue, 27 Jun 2023 19:42:23 +0200 +Subject: [PATCH] Resolves: CVE-2023-28321 - fix host name wildcard checking + +--- + lib/hostcheck.c | 50 +++++++-------- + tests/data/test1397 | 10 ++- + tests/unit/Makefile.am | 94 ---------------------------- + tests/unit/Makefile.inc | 94 ++++++++++++++++++++++++++++ + tests/unit/unit1397.c | 134 ++++++++++++++++++++++++---------------- + 5 files changed, 202 insertions(+), 180 deletions(-) + +diff --git a/lib/hostcheck.c b/lib/hostcheck.c +index e827dc58f378c..d061c6356f97f 100644 +--- a/lib/hostcheck.c ++++ b/lib/hostcheck.c +@@ -43,6 +43,17 @@ + /* The last #include file should be: */ + #include "memdebug.h" + ++/* check the two input strings with given length, but do not ++ assume they end in nul-bytes */ ++static int pmatch(const char *hostname, size_t hostlen, ++ const char *pattern, size_t patternlen) ++{ ++ if(hostlen != patternlen) ++ return CURL_HOST_NOMATCH; ++ return strncasecompare(hostname, pattern, hostlen) ? ++ CURL_HOST_MATCH : CURL_HOST_NOMATCH; ++} ++ + /* + * Match a hostname against a wildcard pattern. + * E.g. +@@ -65,26 +76,27 @@ + + static int hostmatch(char *hostname, char *pattern) + { +- const char *pattern_label_end, *pattern_wildcard, *hostname_label_end; +- int wildcard_enabled; +- size_t prefixlen, suffixlen; ++ size_t hostlen, patternlen; ++ const char *pattern_label_end; + struct in_addr ignored; + #ifdef ENABLE_IPV6 + struct sockaddr_in6 si6; + #endif + ++ DEBUGASSERT(pattern); ++ DEBUGASSERT(hostname); ++ ++ hostlen = strlen(hostname); ++ patternlen = strlen(pattern); ++ + /* normalize pattern and hostname by stripping off trailing dots */ +- size_t len = strlen(hostname); +- if(hostname[len-1]=='.') +- hostname[len-1] = 0; +- len = strlen(pattern); +- if(pattern[len-1]=='.') +- pattern[len-1] = 0; +- +- pattern_wildcard = strchr(pattern, '*'); +- if(pattern_wildcard == NULL) +- return strcasecompare(pattern, hostname) ? +- CURL_HOST_MATCH : CURL_HOST_NOMATCH; ++ if(hostname[hostlen-1]=='.') ++ hostname[hostlen-1] = 0; ++ if(pattern[patternlen-1]=='.') ++ pattern[patternlen-1] = 0; ++ ++ if(strncmp(pattern, "*.", 2)) ++ return pmatch(hostname, hostlen, pattern, patternlen); + + /* detect IP address as hostname and fail the match if so */ + if(Curl_inet_pton(AF_INET, hostname, &ignored) > 0) +@@ -96,34 +108,20 @@ static int hostmatch(char *hostname, char *pattern) + + /* We require at least 2 dots in pattern to avoid too wide wildcard + match. */ +- wildcard_enabled = 1; + pattern_label_end = strchr(pattern, '.'); +- if(pattern_label_end == NULL || strchr(pattern_label_end + 1, '.') == NULL || +- pattern_wildcard > pattern_label_end || +- strncasecompare(pattern, "xn--", 4)) { +- wildcard_enabled = 0; ++ if(pattern_label_end == NULL || ++ (strrchr(pattern, '.') == pattern_label_end)) ++ return pmatch(pattern, patternlen, hostname, hostlen); ++ ++ const char *hostname_label_end = strchr(hostname, '.'); ++ if(hostname_label_end != NULL) { ++ size_t skiphost = hostname_label_end - hostname; ++ size_t skiplen = pattern_label_end - pattern; ++ return pmatch(hostname_label_end, hostlen - skiphost, ++ pattern_label_end, patternlen - skiplen); + } +- if(!wildcard_enabled) +- return strcasecompare(pattern, hostname) ? +- CURL_HOST_MATCH : CURL_HOST_NOMATCH; +- +- hostname_label_end = strchr(hostname, '.'); +- if(hostname_label_end == NULL || +- !strcasecompare(pattern_label_end, hostname_label_end)) +- return CURL_HOST_NOMATCH; + +- /* The wildcard must match at least one character, so the left-most +- label of the hostname is at least as large as the left-most label +- of the pattern. */ +- if(hostname_label_end - hostname < pattern_label_end - pattern) +- return CURL_HOST_NOMATCH; +- +- prefixlen = pattern_wildcard - pattern; +- suffixlen = pattern_label_end - (pattern_wildcard + 1); +- return strncasecompare(pattern, hostname, prefixlen) && +- strncasecompare(pattern_wildcard + 1, hostname_label_end - suffixlen, +- suffixlen) ? +- CURL_HOST_MATCH : CURL_HOST_NOMATCH; ++ return CURL_HOST_NOMATCH; + } + + int Curl_cert_hostcheck(const char *match_pattern, const char *hostname) +diff --git a/tests/data/test1397 b/tests/data/test1397 +index 84f962abebee3..f31b2c2a3f330 100644 +--- a/tests/data/test1397 ++++ b/tests/data/test1397 +@@ -2,8 +2,7 @@ + <info> + <keywords> + unittest +-ssl +-wildcard ++Curl_cert_hostcheck + </keywords> + </info> + +@@ -15,9 +14,9 @@ none + <features> + unittest + </features> +- <name> +-Check wildcard certificate matching function Curl_cert_hostcheck +- </name> ++<name> ++Curl_cert_hostcheck unit tests ++</name> + </client> + + </testcase> +diff --git a/tests/unit/unit1397.c b/tests/unit/unit1397.c +index 2f3d3aa4d09e1..3ae75618d5d10 100644 +--- a/tests/unit/unit1397.c ++++ b/tests/unit/unit1397.c +@@ -21,8 +21,6 @@ + ***************************************************************************/ + #include "curlcheck.h" + +-#include "hostcheck.h" /* from the lib dir */ +- + static CURLcode unit_setup(void) + { + return CURLE_OK; +@@ -30,50 +28,93 @@ static CURLcode unit_setup(void) + + static void unit_stop(void) + { +- /* done before shutting down and exiting */ + } + +-UNITTEST_START +- + /* only these backends define the tested functions */ +-#if defined(USE_OPENSSL) || defined(USE_GSKIT) +- +- /* here you start doing things and checking that the results are good */ ++#if defined(USE_OPENSSL) || defined(USE_GSKIT) || defined(USE_SCHANNEL) ++#include "hostcheck.h" ++struct testcase { ++ const char *host; ++ const char *pattern; ++ bool match; ++}; + +-fail_unless(Curl_cert_hostcheck("www.example.com", "www.example.com"), +- "good 1"); +-fail_unless(Curl_cert_hostcheck("*.example.com", "www.example.com"), +- "good 2"); +-fail_unless(Curl_cert_hostcheck("xxx*.example.com", "xxxwww.example.com"), +- "good 3"); +-fail_unless(Curl_cert_hostcheck("f*.example.com", "foo.example.com"), +- "good 4"); +-fail_unless(Curl_cert_hostcheck("192.168.0.0", "192.168.0.0"), +- "good 5"); +- +-fail_if(Curl_cert_hostcheck("xxx.example.com", "www.example.com"), "bad 1"); +-fail_if(Curl_cert_hostcheck("*", "www.example.com"), "bad 2"); +-fail_if(Curl_cert_hostcheck("*.*.com", "www.example.com"), "bad 3"); +-fail_if(Curl_cert_hostcheck("*.example.com", "baa.foo.example.com"), "bad 4"); +-fail_if(Curl_cert_hostcheck("f*.example.com", "baa.example.com"), "bad 5"); +-fail_if(Curl_cert_hostcheck("*.com", "example.com"), "bad 6"); +-fail_if(Curl_cert_hostcheck("*fail.com", "example.com"), "bad 7"); +-fail_if(Curl_cert_hostcheck("*.example.", "www.example."), "bad 8"); +-fail_if(Curl_cert_hostcheck("*.example.", "www.example"), "bad 9"); +-fail_if(Curl_cert_hostcheck("", "www"), "bad 10"); +-fail_if(Curl_cert_hostcheck("*", "www"), "bad 11"); +-fail_if(Curl_cert_hostcheck("*.168.0.0", "192.168.0.0"), "bad 12"); +-fail_if(Curl_cert_hostcheck("www.example.com", "192.168.0.0"), "bad 13"); +- +-#ifdef ENABLE_IPV6 +-fail_if(Curl_cert_hostcheck("*::3285:a9ff:fe46:b619", +- "fe80::3285:a9ff:fe46:b619"), "bad 14"); +-fail_unless(Curl_cert_hostcheck("fe80::3285:a9ff:fe46:b619", +- "fe80::3285:a9ff:fe46:b619"), "good 6"); +-#endif ++static struct testcase tests[] = { ++ {"", "", FALSE}, ++ {"a", "", FALSE}, ++ {"", "b", FALSE}, ++ {"a", "b", FALSE}, ++ {"aa", "bb", FALSE}, ++ {"\xff", "\xff", TRUE}, ++ {"aa.aa.aa", "aa.aa.bb", FALSE}, ++ {"aa.aa.aa", "aa.aa.aa", TRUE}, ++ {"aa.aa.aa", "*.aa.bb", FALSE}, ++ {"aa.aa.aa", "*.aa.aa", TRUE}, ++ {"192.168.0.1", "192.168.0.1", TRUE}, ++ {"192.168.0.1", "*.168.0.1", FALSE}, ++ {"192.168.0.1", "*.0.1", FALSE}, ++ {"h.ello", "*.ello", FALSE}, ++ {"h.ello.", "*.ello", FALSE}, ++ {"h.ello", "*.ello.", FALSE}, ++ {"h.e.llo", "*.e.llo", TRUE}, ++ {"h.e.llo", " *.e.llo", FALSE}, ++ {" h.e.llo", "*.e.llo", TRUE}, ++ {"h.e.llo.", "*.e.llo", TRUE}, ++ {"*.e.llo.", "*.e.llo", TRUE}, ++ {"************.e.llo.", "*.e.llo", TRUE}, ++ {"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" ++ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" ++ "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC" ++ "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD" ++ "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE" ++ ".e.llo.", "*.e.llo", TRUE}, ++ {"\xfe\xfe.e.llo.", "*.e.llo", TRUE}, ++ {"h.e.llo.", "*.e.llo.", TRUE}, ++ {"h.e.llo", "*.e.llo.", TRUE}, ++ {".h.e.llo", "*.e.llo.", FALSE}, ++ {"h.e.llo", "*.*.llo.", FALSE}, ++ {"h.e.llo", "h.*.llo", FALSE}, ++ {"h.e.llo", "h.e.*", FALSE}, ++ {"hello", "*.ello", FALSE}, ++ {"hello", "**llo", FALSE}, ++ {"bar.foo.example.com", "*.example.com", FALSE}, ++ {"foo.example.com", "*.example.com", TRUE}, ++ {"baz.example.net", "b*z.example.net", FALSE}, ++ {"foobaz.example.net", "*baz.example.net", FALSE}, ++ {"xn--l8j.example.local", "x*.example.local", FALSE}, ++ {"xn--l8j.example.net", "*.example.net", TRUE}, ++ {"xn--l8j.example.net", "*j.example.net", FALSE}, ++ {"xn--l8j.example.net", "xn--l8j.example.net", TRUE}, ++ {"xn--l8j.example.net", "xn--l8j.*.net", FALSE}, ++ {"xl8j.example.net", "*.example.net", TRUE}, ++ {"fe80::3285:a9ff:fe46:b619", "*::3285:a9ff:fe46:b619", FALSE}, ++ {"fe80::3285:a9ff:fe46:b619", "fe80::3285:a9ff:fe46:b619", TRUE}, ++ {NULL, NULL, FALSE} ++}; + +-#endif ++UNITTEST_START ++{ ++ int i; ++ for(i = 0; tests[i].host; i++) { ++ if(tests[i].match != Curl_cert_hostcheck(tests[i].pattern, ++ strlen(tests[i].pattern), ++ tests[i].host, ++ strlen(tests[i].host))) { ++ fprintf(stderr, ++ "HOST: %s\n" ++ "PTRN: %s\n" ++ "did %sMATCH\n", ++ tests[i].host, ++ tests[i].pattern, ++ tests[i].match ? "NOT ": ""); ++ unitfail++; ++ } ++ } ++} ++UNITTEST_STOP ++#else + +- /* you end the test code like this: */ ++UNITTEST_START + + UNITTEST_STOP ++#endif diff -Nru curl-7.74.0/debian/patches/CVE-2023-28322.patch curl-7.74.0/debian/patches/CVE-2023-28322.patch --- curl-7.74.0/debian/patches/CVE-2023-28322.patch 1970-01-01 07:30:00.000000000 +0730 +++ curl-7.74.0/debian/patches/CVE-2023-28322.patch 2023-09-10 17:49:20.000000000 +0800 @@ -0,0 +1,422 @@ +From 7815647d6582c0a4900be2e1de6c5e61272c496b Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg <dan...@haxx.se> +Date: Tue, 25 Apr 2023 08:28:01 +0200 +Subject: [PATCH] lib: unify the upload/method handling + +By making sure we set state.upload based on the set.method value and not +independently as set.upload, we reduce confusion and mixup risks, both +internally and externally. + +Closes #11017 +--- + lib/curl_rtmp.c | 4 ++-- + lib/file.c | 4 ++-- + lib/ftp.c | 8 ++++---- + lib/http.c | 4 ++-- + lib/imap.c | 6 +++--- + lib/rtsp.c | 4 ++-- + lib/setopt.c | 6 ++---- + lib/smb.c | 4 ++-- + lib/smtp.c | 4 ++-- + lib/tftp.c | 8 ++++---- + lib/transfer.c | 4 ++-- + lib/urldata.h | 2 +- + lib/vssh/libssh.c | 6 +++--- + lib/vssh/libssh2.c | 6 +++--- + lib/vssh/wolfssh.c | 2 +- + 15 files changed, 35 insertions(+), 37 deletions(-) + +diff --git a/lib/curl_rtmp.c b/lib/curl_rtmp.c +index ba471a2..a91df76 100644 +--- a/lib/curl_rtmp.c ++++ b/lib/curl_rtmp.c +@@ -219,7 +219,7 @@ static CURLcode rtmp_connect(struct connectdata *conn, bool *done) + /* We have to know if it's a write before we send the + * connect request packet + */ +- if(conn->data->set.upload) ++ if(conn->data->state.upload) + r->Link.protocol |= RTMP_FEATURE_WRITE; + + /* For plain streams, use the buffer toggle trick to keep data flowing */ +@@ -251,7 +251,7 @@ static CURLcode rtmp_do(struct connectdata *conn, bool *done) + if(!RTMP_ConnectStream(r, 0)) + return CURLE_FAILED_INIT; + +- if(conn->data->set.upload) { ++ if(conn->data->state.upload) { + Curl_pgrsSetUploadSize(data, data->state.infilesize); + Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET); + } +diff --git a/lib/file.c b/lib/file.c +index a65eb77..9a13910 100644 +--- a/lib/file.c ++++ b/lib/file.c +@@ -196,7 +196,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done) + file->freepath = real_path; /* free this when done */ + + file->fd = fd; +- if(!data->set.upload && (fd == -1)) { ++ if(!data->state.upload && (fd == -1)) { + failf(data, "Couldn't open file %s", data->state.up.path); + file_done(conn, CURLE_FILE_COULDNT_READ_FILE, FALSE); + return CURLE_FILE_COULDNT_READ_FILE; +@@ -378,7 +378,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done) + + Curl_pgrsStartNow(data); + +- if(data->set.upload) ++ if(data->state.upload) + return file_upload(conn); + + file = conn->data->req.p.file; +diff --git a/lib/ftp.c b/lib/ftp.c +index 36a2a09..fe2636e 100644 +--- a/lib/ftp.c ++++ b/lib/ftp.c +@@ -1361,7 +1361,7 @@ static CURLcode ftp_state_prepare_transfer(struct connectdata *conn) + data->set.str[STRING_CUSTOMREQUEST]? + data->set.str[STRING_CUSTOMREQUEST]: + (data->set.ftp_list_only?"NLST":"LIST")); +- else if(data->set.upload) ++ else if(data->state.upload) + result = Curl_pp_sendf(&ftpc->pp, "PRET STOR %s", + conn->proto.ftpc.file); + else +@@ -3328,7 +3328,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, + /* the response code from the transfer showed an error already so no + use checking further */ + ; +- else if(data->set.upload) { ++ else if(data->state.upload) { + if((-1 != data->state.infilesize) && + (data->state.infilesize != data->req.writebytecount) && + !data->set.crlf && +@@ -3598,7 +3598,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep) + connected back to us */ + } + } +- else if(data->set.upload) { ++ else if(data->state.upload) { + result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE); + if(result) + return result; +@@ -4169,7 +4169,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) + ftpc->file = NULL; /* instead of point to a zero byte, + we make it a NULL pointer */ + +- if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) { ++ if(data->state.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) { + /* We need a file name when uploading. Return error! */ + failf(data, "Uploading to a URL without a file name!"); + free(rawPath); +diff --git a/lib/http.c b/lib/http.c +index 35ec7c5..1350125 100644 +--- a/lib/http.c ++++ b/lib/http.c +@@ -2003,7 +2003,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) + } + + if((conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_FTP)) && +- data->set.upload) { ++ data->state.upload) { + httpreq = HTTPREQ_PUT; + } + +@@ -2181,7 +2181,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) + if((conn->handler->protocol & PROTO_FAMILY_HTTP) && + (((httpreq == HTTPREQ_POST_MIME || httpreq == HTTPREQ_POST_FORM) && + http->postsize < 0) || +- ((data->set.upload || httpreq == HTTPREQ_POST) && ++ ((data->state.upload || httpreq == HTTPREQ_POST) && + data->state.infilesize == -1))) { + if(conn->bits.authneg) + /* don't enable chunked during auth neg */ +diff --git a/lib/imap.c b/lib/imap.c +index f3361cf..47d5b94 100644 +--- a/lib/imap.c ++++ b/lib/imap.c +@@ -1476,11 +1476,11 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status, + result = status; /* use the already set error code */ + } + else if(!data->set.connect_only && !imap->custom && +- (imap->uid || imap->mindex || data->set.upload || ++ (imap->uid || imap->mindex || data->state.upload || + data->set.mimepost.kind != MIMEKIND_NONE)) { + /* Handle responses after FETCH or APPEND transfer has finished */ + +- if(!data->set.upload && data->set.mimepost.kind == MIMEKIND_NONE) ++ if(!data->state.upload && data->set.mimepost.kind == MIMEKIND_NONE) + state(conn, IMAP_FETCH_FINAL); + else { + /* End the APPEND command first by sending an empty line */ +@@ -1546,7 +1546,7 @@ static CURLcode imap_perform(struct connectdata *conn, bool *connected, + selected = TRUE; + + /* Start the first command in the DO phase */ +- if(conn->data->set.upload || data->set.mimepost.kind != MIMEKIND_NONE) ++ if(conn->data->state.upload || data->set.mimepost.kind != MIMEKIND_NONE) + /* APPEND can be executed directly */ + result = imap_perform_append(conn); + else if(imap->custom && (selected || !imap->mailbox)) +diff --git a/lib/rtsp.c b/lib/rtsp.c +index 151ff4a..89ad782 100644 +--- a/lib/rtsp.c ++++ b/lib/rtsp.c +@@ -497,7 +497,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) + rtspreq == RTSPREQ_SET_PARAMETER || + rtspreq == RTSPREQ_GET_PARAMETER) { + +- if(data->set.upload) { ++ if(data->state.upload) { + putsize = data->state.infilesize; + data->state.httpreq = HTTPREQ_PUT; + +@@ -516,7 +516,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) + result = + Curl_dyn_addf(&req_buffer, + "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n", +- (data->set.upload ? putsize : postsize)); ++ (data->state.upload ? putsize : postsize)); + if(result) + return result; + } +diff --git a/lib/setopt.c b/lib/setopt.c +index 3c43cdb..90d2dac 100644 +--- a/lib/setopt.c ++++ b/lib/setopt.c +@@ -297,8 +297,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) + * We want to sent data to the remote host. If this is HTTP, that equals + * using the PUT request. + */ +- data->set.upload = (0 != va_arg(param, long)) ? TRUE : FALSE; +- if(data->set.upload) { ++ arg = va_arg(param, long); ++ if(arg) { + /* If this is HTTP, PUT is what's needed to "upload" */ + data->set.method = HTTPREQ_PUT; + data->set.opt_no_body = FALSE; /* this is implied */ +@@ -626,7 +626,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) + } + else + data->set.method = HTTPREQ_GET; +- data->set.upload = FALSE; + break; + + case CURLOPT_HTTPPOST: +@@ -848,7 +847,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) + */ + if(va_arg(param, long)) { + data->set.method = HTTPREQ_GET; +- data->set.upload = FALSE; /* switch off upload */ + data->set.opt_no_body = FALSE; /* this is implied */ + } + break; +diff --git a/lib/smb.c b/lib/smb.c +index 0abed77..4584c91 100644 +--- a/lib/smb.c ++++ b/lib/smb.c +@@ -516,7 +516,7 @@ static CURLcode smb_send_open(struct connectdata *conn) + byte_count = strlen(req->path); + msg.name_length = smb_swap16((unsigned short)byte_count); + msg.share_access = smb_swap32(SMB_FILE_SHARE_ALL); +- if(conn->data->set.upload) { ++ if(conn->data->state.upload) { + msg.access = smb_swap32(SMB_GENERIC_READ | SMB_GENERIC_WRITE); + msg.create_disposition = smb_swap32(SMB_FILE_OVERWRITE_IF); + } +@@ -792,7 +792,7 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done) + smb_m = (const struct smb_nt_create_response*) msg; + req->fid = smb_swap16(smb_m->fid); + conn->data->req.offset = 0; +- if(conn->data->set.upload) { ++ if(conn->data->state.upload) { + conn->data->req.size = conn->data->state.infilesize; + Curl_pgrsSetUploadSize(conn->data, conn->data->req.size); + next_state = SMB_UPLOAD; +diff --git a/lib/smtp.c b/lib/smtp.c +index 51a2a56..ad3692b 100644 +--- a/lib/smtp.c ++++ b/lib/smtp.c +@@ -1382,7 +1382,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, + result = status; /* use the already set error code */ + } + else if(!data->set.connect_only && data->set.mail_rcpt && +- (data->set.upload || data->set.mimepost.kind)) { ++ (data->state.upload || data->set.mimepost.kind)) { + /* Calculate the EOB taking into account any terminating CRLF from the + previous line of the email or the CRLF of the DATA command when there + is "no mail data". RFC-5321, sect. 4.1.1.4. +@@ -1475,7 +1475,7 @@ static CURLcode smtp_perform(struct connectdata *conn, bool *connected, + smtp->eob = 2; + + /* Start the first command in the DO phase */ +- if((data->set.upload || data->set.mimepost.kind) && data->set.mail_rcpt) ++ if((data->state.upload || data->set.mimepost.kind) && data->set.mail_rcpt) + /* MAIL transfer */ + result = smtp_perform_mail(conn); + else +diff --git a/lib/tftp.c b/lib/tftp.c +index fba3f5e..b5b8bf5 100644 +--- a/lib/tftp.c ++++ b/lib/tftp.c +@@ -391,7 +391,7 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state, + + /* tsize should be ignored on upload: Who cares about the size of the + remote file? */ +- if(!data->set.upload) { ++ if(!data->state.upload) { + if(!tsize) { + failf(data, "invalid tsize -:%s:- value in OACK packet", value); + return CURLE_TFTP_ILLEGAL; +@@ -472,7 +472,7 @@ static CURLcode tftp_send_first(struct tftp_state_data *state, + return result; + } + +- if(data->set.upload) { ++ if(data->state.upload) { + /* If we are uploading, send an WRQ */ + setpacketevent(&state->spacket, TFTP_EVENT_WRQ); + state->conn->data->req.upload_fromhere = +@@ -507,7 +507,7 @@ static CURLcode tftp_send_first(struct tftp_state_data *state, + if(!data->set.tftp_no_options) { + char buf[64]; + /* add tsize option */ +- if(data->set.upload && (data->state.infilesize != -1)) ++ if(data->state.upload && (data->state.infilesize != -1)) + msnprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T, + data->state.infilesize); + else +@@ -561,7 +561,7 @@ static CURLcode tftp_send_first(struct tftp_state_data *state, + break; + + case TFTP_EVENT_OACK: +- if(data->set.upload) { ++ if(data->state.upload) { + result = tftp_connect_for_tx(state, event); + } + else { +diff --git a/lib/transfer.c b/lib/transfer.c +index fcc720d..fe8ffb4 100644 +--- a/lib/transfer.c ++++ b/lib/transfer.c +@@ -1419,6 +1419,7 @@ void Curl_init_CONNECT(struct Curl_easy *data) + { + data->state.fread_func = data->set.fread_func_set; + data->state.in = data->set.in_set; ++ data->state.upload = (data->state.httpreq == HTTPREQ_PUT); + } + + /* +@@ -1803,7 +1804,6 @@ CURLcode Curl_follow(struct Curl_easy *data, + data->state.httpreq != HTTPREQ_POST_MIME) || + !(data->set.keep_post & CURL_REDIR_POST_303))) { + data->state.httpreq = HTTPREQ_GET; +- data->set.upload = false; + infof(data, "Switch to %s\n", + data->set.opt_no_body?"HEAD":"GET"); + } +@@ -1842,7 +1842,7 @@ CURLcode Curl_retry_request(struct connectdata *conn, + + /* if we're talking upload, we can't do the checks below, unless the protocol + is HTTP as when uploading over HTTP we will still get a response */ +- if(data->set.upload && ++ if(data->state.upload && + !(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP))) + return CURLE_OK; + +diff --git a/lib/urldata.h b/lib/urldata.h +index 20664a6..b72da7c 100644 +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -1464,6 +1464,7 @@ struct UrlState { + BIT(stream_depends_e); /* set or don't set the Exclusive bit */ + BIT(previouslypending); /* this transfer WAS in the multi->pending queue */ + BIT(cookie_engine); ++ BIT(upload); /* upload request */ + }; + + +@@ -1824,7 +1825,6 @@ struct UserDefined { + BIT(http_auto_referer); /* set "correct" referer when following + location: */ + BIT(opt_no_body); /* as set with CURLOPT_NOBODY */ +- BIT(upload); /* upload request */ + BIT(verbose); /* output verbosity */ + BIT(krb); /* Kerberos connection requested */ + BIT(reuse_forbid); /* forbidden to be reused, close after use */ +diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c +index e79d8e8..cb98a2f 100644 +--- a/lib/vssh/libssh.c ++++ b/lib/vssh/libssh.c +@@ -1186,7 +1186,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block) + } + + case SSH_SFTP_TRANS_INIT: +- if(data->set.upload) ++ if(data->state.upload) + state(conn, SSH_SFTP_UPLOAD_INIT); + else { + if(protop->path[strlen(protop->path)-1] == '/') +@@ -1789,7 +1789,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block) + /* Functions from the SCP subsystem cannot handle/return SSH_AGAIN */ + ssh_set_blocking(sshc->ssh_session, 1); + +- if(data->set.upload) { ++ if(data->state.upload) { + if(data->state.infilesize < 0) { + failf(data, "SCP requires a known file size for upload"); + sshc->actualcode = CURLE_UPLOAD_FAILED; +@@ -1890,7 +1890,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block) + break; + } + case SSH_SCP_DONE: +- if(data->set.upload) ++ if(data->state.upload) + state(conn, SSH_SCP_SEND_EOF); + else + state(conn, SSH_SCP_CHANNEL_FREE); +diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c +index a69bcda..6fd853a 100644 +--- a/lib/vssh/libssh2.c ++++ b/lib/vssh/libssh2.c +@@ -1844,7 +1844,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) + } + + case SSH_SFTP_TRANS_INIT: +- if(data->set.upload) ++ if(data->state.upload) + state(conn, SSH_SFTP_UPLOAD_INIT); + else { + if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/') +@@ -2517,7 +2517,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) + break; + } + +- if(data->set.upload) { ++ if(data->state.upload) { + if(data->state.infilesize < 0) { + failf(data, "SCP requires a known file size for upload"); + sshc->actualcode = CURLE_UPLOAD_FAILED; +@@ -2657,7 +2657,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) + break; + + case SSH_SCP_DONE: +- if(data->set.upload) ++ if(data->state.upload) + state(conn, SSH_SCP_SEND_EOF); + else + state(conn, SSH_SCP_CHANNEL_FREE); +diff --git a/lib/vssh/wolfssh.c b/lib/vssh/wolfssh.c +index b0dfb20..97f464b 100644 +--- a/lib/vssh/wolfssh.c ++++ b/lib/vssh/wolfssh.c +@@ -542,7 +542,7 @@ static CURLcode wssh_statemach_act(struct connectdata *conn, bool *block) + } + break; + case SSH_SFTP_TRANS_INIT: +- if(data->set.upload) ++ if(data->state.upload) + state(conn, SSH_SFTP_UPLOAD_INIT); + else { + if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/') diff -Nru curl-7.74.0/debian/patches/series curl-7.74.0/debian/patches/series --- curl-7.74.0/debian/patches/series 2023-04-03 03:34:17.000000000 +0800 +++ curl-7.74.0/debian/patches/series 2023-09-10 17:49:20.000000000 +0800 @@ -38,6 +38,8 @@ add_Curl_timestrcmp.patch CVE-2023-27535.patch CVE-2023-27536.patch +CVE-2023-28321.patch +CVE-2023-28322.patch # Always add CVE patches before these two patches 90_gnutls.patch