From fadd70f9a4afbf392234c570ac1fa86ffc78cd42 Mon Sep 17 00:00:00 2001 From: Azure Linux Security Servicing Account Date: Tue, 17 Mar 2026 08:50:19 +0000 Subject: [PATCH 1/2] Patch curl for CVE-2026-3784, CVE-2026-3783, CVE-2026-1965 --- SPECS/curl/CVE-2026-1965.patch | 123 ++++++++++++++ SPECS/curl/CVE-2026-3783.patch | 150 +++++++++++++++++ SPECS/curl/CVE-2026-3784.patch | 157 ++++++++++++++++++ SPECS/curl/curl.spec | 8 +- .../manifests/package/pkggen_core_aarch64.txt | 6 +- .../manifests/package/pkggen_core_x86_64.txt | 6 +- .../manifests/package/toolchain_aarch64.txt | 8 +- .../manifests/package/toolchain_x86_64.txt | 8 +- 8 files changed, 451 insertions(+), 15 deletions(-) create mode 100644 SPECS/curl/CVE-2026-1965.patch create mode 100644 SPECS/curl/CVE-2026-3783.patch create mode 100644 SPECS/curl/CVE-2026-3784.patch diff --git a/SPECS/curl/CVE-2026-1965.patch b/SPECS/curl/CVE-2026-1965.patch new file mode 100644 index 00000000000..b0527d29d9d --- /dev/null +++ b/SPECS/curl/CVE-2026-1965.patch @@ -0,0 +1,123 @@ +From ea09565f97ec01556a181d7e0f620020dc9a3fae Mon Sep 17 00:00:00 2001 +From: AllSpark +Date: Tue, 17 Mar 2026 08:42:29 +0000 +Subject: [PATCH] url: fix reuse of connections using HTTP Negotiate + +Assume Negotiate means connection-based + +Reported-by: Zhicheng Chen +Closes #20534 + +Follow-up: fix copy and paste url_match_auth_nego mistake +Reported-by: dahmono on github +Closes #20662 + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: AI Backport of https://github.com/curl/curl/commit/34fa034d9a390c4bd65e2d05262755ec8646ac12.patch https://github.com/curl/curl/commit/f1a39f221d57354990e3eeeddc3404aede2aff70.patch +--- + lib/url.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 68 insertions(+) + +diff --git a/lib/url.c b/lib/url.c +index e1e1114..9cf4212 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -923,6 +923,20 @@ ConnectionExists(struct Curl_easy *data, + bool wantProxyNTLMhttp = FALSE; + #endif + #endif ++#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) ++ bool wantNEGOhttp = ++ ((data->state.authhost.want & CURLAUTH_NEGOTIATE) && ++ (needle->handler->protocol & PROTO_FAMILY_HTTP)); ++#ifndef CURL_DISABLE_PROXY ++ bool wantProxyNEGOhttp = ++ (needle->bits.proxy_user_passwd && ++ (data->state.authproxy.want & CURLAUTH_NEGOTIATE) && ++ (needle->handler->protocol & PROTO_FAMILY_HTTP)); ++#else ++ bool wantProxyNEGOhttp = FALSE; ++#endif ++#endif ++ + /* plain HTTP with upgrade */ + bool h2upgrade = (data->state.httpwant == CURL_HTTP_VERSION_2_0) && + (needle->handler->protocol & CURLPROTO_HTTP); +@@ -1199,6 +1213,58 @@ ConnectionExists(struct Curl_easy *data, + } + } + ++#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) ++ /* If we are looking for an HTTP+Negotiate connection, check if this is ++ already authenticating with the right credentials. If not, keep ++ looking so that we can reuse Negotiate connections if possible. */ ++ if(wantNEGOhttp) { ++ if(Curl_timestrcmp(needle->user, check->user) || ++ Curl_timestrcmp(needle->passwd, check->passwd)) ++ continue; ++ } ++ else if(check->http_negotiate_state != GSS_AUTHNONE) { ++ /* Connection is using Negotiate auth but we don't want Negotiate */ ++ continue; ++ } ++ ++#ifndef CURL_DISABLE_PROXY ++ /* Same for Proxy Negotiate authentication */ ++ if(wantProxyNEGOhttp) { ++ /* Both check->http_proxy.user and check->http_proxy.passwd can be ++ * NULL */ ++ if(!check->http_proxy.user || !check->http_proxy.passwd) ++ continue; ++ ++ if(Curl_timestrcmp(needle->http_proxy.user, ++ check->http_proxy.user) || ++ Curl_timestrcmp(needle->http_proxy.passwd, ++ check->http_proxy.passwd)) ++ continue; ++ } ++ else if(check->proxy_negotiate_state != GSS_AUTHNONE) { ++ /* Proxy connection is using Negotiate auth but we don't want Negotiate */ ++ continue; ++ } ++#endif ++ if(wantNEGOhttp || wantProxyNEGOhttp) { ++ /* Credentials are already checked, we may use this connection. We MUST ++ * use a connection where it has already been fully negotiated. If it has ++ * not, we keep on looking for a better one. */ ++ chosen = check; ++ ++ if((wantNEGOhttp && ++ (check->http_negotiate_state != GSS_AUTHNONE)) || ++ (wantProxyNEGOhttp && ++ (check->proxy_negotiate_state != GSS_AUTHNONE))) { ++ /* We must use this connection, no other */ ++ *force_reuse = TRUE; ++ break; ++ } ++ /* Continue look up for a better connection */ ++ continue; ++ } ++#endif ++ + #if defined(USE_NTLM) + /* If we are looking for an HTTP+NTLM connection, check if this is + already authenticating with the right credentials. If not, keep +@@ -1245,6 +1311,7 @@ ConnectionExists(struct Curl_easy *data, + * With NTLM being weird as it is, we MUST use a + * connection where it has already been fully negotiated. + * If it has not, we keep on looking for a better one. */ ++ + chosen = check; + + if((wantNTLMhttp && +@@ -1311,6 +1378,7 @@ ConnectionExists(struct Curl_easy *data, + /* + * verboseconnect() displays verbose information after a connect + */ ++ + #ifndef CURL_DISABLE_VERBOSE_STRINGS + void Curl_verboseconnect(struct Curl_easy *data, + struct connectdata *conn, int sockindex) +-- +2.45.4 + diff --git a/SPECS/curl/CVE-2026-3783.patch b/SPECS/curl/CVE-2026-3783.patch new file mode 100644 index 00000000000..8036142a2b4 --- /dev/null +++ b/SPECS/curl/CVE-2026-3783.patch @@ -0,0 +1,150 @@ +From e6c4f5b335c4262e91557d7aa4b36b0f5e24350d Mon Sep 17 00:00:00 2001 +From: AllSpark +Date: Tue, 17 Mar 2026 08:31:07 +0000 +Subject: [PATCH] http: only send bearer if auth is allowed + +Verify with test 2006 + +Closes #20843 + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: AI Backport of https://github.com/curl/curl/commit/e3d7401a32a46516c9e5ee877e613e62ed35bddc.patch +--- + lib/http.c | 1 + + tests/data/Makefile.inc | 2 +- + tests/data/test2006 | 98 +++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 100 insertions(+), 1 deletion(-) + create mode 100644 tests/data/test2006 + +diff --git a/lib/http.c b/lib/http.c +index 2a41f80..093954f 100644 +--- a/lib/http.c ++++ b/lib/http.c +@@ -659,6 +659,7 @@ output_auth_headers(struct Curl_easy *data, + if(authstatus->picked == CURLAUTH_BEARER) { + /* Bearer */ + if((!proxy && data->set.str[STRING_BEARER] && ++ Curl_auth_allowed_to_host(data) && + !Curl_checkheaders(data, STRCONST("Authorization")))) { + auth = "Bearer"; + result = http_output_bearer(data); +diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc +index f34dd00..16af0e5 100644 +--- a/tests/data/Makefile.inc ++++ b/tests/data/Makefile.inc +@@ -231,7 +231,7 @@ test1941 test1942 test1943 test1944 test1945 test1946 test1947 test1948 \ + test1955 test1956 test1957 test1958 test1959 test1960 test1964 \ + test1970 test1971 test1972 test1973 test1974 test1975 \ + \ +-test2000 test2001 test2002 test2003 test2004 \ ++test2000 test2001 test2002 test2003 test2004 test2006 \ + \ + test2023 \ + test2024 test2025 test2026 test2027 test2028 test2029 test2030 test2031 \ +diff --git a/tests/data/test2006 b/tests/data/test2006 +new file mode 100644 +index 0000000..200d30a +--- /dev/null ++++ b/tests/data/test2006 +@@ -0,0 +1,98 @@ ++ ++ ++ ++ ++netrc ++HTTP ++ ++ ++# Server-side ++ ++ ++HTTP/1.1 301 Follow this you fool ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT ++ETag: "21025-dc7-39462498" ++Accept-Ranges: bytes ++Content-Length: 6 ++Connection: close ++Location: http://b.com/%TESTNUMBER0002 ++ ++-foo- ++ ++ ++ ++HTTP/1.1 200 OK ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT ++ETag: "21025-dc7-39462498" ++Accept-Ranges: bytes ++Content-Length: 7 ++Connection: close ++ ++target ++ ++ ++ ++HTTP/1.1 301 Follow this you fool ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT ++ETag: "21025-dc7-39462498" ++Accept-Ranges: bytes ++Content-Length: 6 ++Connection: close ++Location: http://b.com/%TESTNUMBER0002 ++ ++HTTP/1.1 200 OK ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Server: test-server/fake ++Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT ++ETag: "21025-dc7-39462498" ++Accept-Ranges: bytes ++Content-Length: 7 ++Connection: close ++ ++target ++ ++ ++ ++# Client-side ++ ++ ++http ++ ++ ++proxy ++ ++ ++.netrc default with redirect plus oauth2-bearer ++ ++ ++--netrc --netrc-file %LOGDIR/netrc%TESTNUMBER --oauth2-bearer SECRET_TOKEN -L -x http://%HOSTIP:%HTTPPORT/ http://a.com/ ++ ++ ++default login testuser password testpass ++ ++ ++ ++ ++ ++GET http://a.com/ HTTP/1.1 ++Host: a.com ++Authorization: Bearer SECRET_TOKEN ++User-Agent: curl/%VERSION ++Accept: */* ++Proxy-Connection: Keep-Alive ++ ++GET http://b.com/%TESTNUMBER0002 HTTP/1.1 ++Host: b.com ++User-Agent: curl/%VERSION ++Accept: */* ++Proxy-Connection: Keep-Alive ++ ++ ++ ++ +-- +2.45.4 + diff --git a/SPECS/curl/CVE-2026-3784.patch b/SPECS/curl/CVE-2026-3784.patch new file mode 100644 index 00000000000..eb36dbcb637 --- /dev/null +++ b/SPECS/curl/CVE-2026-3784.patch @@ -0,0 +1,157 @@ +From d7337fa3771417e046f1d816cc3c66d6517fe380 Mon Sep 17 00:00:00 2001 +From: AllSpark +Date: Tue, 17 Mar 2026 08:36:04 +0000 +Subject: [PATCH] proxy-auth: additional tests and unify socks proxy matching + with proxy_info_matches; allow per-URL options in test curl client + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: AI Backport of https://github.com/curl/curl/commit/5f13a7645e565c5c1a06f3ef86e97afb856fb364.patch +--- + lib/url.c | 29 ++++++++--------------------- + tests/http/test_13_proxy_auth.py | 21 +++++++++++++++++++++ + tests/http/testenv/curl.py | 16 +++++++++++++--- + 3 files changed, 42 insertions(+), 24 deletions(-) + +diff --git a/lib/url.c b/lib/url.c +index 10d875a..e1e1114 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -710,34 +710,21 @@ proxy_info_matches(const struct proxy_info *data, + { + if((data->proxytype == needle->proxytype) && + (data->port == needle->port) && +- strcasecompare(data->host.name, needle->host.name)) +- return TRUE; ++ strcasecompare(data->host.name, needle->host.name)) { + ++ if(Curl_timestrcmp(data->user, needle->user) || ++ Curl_timestrcmp(data->passwd, needle->passwd)) ++ return FALSE; ++ return TRUE; ++ } + return FALSE; + } + +-static bool +-socks_proxy_info_matches(const struct proxy_info *data, +- const struct proxy_info *needle) +-{ +- if(!proxy_info_matches(data, needle)) +- return FALSE; +- +- /* the user information is case-sensitive +- or at least it is not defined as case-insensitive +- see https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.1 */ + +- /* curl_strequal does a case insensitive comparison, +- so do not use it here! */ +- if(Curl_timestrcmp(data->user, needle->user) || +- Curl_timestrcmp(data->passwd, needle->passwd)) +- return FALSE; +- return TRUE; +-} + #else + /* disabled, won't get called */ + #define proxy_info_matches(x,y) FALSE +-#define socks_proxy_info_matches(x,y) FALSE ++#define socks_proxy_info_matches(x,y) FALSE /* removed */ + #endif + + /* A connection has to have been idle for a shorter time than 'maxage_conn' +@@ -1072,7 +1059,7 @@ ConnectionExists(struct Curl_easy *data, + continue; + + if(needle->bits.socksproxy && +- !socks_proxy_info_matches(&needle->socks_proxy, ++ !proxy_info_matches(&needle->socks_proxy, + &check->socks_proxy)) + continue; + +diff --git a/tests/http/test_13_proxy_auth.py b/tests/http/test_13_proxy_auth.py +index abeae01..c35be91 100644 +--- a/tests/http/test_13_proxy_auth.py ++++ b/tests/http/test_13_proxy_auth.py +@@ -155,3 +155,24 @@ class TestProxyAuth: + protocol='HTTP/2' if proto == 'h2' else 'HTTP/1.1') + assert self.get_tunnel_proto_used(r) == 'HTTP/2' \ + if tunnel == 'h2' else 'HTTP/1.1' ++ ++ ++ def test_13_10_tunnels_mixed_auth(self, env: Env, httpd, configures_httpd): ++ self.httpd_configure(env, httpd) ++ curl = CurlClient(env=env) ++ url1 = f'http://localhost:{env.http_port}/data.json?1' ++ url2 = f'http://localhost:{env.http_port}/data.json?2' ++ url3 = f'http://localhost:{env.http_port}/data.json?3' ++ xargs1 = curl.get_proxy_args(proxys=False, tunnel=True) ++ xargs1.extend(['--proxy-user', 'proxy:proxy']) # good auth ++ xargs2 = curl.get_proxy_args(proxys=False, tunnel=True) ++ xargs2.extend(['--proxy-user', 'ungood:ungood']) # bad auth ++ xargs3 = curl.get_proxy_args(proxys=False, tunnel=True) ++ # no auth ++ r = curl.http_download(urls=[url1, url2, url3], alpn_proto='http/1.1', with_stats=True, ++ url_options={url1: xargs1, url2: xargs2, url3: xargs3}) ++ # only url1 succeeds, others fail, no connection reuse ++ assert r.stats[0]['http_code'] == 200, f'{r.dump_logs()}' ++ assert r.stats[1]['http_code'] == 0, f'{r.dump_logs()}' ++ assert r.stats[2]['http_code'] == 0, f'{r.dump_logs()}' ++ assert r.total_connects == 3, f'{r.dump_logs()}' +diff --git a/tests/http/testenv/curl.py b/tests/http/testenv/curl.py +index 23b70b2..cdaa25b 100644 +--- a/tests/http/testenv/curl.py ++++ b/tests/http/testenv/curl.py +@@ -431,7 +431,8 @@ class CurlClient: + with_headers: bool = False, + with_profile: bool = False, + no_save: bool = False, +- extra_args: List[str] = None): ++ extra_args: List[str] = None, ++ url_options: Optional[Dict[str,List[str]]] = None): + if extra_args is None: + extra_args = [] + if no_save: +@@ -451,6 +452,7 @@ class CurlClient: + ]) + return self._raw(urls, alpn_proto=alpn_proto, options=extra_args, + with_stats=with_stats, ++ url_options=url_options, + with_headers=with_headers, + with_profile=with_profile) + +@@ -659,7 +661,8 @@ class CurlClient: + args = self._complete_args( + urls=urls, timeout=timeout, options=options, insecure=insecure, + alpn_proto=alpn_proto, force_resolve=force_resolve, +- with_headers=with_headers, def_tracing=def_tracing) ++ with_headers=with_headers, def_tracing=def_tracing, ++ url_options=url_options) + r = self._run(args, intext=intext, with_stats=with_stats, + with_profile=with_profile) + if r.exit_code == 0 and with_headers: +@@ -671,6 +674,7 @@ class CurlClient: + def _complete_args(self, urls, timeout=None, options=None, + insecure=False, force_resolve=True, + alpn_proto: Optional[str] = None, ++ url_options=None, + with_headers: bool = True, + def_tracing: bool = True): + if not isinstance(urls, list): +@@ -689,8 +693,14 @@ class CurlClient: + if options is not None and '--next' in options: + active_options = options[options.index('--next') + 1:] + ++ url_sep = [] + for url in urls: +- u = urlparse(urls[0]) ++ args.extend(url_sep) ++ if url_options is not None: ++ url_sep = ['--next'] ++ u = urlparse(url) ++ if url_options is not None and url in url_options: ++ args.extend(url_options[url]) + if options: + args.extend(options) + if alpn_proto is not None: +-- +2.45.4 + diff --git a/SPECS/curl/curl.spec b/SPECS/curl/curl.spec index 48d4ad58772..4766fa60777 100644 --- a/SPECS/curl/curl.spec +++ b/SPECS/curl/curl.spec @@ -1,7 +1,7 @@ Summary: An URL retrieval utility and library Name: curl Version: 8.8.0 -Release: 8%{?dist} +Release: 9%{?dist} License: curl Vendor: Microsoft Corporation Distribution: Mariner @@ -15,6 +15,9 @@ Patch3: CVE-2024-9681.patch Patch4: CVE-2025-0167.patch Patch5: CVE-2025-10148.patch Patch6: CVE-2025-14017.patch +Patch7: CVE-2026-1965.patch +Patch8: CVE-2026-3783.patch +Patch9: CVE-2026-3784.patch BuildRequires: krb5-devel BuildRequires: libssh2-devel BuildRequires: nghttp2-devel @@ -92,6 +95,9 @@ find %{buildroot} -type f -name "*.la" -delete -print %{_libdir}/libcurl.so.* %changelog +* Tue Mar 17 2026 Azure Linux Security Servicing Account - 8.8.0-9 +- Patch for CVE-2026-3784, CVE-2026-3783, CVE-2026-1965 + * Fri Jan 09 2026 Azure Linux Security Servicing Account - 8.8.0-8 - Patch for CVE-2025-14017 diff --git a/toolkit/resources/manifests/package/pkggen_core_aarch64.txt b/toolkit/resources/manifests/package/pkggen_core_aarch64.txt index a3002ac039e..92841664eb1 100644 --- a/toolkit/resources/manifests/package/pkggen_core_aarch64.txt +++ b/toolkit/resources/manifests/package/pkggen_core_aarch64.txt @@ -190,9 +190,9 @@ libssh2-1.9.0-4.cm2.aarch64.rpm libssh2-devel-1.9.0-4.cm2.aarch64.rpm krb5-1.19.4-5.cm2.aarch64.rpm nghttp2-1.57.0-2.cm2.aarch64.rpm -curl-8.8.0-8.cm2.aarch64.rpm -curl-devel-8.8.0-8.cm2.aarch64.rpm -curl-libs-8.8.0-8.cm2.aarch64.rpm +curl-8.8.0-9.cm2.aarch64.rpm +curl-devel-8.8.0-9.cm2.aarch64.rpm +curl-libs-8.8.0-9.cm2.aarch64.rpm createrepo_c-0.17.5-1.cm2.aarch64.rpm libxml2-2.10.4-11.cm2.aarch64.rpm libxml2-devel-2.10.4-11.cm2.aarch64.rpm diff --git a/toolkit/resources/manifests/package/pkggen_core_x86_64.txt b/toolkit/resources/manifests/package/pkggen_core_x86_64.txt index 9735869dfdc..351176940f7 100644 --- a/toolkit/resources/manifests/package/pkggen_core_x86_64.txt +++ b/toolkit/resources/manifests/package/pkggen_core_x86_64.txt @@ -190,9 +190,9 @@ libssh2-1.9.0-4.cm2.x86_64.rpm libssh2-devel-1.9.0-4.cm2.x86_64.rpm krb5-1.19.4-5.cm2.x86_64.rpm nghttp2-1.57.0-2.cm2.x86_64.rpm -curl-8.8.0-8.cm2.x86_64.rpm -curl-devel-8.8.0-8.cm2.x86_64.rpm -curl-libs-8.8.0-8.cm2.x86_64.rpm +curl-8.8.0-9.cm2.x86_64.rpm +curl-devel-8.8.0-9.cm2.x86_64.rpm +curl-libs-8.8.0-9.cm2.x86_64.rpm createrepo_c-0.17.5-1.cm2.x86_64.rpm libxml2-2.10.4-11.cm2.x86_64.rpm libxml2-devel-2.10.4-11.cm2.x86_64.rpm diff --git a/toolkit/resources/manifests/package/toolchain_aarch64.txt b/toolkit/resources/manifests/package/toolchain_aarch64.txt index ae98412399f..3287afd2bcb 100644 --- a/toolkit/resources/manifests/package/toolchain_aarch64.txt +++ b/toolkit/resources/manifests/package/toolchain_aarch64.txt @@ -46,10 +46,10 @@ cracklib-lang-2.9.7-5.cm2.aarch64.rpm createrepo_c-0.17.5-1.cm2.aarch64.rpm createrepo_c-debuginfo-0.17.5-1.cm2.aarch64.rpm createrepo_c-devel-0.17.5-1.cm2.aarch64.rpm -curl-8.8.0-8.cm2.aarch64.rpm -curl-debuginfo-8.8.0-8.cm2.aarch64.rpm -curl-devel-8.8.0-8.cm2.aarch64.rpm -curl-libs-8.8.0-8.cm2.aarch64.rpm +curl-8.8.0-9.cm2.aarch64.rpm +curl-debuginfo-8.8.0-9.cm2.aarch64.rpm +curl-devel-8.8.0-9.cm2.aarch64.rpm +curl-libs-8.8.0-9.cm2.aarch64.rpm Cython-debuginfo-0.29.33-2.cm2.aarch64.rpm debugedit-5.0-2.cm2.aarch64.rpm debugedit-debuginfo-5.0-2.cm2.aarch64.rpm diff --git a/toolkit/resources/manifests/package/toolchain_x86_64.txt b/toolkit/resources/manifests/package/toolchain_x86_64.txt index 6a330887776..1da9d00f290 100644 --- a/toolkit/resources/manifests/package/toolchain_x86_64.txt +++ b/toolkit/resources/manifests/package/toolchain_x86_64.txt @@ -49,10 +49,10 @@ createrepo_c-debuginfo-0.17.5-1.cm2.x86_64.rpm createrepo_c-devel-0.17.5-1.cm2.x86_64.rpm cross-binutils-common-2.37-20.cm2.noarch.rpm cross-gcc-common-11.2.0-9.cm2.noarch.rpm -curl-8.8.0-8.cm2.x86_64.rpm -curl-debuginfo-8.8.0-8.cm2.x86_64.rpm -curl-devel-8.8.0-8.cm2.x86_64.rpm -curl-libs-8.8.0-8.cm2.x86_64.rpm +curl-8.8.0-9.cm2.x86_64.rpm +curl-debuginfo-8.8.0-9.cm2.x86_64.rpm +curl-devel-8.8.0-9.cm2.x86_64.rpm +curl-libs-8.8.0-9.cm2.x86_64.rpm Cython-debuginfo-0.29.33-2.cm2.x86_64.rpm debugedit-5.0-2.cm2.x86_64.rpm debugedit-debuginfo-5.0-2.cm2.x86_64.rpm From eb258f9b12a20f3da689a6c98c8036a177b972a7 Mon Sep 17 00:00:00 2001 From: akhila-guruju Date: Wed, 18 Mar 2026 11:05:07 +0000 Subject: [PATCH 2/2] modify AI patches --- SPECS/curl/CVE-2026-1965.patch | 159 ++++++++++++++------------------- SPECS/curl/CVE-2026-3783.patch | 21 +++-- SPECS/curl/CVE-2026-3784.patch | 55 +++++++----- 3 files changed, 111 insertions(+), 124 deletions(-) diff --git a/SPECS/curl/CVE-2026-1965.patch b/SPECS/curl/CVE-2026-1965.patch index b0527d29d9d..82544d662bd 100644 --- a/SPECS/curl/CVE-2026-1965.patch +++ b/SPECS/curl/CVE-2026-1965.patch @@ -1,6 +1,6 @@ -From ea09565f97ec01556a181d7e0f620020dc9a3fae Mon Sep 17 00:00:00 2001 -From: AllSpark -Date: Tue, 17 Mar 2026 08:42:29 +0000 +From 34fa034d9a390c4bd65e2d05262755ec8646ac12 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Thu, 5 Feb 2026 08:34:21 +0100 Subject: [PATCH] url: fix reuse of connections using HTTP Negotiate Assume Negotiate means connection-based @@ -8,116 +8,93 @@ Assume Negotiate means connection-based Reported-by: Zhicheng Chen Closes #20534 -Follow-up: fix copy and paste url_match_auth_nego mistake -Reported-by: dahmono on github -Closes #20662 - -Signed-off-by: Azure Linux Security Servicing Account -Upstream-reference: AI Backport of https://github.com/curl/curl/commit/34fa034d9a390c4bd65e2d05262755ec8646ac12.patch https://github.com/curl/curl/commit/f1a39f221d57354990e3eeeddc3404aede2aff70.patch +Upstream reference: +origin: https://github.com/curl/curl/commit/34fa034d9a390c4bd65e2d05262755ec8646ac12.patch & https://github.com/curl/curl/commit/f1a39f221d57354990e3eeeddc3404aede2aff70.patch +Backported patch: https://git.launchpad.net/ubuntu/+source/curl/commit/?id=74697d38d36fa04b9656361a714b7a3d863e43b9 --- - lib/url.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 68 insertions(+) + lib/url.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 62 insertions(+) diff --git a/lib/url.c b/lib/url.c -index e1e1114..9cf4212 100644 +index 10d875a..6ad8115 100644 --- a/lib/url.c +++ b/lib/url.c -@@ -923,6 +923,20 @@ ConnectionExists(struct Curl_easy *data, +@@ -935,6 +935,18 @@ ConnectionExists(struct Curl_easy *data, + #else bool wantProxyNTLMhttp = FALSE; #endif - #endif ++#endif ++ +#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) -+ bool wantNEGOhttp = -+ ((data->state.authhost.want & CURLAUTH_NEGOTIATE) && -+ (needle->handler->protocol & PROTO_FAMILY_HTTP)); ++ bool wantNegohttp = ++ (data->state.authhost.want & CURLAUTH_NEGOTIATE) && ++ (needle->handler->protocol & PROTO_FAMILY_HTTP); +#ifndef CURL_DISABLE_PROXY -+ bool wantProxyNEGOhttp = -+ (needle->bits.proxy_user_passwd && -+ (data->state.authproxy.want & CURLAUTH_NEGOTIATE) && -+ (needle->handler->protocol & PROTO_FAMILY_HTTP)); -+#else -+ bool wantProxyNEGOhttp = FALSE; -+#endif ++ bool wantProxyNegohttp = ++ needle->bits.proxy_user_passwd && ++ (data->state.authproxy.want & CURLAUTH_NEGOTIATE) && ++ (needle->handler->protocol & PROTO_FAMILY_HTTP); +#endif -+ + #endif /* plain HTTP with upgrade */ bool h2upgrade = (data->state.httpwant == CURL_HTTP_VERSION_2_0) && - (needle->handler->protocol & CURLPROTO_HTTP); -@@ -1199,6 +1213,58 @@ ConnectionExists(struct Curl_easy *data, - } +@@ -1273,6 +1285,56 @@ ConnectionExists(struct Curl_easy *data, } + #endif -+#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO) -+ /* If we are looking for an HTTP+Negotiate connection, check if this is -+ already authenticating with the right credentials. If not, keep -+ looking so that we can reuse Negotiate connections if possible. */ -+ if(wantNEGOhttp) { -+ if(Curl_timestrcmp(needle->user, check->user) || -+ Curl_timestrcmp(needle->passwd, check->passwd)) -+ continue; -+ } -+ else if(check->http_negotiate_state != GSS_AUTHNONE) { -+ /* Connection is using Negotiate auth but we don't want Negotiate */ ++#ifdef USE_SPNEGO ++ /* If we are looking for an HTTP+Negotiate connection, check if this is ++ already authenticating with the right credentials. If not, keep looking ++ so that we can reuse Negotiate connections if possible. */ ++ if(wantNegohttp) { ++ if(Curl_timestrcmp(needle->user, check->user) || ++ Curl_timestrcmp(needle->passwd, check->passwd)) + continue; -+ } ++ } ++ else if(check->http_negotiate_state != GSS_AUTHNONE) { ++ /* Connection is using Negotiate auth but we do not want Negotiate */ ++ continue; ++ } + +#ifndef CURL_DISABLE_PROXY -+ /* Same for Proxy Negotiate authentication */ -+ if(wantProxyNEGOhttp) { -+ /* Both check->http_proxy.user and check->http_proxy.passwd can be -+ * NULL */ -+ if(!check->http_proxy.user || !check->http_proxy.passwd) -+ continue; -+ -+ if(Curl_timestrcmp(needle->http_proxy.user, -+ check->http_proxy.user) || -+ Curl_timestrcmp(needle->http_proxy.passwd, -+ check->http_proxy.passwd)) -+ continue; -+ } -+ else if(check->proxy_negotiate_state != GSS_AUTHNONE) { -+ /* Proxy connection is using Negotiate auth but we don't want Negotiate */ ++ /* Same for Proxy Negotiate authentication */ ++ if(wantProxyNegohttp) { ++ /* Both check->http_proxy.user and check->http_proxy.passwd can be ++ * NULL */ ++ if(!check->http_proxy.user || !check->http_proxy.passwd) + continue; -+ } -+#endif -+ if(wantNEGOhttp || wantProxyNEGOhttp) { -+ /* Credentials are already checked, we may use this connection. We MUST -+ * use a connection where it has already been fully negotiated. If it has -+ * not, we keep on looking for a better one. */ -+ chosen = check; + -+ if((wantNEGOhttp && -+ (check->http_negotiate_state != GSS_AUTHNONE)) || -+ (wantProxyNEGOhttp && -+ (check->proxy_negotiate_state != GSS_AUTHNONE))) { -+ /* We must use this connection, no other */ -+ *force_reuse = TRUE; -+ break; -+ } -+ /* Continue look up for a better connection */ ++ if(Curl_timestrcmp(needle->http_proxy.user, ++ check->http_proxy.user) || ++ Curl_timestrcmp(needle->http_proxy.passwd, ++ check->http_proxy.passwd)) + continue; ++ } ++ else if(check->proxy_negotiate_state != GSS_AUTHNONE) { ++ /* Proxy connection is using Negotiate auth but we do not want Negotiate */ ++ continue; ++ } ++#endif ++ if(wantNegohttp || wantProxyNegohttp) { ++ /* Credentials are already checked, we may use this connection. We MUST ++ * use a connection where it has already been fully negotiated. If it has ++ * not, we keep on looking for a better one. */ ++ chosen = check; ++ if((wantNegohttp && ++ (check->http_negotiate_state != GSS_AUTHNONE)) || ++ (wantProxyNegohttp && ++ (check->proxy_negotiate_state != GSS_AUTHNONE))) { ++ /* We must use this connection, no other */ ++ *force_reuse = TRUE; ++ break; + } ++ continue; /* get another */ ++ } +#endif + - #if defined(USE_NTLM) - /* If we are looking for an HTTP+NTLM connection, check if this is - already authenticating with the right credentials. If not, keep -@@ -1245,6 +1311,7 @@ ConnectionExists(struct Curl_easy *data, - * With NTLM being weird as it is, we MUST use a - * connection where it has already been fully negotiated. - * If it has not, we keep on looking for a better one. */ -+ - chosen = check; - - if((wantNTLMhttp && -@@ -1311,6 +1378,7 @@ ConnectionExists(struct Curl_easy *data, - /* - * verboseconnect() displays verbose information after a connect - */ -+ - #ifndef CURL_DISABLE_VERBOSE_STRINGS - void Curl_verboseconnect(struct Curl_easy *data, - struct connectdata *conn, int sockindex) + if(CONN_INUSE(check)) { + DEBUGASSERT(canmultiplex); + DEBUGASSERT(check->bits.multiplex); -- -2.45.4 +2.43.0 diff --git a/SPECS/curl/CVE-2026-3783.patch b/SPECS/curl/CVE-2026-3783.patch index 8036142a2b4..3f5f7f43b99 100644 --- a/SPECS/curl/CVE-2026-3783.patch +++ b/SPECS/curl/CVE-2026-3783.patch @@ -1,14 +1,13 @@ -From e6c4f5b335c4262e91557d7aa4b36b0f5e24350d Mon Sep 17 00:00:00 2001 -From: AllSpark -Date: Tue, 17 Mar 2026 08:31:07 +0000 +From e3d7401a32a46516c9e5ee877e613e62ed35bddc Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Fri, 6 Mar 2026 23:13:07 +0100 Subject: [PATCH] http: only send bearer if auth is allowed Verify with test 2006 Closes #20843 -Signed-off-by: Azure Linux Security Servicing Account -Upstream-reference: AI Backport of https://github.com/curl/curl/commit/e3d7401a32a46516c9e5ee877e613e62ed35bddc.patch +Upstream Patch reference: https://github.com/curl/curl/commit/e3d7401a32a46516c9e5ee877e613e62ed35bddc.patch --- lib/http.c | 1 + tests/data/Makefile.inc | 2 +- @@ -43,7 +42,7 @@ index f34dd00..16af0e5 100644 test2024 test2025 test2026 test2027 test2028 test2029 test2030 test2031 \ diff --git a/tests/data/test2006 b/tests/data/test2006 new file mode 100644 -index 0000000..200d30a +index 0000000..4b8b269 --- /dev/null +++ b/tests/data/test2006 @@ -0,0 +1,98 @@ @@ -57,7 +56,7 @@ index 0000000..200d30a + +# Server-side + -+ ++ +HTTP/1.1 301 Follow this you fool +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake @@ -71,7 +70,7 @@ index 0000000..200d30a +-foo- + + -+ ++ +HTTP/1.1 200 OK +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake @@ -84,7 +83,7 @@ index 0000000..200d30a +target + + -+ ++ +HTTP/1.1 301 Follow this you fool +Date: Tue, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake @@ -128,7 +127,7 @@ index 0000000..200d30a + + + -+ ++ +GET http://a.com/ HTTP/1.1 +Host: a.com +Authorization: Bearer SECRET_TOKEN @@ -146,5 +145,5 @@ index 0000000..200d30a + + -- -2.45.4 +2.43.0 diff --git a/SPECS/curl/CVE-2026-3784.patch b/SPECS/curl/CVE-2026-3784.patch index eb36dbcb637..d0fb7546b09 100644 --- a/SPECS/curl/CVE-2026-3784.patch +++ b/SPECS/curl/CVE-2026-3784.patch @@ -1,19 +1,21 @@ -From d7337fa3771417e046f1d816cc3c66d6517fe380 Mon Sep 17 00:00:00 2001 -From: AllSpark -Date: Tue, 17 Mar 2026 08:36:04 +0000 -Subject: [PATCH] proxy-auth: additional tests and unify socks proxy matching - with proxy_info_matches; allow per-URL options in test curl client +From 5f13a7645e565c5c1a06f3ef86e97afb856fb364 Mon Sep 17 00:00:00 2001 +From: Stefan Eissing +Date: Fri, 6 Mar 2026 14:54:09 +0100 +Subject: [PATCH] proxy-auth: additional tests -Signed-off-by: Azure Linux Security Servicing Account -Upstream-reference: AI Backport of https://github.com/curl/curl/commit/5f13a7645e565c5c1a06f3ef86e97afb856fb364.patch +Also eliminate the special handling for socks proxy match. + +Closes #20837 + +Upstream Patch reference: https://github.com/curl/curl/commit/5f13a7645e565c5c1a06f3ef86e97afb856fb364.patch --- lib/url.c | 29 ++++++++--------------------- - tests/http/test_13_proxy_auth.py | 21 +++++++++++++++++++++ - tests/http/testenv/curl.py | 16 +++++++++++++--- - 3 files changed, 42 insertions(+), 24 deletions(-) + tests/http/test_13_proxy_auth.py | 20 ++++++++++++++++++++ + tests/http/testenv/curl.py | 18 +++++++++++++++--- + 3 files changed, 43 insertions(+), 24 deletions(-) diff --git a/lib/url.c b/lib/url.c -index 10d875a..e1e1114 100644 +index 6ad8115..0f8dccb 100644 --- a/lib/url.c +++ b/lib/url.c @@ -710,34 +710,21 @@ proxy_info_matches(const struct proxy_info *data, @@ -58,7 +60,7 @@ index 10d875a..e1e1114 100644 #endif /* A connection has to have been idle for a shorter time than 'maxage_conn' -@@ -1072,7 +1059,7 @@ ConnectionExists(struct Curl_easy *data, +@@ -1084,7 +1071,7 @@ ConnectionExists(struct Curl_easy *data, continue; if(needle->bits.socksproxy && @@ -68,15 +70,14 @@ index 10d875a..e1e1114 100644 continue; diff --git a/tests/http/test_13_proxy_auth.py b/tests/http/test_13_proxy_auth.py -index abeae01..c35be91 100644 +index abeae01..1bf8429 100644 --- a/tests/http/test_13_proxy_auth.py +++ b/tests/http/test_13_proxy_auth.py -@@ -155,3 +155,24 @@ class TestProxyAuth: +@@ -155,3 +155,23 @@ class TestProxyAuth: protocol='HTTP/2' if proto == 'h2' else 'HTTP/1.1') assert self.get_tunnel_proto_used(r) == 'HTTP/2' \ if tunnel == 'h2' else 'HTTP/1.1' + -+ + def test_13_10_tunnels_mixed_auth(self, env: Env, httpd, configures_httpd): + self.httpd_configure(env, httpd) + curl = CurlClient(env=env) @@ -97,7 +98,7 @@ index abeae01..c35be91 100644 + assert r.stats[2]['http_code'] == 0, f'{r.dump_logs()}' + assert r.total_connects == 3, f'{r.dump_logs()}' diff --git a/tests/http/testenv/curl.py b/tests/http/testenv/curl.py -index 23b70b2..cdaa25b 100644 +index 23b70b2..e7c6754 100644 --- a/tests/http/testenv/curl.py +++ b/tests/http/testenv/curl.py @@ -431,7 +431,8 @@ class CurlClient: @@ -118,7 +119,15 @@ index 23b70b2..cdaa25b 100644 with_headers=with_headers, with_profile=with_profile) -@@ -659,7 +661,8 @@ class CurlClient: +@@ -651,6 +653,7 @@ class CurlClient: + + def _raw(self, urls, intext='', timeout=None, options=None, insecure=False, + alpn_proto: Optional[str] = None, ++ url_options=None, + force_resolve=True, + with_stats=False, + with_headers=True, +@@ -659,7 +662,8 @@ class CurlClient: args = self._complete_args( urls=urls, timeout=timeout, options=options, insecure=insecure, alpn_proto=alpn_proto, force_resolve=force_resolve, @@ -128,24 +137,26 @@ index 23b70b2..cdaa25b 100644 r = self._run(args, intext=intext, with_stats=with_stats, with_profile=with_profile) if r.exit_code == 0 and with_headers: -@@ -671,6 +674,7 @@ class CurlClient: +@@ -671,8 +675,10 @@ class CurlClient: def _complete_args(self, urls, timeout=None, options=None, insecure=False, force_resolve=True, alpn_proto: Optional[str] = None, + url_options=None, with_headers: bool = True, def_tracing: bool = True): ++ url_sep = [] if not isinstance(urls, list): -@@ -689,8 +693,14 @@ class CurlClient: - if options is not None and '--next' in options: + urls = [urls] + +@@ -690,7 +696,13 @@ class CurlClient: active_options = options[options.index('--next') + 1:] -+ url_sep = [] for url in urls: - u = urlparse(urls[0]) + args.extend(url_sep) + if url_options is not None: + url_sep = ['--next'] ++ + u = urlparse(url) + if url_options is not None and url in url_options: + args.extend(url_options[url]) @@ -153,5 +164,5 @@ index 23b70b2..cdaa25b 100644 args.extend(options) if alpn_proto is not None: -- -2.45.4 +2.43.0