From patchwork Fri Nov 6 07:19:24 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darsh Kelaiya -X (dkelaiya - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 103219 Received: from rcdn-iport-7.cisco.com (rcdn-iport-7.cisco.com [173.37.86.78]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.1219.1793949576440671950 for ; Thu, 05 Nov 2026 23:19:36 -0800 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=BJ9koAsf; spf=pass (domain: cisco.com, ip: 173.37.86.78, mailfrom: dkelaiya@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=7313; q=dns/txt; s=iport01; t=1793949576; x=1795159176; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=nssQ8Wso8i12nBne3miY76Auy5XAdB3NXsyMPSU2tQE=; b=BJ9koAsfgRYtoy9+cSLW24NyW0+8EBueX6IZGaeiv9eLd3awg7Bxl2u7 ZmNtCRRXMRyOSURwNGBMBYFz2kYmgQ21WnNDV6QgLAJotJaB1rCPWan0/ NDsRpw6+7/LkgdZPuVB5ViaEoEkfOnRJWrFEWI7rc7/uAVebhRGysy2hV VcQmnu0Bf000aGE1Zqo1I9m8n7S+VYqlGFFa17DfHiwOzDLHHvQfuv6Zl ErPehevNr9si4eDEbzJReCzX9a2nTyVP0ShPp8AG9qXImXvsEq8l4Os/9 w3M6ouXNxAkFr/10vOWOndK48ql6PIiTQE+RJ0dnADhj2FZwGQpH3+qx8 g==; X-CSE-ConnectionGUID: 5RXvW9f6Teu/IcRW8zStuA== X-CSE-MsgGUID: THdPAv0UQ1ewjO6rr3p/ig== X-IPAS-Result: A0DQAgDtfu1q/5X/Ja1aglmCV3VgQ0mWSwOeIRSBag8BAQEPRA0EAQGBcQEggnMCjh0CJjQJDgECBAMCAwEBAQEBAQEBAQEBAQoBAQUBAQECAQcFgQ4Thk8Nd4ZjiDgBAgEDJwsBGAEtEBwDAQIvKyMIGYMCAYJ0AxEGuzgbN4F5M4EBgykBPwICQAFQ2zMBCxQBgTiFQIgjXRgBhH0nGxuBcoEVg2mBBYFcAgGBIocDBIIigQyBWh5lCYwMAoFRhnlIgR4DWSwBVRMNCgsHBYFoAzUSKhVuMh2BIz4XgQcbBgWBHYEegRKBB12BKyhdASGBCIF2AoJRggACAUlBDgdFUwklQxJHJCIIEgkBExosCoEaNTwJJj8VDGQLGgVhCAINDHQ5EDAeJC8FHCY+GwovGA1IESw3FRkEPm4Hkj2DEjEMIwEhDAETFgIvgg4pklcdB5AggiGBNZ9cCiiDeIwklToaM4VbpRYLmH2OCpYETYRpgWg8gVlwFYMiCRY0GQ+OLgsLgXiBaIZAxgUmMgIJMgEBBwIHDgMLgWiRfgEB IronPort-Data: A9a23:yBKxn6Mk7gCR1LTvrR30lsFynXyQoLVcMsEvi/4bfWQNrUpx1DYDy TAWDDvXa/iPZDSgfIslb4q/8RkBsJbRmIUyG3M5pCpnJ55oRWUpJjg4wmPYZX76whjrFRo/h ykmQoCeap1yFjmD9k/F3oHJ9RFUzbuPSqf3FNnKMyVwQR4MYCo6gHqPocZh6mJTqYb/WVzlV e/a+ZWFZgb8g2Msawr41orawP9RlKWq0N8nlgRWicBj5Df2i3QTBZQDEqC9R1OQapVUBOOzW 9HYx7i/+G7Dlz91Yj9yuu+mGqGiaue60Tmm0hK6aYD76vRxjnBaPpIACRYpQRw/ZwNlMDxG4 I4lWZSYEW/FN0BX8QgXe0Ew/ypWZcWq9FJbSJSymZT78qHIT5fj66hUPF8JbINGxutqRkBFz 8NIOgsRcznW0opawJrjIgVtrt4oIM+uOMYUvWttiGiDS/0nWpvEBa7N4Le03h9p2ZsIRqmYP ZdEL2MzPXwsYDUXUrsTIJ49keOhh2j2WzZZs1mS46Ew5gA/ySQsjOS2b4WFJobiqcN9omaUn kvYp1nAWxwFNvvB0yDe6jWtibqa9c/8cMdIfFGizdZtmFCVy2kZBREaWFf+qv6jh2a6WslDM AoT4icooK04+UCnQ9W7WAe3yENopTYGUNZWVul/4waXx++NuUCSB3MPSXhKb9lOWNIKeAHGH 2Shx7vBbQGDepXPIZ5B3t94dQ+PBBU= IronPort-HdrOrdr: A9a23:4MKVEK6UwG+D7hLtAAPXwOrXdLJyesId70hD6qm+c3Nom6uj5q eTdZsgtCMc5Ax9ZJhko6HjBEDiewK5yXcK2+ks1N6ZNWGM0ldAbrsSiLcKqAePJ8SRzIJgPN 9bAstDIey1K0RmhsDn5wT9OdMhzN6btJ2Mv47lvhFQpcUAUdAZ0++/YTzra3FLeA== X-Talos-CUID: 9a23:4P7HwmED1q1xlK4GqmI6zn4KJZErLEHQ0TDxKHWHWXRSVKC8HAo= X-Talos-MUID: 9a23:pwKV/gucFjVjFdLM1M2nuBFuDO52u5mXUU0Sk7JYodPfLWtxNGLI X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.27,197,1787011200"; d="scan'208";a="544377842" Received: from rcdn-l-core-12.cisco.com ([173.37.255.149]) by rcdn-iport-7.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 06 Nov 2026 07:19:35 +0000 Received: from sjc-ads-5675.cisco.com (sjc-ads-5675.cisco.com [10.28.88.189]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-12.cisco.com (Postfix) with ESMTPS id 454AD18000326; Fri, 6 Nov 2026 07:19:35 +0000 (GMT) Received: by sjc-ads-5675.cisco.com (Postfix, from userid 1887444) id E0600CBF201; Thu, 5 Nov 2026 23:19:34 -0800 (PST) From: "Darsh Kelaiya -X (dkelaiya - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-core@lists.openembedded.org Cc: Darsh Kelaiya Subject: [OE-core][wrynose][PATCH 1/9] curl: fix CVE-2026-92391 Date: Thu, 5 Nov 2026 23:19:24 -0800 Message-Id: <20261106071932.490299-2-dkelaiya@cisco.com> X-Mailer: git-send-email 2.35.6 In-Reply-To: <20261106071932.490299-1-dkelaiya@cisco.com> References: <20261106071932.490299-1-dkelaiya@cisco.com> MIME-Version: 1.0 X-Outbound-Client-TLS: ANONYMOUS;sjc-ads-5675.cisco.com [10.28.88.189];TLSv1.3;TLS_AES_256_GCM_SHA384;256 X-Outbound-SMTP-Client: 10.28.88.189, sjc-ads-5675.cisco.com X-Outbound-Node: rcdn-l-core-12.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Fri, 06 Nov 2026 07:19:48 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/249600 From: Darsh Kelaiya This patch applies the upstream fix as referenced in [2], using the commit shown in [1]. Avoid recursive cleanup of deeply nested MIME structures. Retain upstream test3595 and register its helper in the older grouped test lists. [1] https://github.com/curl/curl/commit/d7546809d5bd548b69ec49fca26565c8f6f0d344 [2] https://curl.se/docs/CVE-2026-92391.html Signed-off-by: Darsh Kelaiya --- .../curl/curl/CVE-2026-92391.patch | 203 ++++++++++++++++++ meta/recipes-support/curl/curl_8.19.0.bb | 1 + 2 files changed, 204 insertions(+) create mode 100644 meta/recipes-support/curl/curl/CVE-2026-92391.patch diff --git a/meta/recipes-support/curl/curl/CVE-2026-92391.patch b/meta/recipes-support/curl/curl/CVE-2026-92391.patch new file mode 100644 index 0000000000..4b952050f1 --- /dev/null +++ b/meta/recipes-support/curl/curl/CVE-2026-92391.patch @@ -0,0 +1,203 @@ +From d7546809d5bd548b69ec49fca26565c8f6f0d344 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Sun, 13 Sep 2026 00:06:44 +0200 +Subject: [PATCH] mime: do curl_mime_free() non-recursively + +Verify with test 3595: deeply nested curl_mime_free() + +Closes #22927 + +CVE: CVE-2026-92391 +Upstream-Status: Backport [https://github.com/curl/curl/commit/d7546809d5bd548b69ec49fca26565c8f6f0d344] + +Backport Changes: +- Register test3595 and lib3595.c in the older grouped TESTCASES and + TESTS_C lists instead of upstream's one-entry-per-line layout. + +Signed-off-by: Darsh Kelaiya +--- + lib/mime.c | 28 +++++++++++---- + tests/data/Makefile.am | 2 +- + tests/data/test3595 | 21 ++++++++++++ + tests/libtest/Makefile.inc | 3 +- + tests/libtest/lib3595.c | 70 ++++++++++++++++++++++++++++++++++++++ + 5 files changed, 116 insertions(+), 8 deletions(-) + create mode 100644 tests/data/test3595 + create mode 100644 tests/libtest/lib3595.c + +diff --git a/lib/mime.c b/lib/mime.c +index 37ea514..3da989b 100644 +--- a/lib/mime.c ++++ b/lib/mime.c +@@ -1078,20 +1078,36 @@ void Curl_mime_cleanpart(curl_mimepart *part) + } + } + +-/* Recursively delete a mime handle and its parts. */ ++/* Non-recursively delete a mime handle and its parts. */ + void curl_mime_free(curl_mime *mime) + { + curl_mimepart *part; + +- if(mime) { +- mime_subparts_unbind(mime); /* Be sure it is not referenced anymore. */ +- while(mime->firstpart) { +- part = mime->firstpart; ++ if(!mime) ++ return; ++ ++ mime_subparts_unbind(mime); /* Be sure it is not referenced anymore. */ ++ ++ while(mime) { ++ part = mime->firstpart; ++ if(part) { + mime->firstpart = part->nextpart; ++ if(part->kind == MIMEKIND_MULTIPART && part->arg && ++ part->freefunc == mime_subparts_free) { ++ curl_mime *subparts = (curl_mime *)part->arg; ++ part->freefunc = NULL; ++ cleanup_part_content(part); ++ subparts->parent = mime->parent; ++ mime->parent = (curl_mimepart *)subparts; ++ } + Curl_mime_cleanpart(part); + curlx_free(part); + } +- curlx_free(mime); ++ else { ++ curl_mime *parent = (curl_mime *)mime->parent; ++ curlx_free(mime); ++ mime = parent; ++ } + } + } + +diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am +index 7a9b8d0..933c3c7 100644 +--- a/tests/data/Makefile.am ++++ b/tests/data/Makefile.am +@@ -287,7 +287,7 @@ test3209 test3210 test3211 test3212 test3213 test3214 test3215 test3216 \ + \ + test3303 test3304 \ + \ +-test3500 \ ++test3500 test3595 \ + \ + test4000 test4001 + +diff --git a/tests/data/test3595 b/tests/data/test3595 +new file mode 100644 +index 0000000..b2b1dd2 +--- /dev/null ++++ b/tests/data/test3595 +@@ -0,0 +1,21 @@ ++ ++ ++ ++ ++mime ++ ++ ++ ++# Client-side ++ ++ ++lib%TESTNUMBER ++ ++ ++curl_mime_free ++ ++ ++ ++ ++ ++ +diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc +index d7af26f..e494189 100644 +--- a/tests/libtest/Makefile.inc ++++ b/tests/libtest/Makefile.inc +@@ -118,4 +118,5 @@ TESTS_C = \ + lib2700.c \ + lib3010.c lib3025.c lib3026.c lib3027.c lib3033.c lib3034.c \ + lib3100.c lib3101.c lib3102.c lib3103.c lib3104.c lib3105.c \ +- lib3207.c lib3208.c ++ lib3207.c lib3208.c \ ++ lib3595.c +diff --git a/tests/libtest/lib3595.c b/tests/libtest/lib3595.c +new file mode 100644 +index 0000000..1f343f5 +--- /dev/null ++++ b/tests/libtest/lib3595.c +@@ -0,0 +1,70 @@ ++/*************************************************************************** ++ * _ _ ____ _ ++ * Project ___| | | | _ \| | ++ * / __| | | | |_) | | ++ * | (__| |_| | _ <| |___ ++ * \___|\___/|_| \_\_____| ++ * ++ * Copyright (C) Daniel Stenberg, , et al. ++ * ++ * This software is licensed as described in the file COPYING, which ++ * you should have received as part of this distribution. The terms ++ * are also available at https://curl.se/docs/copyright.html. ++ * ++ * You may opt to use, copy, modify, merge, publish, distribute and/or sell ++ * copies of the Software, and permit persons to whom the Software is ++ * furnished to do so, under the terms of the COPYING file. ++ * ++ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY ++ * KIND, either express or implied. ++ * ++ * SPDX-License-Identifier: curl ++ * ++ ***************************************************************************/ ++#include "unitcheck.h" ++ ++static CURLcode test_lib3595(const char *arg) ++{ ++ UNITTEST_BEGIN_SIMPLE ++ ++#if !defined(CURL_DISABLE_MIME) && \ ++ (!defined(CURL_DISABLE_HTTP) || \ ++ !defined(CURL_DISABLE_SMTP) || \ ++ !defined(CURL_DISABLE_IMAP)) ++ ++ curl_mime *root = NULL; ++ curl_mime *current = NULL; ++ curl_mime *sub = NULL; ++ curl_mimepart *part = NULL; ++ int i; ++ ++ if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { ++ curl_mfprintf(stderr, "curl_global_init() failed\n"); ++ return TEST_ERR_MAJOR_BAD; ++ } ++ ++ /* Create a deeply nested mime structure to verify that non-recursive ++ curl_mime_free works properly. */ ++ (void)arg; ++ root = curl_mime_init(NULL); ++ fail_unless(root != NULL, "curl_mime_init root failed"); ++ current = root; ++ ++ for(i = 0; i < 50; i++) { ++ part = curl_mime_addpart(current); ++ fail_unless(part != NULL, "curl_mime_addpart failed"); ++ sub = curl_mime_init(NULL); ++ fail_unless(sub != NULL, "curl_mime_init sub failed"); ++ curl_mime_subparts(part, sub); ++ current = sub; ++ } ++ ++ /* Free deep structure */ ++ curl_mime_free(root); ++ curl_global_cleanup(); ++#else ++ (void)arg; ++#endif ++ ++ UNITTEST_END_SIMPLE ++} +-- +2.35.6 diff --git a/meta/recipes-support/curl/curl_8.19.0.bb b/meta/recipes-support/curl/curl_8.19.0.bb index f2de4dfa04..20dbeb9dfd 100644 --- a/meta/recipes-support/curl/curl_8.19.0.bb +++ b/meta/recipes-support/curl/curl_8.19.0.bb @@ -60,6 +60,7 @@ SRC_URI = "https://curl.se/download/${BP}.tar.xz \ file://CVE-2026-92389.patch \ file://CVE-2026-87865_p1.patch \ file://CVE-2026-87865_p2.patch \ + file://CVE-2026-92391.patch \ " SRC_URI:append:class-nativesdk = " \ From patchwork Fri Nov 6 07:19:25 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darsh Kelaiya -X (dkelaiya - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 103223 Received: from rcdn-iport-9.cisco.com (rcdn-iport-9.cisco.com [173.37.86.80]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.1246.1793949576439388498 for ; Thu, 05 Nov 2026 23:19:36 -0800 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=OrF7JOiR; spf=pass (domain: cisco.com, ip: 173.37.86.80, mailfrom: dkelaiya@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=7835; q=dns/txt; s=iport01; t=1793949576; x=1795159176; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=BauOyKL5mh2pvI445fMbGQU9N5hXO/aGXBBE8THArN8=; b=OrF7JOiRnojZT3vu34HgMFB+Qf0y2SD8GBZsp8L4Tz1TVso75vwZzO02 N9w9/NOIiKJujYUwSN29XMA+g1Ao8Li0rHfzpdcWGyqQPta951NJAOyZY eOxo1uWrMk/nDy6ta71jfBCWWqmBG8NAMhfQ51YT3uD1Zf+2CE0eYgra1 l917cwNZYM3nwKmGWcKmAO8WU2Ju4s8NBvFtdieAC20GZpqzJMVDC0WnN 2gKCxxst+FpLKC3DM4jSfyE18fSM5tQbj//hIPT6e80x/AquMnUGCReJM CNMAnzF5nNMl6Rdv4AH41hhxt8ps3f9YVfpL8FQcbfCoRIA387rJohcV7 A==; X-CSE-ConnectionGUID: Ls6t61MZT0O17rlvAp2Odg== X-CSE-MsgGUID: 4O42ckI0RmKOUCq/bHmFsg== X-IPAS-Result: A0AnAADtfu1q/5X/Ja1aHQEBAQEJARIBBQUBgXwIAQsBglZ1YENJjHKJWQOeIYF+DwEBAQ9EDQQBAYUFAo4dAiY0CQ4BAgQDAgMBAQEBAQEBAQEBAQEKAQEFAQEBAgEHBYEOE4ZPDZASAQIBAycLARgBLRAcAwECLysjCBmDAgGCdAMRBrs4GzeBeTOBAYMpAT8CAkABUNszAQsUAYE4AYU/iCNdGAGEfScbG4FygRWDaYEFgVwCAYE3EIZeBIIigQyBWh5ljBUCgVGGeUiBHgNZLAFVEw0KCwcFgWgDNRIqFW4yHYEjPheBBxsGBYEdgR6BEoEHXYErKF0BIYEIgXYCglGCAAIBSUEOB0VTCSVDEkckIggSCQETGiwKgRo1PAkmPxUMZAsaBWEIAg0MdDkQMB4kLwUcJj4bCi8YDUgRLDcVGQQ+bgeSPYMSWQggDQEpAQEEE25AGyIGJBELBhgUkmiQH4IhoREKKIN4jCSVOhozhVulFguYfY4KlWkbTYRpgWg8gVlwFTuCZwkWNBkPji4LC4F4gWiGQMYFJjICCTIBAQcCBw4DC4FokAGBfQEB IronPort-Data: A9a23:eMN7jal1k7YKCiWJaWUvff/o5gzQJ0RdPkR7XQ2eYbSJt1+Wr1Gzt xIdUW/UPPiDM2D2fIwibozkoU9Q7J/WmoRqGQo4rSpjEltH+JHPbTi7wugcHM8zwunrFh8PA xA2M4GYRCwMZiaC4Errav6+/SEUOZigHtLUEPTDNj16WThqQSIgjQMLs+Mii+aEu/Dha++2k Y20+ZK31GONgWYubDtNs//b8XuDgdyr0N8mlg1mDRx0lAe2e0k9VPo3Oay3Jn3kdYhYdsbSb /rD1ryw4lTC9B4rDN6/+p6jGqHdauePVeQmoiM+t5mK2nCulARrukoIHKZ0hXNsttm8t4sZJ OOhGnCHYVxB0qXkwIzxWvTDes10FfUuFLTveRBTvSEPpqHLWyOE/hlgMK05FakDpPopWER8y aQ/cW8Xag6qn7iRzL3uH4GAhux7RCXqFJkUtnclyXTSCuwrBMmZBa7L/tRfmjw3g6iiH96HO JFfMmUpNkmdJUQTaz/7C7pm9AusrnX8fjlRqUOcjaE2+GPUigd21dABNfKIJoDTHZ8PwBbwS mTuo0OlWBoZFYSlzBmiz1m1weXvmA3gV9dHfFG/3rsw6LGJ/UQUEBAQWF6xrPW1h0L7UNVFJ mQQ+zEytu417EGtQ9z3UhG0rXLCuQQTM+e8CMUg4w2Lj66R6AGDCy1dFHhKaccts4k9QjlCO kK1ou4FzAdH6NW9IU9xPJ/Nxd9uEUD59VM/WBI= IronPort-HdrOrdr: A9a23:9ozC16jYKH2IPgQcNqwC0iYs9HBQXvgji2hC6mlwRA09TyVXra +TdZMgpHjJYVkqOU3I9ersBEDEewK/yXcX2/h0AV7dZmnbUQKTRekIh7cKgQeQfhEWndQy6U 4PScRD4aXLfDtHpPe/xhWkGNA9x9TC2qWpieDCi0pJd2hRGsddB8MTMHfiLqWwLzM2fKYEKA == X-Talos-CUID: 9a23:tAxqB26oeFFNObYouNss0FVKBp58V0/hlFCJfFW8F09xEpqZRgrF X-Talos-MUID: 9a23:QLb3dwv5upnXXPcfqc2n2BY+bsxrwvyUDWMqrL4f/MOkMAJrNGLI X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.27,197,1787011200"; d="scan'208";a="544102268" Received: from rcdn-l-core-12.cisco.com ([173.37.255.149]) by rcdn-iport-9.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 06 Nov 2026 07:19:35 +0000 Received: from sjc-ads-5675.cisco.com (sjc-ads-5675.cisco.com [10.28.88.189]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-12.cisco.com (Postfix) with ESMTPS id 49C0118000337; Fri, 6 Nov 2026 07:19:35 +0000 (GMT) Received: by sjc-ads-5675.cisco.com (Postfix, from userid 1887444) id E4295CBF202; Thu, 5 Nov 2026 23:19:34 -0800 (PST) From: "Darsh Kelaiya -X (dkelaiya - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-core@lists.openembedded.org Cc: Darsh Kelaiya Subject: [OE-core][wrynose][PATCH 2/9] curl: fix CVE-2026-87863 Date: Thu, 5 Nov 2026 23:19:25 -0800 Message-Id: <20261106071932.490299-3-dkelaiya@cisco.com> X-Mailer: git-send-email 2.35.6 In-Reply-To: <20261106071932.490299-1-dkelaiya@cisco.com> References: <20261106071932.490299-1-dkelaiya@cisco.com> MIME-Version: 1.0 X-Outbound-Client-TLS: ANONYMOUS;sjc-ads-5675.cisco.com [10.28.88.189];TLSv1.3;TLS_AES_256_GCM_SHA384;256 X-Outbound-SMTP-Client: 10.28.88.189, sjc-ads-5675.cisco.com X-Outbound-Node: rcdn-l-core-12.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Fri, 06 Nov 2026 07:19:49 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/249601 From: Darsh Kelaiya This patch applies the upstream fix as referenced in [2], using the commit shown in [1]. Cap HSTS max-age at two years and keep saving valid entries if one date cannot be serialized. Adapt the older parser so oversized quoted ages are capped while preserving unquoted suffix handling. Retain upstream test1862. [1] https://github.com/curl/curl/commit/08d50a791b3197a3d0a4fc2f778e243f5501c67e [2] https://curl.se/docs/CVE-2026-87863.html Signed-off-by: Darsh Kelaiya --- .../curl/curl/CVE-2026-87863.patch | 203 ++++++++++++++++++ meta/recipes-support/curl/curl_8.19.0.bb | 1 + 2 files changed, 204 insertions(+) create mode 100644 meta/recipes-support/curl/curl/CVE-2026-87863.patch diff --git a/meta/recipes-support/curl/curl/CVE-2026-87863.patch b/meta/recipes-support/curl/curl/CVE-2026-87863.patch new file mode 100644 index 0000000000..d1f489e47e --- /dev/null +++ b/meta/recipes-support/curl/curl/CVE-2026-87863.patch @@ -0,0 +1,203 @@ +From 08d50a791b3197a3d0a4fc2f778e243f5501c67e Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Tue, 8 Sep 2026 16:04:42 +0200 +Subject: [PATCH] hsts: cap max-age to two years + +And ignore problems saving individual HSTS entries - a single entry +problem should not affect storing other entries. + +Added test 1862 to verify. + +Closes #22878 + +CVE: CVE-2026-87863 +Upstream-Status: Backport [https://github.com/curl/curl/commit/08d50a791b3197a3d0a4fc2f778e243f5501c67e] + +Backport Changes: +- Keep curl 8.19.0's max-age parser, which reads directly from the + header using TIME_T_MAX as its numeric limit. Upstream first + extracts the value and parses it with a two-year numeric limit. + Cap parsed ages and numeric overflows at two years. +- After overflow in a quoted age, skip its digits before checking + the closing quote. The older number reader leaves its position + unchanged on overflow. For unquoted overflow, keep that position + so trailing text is handled as before. +- Register test1862 in the older grouped tests/data/Makefile.am list. + +Signed-off-by: Darsh Kelaiya +--- + lib/hsts.c | 32 ++++++++++-------- + tests/data/Makefile.am | 2 +- + tests/data/test1862 | 73 ++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 93 insertions(+), 14 deletions(-) + create mode 100644 tests/data/test1862 + +diff --git a/lib/hsts.c b/lib/hsts.c +index 5ad5bd4..9e5b456 100644 +--- a/lib/hsts.c ++++ b/lib/hsts.c +@@ -43,6 +43,8 @@ + #define MAX_HSTS_DATELEN 256 + #define UNLIMITED "unlimited" + ++#define CAP_HSTS_MAX_AGE (2*365*24*3600) /* two years cap */ ++ + #if defined(DEBUGBUILD) || defined(UNITTESTS) + /* to play well with debug builds, we can *set* a fixed time this will + return */ +@@ -152,11 +154,18 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname, + quoted = TRUE; + + rc = curlx_str_number(&p, &expires, TIME_T_MAX); +- if(rc == STRE_OVERFLOW) +- expires = CURL_OFF_T_MAX; ++ if(rc == STRE_OVERFLOW) { ++ expires = CAP_HSTS_MAX_AGE; ++ if(quoted) { ++ while(ISDIGIT(*p)) ++ p++; ++ } ++ } + else if(rc) + /* invalid max-age */ + return CURLE_BAD_FUNCTION_ARGUMENT; ++ else if(expires > CAP_HSTS_MAX_AGE) ++ expires = CAP_HSTS_MAX_AGE; + + if(quoted) { + if(*p != '\"') +@@ -304,22 +313,21 @@ static CURLcode hsts_push(struct Curl_easy *data, + /* + * Write this single hsts entry to a single output line + */ +-static CURLcode hsts_out(struct stsentry *sts, FILE *fp) ++static void hsts_out(struct stsentry *sts, FILE *fp) + { + struct tm stamp; + if(sts->expires != TIME_T_MAX) { + CURLcode result = curlx_gmtime((time_t)sts->expires, &stamp); +- if(result) +- return result; +- curl_mfprintf(fp, "%s%s \"%d%02d%02d %02d:%02d:%02d\"\n", +- sts->includeSubDomains ? "." : "", sts->host, +- stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday, +- stamp.tm_hour, stamp.tm_min, stamp.tm_sec); ++ if(!result) ++ /* skip the entry if the date function fails */ ++ curl_mfprintf(fp, "%s%s \"%d%02d%02d %02d:%02d:%02d\"\n", ++ sts->includeSubDomains ? "." : "", sts->host, ++ stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday, ++ stamp.tm_hour, stamp.tm_min, stamp.tm_sec); + } + else + curl_mfprintf(fp, "%s%s \"%s\"\n", + sts->includeSubDomains ? "." : "", sts->host, UNLIMITED); +- return CURLE_OK; + } + + /* +@@ -354,9 +362,7 @@ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h, + for(e = Curl_llist_head(&h->list); e; e = n) { + struct stsentry *sts = Curl_node_elem(e); + n = Curl_node_next(e); +- result = hsts_out(sts, out); +- if(result) +- break; ++ hsts_out(sts, out); + } + curlx_fclose(out); + if(!result && tempstore && curlx_rename(tempstore, file)) +diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am +index 7a9b8d0..e678290 100644 +--- a/tests/data/Makefile.am ++++ b/tests/data/Makefile.am +@@ -231,7 +231,7 @@ test1680 test1681 test1682 test1683 test1685 \ + test1700 test1701 test1702 test1703 test1704 test1705 test1706 test1707 \ + test1708 test1709 test1710 test1711 test1712 \ + \ +-test1800 test1801 test1802 test1847 test1848 test1849 test1850 \ ++test1800 test1801 test1802 test1847 test1848 test1849 test1850 test1862 \ + \ + test1900 test1901 test1902 test1903 test1904 test1905 test1906 test1907 \ + test1908 test1909 test1910 test1911 test1912 test1913 test1914 test1915 \ +diff --git a/tests/data/test1862 b/tests/data/test1862 +new file mode 100644 +index 0000000..b9a29f6 +--- /dev/null ++++ b/tests/data/test1862 +@@ -0,0 +1,73 @@ ++ ++ ++ ++ ++HTTP ++HSTS ++ ++ ++ ++ ++ ++ ++HTTP/1.1 200 OK ++Date: Tue, 09 Nov 2010 14:49:00 GMT ++Content-Length: 6 ++Connection: close ++Strict-Transport-Security: max-age=1152921504606846976 ++ ++-foo- ++ ++ ++ ++ ++ ++http ++ ++ ++HSTS ++Debug ++ ++ ++# November 11, 2030 ++ ++CURL_HSTS_HTTP=yes ++CURL_TIME=1920582000 ++ ++ ++ ++HSTS with extreme max-age ++ ++ ++http://this.hsts.example:%HTTPPORT/%TESTNUMBER --hsts %LOGDIR/input%TESTNUMBER --resolve this.hsts.example:%HTTPPORT:%HOSTIP ++ ++ ++# Your HSTS cache. https://curl.se/docs/hsts.html ++# This file was generated by libcurl! Edit at your own risk. ++somehere.example "20330525 03:33:20" ++elsewhere.example.com "20330727 03:33:20" ++ ++ ++test-duphandle ++ ++ ++ ++ ++# we let it CONNECT to the server to confirm HSTS but deny from there ++ ++GET /1862 HTTP/1.1 ++Host: this.hsts.example:%HTTPPORT ++User-Agent: curl/%VERSION ++Accept: */* ++ ++ ++ ++# Your HSTS cache. https://curl.se/docs/hsts.html ++# This file was generated by libcurl! Edit at your own risk. ++somehere.example "20330525 03:33:20" ++elsewhere.example.com "20330727 03:33:20" ++this.hsts.example "20321109 23:00:00" ++ ++ ++ ++ +-- +2.35.6 diff --git a/meta/recipes-support/curl/curl_8.19.0.bb b/meta/recipes-support/curl/curl_8.19.0.bb index 20dbeb9dfd..9fd78a0fd8 100644 --- a/meta/recipes-support/curl/curl_8.19.0.bb +++ b/meta/recipes-support/curl/curl_8.19.0.bb @@ -61,6 +61,7 @@ SRC_URI = "https://curl.se/download/${BP}.tar.xz \ file://CVE-2026-87865_p1.patch \ file://CVE-2026-87865_p2.patch \ file://CVE-2026-92391.patch \ + file://CVE-2026-87863.patch \ " SRC_URI:append:class-nativesdk = " \ From patchwork Fri Nov 6 07:19:26 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darsh Kelaiya -X (dkelaiya - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 103218 Received: from rcdn-iport-8.cisco.com (rcdn-iport-8.cisco.com [173.37.86.79]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.1218.1793949576373352610 for ; Thu, 05 Nov 2026 23:19:36 -0800 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=TFphk3AF; spf=pass (domain: cisco.com, ip: 173.37.86.79, mailfrom: dkelaiya@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=5544; q=dns/txt; s=iport01; t=1793949576; x=1795159176; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=oYK51aEoqVivrGSVe96twsA3mkOrXyOfAMm2GxWTMFI=; b=TFphk3AFnhY1Gje3xHSU2TKC6vrmM5cXFwK+3/dCsIz+b7X19BaCiCQd MMoChFWYWs6pYIpV24lYIKjoSlhrEuY66mNZKtaW3t4QfRe8sAdHvQSWV EnyVqtPndsRHZ1SQE1ocak8Y5J11NfZvxYXwKDVPzKjLTkMY1Qo6n4gxK s5ZOu7KZZXgk2OjP1ewE/7oDQHGxQflzzeEkixksaQpGuN5453pvwINr/ Idch4Dy/wVwPM1F+5h1LDwuVWHUlq1vinZ12fGSD4FbxliJhMEr3T0Xfd f6JeQ8khnsNN4+hHVGwLNFZlcgnmdXPAQW5V1QuhYXbBzKoKObsedPjdq Q==; X-CSE-ConnectionGUID: XfKW1LUCRd6eSgaMFKykrA== X-CSE-MsgGUID: DirHQHC+QTe8oe83INOSNQ== X-IPAS-Result: A0BIAgBrfu1q/5H/Ja1aglmCV3VgQ0mWSwOeIRSBag8BAQEPRA0EAQGFBQKOHQImNAkOAQIEAwIDAQEBAQEBAQEBAQEBCgEBBQEBAQIBBwWBDhOGTw2QEgECAQMnCwEYAS0QHAMBAi8rIwgZgwIBgnQDEQa7Oxs3gXkzgQGDKQE/AgJAAVDbMwELFAGBOIVAiCNdGAGEfScbG4FygRWDaYEFgVwCAYFGhl8EgiKBDIFaHm6FNIZYAoFRhnlIgR4DWSwBVRMNCgsHBYFoAzUSKhVuMh2BIz4XgQcbBgWBHYEegRKBB12BKyhdASGBCIF2AoJRggACAUlBDgdFUwklQxJHJCIIEgkBExosCoEaNTwJJj8VDGQLGgVhCAINDHQ5EDAeJC8FHCY+GwovGA1IESw3FRkEPm4Hkj2DEgEwMC0BKQEBBIEWgRIRKRGSRicHkjehEQoog3iMJJU6GjOEBKZtC5h9glmLMZV0XYRpgWg8gVlwFYMiCRY0GQ+OLgsLg2CGQMYFJjICCTIBAQcCBw4DC4FokAAsgVIBAQ IronPort-Data: A9a23:bg2sVKoh2/m7Wg/YjnZOsImJXEleBmJJZBIvgKrLsJaIsI4StFCzt garIBnSbKyCYjD3KIojPN7n8hsA6pLXmtFqHQZlr303Eiwb9ePIVI+TRqvS04x+DSFioGZPt Zh2hgzodZhsJpPkjk7zdOWn9T8jhfngqoPUUIbsIjp2SRJvVBAvgBdin/9RqoNziLBVOSvV0 T/Ji5OZYgDNNwJcaDpOtfva8E435ZwehRtB1rAATaET1LPhvyF94KI3fcmZM3b+S49IKe+2L 86r5K255G7Q4yA2AdqjlLvhGmVSKlIFFVHT4pb+c/HKbilq/kTe4I5iXBYvQRs/ZwGyojxE4 I4lWapc5useFvakdOw1C3G0GszlVEFM0OevzXOX6aR/w6BaGpfh660GMa04AWEX0tZ5Il4X0 cEzEjxTYyuMjseY46O4UMA506zPLOGzVG8ekmtrwTecCbMtRorOBv2ao9RZxzw3wMtJGJ4yZ eJANmEpN0uGOUASfA5LVfrSn8/w7pX7WzFbpVacpLs+y2PS1wd2lrPqNbI5f/TXHpsFxxrI+ TKuE2LRLhAAFOW/4nm8zn/8geKfxgLdf7k0LejtnhJtqBjJroAJMzURTVa9rPyzh0KyVt4aI EsO9wIqrLMu7wqsVtT7UhiyrXKIsxJaXMBfe9DW8ymXwabSpgLcDW8eQ3sZOJottdQ9Qnoh0 Vrhc87VOAGDeYa9ERq1nop4ZxvrUcTJBQfuvRM5cDY= IronPort-HdrOrdr: A9a23:qBBY16P6N2mEzMBcTuOjsMiBIKoaSvp037Dk7S9MoHtuA6ulfq +V/cjzuSWYtN9VYgBDpTniAtjlfZqjz/5ICOAqVN/INjUO+lHYSb2KhrGN/9SPIUHDH5ZmpM RdWpk7LsHsBl5nisu/ygy5H9E8hOSjysmT9IHjJ7MHd3ATV0mmhD0JczqmLg== X-Talos-CUID: 9a23:dZloPWr14h1sZZzbHUcOgX7mUfArUUKE6Er7GUPmBF1mQZi7ak6T4ooxxg== X-Talos-MUID: 9a23:1oUJXg6e/2KGtWz/v4FRkugaxoxE4r6OMWAm0qw6tpmDOHwrGhG6txKOF9o= X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.27,197,1787011200"; d="scan'208";a="536814878" Received: from rcdn-l-core-08.cisco.com ([173.37.255.145]) by rcdn-iport-8.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 06 Nov 2026 07:19:35 +0000 Received: from sjc-ads-5675.cisco.com (sjc-ads-5675.cisco.com [10.28.88.189]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-08.cisco.com (Postfix) with ESMTPS id 4B77A180001DB; Fri, 6 Nov 2026 07:19:35 +0000 (GMT) Received: by sjc-ads-5675.cisco.com (Postfix, from userid 1887444) id E94D0CBF203; Thu, 5 Nov 2026 23:19:34 -0800 (PST) From: "Darsh Kelaiya -X (dkelaiya - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-core@lists.openembedded.org Cc: Darsh Kelaiya Subject: [OE-core][wrynose][PATCH 3/9] curl: fix CVE-2026-86410 Date: Thu, 5 Nov 2026 23:19:26 -0800 Message-Id: <20261106071932.490299-4-dkelaiya@cisco.com> X-Mailer: git-send-email 2.35.6 In-Reply-To: <20261106071932.490299-1-dkelaiya@cisco.com> References: <20261106071932.490299-1-dkelaiya@cisco.com> MIME-Version: 1.0 X-Outbound-Client-TLS: ANONYMOUS;sjc-ads-5675.cisco.com [10.28.88.189];TLSv1.3;TLS_AES_256_GCM_SHA384;256 X-Outbound-SMTP-Client: 10.28.88.189, sjc-ads-5675.cisco.com X-Outbound-Node: rcdn-l-core-08.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Fri, 06 Nov 2026 07:19:48 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/249599 From: Darsh Kelaiya This patch applies the upstream fix as referenced in [2], using the commit shown in [1]. Install SSH host verification options before following redirects from other protocols. The missing-file fallback keeps ordinary HTTP usable when no known_hosts file exists. Adapt the older findfile() ownership path. The omitted test1679 hunk only filters a generated CURLOPT_SSH_KNOWNHOSTS line. The SSL reset test and its data1679.c fixture were introduced after curl 8.19.0 by [3]; they do not exercise SSH redirects. The older --libcurl comparisons already filter this option. [1] https://github.com/curl/curl/commit/6ae9befb2fb6bdfdb5fc11fdf76bbe519fe1f52c [2] https://curl.se/docs/CVE-2026-86410.html [3] https://github.com/curl/curl/commit/19d0f4acfa9df373e8e1f987c11b7165e1edac34 Signed-off-by: Darsh Kelaiya --- .../curl/curl/CVE-2026-86410.patch | 102 ++++++++++++++++++ meta/recipes-support/curl/curl_8.19.0.bb | 1 + 2 files changed, 103 insertions(+) create mode 100644 meta/recipes-support/curl/curl/CVE-2026-86410.patch diff --git a/meta/recipes-support/curl/curl/CVE-2026-86410.patch b/meta/recipes-support/curl/curl/CVE-2026-86410.patch new file mode 100644 index 0000000000..1f15da547b --- /dev/null +++ b/meta/recipes-support/curl/curl/CVE-2026-86410.patch @@ -0,0 +1,102 @@ +From 6ae9befb2fb6bdfdb5fc11fdf76bbe519fe1f52c Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Sat, 5 Sep 2026 15:55:58 +0200 +Subject: [PATCH] config2setopts: always set the security options for SCP/SFTP + +If the protocols are built-in + +Closes #22839 + +CVE: CVE-2026-86410 +Upstream-Status: Backport [https://github.com/curl/curl/commit/6ae9befb2fb6bdfdb5fc11fdf76bbe519fe1f52c] + +Backport Changes: +- Use curl 8.19.0's directly owned findfile() result. Add the + missing-file fallback when that result is NULL; upstream places + it after a newer temporary-path copy branch. +- Omit test1679's stripfile update. Test1679 and data1679.c were + introduced by [1] after curl 8.19.0 and are absent here. They check + SSL option resets across --next in generated --libcurl output. + The omitted line only strips CURLOPT_SSH_KNOWNHOSTS from that + comparison; it does not exercise SSH redirects. + Existing --libcurl tests already filter that option. + +[1] https://github.com/curl/curl/commit/19d0f4acfa9df373e8e1f987c11b7165e1edac34 + +Signed-off-by: Darsh Kelaiya +--- + src/config2setopts.c | 34 +++++++++++++++++++++++----------- + 1 file changed, 23 insertions(+), 11 deletions(-) + +diff --git a/src/config2setopts.c b/src/config2setopts.c +index 20d87a0..27ca721 100644 +--- a/src/config2setopts.c ++++ b/src/config2setopts.c +@@ -178,12 +178,11 @@ static CURLcode url_proto_and_rewrite(char **url, + return result; + } + +-static CURLcode ssh_setopts(struct OperationConfig *config, CURL *curl, +- const char *use_proto) ++static CURLcode ssh_setopts(struct OperationConfig *config, CURL *curl) + { + CURLcode result; + +- if(use_proto != proto_scp && use_proto != proto_sftp) ++ if(!proto_scp && !proto_sftp) + return CURLE_OK; + + /* SSH and SSL private key uses same command-line option */ +@@ -204,8 +203,27 @@ static CURLcode ssh_setopts(struct OperationConfig *config, CURL *curl, + + if(!config->insecure_ok) { + char *known = config->knownhosts; +- if(!known) ++ if(!known) { + known = findfile(".ssh/known_hosts", FALSE); ++ if(!known && !config->hostpubmd5 && !config->hostpubsha256) { ++ /* couldn't find an existing one, instead set one that MIGHT work as ++ we don't verify the host using other means */ ++ struct dynbuf k; ++ char *home = getenv("HOME"); ++ curlx_dyn_init(&k, 256); ++ ++ /* If the HOME environment variable is missing this renders a path ++ that is likely to not work but the HOME one also does not exist! ++ */ ++ result = curlx_dyn_addf(&k, ++ "%s" DIR_CHAR ".ssh" DIR_CHAR "known_hosts", ++ home ? home : ""); ++ if(result) ++ return result; ++ known = curlx_dyn_ptr(&k); ++ } ++ } ++ + if(known) { + result = my_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, known); + if(result) { +@@ -216,12 +234,6 @@ static CURLcode ssh_setopts(struct OperationConfig *config, CURL *curl, + /* store it in global to avoid repeated checks */ + config->knownhosts = known; + } +- else if(!config->hostpubmd5 && !config->hostpubsha256) { +- errorf("Could not find a known_hosts file"); +- return CURLE_FAILED_INIT; +- } +- else +- warnf("Could not find a known_hosts file"); + } + return CURLE_OK; /* ignore if SHA256 did not work */ + } +@@ -928,7 +940,7 @@ CURLcode config2setopts(struct OperationConfig *config, + MY_SETOPT_STR(curl, CURLOPT_KEYPASSWD, config->key_passwd); + MY_SETOPT_STR(curl, CURLOPT_PROXY_KEYPASSWD, config->proxy_key_passwd); + +- result = ssh_setopts(config, curl, use_proto); ++ result = ssh_setopts(config, curl); + if(setopt_bad(result)) + return result; + +-- +2.35.6 diff --git a/meta/recipes-support/curl/curl_8.19.0.bb b/meta/recipes-support/curl/curl_8.19.0.bb index 9fd78a0fd8..e5b9203678 100644 --- a/meta/recipes-support/curl/curl_8.19.0.bb +++ b/meta/recipes-support/curl/curl_8.19.0.bb @@ -62,6 +62,7 @@ SRC_URI = "https://curl.se/download/${BP}.tar.xz \ file://CVE-2026-87865_p2.patch \ file://CVE-2026-92391.patch \ file://CVE-2026-87863.patch \ + file://CVE-2026-86410.patch \ " SRC_URI:append:class-nativesdk = " \ From patchwork Fri Nov 6 07:19:27 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darsh Kelaiya -X (dkelaiya - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 103225 Received: from rcdn-iport-1.cisco.com (rcdn-iport-1.cisco.com [173.37.86.72]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.1248.1793949576635451417 for ; Thu, 05 Nov 2026 23:19:36 -0800 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=V2rzZjmQ; spf=pass (domain: cisco.com, ip: 173.37.86.72, mailfrom: dkelaiya@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=14511; q=dns/txt; s=iport01; t=1793949576; x=1795159176; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=FFYuYW7NS4bfg7zY2qhLaXMI+eshf99Hh/aRLWyncCQ=; b=V2rzZjmQ6+55MWX8rzluIFU2BLkOhSmL8X82YQsaz0VTCIYmVRSMH5kN kEBwhlN2ylRu+HSLddrI8LhU40k2avNJSY43FGfFPjOKZtqdTiCU25sB0 QktomWmWl2MdmOY0J/+8L5xMCBBbluYuHeBbStHVHEqhGIuGLSRNtZuRg qEcuoDeUxXrhLEK/t987GskPt/yBoDs5HdHb4UAUbjZwmDZVKxyiNlmJJ r64Knt5d3Ckiv/K5joKvpRMlA8KIkrsWJrj6NcssZ/TNQur7lvjCZL4Id XJ1L216ct3//HhYsS0Dbnq3FQycxFQd/C0XRGsJomAHnm2c2oQ2o5tC7H w==; X-CSE-ConnectionGUID: xRaZTMcHS9SWOmk1Akx6Qg== X-CSE-MsgGUID: rbdH8tUNQDiAZEaeJaLHWw== X-IPAS-Result: A0BIAgBrfu1q/4//Ja1aglmCV3VgQ0mWSwOeIYF+DwEBAQ9EDQQBAYUFAo4dAiY0CQ4BAgQDAgMBAQEBAQEBAQEBAQEKAQEFAQEBAgEHBYEOE4ZPDZASAQIBAycLARgBLRAcAwECLysjCBAJgwIBgnQDEQa7Oxs3gXkzgQGDKQE/AgJAAVDbMwELFAGBOIVAiCNdGAGEfScbG4FygRWBO4IugQWBXAIBgUeGXgSCIoEMgVoeZYwVAoFRhnlIgR4DWSwBVRMNCgsHBYFoAzUSKhVuMh2BIz4XgQcbBgWBHYEegRKBB12BKyhdASGBCIF2AoJRggACAUlBDgdFUwklQxJHJCIIEgkBExosCoEaNTwJJj8VDGQLGgVhCAINDHQ5EDAeJC8FHCY+GwovGA1IESw3FRkEPm4Hkj2CTiQgARUbMC0BKQEBfxIHQiMFLwwLAhQIFJJDJQmQFoIhn1OBPgoog3iMJJU6GjOFW6UWC5h9jgqVaSZChGmBaDyBWXAVO4JnCRY0GQ9YjVMDCwuBeIFohkDGBSYyAgkyAQEHAgcOAwuBaJF+AQE IronPort-Data: A9a23:4JDvBa+RTkDxvthUnCgCDrUD0X+TJUtcMsCJ2f8bNWPcYEJGY0x3y TFNUG7VO6qKNGugfosnOY21904EusPWyN42Gwto/y5EQiMRo6IpJzg2wmQcns+2BpeeJK6yx 5xGMrEsFOhtEDmB4E/rbei5xZVF/fngbqLmD+LZMTxGSwZhSSMw4TpugOdRbrRA2bBVOCvT/ 4mtyyHjEAX9gWAtazpJs/vrRC5H5ZwehhtJ5jTSWtgT1LPuvyF9JI4SI6i3M0z5TuF8dsamR /zOxa2O5WjQ+REgELuNyt4XpWVTH9Y+lSDX4pZnc/DKbipq/0Te4Y5nXBYoUnq7vh3S9zxHJ HqhgrTrIeshFvWkdO3wyHC0GQkmVUFN0OevzXRSLaV/wmWeG0YAzcmCA2kmB4QqxsN8IVofz sM/LTNURxOT2du5lefTpulE3qzPLeHxN48Z/3UlxjbDALN+H9bIQr7B4plT2zJYasJmRKmFI ZFGL2AyMVKZP0Yn1lQ/UPrSmM+khXT7ejxJoXqepLE85C7YywkZPL3FbYaJJYPUHpUO9qqej njM80SpHiw8DfCe4Aio+3+Oj8vvojyuDer+E5X9rJaGmma7wXQeDhATX1a3rfS1z0W5Qd93L 00P5jFoqrA/8kGuRNTxUxC05nmesXYht8F4CeY27kSJj6HT+QvcXjZCRT9aY9tgv8gzLdA36 mK0cxrSLWQHmNWopbi1r994cRva1fApEFI/ IronPort-HdrOrdr: A9a23:n5GOGKN70jz/1cBcTuOjsMiBIKoaSvp037Dk7S9MoHtuA6ulfq +V/cjzuSWYtN9VYgBDpTniAtjlfZqjz/5ICOAqVN/INjUO+lHYSb2KhrGN/9SPIUHDH5ZmpM RdWpk7LsHsBl5nisu/ygy5H9E8hOSjysmT9IHjJ7MHd3ATV0mmhD0JczqmLg== X-Talos-CUID: 9a23:2wB71m2HT14yigHAvVVlN7xfCvosQEH4x1frcnSHLmNqEZSWWQGp9/Yx X-Talos-MUID: 9a23:uugfmAgNs3yYzi/tdFa+D8MpLs1kw/SyNWY0vZQvieSNOA55Hxeik2Hi X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.27,197,1787011200"; d="scan'208";a="544776383" Received: from rcdn-l-core-06.cisco.com ([173.37.255.143]) by rcdn-iport-1.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 06 Nov 2026 07:19:35 +0000 Received: from sjc-ads-5675.cisco.com (sjc-ads-5675.cisco.com [10.28.88.189]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-06.cisco.com (Postfix) with ESMTPS id 4E09B1800025A; Fri, 6 Nov 2026 07:19:35 +0000 (GMT) Received: by sjc-ads-5675.cisco.com (Postfix, from userid 1887444) id EDA79CBF204; Thu, 5 Nov 2026 23:19:34 -0800 (PST) From: "Darsh Kelaiya -X (dkelaiya - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-core@lists.openembedded.org Cc: Darsh Kelaiya Subject: [OE-core][wrynose][PATCH 4/9] curl: fix CVE-2026-92390 Date: Thu, 5 Nov 2026 23:19:27 -0800 Message-Id: <20261106071932.490299-5-dkelaiya@cisco.com> X-Mailer: git-send-email 2.35.6 In-Reply-To: <20261106071932.490299-1-dkelaiya@cisco.com> References: <20261106071932.490299-1-dkelaiya@cisco.com> MIME-Version: 1.0 X-Outbound-Client-TLS: ANONYMOUS;sjc-ads-5675.cisco.com [10.28.88.189];TLSv1.3;TLS_AES_256_GCM_SHA384;256 X-Outbound-SMTP-Client: 10.28.88.189, sjc-ads-5675.cisco.com X-Outbound-Node: rcdn-l-core-06.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Fri, 06 Nov 2026 07:19:49 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/249603 From: Darsh Kelaiya This patch applies the upstream fix as referenced in [2], using the commit shown in [1]. Delay output creation until the remote filename is selected, preserving -J anti-clobber handling for 103 and ETag headers. Include the later upstream filename-less Content-Disposition fix [3]. It closes another early-open path and writes buffered headers when a transfer completes without a body. Keep both fixes in separate patches with upstream tests 3037, 3038 and 1718. [1] https://github.com/curl/curl/commit/c24a69d8cd368de4e25e3540bf0b7b000a31d5a7 [2] https://curl.se/docs/CVE-2026-92390.html [3] https://github.com/curl/curl/commit/631ed306872956f86617df9b5664614e8a2dee54 Signed-off-by: Darsh Kelaiya --- .../curl/curl/CVE-2026-92390_p1.patch | 270 ++++++++++++++++++ .../curl/curl/CVE-2026-92390_p2.patch | 150 ++++++++++ meta/recipes-support/curl/curl_8.19.0.bb | 2 + 3 files changed, 422 insertions(+) create mode 100644 meta/recipes-support/curl/curl/CVE-2026-92390_p1.patch create mode 100644 meta/recipes-support/curl/curl/CVE-2026-92390_p2.patch diff --git a/meta/recipes-support/curl/curl/CVE-2026-92390_p1.patch b/meta/recipes-support/curl/curl/CVE-2026-92390_p1.patch new file mode 100644 index 0000000000..fa25d06b36 --- /dev/null +++ b/meta/recipes-support/curl/curl/CVE-2026-92390_p1.patch @@ -0,0 +1,270 @@ +From c24a69d8cd368de4e25e3540bf0b7b000a31d5a7 Mon Sep 17 00:00:00 2001 +From: Joshua Rogers +Date: Sat, 12 Sep 2026 02:57:04 +0200 +Subject: [PATCH] tool: buffer headers before remote filename selection + +Verified by test 3037 and 3038. + +Closes #22977 + +CVE: CVE-2026-92390 +Upstream-Status: Backport [https://github.com/curl/curl/commit/c24a69d8cd368de4e25e3540bf0b7b000a31d5a7] + +Backport Changes: +- In content_disposition(), remove curl 8.19.0's curl_maprintf() + header-copy block; the upstream block uses curlx_memdup0(). +- Register test3037 and test3038 together in the older grouped + tests/data/Makefile.am list instead of one line per test. + +Signed-off-by: Darsh Kelaiya +--- + src/tool_cb_hdr.c | 53 +++++++++++++++++++++++++++-------------- + tests/data/Makefile.am | 1 + + tests/data/test3037 | 62 ++++++++++++++++++++++++++++++++++++++++++++++++ + tests/data/test3038 | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 162 insertions(+), 18 deletions(-) + +diff --git a/src/tool_cb_hdr.c b/src/tool_cb_hdr.c +index fc03cf1..15abb5b 100644 +--- a/src/tool_cb_hdr.c ++++ b/src/tool_cb_hdr.c +@@ -248,6 +248,28 @@ fail: + return rc; + } + ++/* Store a header until the output filename has been decided. */ ++static size_t buffer_header(struct HdrCbData *hdrcbdata, ++ const char *str, size_t cb) ++{ ++ char *clone = curlx_memdup0(str, cb); ++ if(clone) { ++ struct curl_slist *old = hdrcbdata->headlist; ++ hdrcbdata->headlist = curl_slist_append(old, clone); ++ curlx_free(clone); ++ if(!hdrcbdata->headlist) { ++ curl_slist_free_all(old); ++ return CURL_WRITEFUNC_ERROR; ++ } ++ } ++ else { ++ curl_slist_free_all(hdrcbdata->headlist); ++ hdrcbdata->headlist = NULL; ++ return CURL_WRITEFUNC_ERROR; ++ } ++ return cb; ++} ++ + /* + * Write etag to file when --etag-save option is given. + */ +@@ -395,24 +417,8 @@ static size_t content_disposition(const char *str, const char *end, + + if(hdrcbdata->honor_cd_filename && + hdrcbdata->config->show_headers) { +- /* still awaiting the Content-Disposition header, store the header in +- memory. Since it is not null-terminated, we need an extra dance. */ +- char *clone = curl_maprintf("%.*s", (int)cb, str); +- if(clone) { +- struct curl_slist *old = hdrcbdata->headlist; +- hdrcbdata->headlist = curl_slist_append(old, clone); +- curlx_free(clone); +- if(!hdrcbdata->headlist) { +- curl_slist_free_all(old); +- return CURL_WRITEFUNC_ERROR; +- } +- } +- else { +- curl_slist_free_all(hdrcbdata->headlist); +- hdrcbdata->headlist = NULL; +- return CURL_WRITEFUNC_ERROR; +- } +- return cb; /* done for now */ ++ /* still awaiting the Content-Disposition header */ ++ return buffer_header(hdrcbdata, str, cb); + } + + return 0; /* ok */ +@@ -434,6 +440,7 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) + const size_t cb = size * nmemb; + const char *end = ptr + cb; + const char *scheme = NULL; ++ bool cd_checked = FALSE; + + if(!per->config) + return CURL_WRITEFUNC_ERROR; +@@ -493,6 +500,9 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) + size_t rc = content_disposition(str, end, cb, per, response); + if(rc) + return rc; ++ /* remember that this was checked to avoid duplicating it further ++ down */ ++ cd_checked = TRUE; + } + } + if(hdrcbdata->config->writeout) { +@@ -512,6 +522,13 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata) + /* bold headers only for selected protocols */ + const char *value = NULL; + ++ /* Informational responses, and ETag headers handled by --etag-save, ++ bypass the content-disposition handling above. Do not open the output ++ file until the filename decision is complete. Only for HTTP(S). */ ++ if(hdrcbdata->honor_cd_filename && !cd_checked && ++ (scheme == proto_http || scheme == proto_https)) ++ return buffer_header(hdrcbdata, str, cb); ++ + if(!outs->stream && !tool_create_output_file(outs, per->config)) + return CURL_WRITEFUNC_ERROR; + +diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am +index 7a9b8d0..6d12c7c 100644 +--- a/tests/data/Makefile.am ++++ b/tests/data/Makefile.am +@@ -279,6 +279,7 @@ test3008 test3009 test3010 test3011 test3012 test3013 test3014 test3015 \ + test3016 test3017 test3018 test3019 test3020 test3021 test3022 test3023 \ + test3024 test3025 test3026 test3027 test3028 test3029 test3030 test3031 \ + test3032 test3033 test3034 test3035 \ ++test3037 test3038 \ + \ + test3100 test3101 test3102 test3103 test3104 test3105 test3109 \ + \ +diff --git a/tests/data/test3037 b/tests/data/test3037 +new file mode 100644 +index 0000000..be29b99 +--- /dev/null ++++ b/tests/data/test3037 +@@ -0,0 +1,62 @@ ++ ++ ++ ++ ++HTTP ++HTTP GET ++103 ++Early Hints ++-J ++--show-headers ++ ++ ++ ++# Server-side ++ ++ ++HTTP/1.1 103 Early Hints ++ ++HTTP/1.1 200 OK ++Content-Length: 6 ++Content-Disposition: attachment; filename="victim%TESTNUMBER" ++Connection: close ++ ++12345 ++ ++ ++ ++# Client-side ++ ++ ++http ++ ++ ++http ++ ++ ++Do not open output for 103 Early Hints with -J and --show-headers ++ ++ ++original ++ ++ ++http://%HOSTIP:%HTTPPORT/victim%TESTNUMBER -O -J -i --output-dir %LOGDIR ++ ++ ++ ++ ++ ++GET /victim%TESTNUMBER HTTP/1.1 ++Host: %HOSTIP:%HTTPPORT ++User-Agent: curl/%VERSION ++Accept: */* ++ ++ ++ ++23 ++ ++ ++original ++ ++ ++ +diff --git a/tests/data/test3038 b/tests/data/test3038 +new file mode 100644 +index 0000000..ff51458 +--- /dev/null ++++ b/tests/data/test3038 +@@ -0,0 +1,64 @@ ++ ++ ++ ++ ++HTTP ++HTTP GET ++ETag ++--etag-save ++-J ++--show-headers ++ ++ ++ ++# Server-side ++ ++ ++HTTP/1.1 200 OK ++ETag: "tag%TESTNUMBER" ++Content-Length: 6 ++Content-Disposition: attachment; filename="victim%TESTNUMBER" ++Connection: close ++ ++12345 ++ ++ ++ ++# Client-side ++ ++ ++http ++ ++ ++http ++ ++ ++Do not open output for ETag with -J, --show-headers, --etag-save ++ ++ ++original ++ ++ ++http://%HOSTIP:%HTTPPORT/victim%TESTNUMBER -O -J -i --etag-save %LOGDIR/etag%TESTNUMBER --output-dir %LOGDIR ++ ++ ++ ++ ++ ++GET /victim%TESTNUMBER HTTP/1.1 ++Host: %HOSTIP:%HTTPPORT ++User-Agent: curl/%VERSION ++Accept: */* ++ ++ ++ ++23 ++ ++ ++original ++ ++ ++"tag%TESTNUMBER" ++ ++ ++ +-- +2.35.6 diff --git a/meta/recipes-support/curl/curl/CVE-2026-92390_p2.patch b/meta/recipes-support/curl/curl/CVE-2026-92390_p2.patch new file mode 100644 index 0000000000..24696ca27b --- /dev/null +++ b/meta/recipes-support/curl/curl/CVE-2026-92390_p2.patch @@ -0,0 +1,150 @@ +From 631ed306872956f86617df9b5664614e8a2dee54 Mon Sep 17 00:00:00 2001 +From: matty69v +Date: Tue, 20 Oct 2026 10:28:31 +0200 +Subject: [PATCH] tool_cb_hdr: do not truncate existing file on filename-less + C-D header + +With -O -J, a Content-Disposition header without a usable filename +(for example "inline") made curl create the URL-derived output file +right away. When a later Content-Disposition header then named that +same file, the no-clobber check refused it, but the file had already +been truncated to zero bytes. The same happened when such a header came +in a 3xx response before the Location: header with -L. + +Defer creating the output file until the body arrives (or the transfer +ends), like for any other header. When the transfer ends without a body, +also write the headers buffered for -i, which were lost before. + +Test 1718 verifies both. +Closes #23501 + +CVE: CVE-2026-92390 +Upstream-Status: Backport [https://github.com/curl/curl/commit/631ed306872956f86617df9b5664614e8a2dee54] + +Backport Changes: +- Register test1718 without indentation to match curl 8.19.0's + grouped TESTCASES list; upstream indents the entry by two spaces. + +Signed-off-by: Darsh Kelaiya +--- + src/tool_cb_hdr.c | 10 +++++---- + src/tool_operate.c | 4 ++++ + tests/data/Makefile.am | 1 + + tests/data/test1718 | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 70 insertions(+), 4 deletions(-) + +diff --git a/src/tool_cb_hdr.c b/src/tool_cb_hdr.c +index 15abb5b..69c0227 100644 +--- a/src/tool_cb_hdr.c ++++ b/src/tool_cb_hdr.c +@@ -409,10 +409,12 @@ static size_t content_disposition(const char *str, const char *end, + } + break; + } +- if(!outs->stream && !tool_create_output_file(outs, per->config)) +- return CURL_WRITEFUNC_ERROR; +- if(tool_write_headers(&per->hdrcbdata, outs->stream)) +- return CURL_WRITEFUNC_ERROR; ++ /* No usable filename in this header. Do not create the output file ++ yet: a later Content-Disposition header may still provide a name, and ++ opening the URL-derived name here would truncate an existing file ++ that -J is meant to leave alone. The file is created once the body ++ arrives (or at the end of the transfer) and any buffered headers are ++ written then. */ + } /* content-disposition handling */ + + if(hdrcbdata->honor_cd_filename && +diff --git a/src/tool_operate.c b/src/tool_operate.c +index 9a29b8e..1458322 100644 +--- a/src/tool_operate.c ++++ b/src/tool_operate.c +@@ -649,6 +649,10 @@ static CURLcode post_output_handling(struct per_transfer *per, + curl_easy_getinfo(curl, CURLINFO_CONDITION_UNMET, &cond_unmet); + if(!cond_unmet && !tool_create_output_file(outs, config)) + return CURLE_WRITE_ERROR; ++ /* write headers buffered while waiting for a -J filename */ ++ if(outs->stream && per->hdrcbdata.headlist && ++ tool_write_headers(&per->hdrcbdata, outs->stream)) ++ return CURLE_WRITE_ERROR; + } + + if(!outs->regular_file && outs->stream) { +diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am +index 6d12c7c..2528286 100644 +--- a/tests/data/Makefile.am ++++ b/tests/data/Makefile.am +@@ -230,6 +230,7 @@ test1680 test1681 test1682 test1683 test1685 \ + \ + test1700 test1701 test1702 test1703 test1704 test1705 test1706 test1707 \ + test1708 test1709 test1710 test1711 test1712 \ ++test1718 \ + \ + test1800 test1801 test1802 test1847 test1848 test1849 test1850 test1862 \ + \ +diff --git a/tests/data/test1718 b/tests/data/test1718 +new file mode 100644 +index 0000000..c4826f3 +--- /dev/null ++++ b/tests/data/test1718 +@@ -0,0 +1,59 @@ ++ ++ ++ ++ ++HTTP ++HTTP GET ++-J ++ ++ ++ ++ ++ ++HTTP/1.1 200 OK ++Content-Disposition: inline ++Content-Disposition: attachment; filename="name%TESTNUMBER" ++Content-Length: 8 ++ ++PAYLOAD ++ ++ ++HTTP/1.1 200 OK ++Content-Disposition: inline ++Content-Length: 0 ++ ++ ++ ++ ++# Client-side ++ ++ ++http ++ ++ ++HTTP GET -OJi, filename-less Content-Disposition first ++ ++ ++http://%HOSTIP:%HTTPPORT/%TESTNUMBER0002 http://%HOSTIP:%HTTPPORT/name%TESTNUMBER -Ji -O -O --output-dir %LOGDIR ++ ++ ++initial content ++ ++ ++ ++# Verify data after the test has been "shot" ++ ++ ++23 ++ ++ ++initial content ++ ++ ++HTTP/1.1 200 OK ++Content-Disposition: inline ++Content-Length: 0 ++ ++ ++ ++ +-- +2.35.6 diff --git a/meta/recipes-support/curl/curl_8.19.0.bb b/meta/recipes-support/curl/curl_8.19.0.bb index e5b9203678..a458a69e20 100644 --- a/meta/recipes-support/curl/curl_8.19.0.bb +++ b/meta/recipes-support/curl/curl_8.19.0.bb @@ -63,6 +63,8 @@ SRC_URI = "https://curl.se/download/${BP}.tar.xz \ file://CVE-2026-92391.patch \ file://CVE-2026-87863.patch \ file://CVE-2026-86410.patch \ + file://CVE-2026-92390_p1.patch \ + file://CVE-2026-92390_p2.patch \ " SRC_URI:append:class-nativesdk = " \ From patchwork Fri Nov 6 07:19:28 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darsh Kelaiya -X (dkelaiya - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 103220 Received: from rcdn-iport-8.cisco.com (rcdn-iport-8.cisco.com [173.37.86.79]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.1218.1793949576373352610 for ; Thu, 05 Nov 2026 23:19:36 -0800 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=Q1pvAKEd; spf=pass (domain: cisco.com, ip: 173.37.86.79, mailfrom: dkelaiya@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=8037; q=dns/txt; s=iport01; t=1793949576; x=1795159176; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=h+wB4xT/R7r7zvzp5eRts5RRoZ/qe+IsO3qX35g93m4=; b=Q1pvAKEdB7FXTbwdEFCyAp858k93QXgz35sAMaX5Pdbkgr2PN6nQE48E 6AL2FtHATEfHwAnZ1aUKrsma0F4vh8yYh138/lO9YxDkDF17e65Z0YjP/ lMwEmHJb/QoTOwIdgRKIRojNdRjAYZD8Zuvg2D89W7G4zVccItTfZur/V hdEmMAqvL2teFSDtao8UDMzZQvKdwLLsqoFlk6obO26+qd+rHPFWlfXAI kucIhDgCl9AhMnwww7LQ843RGwhr6fZNrnKseVzEUn8Hbm5Y3BpjydwVX dVVJgsCY86/NO5mp9NL/+dM+OtpeckI/roivHk20Ay5+HiJ6pyfORhbuJ g==; X-CSE-ConnectionGUID: jw9TGChTQU2RlPKVRBbizQ== X-CSE-MsgGUID: vhbyuAC9QkuAD5e/b8voxg== X-IPAS-Result: A0BJAgBrfu1q/4v/Ja1aglmCV3VgQ0mWSwOBE50OgX4PAQEBD0QNBAEBhQUCjh0CJjQJDgECBAMCAwEBAQEBAQEBAQEBAQoBAQUBAQECAQcFgQ4Thk8NkBIBAgEDJwsBGAEtEBwDAQIvKyMIEAmDAgGCdAMRBrs7GzeBeTOBAYMpAT8CAkABUNszAQsUAYE4hUCII10YAYR9JxsbgXKBFYJzdoEFgVwCAYEZDYZ/BIIigQyBWh5ljBUCgVGGeUiBHgNZLAFVEw0KCwcFgWgDNRIqFW4yHYEjPheBBxsGBYEdgR6BEoEHXYErKF0BIYEIgXYCglGCAAIBSUEOB0VTCSVDEkckIggSCQETGiwKgRo1PAkmPxUMZAsaBWEIAg0MdDkQMB4kLwUcJj4bCi8YDUgRLDcVGQQ+bgeSPYMLB2EtAQciAoEgXQ4yPZJgBwqSN4E1n1wKKIN4jCSVOhozqnELmH2OCpVpaIRpgWg8gVlwFTuCZwkWNBkPji4LC4NghkDGBSYyAgkyAQEHAgcOAwuBaJAAgX4BAQ IronPort-Data: A9a23:N/eoEKrxCKRn4cvd4sDpMnDHIEBeBmJJZBIvgKrLsJaIsI4StFCzt garIBmCOP6INmagfNxxOY/k/EhUuMeGyNZrG1dupCE9Rn5B9ePIVI+TRqvS04x+DSFioGZPt Zh2hgzodZhsJpPkjk7zdOWn9T8jhfngqoPUUIbsIjp2SRJvVBAvgBdin/9RqoNziLBVOSvV0 T/Ji5OZYgDNNwJcaDpOtfva8E435ZwehRtB1rAATaET1LPhvyF94KI3fcmZM3b+S49IKe+2L 86r5K255G7Q4yA2AdqjlLvhGmVSKlIFFVHT4pb+c/HKbilq/kTe4I5iXBYvQRs/ZwGyojxE4 I4lWapc5useFvakdOw1C3G0GszlVEFM0OevzXOX6aR/w6BaGpfh660GMa04AWEX0uRoUF1h3 vwkEQ1XVBS7pNyM6ri6WNA506zPLOGzVG8ekmtrwTecCbMtRorOBv2Qo9RZxzw3wMtJGJ4yZ eJANmEpN0uGOUASfA5MWfrSn8/w7pX7WzFbpVacpLs+y2PS1wd2lrPqNbI5f/TXHpsFxxrI9 juuE2LRHBEQJcG24mu88W+FqrLC2imrRoUCG+jtnhJtqBjJroAJMzURTVa9rPyzh0KyVt4aI EsO9wIqrLMu7wqsVtT7UhiyrXKIsxJaXMBfe9DW8ymXwabSpgLcDW8eQ3sZMpottdQ9Qnoh0 Vrhc87VOAGDeYa9ERq1nop4ZxvrUcTJBQfuvRM5cDY= IronPort-HdrOrdr: A9a23:oUWRha+1Ab/D69WBJipuk+D6I+orL9Y04lQ7vn2ZhyY7TiX+rb HIoB11737JYVoqNU3I3OrwWpVoIkmskaKdn7NwAV7KZmCP0wGVxcNZnO7fKlbbdREWmNQw6U 4ZSdkcNPTASX5nkM39/A60V/wkwNWB7eSUoN229QYKcemvAJsQlzuQzW2gYzRLeDU= X-Talos-CUID: 9a23:q3TOJmpD5CsRMFD4taKEIizmUcI6I0Hy53fsGnLiM2JRa4OvY1WR6poxxg== X-Talos-MUID: 9a23:HmglGQrBWhxn4zRd2eUezy9iPtZ1yo//MUMQuLlbto6OZTJ3KzjI2Q== X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.27,197,1787011200"; d="scan'208";a="536814881" Received: from rcdn-l-core-02.cisco.com ([173.37.255.139]) by rcdn-iport-8.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 06 Nov 2026 07:19:35 +0000 Received: from sjc-ads-5675.cisco.com (sjc-ads-5675.cisco.com [10.28.88.189]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-02.cisco.com (Postfix) with ESMTPS id A8569180007DA; Fri, 6 Nov 2026 07:19:35 +0000 (GMT) Received: by sjc-ads-5675.cisco.com (Postfix, from userid 1887444) id F2A6CCBF21E; Thu, 5 Nov 2026 23:19:34 -0800 (PST) From: "Darsh Kelaiya -X (dkelaiya - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-core@lists.openembedded.org Cc: Darsh Kelaiya Subject: [OE-core][wrynose][PATCH 5/9] curl: fix CVE-2026-92388 Date: Thu, 5 Nov 2026 23:19:28 -0800 Message-Id: <20261106071932.490299-6-dkelaiya@cisco.com> X-Mailer: git-send-email 2.35.6 In-Reply-To: <20261106071932.490299-1-dkelaiya@cisco.com> References: <20261106071932.490299-1-dkelaiya@cisco.com> MIME-Version: 1.0 X-Outbound-Client-TLS: ANONYMOUS;sjc-ads-5675.cisco.com [10.28.88.189];TLSv1.3;TLS_AES_256_GCM_SHA384;256 X-Outbound-SMTP-Client: 10.28.88.189, sjc-ads-5675.cisco.com X-Outbound-Node: rcdn-l-core-02.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Fri, 06 Nov 2026 07:19:48 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/249604 From: Darsh Kelaiya This patch applies the upstream fixes referenced in [3], using the commits shown in [1] and [2]. Route wildcard directory listings through the internal write path without replacing the application's WRITEFUNCTION or WRITEDATA. Previously, ftp_wc.backup saved those options for restoration after LIST. Failed listings could skip that restoration and leave internal parser state in the application settings. The writer now selects the listing parser and easy handle directly without changing application options. This removes the need to save and restore callbacks, so remove the backup fields and that code, as upstream does. Apply the field removal in curl 8.19.0's lib/ftp.h. Keep the matching-state correction in a separate patch. [1] https://github.com/curl/curl/commit/ba8f8a7f27a5c5e19e4ef212b90b35a93559163e [2] https://github.com/curl/curl/commit/b85acacec9b38442741bb019bc992e77b5f665d4 [3] https://curl.se/docs/CVE-2026-92388.html Signed-off-by: Darsh Kelaiya --- .../curl/curl/CVE-2026-92388_p1.patch | 139 ++++++++++++++++++ .../curl/curl/CVE-2026-92388_p2.patch | 33 +++++ meta/recipes-support/curl/curl_8.19.0.bb | 2 + 3 files changed, 174 insertions(+) create mode 100644 meta/recipes-support/curl/curl/CVE-2026-92388_p1.patch create mode 100644 meta/recipes-support/curl/curl/CVE-2026-92388_p2.patch diff --git a/meta/recipes-support/curl/curl/CVE-2026-92388_p1.patch b/meta/recipes-support/curl/curl/CVE-2026-92388_p1.patch new file mode 100644 index 0000000000..92752eb21e --- /dev/null +++ b/meta/recipes-support/curl/curl/CVE-2026-92388_p1.patch @@ -0,0 +1,139 @@ +From ba8f8a7f27a5c5e19e4ef212b90b35a93559163e Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Wed, 16 Sep 2026 15:17:37 +0200 +Subject: [PATCH] ftplistparser: no more overwriting set.write_func + +The entries in the 'set' struct should remain as set by the application. + +Closes #22969 + +CVE: CVE-2026-92388 +Upstream-Status: Backport [https://github.com/curl/curl/commit/ba8f8a7f27a5c5e19e4ef212b90b35a93559163e] + +Backport Changes: +- Remove the ftp_wc backup fields from lib/ftp.h instead of + lib/ftp-int.h, which is absent from curl 8.19.0. + +Signed-off-by: Darsh Kelaiya +--- + lib/cw-out.c | 10 ++++++++-- + lib/ftp.c | 13 ------------- + lib/ftp.h | 5 ----- + lib/ftplistparser.c | 10 ++++++++++ + lib/ftplistparser.h | 5 +++++ + 5 files changed, 23 insertions(+), 20 deletions(-) + +diff --git a/lib/cw-out.c b/lib/cw-out.c +index 554c32e..2500ea8 100644 +--- a/lib/cw-out.c ++++ b/lib/cw-out.c +@@ -148,8 +148,14 @@ static void cw_get_writefunc(struct Curl_easy *data, cw_out_type otype, + switch(otype) { + case CW_OUT_BODY: + case CW_OUT_BODY_0LEN: +- *pwcb = data->set.fwrite_func; +- *pwcb_data = data->set.out; ++ if(Curl_ftp_listmode(data)) { ++ *pwcb = Curl_ftp_parselist; ++ *pwcb_data = data; ++ } ++ else { ++ *pwcb = data->set.fwrite_func; ++ *pwcb_data = data->set.out; ++ } + *pmax_write = CURL_MAX_WRITE_SIZE; + /* if we ever want buffering of BODY output, we can set `min_write` + * the preferred size. The default should always be to pass data +diff --git a/lib/ftp.c b/lib/ftp.c +index 6047759..6b13fb6 100644 +--- a/lib/ftp.c ++++ b/lib/ftp.c +@@ -3988,15 +3988,6 @@ static CURLcode init_wc_data(struct Curl_easy *data, + goto fail; + } + +- /* backup old write_function */ +- ftpwc->backup.write_function = data->set.fwrite_func; +- /* parsing write function */ +- data->set.fwrite_func = Curl_ftp_parselist; +- /* backup old file descriptor */ +- ftpwc->backup.file_descriptor = data->set.out; +- /* let the writefunc callback know the transfer */ +- data->set.out = data; +- + infof(data, "Wildcard - Parsing started"); + return CURLE_OK; + +@@ -4032,10 +4023,6 @@ static CURLcode wc_statemach(struct Curl_easy *data, + /* In this state is LIST response successfully parsed, so lets restore + previous WRITEFUNCTION callback and WRITEDATA pointer */ + struct ftp_wc *ftpwc = wildcard->ftpwc; +- data->set.fwrite_func = ftpwc->backup.write_function; +- data->set.out = ftpwc->backup.file_descriptor; +- ftpwc->backup.write_function = ZERO_NULL; +- ftpwc->backup.file_descriptor = NULL; + wildcard->state = CURLWC_DOWNLOADING; + + if(Curl_ftp_parselist_geterror(ftpwc->parser)) { +diff --git a/lib/ftp.h b/lib/ftp.h +index 20b3600..b1d3706 100644 +--- a/lib/ftp.h ++++ b/lib/ftp.h +@@ -85,11 +85,6 @@ struct ftp_parselist_data; /* defined later in ftplistparser.c */ + + struct ftp_wc { + struct ftp_parselist_data *parser; +- +- struct { +- curl_write_callback write_function; +- FILE *file_descriptor; +- } backup; + }; + + typedef enum { +diff --git a/lib/ftplistparser.c b/lib/ftplistparser.c +index f82895d..9c7ad6e 100644 +--- a/lib/ftplistparser.c ++++ b/lib/ftplistparser.c +@@ -1010,6 +1010,16 @@ static CURLcode parse_winnt(struct Curl_easy *data, + return CURLE_OK; + } + ++/* returns TRUE if in wildcard listing mode */ ++bool Curl_ftp_listmode(struct Curl_easy *data) ++{ ++ if(data->state.wildcardmatch) { ++ struct WildcardData * const wildcard = data->wildcard; ++ return wildcard && (wildcard->state <= CURLWC_MATCHING); ++ } ++ return FALSE; ++} ++ + size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, + void *connptr) + { +diff --git a/lib/ftplistparser.h b/lib/ftplistparser.h +index 5d7aa49..942e102 100644 +--- a/lib/ftplistparser.h ++++ b/lib/ftplistparser.h +@@ -27,6 +27,9 @@ + + #ifndef CURL_DISABLE_FTP + ++/* returns TRUE if in wildcard listing mode */ ++bool Curl_ftp_listmode(struct Curl_easy *data); ++ + /* WRITEFUNCTION callback for parsing LIST responses */ + size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, + void *connptr); +@@ -71,6 +74,8 @@ void Curl_wildcard_dtor(struct WildcardData **wcp); + struct Curl_easy; + + #else /* CURL_DISABLE_FTP */ ++#define Curl_ftp_listmode(x) FALSE ++#define Curl_ftp_parselist ZERO_NULL + #define Curl_wildcard_dtor(x) + #endif /* !CURL_DISABLE_FTP */ + +-- +2.35.6 diff --git a/meta/recipes-support/curl/curl/CVE-2026-92388_p2.patch b/meta/recipes-support/curl/curl/CVE-2026-92388_p2.patch new file mode 100644 index 0000000000..0f819509f5 --- /dev/null +++ b/meta/recipes-support/curl/curl/CVE-2026-92388_p2.patch @@ -0,0 +1,33 @@ +From b85acacec9b38442741bb019bc992e77b5f665d4 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Thu, 17 Sep 2026 14:32:52 +0200 +Subject: [PATCH] ftplistparser: only use the list parser in CURLWC_MATCHING + state + +Follow-up to ba8f8a7f27a5c5e1 + +Closes #22985 + +CVE: CVE-2026-92388 +Upstream-Status: Backport [https://github.com/curl/curl/commit/b85acacec9b38442741bb019bc992e77b5f665d4] + +Signed-off-by: Darsh Kelaiya +--- + lib/ftplistparser.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/ftplistparser.c b/lib/ftplistparser.c +index 9c7ad6e..91b2425 100644 +--- a/lib/ftplistparser.c ++++ b/lib/ftplistparser.c +@@ -1015,7 +1015,7 @@ bool Curl_ftp_listmode(struct Curl_easy *data) + { + if(data->state.wildcardmatch) { + struct WildcardData * const wildcard = data->wildcard; +- return wildcard && (wildcard->state <= CURLWC_MATCHING); ++ return wildcard && (wildcard->state == CURLWC_MATCHING); + } + return FALSE; + } +-- +2.35.6 diff --git a/meta/recipes-support/curl/curl_8.19.0.bb b/meta/recipes-support/curl/curl_8.19.0.bb index a458a69e20..5abde681e7 100644 --- a/meta/recipes-support/curl/curl_8.19.0.bb +++ b/meta/recipes-support/curl/curl_8.19.0.bb @@ -65,6 +65,8 @@ SRC_URI = "https://curl.se/download/${BP}.tar.xz \ file://CVE-2026-86410.patch \ file://CVE-2026-92390_p1.patch \ file://CVE-2026-92390_p2.patch \ + file://CVE-2026-92388_p1.patch \ + file://CVE-2026-92388_p2.patch \ " SRC_URI:append:class-nativesdk = " \ From patchwork Fri Nov 6 07:19:29 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darsh Kelaiya -X (dkelaiya - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 103224 Received: from rcdn-iport-5.cisco.com (rcdn-iport-5.cisco.com [173.37.86.76]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.1247.1793949576625009037 for ; Thu, 05 Nov 2026 23:19:36 -0800 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=lfQ95p5M; spf=pass (domain: cisco.com, ip: 173.37.86.76, mailfrom: dkelaiya@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=4018; q=dns/txt; s=iport01; t=1793949576; x=1795159176; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=UFSPe8pK6Tdm5bJeDdQ18CzIJRKpG5E54efgFKKgXpc=; b=lfQ95p5MkMxreMHxnJ988IjROgpKpK+d+Qu5CqH6taGdgl0zaajBepAc bwc+ZRBiE9RFXPXFoXvxLf4Z7Macxi3rDlVzKlcr9YhJMsqCRIsXArAgl hOAlcyTrRer/MCFbLWUaOqF2rNuFTyunJiYqFlOFd15P7yjbk1SFhqxLz wYU0vH6pIL5t1nqGExAGsCjgyg6jFGFaJpivSafAxUCr7/9f7PjNI4bTm 70xvJe9IYL2JJOVZWUETqK5menqkTqQhhuSenHtsTcNn98R0EP1UP3Lj0 r4GdXLZVGQ2XA323dzWaio300+r522JGQaW60P7yhrpcb6aHaHrdyMsa+ g==; X-CSE-ConnectionGUID: nfjJSM3cRCOqV2TmM9RbsA== X-CSE-MsgGUID: beNJWl/OQ3yjVdbIwOkKEw== X-IPAS-Result: A0BIAgBrfu1q/5L/Ja1aglmCV3VgQ0mWSwOeIYF+DwEBAQ9EDQQBAYUFAo4dAiY0CQ4BAgQDAgMBAQEBAQEBAQEBAQEKAQEFAQEBAgEHBYEOE4ZPDZASAQIBAycLARgBLRAcAwECLysjCBAJgwIBgnQDEQa7Oxs3gXkzgQGDKQE/AgJAAVDbMwELFAGBOIVAiCNdGAGEfScbG4FyhH6BBYFcAgGIJQSCIoEMgVoejHoCgVGGeUiBHgNZLAFVEw0KCwcFgWgDNRIqFW4yHYEjPheBBxsGBYEdgR6BEoEHXYErKF0BIYEIgXYCglGCAAIBSUEOB0VTCSVDEkckIggSCQETGiwKgRo1PAkmPxUMZAsaBWEIAg0MdDkQMB4kLwUcJj4bCi8YDUgRLDcVGQQ+bgeSPYJyIGEtASkBAVQvSjc5kySSQaERCiiDeIwkglmSYRozhASmbQuYfY4KlWkYA02EaYFoPIFZcBWDIgkWNBkPjjmDa4ZAxgUmMgIJMgEBBwIHDgMLgWiRfgEB IronPort-Data: A9a23:G7FCHaM278eb+OfvrR30lsFynXyQoLVcMsEvi/4bfWQNrUoh0zYFy zMbXj3SOv3fYWH8eNpzPYTg8UsCu57SzNA3GXM5pCpnJ55oRWUpJjg4wmPYZX76whjrFRo/h ykmQoCeap1yFjmD9k/F3oHJ9RFUzbuPSqf3FNnKMyVwQR4MYCo6gHqPocZh6mJTqYb/WVzlV e/a+ZWFZgb8g2Msawr41orawP9RlKWq0N8nlgRWicBj5Df2i3QTBZQDEqC9R1OQapVUBOOzW 9HYx7i/+G7Dlz91Yj9yuu+mGqGiaue60Tmm0hK6aYD76vRxjnBaPpIACRYpQRw/ZwNlMDxG4 I4lWZSYEW/FN0BX8QgXe0Ew/ypWZcWq9FJbSJSymZT78qHIT5fj6/NgDmMNGNYTwM1QGF8Uy fk9eQoHdTnW0opawJrjIgVtrt4oIM+uOMYUvWttiGmIS/0nWpvEBa7N4Le03h9p2ZsIRqmYP ZdEL2MzMnwsYDUXUrsTIJ49keOhh2j2WzZZs1mS46Ew5gA/ySQsjOW3YISEI43iqcN9lEu+h F3CuEPAWQAYCtCV6CWi8VGBmbqa9c/8cMdIfFGizdZtmFCVy2kZBREaWFf+qv6jh2a6WslDM AoT4icooK04+UCnQ9W7WAe3yENopTYGUNZWVul/4waXx++MskCSB3MPSXhKb9lOWNIKeAHGH 2Shx7vBbQGDepXMIZ5B3t94dQ+PBBU= IronPort-HdrOrdr: A9a23:23PxiaN6yrgfosBcTuOjsMiBIKoaSvp037Dk7S9MoHtuA6ulfq +V/cjzuSWYtN9VYgBDpTniAtjlfZqjz/5ICOAqVN/INjUO+lHYSb2KhrGN/9SPIUHDH5ZmpM RdWpk7LsHsBl5nisu/ygy5H9E8hOSjysmT9IHjJ7MHd3ATV0mmhD0JczqmLg== X-Talos-CUID: 9a23:WljxhmsfjkrdvXkv1bphmiD96IsjfH//91KLKHWTLn9XEoGQbA6q8rhNxp8= X-Talos-MUID: 9a23:cydjIQUIahxrYX3q/DXhohNdMIBP2v+/Cn4Bm7QZnMqnGDMlbg== X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.27,197,1787011200"; d="scan'208";a="545286919" Received: from rcdn-l-core-09.cisco.com ([173.37.255.146]) by rcdn-iport-5.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 06 Nov 2026 07:19:35 +0000 Received: from sjc-ads-5675.cisco.com (sjc-ads-5675.cisco.com [10.28.88.189]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-09.cisco.com (Postfix) with ESMTPS id AA09018000202; Fri, 6 Nov 2026 07:19:35 +0000 (GMT) Received: by sjc-ads-5675.cisco.com (Postfix, from userid 1887444) id 05C9ECBF234; Thu, 5 Nov 2026 23:19:35 -0800 (PST) From: "Darsh Kelaiya -X (dkelaiya - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-core@lists.openembedded.org Cc: Darsh Kelaiya Subject: [OE-core][wrynose][PATCH 6/9] curl: fix CVE-2026-92392 Date: Thu, 5 Nov 2026 23:19:29 -0800 Message-Id: <20261106071932.490299-7-dkelaiya@cisco.com> X-Mailer: git-send-email 2.35.6 In-Reply-To: <20261106071932.490299-1-dkelaiya@cisco.com> References: <20261106071932.490299-1-dkelaiya@cisco.com> MIME-Version: 1.0 X-Outbound-Client-TLS: ANONYMOUS;sjc-ads-5675.cisco.com [10.28.88.189];TLSv1.3;TLS_AES_256_GCM_SHA384;256 X-Outbound-SMTP-Client: 10.28.88.189, sjc-ads-5675.cisco.com X-Outbound-Node: rcdn-l-core-09.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Fri, 06 Nov 2026 07:19:49 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/249602 From: Darsh Kelaiya This patch applies the upstream fix as referenced in [2], using the commit shown in [1]. Finish request flushing before connection filters release their references to the easy handle. Detach or return the connection before resuming pending transfers, including HTTP/2 upload retry paths. Adapt the order to curl 8.19.0's Curl_cpool_do_locked() callback and process_pending_handles(). Keep detachment under the existing pool share lock rather than importing the newer pool APIs. [1] https://github.com/curl/curl/commit/8b0744af5b1b631da5b938ca31c3f9895ad5a321 [2] https://curl.se/docs/CVE-2026-92392.html Signed-off-by: Darsh Kelaiya --- .../curl/curl/CVE-2026-92392.patch | 59 +++++++++++++++++++ meta/recipes-support/curl/curl_8.19.0.bb | 1 + 2 files changed, 60 insertions(+) create mode 100644 meta/recipes-support/curl/curl/CVE-2026-92392.patch diff --git a/meta/recipes-support/curl/curl/CVE-2026-92392.patch b/meta/recipes-support/curl/curl/CVE-2026-92392.patch new file mode 100644 index 0000000000..4129d7f013 --- /dev/null +++ b/meta/recipes-support/curl/curl/CVE-2026-92392.patch @@ -0,0 +1,59 @@ +From 8b0744af5b1b631da5b938ca31c3f9895ad5a321 Mon Sep 17 00:00:00 2001 +From: Stefan Eissing +Date: Mon, 12 Oct 2026 07:40:45 +0200 +Subject: [PATCH] multi: adjust the cleanup order in multi_done + +Closes #23370 + +CVE: CVE-2026-92392 +Upstream-Status: Backport [https://github.com/curl/curl/commit/8b0744af5b1b631da5b938ca31c3f9895ad5a321] + +Backport Changes: +- Use curl 8.19.0's process_pending_handles() and retain its + connection/multiplex comment; multi_schedule_pending() is absent. +- Keep Curl_cpool_do_locked(), whose callback detaches the connection, + instead of the newer Curl_cpool_return() and outer detach calls. + Notify filters after request cleanup and before that callback, + then process pending transfers after the pool lock is released. +- Apply this to the older function's connection-required layout, + which has no outer if(conn) block. Keep a blank line between the + pending-transfer block and netrc cleanup. + +Signed-off-by: Darsh Kelaiya +--- + lib/multi.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/lib/multi.c b/lib/multi.c +index ec2d531..4e81001 100644 +--- a/lib/multi.c ++++ b/lib/multi.c +@@ -720,19 +720,21 @@ static CURLcode multi_done(struct Curl_easy *data, + /* Make sure that transfer client writes are really done now. */ + result = Curl_1st_fatal(result, Curl_xfer_write_done(data, premature)); + +- /* Inform connection filters that this transfer is done */ +- Curl_conn_ev_data_done(data, premature); +- +- process_pending_handles(data->multi); /* connection / multiplex */ +- + if(!result) + result = Curl_req_done(&data->req, data, premature); + ++ /* Inform connection filters that this transfer is done and they ++ * need to give up any references to `data`. */ ++ Curl_conn_ev_data_done(data, premature); ++ + /* Under the potential connection pool's share lock, decide what to + * do with the transfer's connection. */ + mdctx.premature = premature; + Curl_cpool_do_locked(data, data->conn, multi_done_locked, &mdctx); + ++ if(data->multi) ++ process_pending_handles(data->multi); /* connection / multiplex */ ++ + /* flush the netrc cache */ + Curl_netrc_cleanup(&data->state.netrc); + return result; +-- +2.35.6 diff --git a/meta/recipes-support/curl/curl_8.19.0.bb b/meta/recipes-support/curl/curl_8.19.0.bb index 5abde681e7..71b7c06e71 100644 --- a/meta/recipes-support/curl/curl_8.19.0.bb +++ b/meta/recipes-support/curl/curl_8.19.0.bb @@ -67,6 +67,7 @@ SRC_URI = "https://curl.se/download/${BP}.tar.xz \ file://CVE-2026-92390_p2.patch \ file://CVE-2026-92388_p1.patch \ file://CVE-2026-92388_p2.patch \ + file://CVE-2026-92392.patch \ " SRC_URI:append:class-nativesdk = " \ From patchwork Fri Nov 6 07:19:30 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darsh Kelaiya -X (dkelaiya - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 103217 Received: from rcdn-iport-4.cisco.com (rcdn-iport-4.cisco.com [173.37.86.75]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.1249.1793949577074943083 for ; Thu, 05 Nov 2026 23:19:37 -0800 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=dDBdVPDh; spf=pass (domain: cisco.com, ip: 173.37.86.75, mailfrom: dkelaiya@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=23805; q=dns/txt; s=iport01; t=1793949577; x=1795159177; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ZHncDlpn5YDJVT1ACW0zcUxbiP7QF4wvUonVL3X0PMQ=; b=dDBdVPDh+LtiHSIqgEwRn4mOqhOFyDTq+SC/O3s8cqwbE/qlIfLoAMpk FQdEO3Es0ogsUGjOKxlJSFVa5UOVIXLzjJ+DqSx3UlS5EBs4kq+F9gXrw CE4dmbcgkKpQhj+ghs5R5CqeDUwhDm2AYtxTyNGeeGOHjc39NdMB/UKtp AVCxfV3WJhr5ZpxV+i/lG/BdLw/HoAu+Qsjs8QmtZcR0uZ0KrTEmqRNKJ W0B/T1DZtTqAYrWz2xt+rm+rs1AIFbM/k8/4VltR6Y9MQAmfIkzpBNN7+ R4L2aaIiWc6L3uWFkZdJP1DbJHT2eX1XO4eBr7uFmiu6ADWQrSWFryyxX w==; X-CSE-ConnectionGUID: xzVppjo2QGqNkO/uXQhg8w== X-CSE-MsgGUID: eXKjMi2SRaOvpsVbsFALKQ== X-IPAS-Result: A0DWAgDtfu1q/4r/Ja1aglmCV3VgQ0mWSwOBE5A5jFUUgWoPAQEBD0oHBAEBgXEBIIJzAo4dAiY1CA4BAgQDAgMBAQEBAQEBAQEBAQEKAQEFAQEBAgEHBYEOE4YVBjQNkBIBAgEDGg0LARgBLRAcAwECFwEBFisjCBAJgwIBgnQDEQa7OBs3gXkzgQGDKQE/AgJAAVDbMwELFAGBOIVAiCNdGAGEfScbG4FygRWCc3aBBYFcAQEBAYEhBB8BAWACBoV2BIINFYEMgVoeZQmFNIY+GgKBUVqGH0iBHgNZLAFVEw0KCwcFgWgDNRIqFW4yHYEjPheBBxsGBYEdgR6BEoEHXYErKF0BIYEIgXYCglGCAAIBSUEOB0VTCSVDEkckIggSCQETGiwKgRo1PAkmPxUMZAsaBWEIAg0MdDkQMB4kLwUcJj4bCi8YDUgRLDcVGQQ+bgeSPYJeLQYBMScIAQIHEQcCCgEHDBYBARcYXRQUGTAFAi0MCwEFEAgRjxmDUQGQH4Ihiy+VYgoog3iKI4IBjg2HLRozhASBV5JCg1OPAQuYfYJZizGVNzIYAQEBFjeEaYFqATmBWXAVO4JnCRY0GQ+MZ4FEAwsLgXiBaIZAxgUmMgIJMgEBBwIHDgMLgWiQAAIkAoFWAQE IronPort-Data: A9a23:smq1dahQ6jKY9rdkpcokPokeX161MREKZh0ujC45NGQN5FlHY01je htvDWiHOP/ZZWHze912Oo++8ElXsMSDx4BiTwFkpC4yF3ljpJueD7x1DKtf0wB+jyHnZBg6h ynLQoCYdKjYdleF+FHwdOCn8ikkvU2xbuKUIPbePSxsThNTRi4kiBZy88Y0mYcAbeKRW2thg vus5ZeAULOZ82QsaDxNsvre8EoHUMna4Vv0gHRvPZing3eG/5UlJMp3Db28KXL+Xr5VEoaSL 87fzKu093/u5BwkDNWoiN7TKiXmlZaLYGBiIlIPM0STqkAqSh4ai87XB9JAAatjsAhlqvgqo Dl7WTNcfi9yVkHEsLx1vxC1iEiSN4UekFPMCSDXXcB+UyQqflO0q8iCAn3aMqUI6NhvGWNJr 8U3MRYOSVeet9u2z+KkH7wEasQLdKEHPasFsX1miDWcBvE8TNWbGuPB5MRT23E7gcUm8fT2P pVCL2EwKk6dPlsWYQd/5JEWxI9EglHzcDBcoVOErII84nPYy0p6172F3N/9J4DXHZ8Ixx/Hz o7A12nJIRM/NYak8zOi7Gq3uOXUswrfe7tHQdVU8dYv2jV/3Fc7DwUbU1a+q/S1hkOyHtlYM UE8/is1sbN081SmSNT4VRC0rHOI+BkGVLJt//YS8gqBzO/Qpg2eHGVBFmcHY909v8hwTjsvv rOUo+7U6fVUmOX9YRqgGn289Fte5QB9wbc+WBI5 IronPort-HdrOrdr: A9a23:4pOeFq+dUOQ9+2VbDXFuk+D6I+orL9Y04lQ7vn2ZhyY7TiX+rb HIoB11737JYVoqNU3I3OrwWpVoIkmskaKdn7NwAV7KZmCP0wGVxcNZnO7fKlbbdREWmNQw6U 4ZSdkcNPTASX5nkM39/A60V/wkwNWB7eSUoN229QYKcemvAJsQlzuQzW2gYzRLeDU= X-Talos-CUID: 9a23:ifi75WketI+IzJwwMKXTMcUu2knXOW3P8m/IIUjiMElwbr6yDkKgwaNrw9U7zg== X-Talos-MUID: 9a23:eGHtLgkKKEdqFjH8Ml6SdnpvBORqxqX0M3oEtoseoPeOLgJZHxSk2WE= X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.27,197,1787011200"; d="scan'208";a="545025117" Received: from rcdn-l-core-01.cisco.com ([173.37.255.138]) by rcdn-iport-4.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 06 Nov 2026 07:19:35 +0000 Received: from sjc-ads-5675.cisco.com (sjc-ads-5675.cisco.com [10.28.88.189]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-01.cisco.com (Postfix) with ESMTPS id A9E28180001CD; Fri, 6 Nov 2026 07:19:35 +0000 (GMT) Received: by sjc-ads-5675.cisco.com (Postfix, from userid 1887444) id 0A2E7CBEF8A; Thu, 5 Nov 2026 23:19:35 -0800 (PST) From: "Darsh Kelaiya -X (dkelaiya - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-core@lists.openembedded.org Cc: Darsh Kelaiya Subject: [OE-core][wrynose][PATCH 7/9] curl: fix CVE-2026-94266 Date: Thu, 5 Nov 2026 23:19:30 -0800 Message-Id: <20261106071932.490299-8-dkelaiya@cisco.com> X-Mailer: git-send-email 2.35.6 In-Reply-To: <20261106071932.490299-1-dkelaiya@cisco.com> References: <20261106071932.490299-1-dkelaiya@cisco.com> MIME-Version: 1.0 X-Outbound-Client-TLS: ANONYMOUS;sjc-ads-5675.cisco.com [10.28.88.189];TLSv1.3;TLS_AES_256_GCM_SHA384;256 X-Outbound-SMTP-Client: 10.28.88.189, sjc-ads-5675.cisco.com X-Outbound-Node: rcdn-l-core-01.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Fri, 06 Nov 2026 07:19:47 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/249607 From: Darsh Kelaiya This patch applies the upstream fix referenced in [4], using [1], and includes the invalid-URL correction in [2]. Remove credentials from CURLINFO_EFFECTIVE_URL, including credentials loaded from netrc. Own the sanitized result in the easy handle and release it on transfer reset and cleanup. Return the actual URL error and a NULL result if parsing fails, rather than exposing an unfiltered URL or reporting every failure as out of memory. Retain tests 1876 and 1990. Select lib1990 explicitly for the older runner and register both tests in curl 8.19.0's grouped lists. Also apply Git's compatibility change [3] to the Wrynose Git 2.53.0 recipe. Git otherwise interprets stripped credentials as a redirect and can discard authentication state. Keep this companion change with the curl API change so the known Git regression is not introduced. [1] https://github.com/curl/curl/commit/7a6bd027d0de2b6857472d35da090ef60cc29f19 [2] https://github.com/curl/curl/commit/589c35f0cb47266394367659648bf3efc03e3790 [3] https://github.com/git/git/commit/76524c2604bceee48481909e7824494498c39a34 [4] https://curl.se/docs/CVE-2026-94266.html Signed-off-by: Darsh Kelaiya --- ...l-stripping-creds-from-effective-url.patch | 140 +++++++++++ meta/recipes-devtools/git/git_2.53.0.bb | 1 + .../curl/curl/CVE-2026-94266_p1.patch | 225 +++++++++++++++++ .../curl/curl/CVE-2026-94266_p2.patch | 235 ++++++++++++++++++ meta/recipes-support/curl/curl_8.19.0.bb | 2 + 5 files changed, 603 insertions(+) create mode 100644 meta/recipes-devtools/git/git/0001-http-handle-curl-stripping-creds-from-effective-url.patch create mode 100644 meta/recipes-support/curl/curl/CVE-2026-94266_p1.patch create mode 100644 meta/recipes-support/curl/curl/CVE-2026-94266_p2.patch diff --git a/meta/recipes-devtools/git/git/0001-http-handle-curl-stripping-creds-from-effective-url.patch b/meta/recipes-devtools/git/git/0001-http-handle-curl-stripping-creds-from-effective-url.patch new file mode 100644 index 0000000000..597ef1c684 --- /dev/null +++ b/meta/recipes-devtools/git/git/0001-http-handle-curl-stripping-creds-from-effective-url.patch @@ -0,0 +1,140 @@ +From 76524c2604bceee48481909e7824494498c39a34 Mon Sep 17 00:00:00 2001 +From: Jeff King +Date: Mon, 28 Sep 2026 00:01:49 -0400 +Subject: [PATCH] http: handle curl stripping creds from effective url + +When we detect that curl performed a redirect of a URL we requested, we +update our base URL to match the new location and flush the http_auth +credentials. This goes back to c93c92f309 (http: update base URLs when +we see redirects, 2013-09-28). + +We detect the redirect by comparing the requested URL to the response +from CURLINFO_EFFECTIVE_URL, using a simple string comparison. This has +worked fine for years, but a change in the upcoming curl 8.23.0 adds a +complication. If our URL directly contains credentials (like +"https://user:pass@example.com/foo.git"), then as of 7a6bd027d0 +(getinfo: make sure CURLINFO_EFFECTIVE_URL does not contain creds, +2026-09-21), curl will strip the credentials from what it returns (so +just "https://example.com/foo.git" in this case). + +This breaks our direct string comparison, and we believe that we've been +redirected. We flush our http_auth credentials, and now subsequent +requests will use the reduced URL, causing us to re-request credentials +from the user. Notably this causes t5550.15 (among others) to complain; +it tries a clone with credentials in the URL, and fails if the user is +prompted at all. + +We can handle this new behavior by doing a more careful comparison: if +the direct string comparison fails, we'll strip out the credentials +ourselves and compare. This is a little extra work, but in practice it +should only happen once per process. + +I've used curl's curl_url() interface to do the stripping here, mostly +because its behavior should match the stripping it does internally. And +also, though we have code to parse a URL, we don't have any to +reconstruct it, making a single string comparison hard. + +One alternative would be to parse with url_parse() or similar, and +compare the individual fields (skipping username/password). I think that +would probably also work in practice, but it seemed to me that the +simplest change would be sticking with string comparisons. + +The curl_url() interface appeared in 7.62.0. We document that 7.61.0 is +still supported, so I've made it conditional here. Only new versions +strip the result from CURLINFO_EFFECTIVE_URL, so it's OK for very old +versions to skip the extra comparison. Likewise if we encounter any +errors, we just quietly skip the comparison. That's fine if you don't +have creds in your URLs, and if you do, you'll get end up in the +existing error path (a redirect warning, and eventually an auth +failure). + +Signed-off-by: Jeff King +Signed-off-by: Junio C Hamano + +Upstream-Status: Backport [https://github.com/git/git/commit/76524c2604bceee48481909e7824494498c39a34] + +Signed-off-by: Darsh Kelaiya +--- + git-curl-compat.h | 7 +++++++ + http.c | 41 ++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 47 insertions(+), 1 deletion(-) + +diff --git a/git-curl-compat.h b/git-curl-compat.h +index 659e5a3..e390e23 100644 +--- a/git-curl-compat.h ++++ b/git-curl-compat.h +@@ -28,6 +28,13 @@ + * introduced, oldest first, in the official version of cURL library. + */ + ++/** ++ * curl_url() interface added in 7.62.0 (October 2018) ++ */ ++#if LIBCURL_VERSION_NUM >= 0x073e00 ++#define GIT_CURL_HAVE_CURL_URL ++#endif ++ + /** + * Versions before curl 7.66.0 (September 2019) required manually setting the + * transfer-encoding for a streaming POST; after that this is handled +diff --git a/http.c b/http.c +index 7815f14..6dd842a 100644 +--- a/http.c ++++ b/http.c +@@ -2201,6 +2201,45 @@ static int http_request(const char *url, + return ret; + } + ++#ifndef GIT_CURL_HAVE_CURL_URL ++#define strip_url_credential(in) NULL ++#else ++static char *strip_url_credential(const char *in) ++{ ++ char *ret = NULL; ++ CURLU *url; ++ ++ url = curl_url(); ++ if (!url) ++ goto out; ++ ++ if (curl_url_set(url, CURLUPART_URL, in, 0)) ++ goto out; ++ ++ curl_url_set(url, CURLUPART_USER, NULL, 0); ++ curl_url_set(url, CURLUPART_PASSWORD, NULL, 0); ++ curl_url_get(url, CURLUPART_URL, &ret, 0); ++ ++out: ++ curl_url_cleanup(url); ++ return ret; ++} ++#endif ++ ++static int match_effective_url(const char *asked, const char *got) ++{ ++ char *stripped; ++ int ret; ++ ++ if (!strcmp(asked, got)) ++ return 1; ++ ++ stripped = strip_url_credential(asked); ++ ret = stripped && !strcmp(stripped, got); ++ curl_free(stripped); ++ return ret; ++} ++ + /* + * Update the "base" url to a more appropriate value, as deduced by + * redirects seen when requesting a URL starting with "url". +@@ -2233,7 +2272,7 @@ static int update_url_from_redirect(struct strbuf *base, + const char *tail; + size_t new_len; + +- if (!strcmp(asked, got->buf)) ++ if (match_effective_url(asked, got->buf)) + return 0; + + if (!skip_prefix(asked, base->buf, &tail)) +-- +2.35.6 diff --git a/meta/recipes-devtools/git/git_2.53.0.bb b/meta/recipes-devtools/git/git_2.53.0.bb index 5244891113..202799e05c 100644 --- a/meta/recipes-devtools/git/git_2.53.0.bb +++ b/meta/recipes-devtools/git/git_2.53.0.bb @@ -10,6 +10,7 @@ PROVIDES:append:class-native = " git-replacement-native" SRC_URI = "${KERNELORG_MIRROR}/software/scm/git/git-${PV}.tar.gz;name=tarball \ file://fixsort.patch \ file://0001-config.mak.uname-do-not-force-RHEL-7-specific-build-.patch \ + file://0001-http-handle-curl-stripping-creds-from-effective-url.patch \ " SRC_URI:append:class-nativesdk = " \ diff --git a/meta/recipes-support/curl/curl/CVE-2026-94266_p1.patch b/meta/recipes-support/curl/curl/CVE-2026-94266_p1.patch new file mode 100644 index 0000000000..8b27e2859e --- /dev/null +++ b/meta/recipes-support/curl/curl/CVE-2026-94266_p1.patch @@ -0,0 +1,225 @@ +From 7a6bd027d0de2b6857472d35da090ef60cc29f19 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Mon, 21 Sep 2026 11:13:13 +0200 +Subject: [PATCH] getinfo: make sure CURLINFO_EFFECTIVE_URL does not contain + creds + +Reported-by: Joshua Rogers + +Verified in test 1876 + +Closes #23016 + +CVE: CVE-2026-94266 +Upstream-Status: Backport [https://github.com/curl/curl/commit/7a6bd027d0de2b6857472d35da090ef60cc29f19] + +Backport Changes: +- Use Curl_safefree() in initialization, transfer reset and cleanup; + curl 8.19.0 does not have the newer curlx_safefree() helper. +- Register test1876 in the older grouped TESTCASES list instead of + upstream's one-entry-per-line list. + +Signed-off-by: Darsh Kelaiya +--- + lib/getinfo.c | 47 +++++++++++++++++++++++++---- + lib/transfer.c | 1 + + lib/url.c | 1 + + lib/urldata.h | 1 + + tests/data/Makefile.am | 2 +- + tests/data/test1876 | 67 ++++++++++++++++++++++++++++++++++++++++++ + 6 files changed, 113 insertions(+), 6 deletions(-) + create mode 100644 tests/data/test1876 + +diff --git a/lib/getinfo.c b/lib/getinfo.c +index dedafd382e..920f1f3a0c 100644 +--- a/lib/getinfo.c ++++ b/lib/getinfo.c +@@ -72,6 +72,7 @@ void Curl_initinfo(struct Curl_easy *data) + + curlx_free(info->wouldredirect); + info->wouldredirect = NULL; ++ Curl_safefree(info->effective_url); + + memset(&info->primary, 0, sizeof(info->primary)); + info->retry_after = 0; +@@ -84,15 +85,51 @@ void Curl_initinfo(struct Curl_easy *data) + #endif + } + ++static CURLcode effective_url(struct Curl_easy *data, ++ const char **param_charp) ++{ ++ const char *s = Curl_bufref_ptr(&data->state.url); ++ *param_charp = s ? s : ""; ++ if(s) { ++ char *url = NULL; ++ /* Make a copy of the URL without credentials */ ++ CURLU *u = curl_url(); ++ CURLUcode uc; ++ if(!u) ++ return CURLE_OUT_OF_MEMORY; ++ ++ uc = curl_url_set(u, CURLUPART_URL, s, ++ CURLU_NON_SUPPORT_SCHEME | ++ (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)); ++ if(!uc) ++ uc = curl_url_set(u, CURLUPART_USER, NULL, 0); ++ if(!uc) ++ uc = curl_url_set(u, CURLUPART_PASSWORD, NULL, 0); ++ if(!uc) ++ uc = curl_url_get(u, CURLUPART_URL, &url, CURLU_GET_EMPTY); ++ ++ curl_url_cleanup(u); ++ ++ if(uc || !url) ++ return CURLE_OUT_OF_MEMORY; ++ if(strcmp(url, s)) { ++ /* they are different */ ++ curlx_free(data->info.effective_url); ++ data->info.effective_url = url; ++ *param_charp = url; ++ } ++ else ++ curl_free(url); ++ } ++ return CURLE_OK; ++} ++ + static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info, + const char **param_charp) + { + switch(info) { +- case CURLINFO_EFFECTIVE_URL: { +- const char *s = Curl_bufref_ptr(&data->state.url); +- *param_charp = s ? s : ""; +- } +- break; ++ case CURLINFO_EFFECTIVE_URL: ++ return effective_url(data, param_charp); + case CURLINFO_EFFECTIVE_METHOD: { + const char *m = data->set.str[STRING_CUSTOMREQUEST]; + if(!m) { +diff --git a/lib/transfer.c b/lib/transfer.c +index 9b55913265..fc7a5177d1 100644 +--- a/lib/transfer.c ++++ b/lib/transfer.c +@@ -534,6 +534,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data) + data->state.authhost.want = data->set.httpauth; + data->state.authproxy.want = data->set.proxyauth; + Curl_safefree(data->info.wouldredirect); ++ Curl_safefree(data->info.effective_url); + Curl_data_priority_clear_state(data); + if(data->set.http_auto_referer) + Curl_bufref_free(&data->state.referer); +diff --git a/lib/url.c b/lib/url.c +index 4a01bafae1..ba3cb7f0b6 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -284,6 +284,7 @@ CURLcode Curl_close(struct Curl_easy **datap) + Curl_safefree(data->state.most_recent_ftp_entrypath); + Curl_safefree(data->info.contenttype); + Curl_safefree(data->info.wouldredirect); ++ Curl_safefree(data->info.effective_url); + + data_priority_cleanup(data); + +diff --git a/lib/urldata.h b/lib/urldata.h +index 0bc9ade696..8b18ce590a 100644 +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -756,6 +756,7 @@ struct PureInfo { + uint32_t httpauthpicked; /* selected host auth type */ + char *contenttype; /* the content type of the object */ + char *wouldredirect; /* URL this would have been redirected to if asked to */ ++ char *effective_url; /* when needed */ + curl_off_t retry_after; /* info from Retry-After: header */ + uint32_t header_size; /* size of read header(s) in bytes */ + +diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am +index 08ece8bc1c..d6aaa71f5d 100644 +--- a/tests/data/Makefile.am ++++ b/tests/data/Makefile.am +@@ -232,7 +232,7 @@ test1700 test1701 test1702 test1703 test1704 test1705 test1706 test1707 \ + test1708 test1709 test1710 test1711 test1712 \ + test1718 \ + \ +-test1800 test1801 test1802 test1847 test1848 test1849 test1850 test1862 \ ++test1800 test1801 test1802 test1847 test1848 test1849 test1850 test1862 test1876 \ + \ + test1900 test1901 test1902 test1903 test1904 test1905 test1906 test1907 \ + test1908 test1909 test1910 test1911 test1912 test1913 test1914 test1915 \ +diff --git a/tests/data/test1876 b/tests/data/test1876 +new file mode 100644 +index 0000000000..4fc3b9fd02 +--- /dev/null ++++ b/tests/data/test1876 +@@ -0,0 +1,67 @@ ++ ++ ++ ++ ++netrc ++ ++ ++ ++# Server-side ++ ++ ++HTTP/1.1 301 redir ++Content-Length: 0 ++Content-Type: text/html ++Location: %TESTNUMBER0002 ++ ++ ++ ++ ++HTTP/1.1 200 OK ++Content-Length: 0 ++Content-Type: text/html ++ ++ ++ ++ ++ ++# Client-side ++ ++ ++http ++ ++ ++verify no credentials present in effective URL after redirect ++ ++ ++machine %HOSTIP ++login netrcuser ++password netrcSECRET123 ++ ++ ++ ++http://%HOSTIP:%HTTPPORT/%TESTNUMBER --netrc-optional --netrc-file %LOGDIR/netrc -L -w 'EFFECTIVE_URL=%{url_effective}\n' ++ ++ ++ ++# Verify data after the test has been "shot" ++ ++ ++GET /%TESTNUMBER HTTP/1.1 ++Host: %HOSTIP:%HTTPPORT ++Authorization: Basic %b64[netrcuser:netrcSECRET123]b64% ++User-Agent: curl/%VERSION ++Accept: */* ++ ++GET /%TESTNUMBER0002 HTTP/1.1 ++Host: %HOSTIP:%HTTPPORT ++Authorization: Basic %b64[netrcuser:netrcSECRET123]b64% ++User-Agent: curl/%VERSION ++Accept: */* ++ ++ ++ ++EFFECTIVE_URL=http://%HOSTIP:%HTTPPORT/%TESTNUMBER0002 ++ ++ ++ +-- +2.35.6 diff --git a/meta/recipes-support/curl/curl/CVE-2026-94266_p2.patch b/meta/recipes-support/curl/curl/CVE-2026-94266_p2.patch new file mode 100644 index 0000000000..54d10dbb0f --- /dev/null +++ b/meta/recipes-support/curl/curl/CVE-2026-94266_p2.patch @@ -0,0 +1,235 @@ +From 589c35f0cb47266394367659648bf3efc03e3790 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?M=C3=A1t=C3=A9=20Szab=C3=B3?= +Date: Fri, 16 Oct 2026 22:23:57 +0200 +Subject: [PATCH] getinfo: clarify invalid URL handling for + CURLINFO_EFFECTIVE_URL + +Since 7a6bd02 `CURLINFO_EFFECTIVE_URL` returns `CURLE_OUT_OF_MEMORY` if +the effective URL couldn't be parsed, which surprised some code that +expected it to be mostly always present in normal operation (we interact +with `libcurl` over HHVM's wrapper, which, akin to PHP, wraps[1] +easy_getinfo and returns a dict with optional entries, so it's been easy +for things to assume that `url` would always be set). + +Clarify the new behaviour in docs and have `CURLINFO_EFFECTIVE_URL` +return the relevant parsing error code rather than `CURLE_OUT_OF_MEMORY` +for invalid URLs. + +[1] https://github.com/facebook/hhvm/blob/c83584cad90cc9327d0b75175135d46882d8dc1f/hphp/runtime/ext/curl/ext_curl.cpp#L208 + +Closes #23444 + +CVE: CVE-2026-94266 +Upstream-Status: Backport [https://github.com/curl/curl/commit/589c35f0cb47266394367659648bf3efc03e3790] + +Backport Changes: +- Register test1990 without indentation in curl 8.19.0's grouped + TESTCASES list; upstream indents its entry by two spaces. +- Add lib1990 to test1990. The 8.19.0 runner does not + select a library tool from the libtest keyword, as upstream does. + +Signed-off-by: Darsh Kelaiya +--- + docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md | 8 +++ + lib/getinfo.c | 10 +++- + tests/data/Makefile.am | 1 + + tests/data/test1990 | 31 ++++++++++ + tests/libtest/Makefile.inc | 1 + + tests/libtest/lib1990.c | 63 +++++++++++++++++++++ + 6 files changed, 111 insertions(+), 3 deletions(-) + create mode 100644 tests/data/test1990 + create mode 100644 tests/libtest/lib1990.c + +diff --git a/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md b/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md +index f7adcd810b..12347bfd5f 100644 +--- a/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md ++++ b/docs/libcurl/opts/CURLINFO_EFFECTIVE_URL.md +@@ -32,6 +32,14 @@ Pass in a pointer to a char pointer and get the last used effective URL. + In cases when you have asked libcurl to follow redirects, it may not be the same + value you set with CURLOPT_URL(3). + ++Any credentials (username and password) present in the URL are removed from ++the returned string. ++ ++If no URL has been used yet, **urlp** points to an empty string. ++ ++If the URL set with CURLOPT_URL(3) cannot be parsed as a valid URL, **urlp** is ++set to NULL and an error is returned, typically *CURLE_URL_MALFORMAT*. ++ + The **urlp** pointer is NULL or points to private memory. You **must not** + free it. It memory gets freed automatically when you call curl_easy_cleanup(3) + on the corresponding curl handle. +diff --git a/lib/getinfo.c b/lib/getinfo.c +index 920f1f3a0c..ce4ac77f52 100644 +--- a/lib/getinfo.c ++++ b/lib/getinfo.c +@@ -29,6 +29,7 @@ + #include "vtls/vtls.h" + #include "connect.h" /* Curl_getconnectinfo() */ + #include "bufref.h" ++#include "url.h" /* Curl_uc_to_curlcode() */ + #include "curlx/strparse.h" + + /* +@@ -89,7 +90,8 @@ static CURLcode effective_url(struct Curl_easy *data, + const char **param_charp) + { + const char *s = Curl_bufref_ptr(&data->state.url); +- *param_charp = s ? s : ""; ++ /* never return the URL unfiltered */ ++ *param_charp = s ? NULL : ""; + if(s) { + char *url = NULL; + /* Make a copy of the URL without credentials */ +@@ -111,15 +113,17 @@ static CURLcode effective_url(struct Curl_easy *data, + curl_url_cleanup(u); + + if(uc || !url) +- return CURLE_OUT_OF_MEMORY; ++ return uc ? Curl_uc_to_curlcode(uc) : CURLE_OUT_OF_MEMORY; + if(strcmp(url, s)) { + /* they are different */ + curlx_free(data->info.effective_url); + data->info.effective_url = url; + *param_charp = url; + } +- else ++ else { + curl_free(url); ++ *param_charp = s; ++ } + } + return CURLE_OK; + } +diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am +index d6aaa71f5d..b348f37bf8 100644 +--- a/tests/data/Makefile.am ++++ b/tests/data/Makefile.am +@@ -243,6 +243,7 @@ test1941 test1942 test1943 test1944 test1945 test1946 test1947 test1948 \ + test1955 test1956 test1957 test1958 test1959 test1960 test1964 \ + test1970 test1971 test1972 test1973 test1974 test1975 test1976 test1977 \ + test1978 test1979 test1980 test1981 \ ++test1990 \ + \ + test2000 test2001 test2002 test2003 test2004 test2005 test2006 \ + test2009 test2010 test2011 \ +diff --git a/tests/data/test1990 b/tests/data/test1990 +new file mode 100644 +index 0000000000..61ef3ca95d +--- /dev/null ++++ b/tests/data/test1990 +@@ -0,0 +1,31 @@ ++ ++ ++ ++ ++CURLINFO_EFFECTIVE_URL ++libtest ++ ++ ++ ++# Client-side ++ ++ ++lib1990 ++ ++ ++CURLINFO_EFFECTIVE_URL with no URL and an invalid URL ++ ++ ++- ++ ++ ++ ++# Verify data after the test has been "shot" ++ ++ ++getinfo: 0, url: '' ++perform: 3 ++getinfo: 3, url: (NULL) ++ ++ ++ +diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc +index e494189f69..fc8534234d 100644 +--- a/tests/libtest/Makefile.inc ++++ b/tests/libtest/Makefile.inc +@@ -111,6 +111,7 @@ TESTS_C = \ + lib1955.c lib1956.c lib1957.c lib1958.c lib1959.c lib1960.c \ + lib1964.c lib1970.c \ + lib1971.c lib1972.c lib1973.c lib1974.c lib1975.c lib1977.c lib1978.c \ ++ lib1990.c \ + lib2023.c lib2032.c lib2082.c \ + lib2301.c lib2302.c lib2304.c lib2306.c lib2308.c lib2309.c \ + lib2402.c lib2404.c lib2405.c \ +diff --git a/tests/libtest/lib1990.c b/tests/libtest/lib1990.c +new file mode 100644 +index 0000000000..96e18d4033 +--- /dev/null ++++ b/tests/libtest/lib1990.c +@@ -0,0 +1,63 @@ ++/*************************************************************************** ++ * _ _ ____ _ ++ * Project ___| | | | _ \| | ++ * / __| | | | |_) | | ++ * | (__| |_| | _ <| |___ ++ * \___|\___/|_| \_\_____| ++ * ++ * Copyright (C) Daniel Stenberg, , et al. ++ * ++ * This software is licensed as described in the file COPYING, which ++ * you should have received as part of this distribution. The terms ++ * are also available at https://curl.se/docs/copyright.html. ++ * ++ * You may opt to use, copy, modify, merge, publish, distribute and/or sell ++ * copies of the Software, and permit persons to whom the Software is ++ * furnished to do so, under the terms of the COPYING file. ++ * ++ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY ++ * KIND, either express or implied. ++ * ++ * SPDX-License-Identifier: curl ++ * ++ ***************************************************************************/ ++#include "first.h" ++ ++static void show_effective_url(CURL *curl) ++{ ++ char untouched[] = "untouched"; ++ char *url = untouched; ++ CURLcode result = curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url); ++ if(url) ++ curl_mprintf("getinfo: %d, url: '%s'\n", (int)result, url); ++ else ++ curl_mprintf("getinfo: %d, url: (NULL)\n", (int)result); ++} ++ ++static CURLcode test_lib1990(const char *URL) ++{ ++ CURL *curl; ++ CURLcode result; ++ ++ (void)URL; ++ curl_global_init(CURL_GLOBAL_ALL); ++ curl = curl_easy_init(); ++ if(!curl) { ++ curl_global_cleanup(); ++ return TEST_ERR_EASY_INIT; ++ } ++ ++ /* no URL used yet */ ++ show_effective_url(curl); ++ ++ /* an invalid URL with credentials must not be returned */ ++ curl_easy_setopt(curl, CURLOPT_URL, "http://user:secret@[invalid/"); ++ result = curl_easy_perform(curl); ++ curl_mprintf("perform: %d\n", (int)result); ++ show_effective_url(curl); ++ ++ curl_easy_cleanup(curl); ++ curl_global_cleanup(); ++ ++ return CURLE_OK; ++} +-- +2.35.6 diff --git a/meta/recipes-support/curl/curl_8.19.0.bb b/meta/recipes-support/curl/curl_8.19.0.bb index 71b7c06e71..a4f7b466c3 100644 --- a/meta/recipes-support/curl/curl_8.19.0.bb +++ b/meta/recipes-support/curl/curl_8.19.0.bb @@ -68,6 +68,8 @@ SRC_URI = "https://curl.se/download/${BP}.tar.xz \ file://CVE-2026-92388_p1.patch \ file://CVE-2026-92388_p2.patch \ file://CVE-2026-92392.patch \ + file://CVE-2026-94266_p1.patch \ + file://CVE-2026-94266_p2.patch \ " SRC_URI:append:class-nativesdk = " \ From patchwork Fri Nov 6 07:19:31 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darsh Kelaiya -X (dkelaiya - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 103222 Received: from rcdn-iport-7.cisco.com (rcdn-iport-7.cisco.com [173.37.86.78]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.1219.1793949576440671950 for ; Thu, 05 Nov 2026 23:19:37 -0800 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=MqHp1PtJ; spf=pass (domain: cisco.com, ip: 173.37.86.78, mailfrom: dkelaiya@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=18339; q=dns/txt; s=iport01; t=1793949577; x=1795159177; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=uLAxnj4Uu1kg9Jv2FS4k3WvjZcsdNzBcCPZMdWnD6pk=; b=MqHp1PtJFufIKx7O8cYnj1r/i0Jj8rCkPcAloP2aN6YXA7VyCPVMCBdk ghvIQAmwiZg09kzvjXC7C63vehp3QFITe//KBXAey/YCzSgkFE5blZPEs A14LVNQTIRv3xWYa4dkcGBJ5j7wO4vFBUpZV8FlWFBu8gdX5czdLinL9q uGFHOJ6xNSGOd28DYtvr22ACjGoWvlYrjZL4TeCmSNXD83/bZhKmaiDZG polPBYKnBM2JTWh1oWuQAKlNAwlZvDAja+vN4y2suX4UKr3AtBRKB0+pO I+KvczBeVuPFJznR3SfKU4wBDeKmbYhpIvvisuDEQJVYEnzUu23y3Ktn8 Q==; X-CSE-ConnectionGUID: sRiS9lFMRuC6EYIUPoP28g== X-CSE-MsgGUID: 1k8vO5CyTHC3ioA2fv6f3Q== X-IPAS-Result: A0AnAADtfu1q/4z/Ja1aHQEBAQEJARIBBQUBgXwIAQsBglZ1YENJjHKJWQOBE5A5jFUUgWoPAQEBD0QNBAEBhQUCjh0CJjQJDgECBAMCAwEBAQEBAQEBAQEBAQoBAQUBAQECAQcFgQ4Thk8NkBIBAgEDJwsBGAEtEBwDAQIWGSsjCBAJgwIBgnQDEQa7OBs3gXkzgQGDKQE/AgJAAVDbMwELFAGBOAGFP4gjXRgBhH0nGxuBcoEVgnN2gQWBXAIBgRiBBoYHBIIigQyBWh6MegKBUYZ5SIEeA1ksAVUTDQoLBwWBaAM1EioVbjIdgSM+F4EHGwYFgR2BHoESgQddgSsoXQEhgQiBdgKCUYIAAgFJQQ4HRVMJJUMSRyQiCBIJARMaLAqBGjU8CSY/FQxkCxoFYQgCDQx0ORAwHiQvBRwmPhsKLxgNSBEsNxUZBD5uB5I9giBgCwUBAQEVSxoJCgETFgEBL1YbRRgGBTURkwMQAggTkAOCIZ9TgT4KKIN4jCSVOhozqnELmH2OCpVbDgsNAU+EaYFoPIFZcBWDIgkWNBkPi0mCZQsLg2CGQMYFJjICCTIBAQcCBw4DC4FokAAsgVIBAQ IronPort-Data: A9a23:tYf/Y6ACz+IRHRVW/3jiw5YqxClBgxIJ4kV8jS/XYbTApG4m02QOz TceWWzQMv3cazOkeIggb4ji/UsGvZ6Bm4dhOVdlrnsFo1CmBibm6XV1Cm+qYkt+++WaFBoPA /02M4eGcYZsCCCM/n9BC5C5xVFkz6aEW7HgP+DNPyF1VGdMRTwo4f5Zs7ZRbrVA357jXGthh fuo+5eBYQb9hmYtWo4pw/vrRC1H7ayaVAww5jTSVdgT1HfCmn8cCo4oJK3ZBxPQXolOE+emc P3Ixbe/83mx109F5gSNy+uTnuUiG9Y+DCDW4pZkc/HKbitq+kTe5p0G2M80Mi+7vdkmc+dZk 72hvbToIesg0zaldO41C3G0GAkmVUFKFSOuzXWX6aSuI0P6n3TE2M9vNxAyE6gi580pLFBvy MQfEGpdYUXW7w626OrTpuhEnM8vKozveYgYoHwllWqfBvc9SpeFSKLPjTNa9G5v3YYVQrCEO pdfMGY3BPjDS0Un1lM/BJEzmO6pl3DXeDxDo1XTrq0yi4TW5FEtjOOyb4qJJbRmQ+0MnRaGg T/t7ljZKUobM/XFxyTb/CmV07qncSTTHdh6+KeD3vlyjVuew2YeBBEbWR6wpuO0okq/QM5Eb UsM9ywjqKI/+ECmQp/6RRLQnZKflgQXV9wVF6gx7xuAj/KPpQ2YHWMDCDVGbbTKqfMLeNDj7 XfR9/uBONClmOf9pa61nltMkQ6PBA== IronPort-HdrOrdr: A9a23:yVbPYq7BhQYdTp48pQPXwOrXdLJyesId70hD6qm+c3Nom6uj5q eTdZsgtCMc5Ax9ZJhko6HjBEDiewK5yXcK2+ks1N6ZNWGM0ldAbrsSiLcKqAePJ8SRzIJgPN 9bAstDIey1K0RmhsDn5wT9OdMhzN6btJ2Mv47lvhFQpcUAUdAZ0++/YTzra3FLeA== X-Talos-CUID: 9a23:jYEh+mjGIP2bDENI6KxlIBKBSDJuaUfc9ybUDWqCFE03ZYy0dGeXwPk0nJ87 X-Talos-MUID: 9a23:3L/Nng1j3gFJrhhhIWxpLy0ZhjUjuqf+FmdQuoQ6m+LfNCtZYTmD0jrse9py X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.27,197,1787011200"; d="scan'208";a="544377847" Received: from rcdn-l-core-03.cisco.com ([173.37.255.140]) by rcdn-iport-7.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 06 Nov 2026 07:19:35 +0000 Received: from sjc-ads-5675.cisco.com (sjc-ads-5675.cisco.com [10.28.88.189]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-03.cisco.com (Postfix) with ESMTPS id AA0AD18000597; Fri, 6 Nov 2026 07:19:35 +0000 (GMT) Received: by sjc-ads-5675.cisco.com (Postfix, from userid 1887444) id 0E57ACBEF98; Thu, 5 Nov 2026 23:19:35 -0800 (PST) From: "Darsh Kelaiya -X (dkelaiya - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-core@lists.openembedded.org Cc: Darsh Kelaiya Subject: [OE-core][wrynose][PATCH 8/9] curl: fix CVE-2026-107929 Date: Thu, 5 Nov 2026 23:19:31 -0800 Message-Id: <20261106071932.490299-9-dkelaiya@cisco.com> X-Mailer: git-send-email 2.35.6 In-Reply-To: <20261106071932.490299-1-dkelaiya@cisco.com> References: <20261106071932.490299-1-dkelaiya@cisco.com> MIME-Version: 1.0 X-Outbound-Client-TLS: ANONYMOUS;sjc-ads-5675.cisco.com [10.28.88.189];TLSv1.3;TLS_AES_256_GCM_SHA384;256 X-Outbound-SMTP-Client: 10.28.88.189, sjc-ads-5675.cisco.com X-Outbound-Node: rcdn-l-core-03.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Fri, 06 Nov 2026 07:19:49 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/249606 From: Darsh Kelaiya This patch applies the upstream fix as referenced in [2], using the commit shown in [1]. Keep the complete CURLOPT_INTERFACE option in the connection and compare it when choosing a connection to reuse. This includes if!, host! and ifhost! prefixes, so a transfer cannot silently inherit an older source binding. Parse that owned option again when binding the socket and release temporary strings on success and failure. Adapt the old string helpers, setopt parameters and nested device-bind check while preserving the complete upstream matching and cleanup. [1] https://github.com/curl/curl/commit/d37d79df1e01066417aff0a9e6bc675edad3edba [2] https://curl.se/docs/CVE-2026-107929.html Signed-off-by: Darsh Kelaiya --- .../curl/curl/CVE-2026-107929.patch | 470 ++++++++++++++++++ meta/recipes-support/curl/curl_8.19.0.bb | 1 + 2 files changed, 471 insertions(+) create mode 100644 meta/recipes-support/curl/curl/CVE-2026-107929.patch diff --git a/meta/recipes-support/curl/curl/CVE-2026-107929.patch b/meta/recipes-support/curl/curl/CVE-2026-107929.patch new file mode 100644 index 0000000000..873b03fd5b --- /dev/null +++ b/meta/recipes-support/curl/curl/CVE-2026-107929.patch @@ -0,0 +1,470 @@ +From d37d79df1e01066417aff0a9e6bc675edad3edba Mon Sep 17 00:00:00 2001 +From: Stefan Eissing +Date: Fri, 9 Oct 2026 09:51:12 +0200 +Subject: [PATCH] url: CURLOPT_INTERFACE fix connection reuse match + +Remember the full option string at the connection for use in reuse +matching and cf-socket binding. + +Parse the string when set for syntax check, but remember the unparsed +version and use that in connection matching. + +Parse that string again when the socket is set up. + +Closes #23326 + +CVE: CVE-2026-107929 +Upstream-Status: Backport [https://github.com/curl/curl/commit/d37d79df1e01066417aff0a9e6bc675edad3edba] + +Backport Changes: +- Use curl 8.19.0's data->set.str[], Curl_setstropt() and + Curl_safefree() instead of the newer string and free helpers. +- Change the older setstropt_interface() parameters and its caller + to pass the easy handle; remove the obsolete output assertions. +- Keep bindlocal()'s older nested SO_BINDTODEVICE test. Route its + success path through cleanup and keep two blank separators around + the new option parsing and binding checks. +- Replace the older braced local-bind comparison and its split + comment ending with upstream's new matching expression. + +Signed-off-by: Darsh Kelaiya +--- + lib/cf-socket.c | 135 +++++++++++++++++++++++++++++++----------------- + lib/setopt.c | 34 +++--------- + lib/url.c | 48 +++++++++-------- + lib/urldata.h | 6 +-- + 4 files changed, 126 insertions(+), 97 deletions(-) + +diff --git a/lib/cf-socket.c b/lib/cf-socket.c +index 2ebbe4d..f3978e2 100644 +--- a/lib/cf-socket.c ++++ b/lib/cf-socket.c +@@ -464,11 +464,13 @@ int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn, + * len [in] - length of the input string. + * dev [in/out] - address where a pointer to newly allocated memory + * holding the interface-or-host will be stored upon +- * completion. ++ * completion or NULL if the caller is not interested. + * iface [in/out] - address where a pointer to newly allocated memory +- * holding the interface will be stored upon completion. ++ * holding the interface will be stored upon completion ++ * or NULL if the caller is not interested. + * host [in/out] - address where a pointer to newly allocated memory +- * holding the host will be stored upon completion. ++ * holding the host will be stored upon completion ++ * or NULL if the caller is not interested. + * + * Returns CURLE_OK on success. + */ +@@ -480,27 +482,36 @@ CURLcode Curl_parse_interface(const char *input, + static const char if_host_prefix[] = "ifhost!"; + size_t len; + +- DEBUGASSERT(dev); +- DEBUGASSERT(iface); +- DEBUGASSERT(host); +- + len = strlen(input); + if(len > 512) + return CURLE_BAD_FUNCTION_ARGUMENT; + ++ if(dev) ++ *dev = NULL; ++ if(iface) ++ *iface = NULL; ++ if(host) ++ *host = NULL; ++ + if(!strncmp(if_prefix, input, strlen(if_prefix))) { + input += strlen(if_prefix); + if(!*input) + return CURLE_BAD_FUNCTION_ARGUMENT; +- *iface = curlx_memdup0(input, len - strlen(if_prefix)); +- return *iface ? CURLE_OK : CURLE_OUT_OF_MEMORY; ++ if(iface) { ++ *iface = curlx_memdup0(input, len - strlen(if_prefix)); ++ return *iface ? CURLE_OK : CURLE_OUT_OF_MEMORY; ++ } ++ return CURLE_OK; + } + else if(!strncmp(host_prefix, input, strlen(host_prefix))) { + input += strlen(host_prefix); + if(!*input) + return CURLE_BAD_FUNCTION_ARGUMENT; +- *host = curlx_memdup0(input, len - strlen(host_prefix)); +- return *host ? CURLE_OK : CURLE_OUT_OF_MEMORY; ++ if(host) { ++ *host = curlx_memdup0(input, len - strlen(host_prefix)); ++ return *host ? CURLE_OK : CURLE_OUT_OF_MEMORY; ++ } ++ return CURLE_OK; + } + else if(!strncmp(if_host_prefix, input, strlen(if_host_prefix))) { + const char *host_part; +@@ -509,23 +520,30 @@ CURLcode Curl_parse_interface(const char *input, + host_part = memchr(input, '!', len); + if(!host_part || !*(host_part + 1)) + return CURLE_BAD_FUNCTION_ARGUMENT; +- *iface = curlx_memdup0(input, host_part - input); +- if(!*iface) +- return CURLE_OUT_OF_MEMORY; ++ if(iface) { ++ *iface = curlx_memdup0(input, host_part - input); ++ if(!*iface) ++ return CURLE_OUT_OF_MEMORY; ++ } + ++host_part; +- *host = curlx_memdup0(host_part, len - (host_part - input)); +- if(!*host) { +- curlx_free(*iface); +- *iface = NULL; +- return CURLE_OUT_OF_MEMORY; ++ if(host) { ++ *host = curlx_memdup0(host_part, len - (host_part - input)); ++ if(!*host) { ++ if(iface) ++ Curl_safefree(*iface); ++ return CURLE_OUT_OF_MEMORY; ++ } + } + return CURLE_OK; + } + + if(!*input) + return CURLE_BAD_FUNCTION_ARGUMENT; +- *dev = curlx_memdup0(input, len); +- return *dev ? CURLE_OK : CURLE_OUT_OF_MEMORY; ++ if(dev) { ++ *dev = curlx_memdup0(input, len); ++ return *dev ? CURLE_OK : CURLE_OUT_OF_MEMORY; ++ } ++ return CURLE_OK; + } + + #ifndef CURL_DISABLE_BINDLOCAL +@@ -545,27 +563,38 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn, + "random" */ + /* how many port numbers to try to bind to, increasing one at a time */ + int portnum = data->set.localportrange; +- const char *dev = data->set.str[STRING_DEVICE]; +- const char *iface_input = data->set.str[STRING_INTERFACE]; +- const char *host_input = data->set.str[STRING_BINDHOST]; +- const char *iface = iface_input ? iface_input : dev; +- const char *host = host_input ? host_input : dev; ++ char *dev_in = NULL, *iface_in = NULL, *host_in = NULL; ++ const char *iface = NULL, *host = NULL; + int error; + #ifdef IP_BIND_ADDRESS_NO_PORT + int on = 1; + #endif ++ CURLcode result = CURLE_OK; ++ + #ifndef USE_IPV6 + (void)scope; + #endif + +- /************************************************************* +- * Select device to bind socket to +- *************************************************************/ ++ if(conn->interface_opts) { ++ /************************************************************* ++ * Select device to bind socket to ++ *************************************************************/ ++ result = Curl_parse_interface(conn->interface_opts, ++ &dev_in, &iface_in, &host_in); ++ if(result) ++ goto out; ++ /* This is how we use the values */ ++ iface = iface_in ? iface_in : dev_in; ++ host = host_in ? host_in : dev_in; ++ } ++ + if(!iface && !host && !port) +- /* no local kind of binding was requested */ +- return CURLE_OK; +- else if(iface && (strlen(iface) >= 255)) +- return CURLE_BAD_FUNCTION_ARGUMENT; ++ goto out; ++ ++ if(iface && (strlen(iface) >= 255)) { ++ result = CURLE_BAD_FUNCTION_ARGUMENT; ++ goto out; ++ } + + memset(&sa, 0, sizeof(struct Curl_sockaddr_storage)); + +@@ -593,14 +622,15 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn, + * succeeds it means the parameter was a valid interface and not an IP + * address. Return immediately. + */ +- if(!host_input) { ++ if(!host_in) { + infof(data, "socket successfully bound to interface '%s'", iface); +- return CURLE_OK; ++ result = CURLE_OK; ++ goto out; + } + } + } + #endif +- if(!host_input) { ++ if(!host_in) { + /* Discover IP from input device, then bind to it */ + if2ip_result = Curl_if2ip(af, + #ifdef USE_IPV6 +@@ -610,18 +640,20 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn, + } + switch(if2ip_result) { + case IF2IP_NOT_FOUND: +- if(iface_input && !host_input) { ++ if(iface_in && !host_in) { + /* Do not fall back to treating it as a hostname */ + char buffer[STRERROR_LEN]; + data->state.os_errno = error = SOCKERRNO; + failf(data, "Could not bind to interface '%s' with errno %d: %s", + iface, error, curlx_strerror(error, buffer, sizeof(buffer))); +- return CURLE_INTERFACE_FAILED; ++ result = CURLE_INTERFACE_FAILED; ++ goto out; + } + break; + case IF2IP_AF_NOT_SUPPORTED: + /* Signal the caller to try another address family if available */ +- return CURLE_UNSUPPORTED_PROTOCOL; ++ result = CURLE_UNSUPPORTED_PROTOCOL; ++ goto out; + case IF2IP_FOUND: + /* + * We now have the numerical IP address in the 'myhost' buffer +@@ -632,7 +664,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn, + done = 1; + break; + } +- if(!iface_input || host_input) { ++ if(!iface_in || host_in) { + /* + * This was not an interface, resolve the name as a hostname + * or IP number +@@ -659,7 +691,8 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn, + if(af != h_af) { + /* bad IP version combo, signal the caller to try another address + family if available */ +- return CURLE_UNSUPPORTED_PROTOCOL; ++ result = CURLE_UNSUPPORTED_PROTOCOL; ++ goto out; + } + done = 1; + } +@@ -692,8 +725,10 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn, + present, is known to be numeric */ + curl_off_t scope_id; + if(curlx_str_number((const char **)CURL_UNCONST(&scope_ptr), +- &scope_id, UINT_MAX)) +- return CURLE_UNSUPPORTED_PROTOCOL; ++ &scope_id, UINT_MAX)) { ++ result = CURLE_UNSUPPORTED_PROTOCOL; ++ goto out; ++ } + si6->sin6_scope_id = (unsigned int)scope_id; + } + #endif +@@ -720,7 +755,8 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn, + data->state.os_errno = error = SOCKERRNO; + failf(data, "Could not bind to '%s' with errno %d: %s", host, + error, curlx_strerror(error, buffer, sizeof(buffer))); +- return CURLE_INTERFACE_FAILED; ++ result = CURLE_INTERFACE_FAILED; ++ goto out; + } + } + else { +@@ -747,7 +783,8 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn, + /* we succeeded to bind */ + infof(data, "Local port: %hu", port); + conn->bits.bound = TRUE; +- return CURLE_OK; ++ result = CURLE_OK; ++ goto out; + } + + if(--portnum > 0) { +@@ -773,7 +810,13 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn, + error, curlx_strerror(error, buffer, sizeof(buffer))); + } + +- return CURLE_INTERFACE_FAILED; ++ result = CURLE_INTERFACE_FAILED; ++ ++out: ++ curlx_free(dev_in); ++ curlx_free(iface_in); ++ curlx_free(host_in); ++ return result; + } + #endif + +diff --git a/lib/setopt.c b/lib/setopt.c +index ae77ae8..4c634a8 100644 +--- a/lib/setopt.c ++++ b/lib/setopt.c +@@ -160,33 +160,18 @@ static CURLcode setstropt_userpwd(const char *option, char **userp, + return CURLE_OK; + } + +-static CURLcode setstropt_interface(char *option, char **devp, +- char **ifacep, char **hostp) ++static CURLcode setstropt_interface(struct Curl_easy *data, char *option) + { +- char *dev = NULL; +- char *iface = NULL; +- char *host = NULL; +- CURLcode result; +- +- DEBUGASSERT(devp); +- DEBUGASSERT(ifacep); +- DEBUGASSERT(hostp); +- ++ if(option && !option[0]) ++ option = NULL; + if(option) { +- /* Parse the interface details if set, otherwise clear them all */ +- result = Curl_parse_interface(option, &dev, &iface, &host); ++ /* Parse for checking syntax */ ++ CURLcode result = Curl_parse_interface(option, NULL, NULL, NULL); + if(result) + return result; ++ return Curl_setstropt(&data->set.str[STRING_INTERFACE_OPT], option); + } +- curlx_free(*devp); +- *devp = dev; +- +- curlx_free(*ifacep); +- *ifacep = iface; +- +- curlx_free(*hostp); +- *hostp = host; +- ++ Curl_safefree(data->set.str[STRING_INTERFACE_OPT]); + return CURLE_OK; + } + +@@ -2267,10 +2252,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, + * Set what interface or address/hostname to bind the socket to when + * performing an operation and thus what from-IP your connection will use. + */ +- return setstropt_interface(ptr, +- &s->str[STRING_DEVICE], +- &s->str[STRING_INTERFACE], +- &s->str[STRING_BINDHOST]); ++ return setstropt_interface(data, ptr); + case CURLOPT_ISSUERCERT: + /* + * Set Issuer certificate file +diff --git a/lib/url.c b/lib/url.c +index 4a01baf..1b6e9e3 100644 +--- a/lib/url.c ++++ b/lib/url.c +@@ -550,7 +550,7 @@ void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn) + Curl_safefree(conn->host.rawalloc); /* hostname buffer */ + Curl_safefree(conn->conn_to_host.rawalloc); /* hostname buffer */ + Curl_safefree(conn->secondaryhostname); +- Curl_safefree(conn->localdev); ++ Curl_safefree(conn->interface_opts); + Curl_ssl_conn_config_cleanup(conn); + + #ifdef USE_UNIX_SOCKETS +@@ -773,24 +773,29 @@ static bool url_match_connect_config(struct connectdata *conn, + m->data->set.ipver != conn->ip_version) + return FALSE; + +- if(m->needle->localdev || m->needle->localport) { ++ /* When needle has specific local bind settings, those have to match. ++ * If it does not, any other connection might do when it comes to ports. */ ++ if(m->needle->localport && ++ ((conn->localport != m->needle->localport) || ++ (conn->localportrange != m->needle->localportrange))) ++ return FALSE; ++ /* For interface related bind options, we require a full match ++ * as connection might go totally different ways (VPNs, for example). */ ++ if((m->needle->interface_opts != conn->interface_opts) && ++ (!m->needle->interface_opts || !conn->interface_opts || ++ strcmp(conn->interface_opts, m->needle->interface_opts))) ++ return FALSE; ++ ++ if((m->needle->interface_opts || m->needle->localport) && + /* If we are bound to a specific local end (IP+port), we must not reuse a + random other one, although if we did not ask for a particular one we +- can reuse one that was bound. +- +- This comparison is a bit rough and too strict. Since the input +- parameters can be specified in numerous ways and still end up the same +- it would take a lot of processing to make it really accurate. Instead, +- this matching will assume that reuses of bound connections will most +- likely also reuse the exact same binding parameters and missing out a +- few edge cases should not hurt anyone much. +- */ +- if((conn->localport != m->needle->localport) || +- (conn->localportrange != m->needle->localportrange) || +- (m->needle->localdev && +- (!conn->localdev || strcmp(conn->localdev, m->needle->localdev)))) +- return FALSE; +- } ++ can reuse one that was bound. */ ++ ((conn->localport != m->needle->localport) || ++ (conn->localportrange != m->needle->localportrange) || ++ (m->needle->interface_opts && ++ (!conn->interface_opts || ++ strcmp(conn->interface_opts, m->needle->interface_opts))))) ++ return FALSE; + + if(m->needle->bits.conn_to_host != conn->bits.conn_to_host) + /* do not mix connections that use the "connect to host" feature and +@@ -1443,9 +1448,10 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) + conn->transport_wanted = TRNSPRT_TCP; /* most of them are TCP streams */ + + /* Store the local bind parameters that will be used for this connection */ +- if(data->set.str[STRING_DEVICE]) { +- conn->localdev = curlx_strdup(data->set.str[STRING_DEVICE]); +- if(!conn->localdev) ++ if(data->set.str[STRING_INTERFACE_OPT]) { ++ conn->interface_opts = ++ curlx_strdup(data->set.str[STRING_INTERFACE_OPT]); ++ if(!conn->interface_opts) + goto error; + } + #ifndef CURL_DISABLE_BINDLOCAL +@@ -1465,7 +1471,7 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) + return conn; + error: + +- curlx_free(conn->localdev); ++ curlx_free(conn->interface_opts); + curlx_free(conn); + return NULL; + } +diff --git a/lib/urldata.h b/lib/urldata.h +index 0bc9ade..327c9f4 100644 +--- a/lib/urldata.h ++++ b/lib/urldata.h +@@ -694,7 +694,7 @@ struct connectdata { + made and will serve the purpose of being used for comparison reasons so + that subsequent bound-requested connections are not accidentally reusing + wrong connections. */ +- char *localdev; ++ char *interface_opts; + uint16_t localportrange; + #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + int socks5_gssapi_enctype; +@@ -1167,9 +1167,7 @@ enum dupstring { + #endif + STRING_CUSTOMREQUEST, /* HTTP/FTP/RTSP request/method to use */ + STRING_DEFAULT_PROTOCOL, /* Protocol to use when the URL does not specify */ +- STRING_DEVICE, /* local network interface/address to use */ +- STRING_INTERFACE, /* local network interface to use */ +- STRING_BINDHOST, /* local address to use */ ++ STRING_INTERFACE_OPT, /* CURLOPT_INTERFACE config */ + STRING_ENCODING, /* Accept-Encoding string */ + #ifndef CURL_DISABLE_FTP + STRING_FTP_ACCOUNT, /* ftp account data */ +-- +2.35.6 diff --git a/meta/recipes-support/curl/curl_8.19.0.bb b/meta/recipes-support/curl/curl_8.19.0.bb index a4f7b466c3..026b5a3638 100644 --- a/meta/recipes-support/curl/curl_8.19.0.bb +++ b/meta/recipes-support/curl/curl_8.19.0.bb @@ -70,6 +70,7 @@ SRC_URI = "https://curl.se/download/${BP}.tar.xz \ file://CVE-2026-92392.patch \ file://CVE-2026-94266_p1.patch \ file://CVE-2026-94266_p2.patch \ + file://CVE-2026-107929.patch \ " SRC_URI:append:class-nativesdk = " \ From patchwork Fri Nov 6 07:19:32 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darsh Kelaiya -X (dkelaiya - E INFOCHIPS PRIVATE LIMITED at Cisco)" X-Patchwork-Id: 103221 Received: from rcdn-iport-6.cisco.com (rcdn-iport-6.cisco.com [173.37.86.77]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.1217.1793949576312656142 for ; Thu, 05 Nov 2026 23:19:36 -0800 Authentication-Results: mx.groups.io; dkim=fail reason="dkim: message contains an insecure body length tag" header.i=@cisco.com header.s=iport01 header.b=Q8tgAH5F; spf=pass (domain: cisco.com, ip: 173.37.86.77, mailfrom: dkelaiya@cisco.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=cisco.com; i=@cisco.com; l=28438; q=dns/txt; s=iport01; t=1793949576; x=1795159176; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=ZqUkH27PYeq3b++p1HYivokxCLUwrKIPbo3exMoZ7Lc=; b=Q8tgAH5FqlY5iaG5EKg0Eju6P7bCn3kffS3uO3i0FZi1DShX8kglZDHC /aN619KGD3BFd14Zqviwmez6s/YYRCmfF2avyP0xHDgM0mvrR3HrESYuN xgvLeCB0j1ofq4+/ybXxC7L5P1R17B4FCPecEYhdHo/Tys98rhtgB/v2z yw+cAkxAXWZBeRMZAORxRmaI8mZjnAJUFoVWl62nzUE47vPiyTHU6hTz3 DQyadC3m5ItutE/xNJ16sz7gWCinNYmivHlbKjEqWihdYo1ylZmuoAEPS 6JZaDDt9xsnjcwTWhfukGlRA0Vn8BZy+uUjHNE2enAEK3zfrxzrmow+RU A==; X-CSE-ConnectionGUID: CzlVFVl5T7eP9DZtsUxf5g== X-CSE-MsgGUID: NAp20Tq1R82tLhWgifzBJw== X-IPAS-Result: A0BJAgDtfu1q/5L/Ja1aglmCV3VgQ0mWSwOBE5A5jFWBfg8BAQEPRA0EAQGFBQKOHQImNAkOAQIEAwIDAQEBAQEBAQEBAQEBCgEBBQEBAQIBBwWBDhOGTw2QEgECAQMaDQsBGAEtEBwDAQIvKyMIGYMCAYJ0AxEGuzgbN4F5M4EBgykBPwICQAFQ2zMBCxQBgTiFQIgjXRgBRIQ5JxsbgXKBFYJzdoEFgVwCAYFHhl4Egg0VgQyBWh5ughmIVYEeAoFRhnlIgR4DWSwBVRMNCgsHBYFoAzUSKhVuMh2BIz4XgQcbBgWBHYEegRKBB12BKyhdASGBCIF2AoJRggACAUlBDgdFUwklQxJHJCIIEgkBExosCoEaNTwJJj8VDGQLGgVhCAINDHQ5EDAeJC8FHCY+GwovGA1IESw3FRkEPm4Hkj2CZRsLBQIBFUsCGBMBKQKBTRsFEAY4AhGSbx0JAQeQFoIhgTWfXAoog3iMJJU6GjOEBIFXiz2ZWQuYfY4KlWkbTYRpgWg8gVlwFYMiCRY0GQ+OLgsLg2CGQMYFJjICCTIBAQcCBw4DC4FohGGNHQEB IronPort-Data: A9a23:We4HDK9slL8jQmZoY7jCDrUD0X+TJUtcMsCJ2f8bNWPcYEJGY0x3n WpMXmqHMv2IYGajftpwOd7gpx4Cv5KGnd8yGwFk+31EQiMRo6IpJzg2wmQcns+2BpeeJK6yx 5xGMrEsFOhtEDmB4E/rbei5xZVF/fngbqLmD+LZMTxGSwZhSSMw4TpugOdRbrRA2bBVOCvT/ 4mtyyHjEAX9gWAtazpJs/vrRC5H5ZwehhtJ5jTSWtgT1LPuvyF9JI4SI6i3M0z5TuF8dsamR /zOxa2O5WjQ+REgELuNyt4XpWVTH9Y+lSDX4pZnc/DKbipq/0Te4Y5nXBYoUnq7vh3S9zxHJ HqhgrTrIeshFvWkdO3wyHC0GQkmVUFN0OevzXRSLaV/wmWeG0YAzcmCA2kdL4km1NhzXF0R+ MRJBAIRdS2Tib+5lefTpulE3qzPLeHxN48Z/3UlxjbDALN+ENbIQr7B4plT2zJYasJmRKmFI ZFGL2AyMVKZP0Mn1lQ/UPrSmM+khXT7ejxJoXqepLE85C7YywkZPL3FbYaJK4LXHJ0J9qqej kTv5z6hPghDDozF1R6FzX2tiP3lvzyuDer+E5X9rJaGmma7wXQeDhATX1a3rfS1z0W5Qd93L 00P5jFoqrA/8kGuRNTxUxC05nmesXYht8F4CeY27kSJj6HT+QvcXjlCRT9aY9tgv8gzLdA36 mK0cxrSLWQHmNWopbi1r994cRva1fApEFI/ IronPort-HdrOrdr: A9a23:gUAWW6vIWcnvpBqsViedHGlc7skDVNV00zEX/kB9WHVpmwKj+P xG+85rsiMc5wxxZJhNo7290ey7MBHhHP1OkO0s1MmZPDUO0VHAROoJ0WKh+UyEJ8SUzIBgPM lbH5SWcOeAbmRSvILd/BSyFcomzZ2s9aClgvqb8lJWJDsaDZ2JK2xCe36m+oocfng+OaYE X-Talos-CUID: 9a23:MRXeJW+FP4BRmPF2HI+Vv2UGHv4LTHmA8CjdGx6UO3pyda2bFFDFrQ== X-Talos-MUID: 9a23:QK2GIAYEiRXaJ+BTkRb03mleLZ5Ss/6yLEAynpQIqeOmKnkl X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.27,197,1787011200"; d="scan'208";a="544965104" Received: from rcdn-l-core-09.cisco.com ([173.37.255.146]) by rcdn-iport-6.cisco.com with ESMTP/TLS/TLS_AES_256_GCM_SHA384; 06 Nov 2026 07:19:35 +0000 Received: from sjc-ads-5675.cisco.com (sjc-ads-5675.cisco.com [10.28.88.189]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by rcdn-l-core-09.cisco.com (Postfix) with ESMTPS id ACA61180004B9; Fri, 6 Nov 2026 07:19:35 +0000 (GMT) Received: by sjc-ads-5675.cisco.com (Postfix, from userid 1887444) id 12E9DCBEFAB; Thu, 5 Nov 2026 23:19:35 -0800 (PST) From: "Darsh Kelaiya -X (dkelaiya - E INFOCHIPS PRIVATE LIMITED at Cisco)" To: openembedded-core@lists.openembedded.org Cc: Darsh Kelaiya Subject: [OE-core][wrynose][PATCH 9/9] curl: fix CVE-2026-87866 Date: Thu, 5 Nov 2026 23:19:32 -0800 Message-Id: <20261106071932.490299-10-dkelaiya@cisco.com> X-Mailer: git-send-email 2.35.6 In-Reply-To: <20261106071932.490299-1-dkelaiya@cisco.com> References: <20261106071932.490299-1-dkelaiya@cisco.com> MIME-Version: 1.0 X-Outbound-Client-TLS: ANONYMOUS;sjc-ads-5675.cisco.com [10.28.88.189];TLSv1.3;TLS_AES_256_GCM_SHA384;256 X-Outbound-SMTP-Client: 10.28.88.189, sjc-ads-5675.cisco.com X-Outbound-Node: rcdn-l-core-09.cisco.com List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by lin-tor-korg-lkml-alma10-1 with HTTPS for ; Fri, 06 Nov 2026 07:19:48 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/249605 From: Darsh Kelaiya This patch applies the upstream fix as referenced in [2], using the commit shown in [1]. Require the two certificate validity time fields to consume their complete ASN.1 element before parsing the subject and public key. This prevents wolfSSL pinning from accepting a different embedded key than the key used for the TLS connection. Carry the shared parser's byte-pointer updates and all TLS caller changes so downstream layers enabling wolfSSL receive the source fix. Retain the valid and malformed certificate regression in unit1657. Adapt the older conversion helpers and unit-test entry point. Document the omitted type-only updates to three tests absent from curl 8.19.0. [1] https://github.com/curl/curl/commit/ed131747c1a3dc7f816d26724c44537ac8acba44 [2] https://curl.se/docs/CVE-2026-87866.html Signed-off-by: Darsh Kelaiya --- .../curl/curl/CVE-2026-87866.patch | 750 ++++++++++++++++++ meta/recipes-support/curl/curl_8.19.0.bb | 1 + 2 files changed, 751 insertions(+) create mode 100644 meta/recipes-support/curl/curl/CVE-2026-87866.patch diff --git a/meta/recipes-support/curl/curl/CVE-2026-87866.patch b/meta/recipes-support/curl/curl/CVE-2026-87866.patch new file mode 100644 index 0000000000..c42aee1f0f --- /dev/null +++ b/meta/recipes-support/curl/curl/CVE-2026-87866.patch @@ -0,0 +1,750 @@ +From ed131747c1a3dc7f816d26724c44537ac8acba44 Mon Sep 17 00:00:00 2001 +From: Stefan Eissing +Date: Wed, 2 Sep 2026 12:25:50 +0200 +Subject: [PATCH] x509: stricter parsing + +Check that the "validity" ASN.1 field has a length matching the +contained date elements and fail the parsing otherwise. + +This is a precaution against malformed cert data that should have been +caught by the TLS backend already. A bit added defense. + +Closes #22799 + +CVE: CVE-2026-87866 +Upstream-Status: Backport [https://github.com/curl/curl/commit/ed131747c1a3dc7f816d26724c44537ac8acba44] + +Backport Changes: +- Apply the byte-pointer updates to curl 8.19.0's older ASN.1 helpers. + Retain its Boolean, bit-string, integer and OID conversion logic, + including OID2str()'s symbolic argument in its updated signature. +- Keep getASN1Element_()'s older flat length branches while applying + the byte reads and bounds comparison. +- Expose getASN1Element() with UNITTEST and remove the older + Curl_x509_getASN1Element() wrapper. Add the private test prototype + to x509asn1.h: the old generator extracts only single-line prototypes. + Guard the production forward declaration to avoid a duplicate in + unit-test builds; retain WARN_UNUSED_RESULT on both declarations. +- Adapt test1657 from the old CURLcode wrapper to the parser's pointer + result with the same success/error expectations. Rename its + inactive-build message to match the parser name. +- Omit the type-only updates to unit1666, unit1667 and unit1676. These + tests are absent in 8.19.0; [1], [2] and [3] introduced them for OID + conversion, ASN.1-to-string conversion and DH public-key extraction. + +[1] https://github.com/curl/curl/commit/673e14cd33ef720b8c2b7e3485084e6e41a2c9dd +[2] https://github.com/curl/curl/commit/14782b36fea2a5f69029b2b898302b6ba5aef838 +[3] https://github.com/curl/curl/commit/61d59c9e39b451b30feb431b780a5cc325757921 + +Signed-off-by: Darsh Kelaiya +--- + lib/vtls/gtls.c | 4 +- + lib/vtls/mbedtls.c | 5 +- + lib/vtls/rustls.c | 13 ++--- + lib/vtls/schannel.c | 10 ++-- + lib/vtls/wolfssl.c | 4 +- + lib/vtls/x509asn1.c | 124 +++++++++++++++++++++--------------------- + lib/vtls/x509asn1.h | 22 ++++---- + tests/unit/unit1651.c | 6 +- + tests/unit/unit1657.c | 79 ++++++++++++++++++++++++--- + 9 files changed, 163 insertions(+), 104 deletions(-) + +diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c +index b87b27d864..02a8147520 100644 +--- a/lib/vtls/gtls.c ++++ b/lib/vtls/gtls.c +@@ -1626,8 +1626,8 @@ CURLcode Curl_gtls_verifyserver(struct Curl_cfilter *cf, + goto out; + + for(i = 0; i < chain.num_certs; i++) { +- const char *beg = (const char *)chain.certs[i].data; +- const char *end = beg + chain.certs[i].size; ++ const uint8_t *beg = chain.certs[i].data; ++ const uint8_t *end = beg + chain.certs[i].size; + + result = Curl_extract_certinfo(data, (int)i, beg, end); + if(result) +diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c +index d2199df884..cf7ac29594 100644 +--- a/lib/vtls/mbedtls.c ++++ b/lib/vtls/mbedtls.c +@@ -431,9 +431,8 @@ static void mbed_extract_certinfo(struct Curl_easy *data, + result = Curl_ssl_init_certinfo(data, cert_count); + + for(i = 0, cur = crt; result == CURLE_OK && cur; ++i, cur = cur->next) { +- const char *beg = (const char *)cur->raw.p; +- const char *end = beg + cur->raw.len; +- result = Curl_extract_certinfo(data, i, beg, end); ++ result = Curl_extract_certinfo(data, i, cur->raw.p, ++ cur->raw.p + cur->raw.len); + } + } + +diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c +index 89619432b8..017e7ddcd8 100644 +--- a/lib/vtls/rustls.c ++++ b/lib/vtls/rustls.c +@@ -1225,15 +1225,10 @@ static CURLcode cr_connect(struct Curl_cfilter *cf, struct Curl_easy *data, + (int)errorlen, errorbuf); + return map_error(rresult); + } +- { +- const char *beg; +- const char *end; +- beg = (const char *)der_data; +- end = (const char *)(der_data + der_len); +- result = Curl_extract_certinfo(data, (int)i, beg, end); +- if(result) +- return result; +- } ++ result = Curl_extract_certinfo(data, (int)i, ++ der_data, der_data + der_len); ++ if(result) ++ return result; + } + } + +diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c +index a4f57c7c0a..643b6d510c 100644 +--- a/lib/vtls/schannel.c ++++ b/lib/vtls/schannel.c +@@ -1108,7 +1108,7 @@ static CURLcode schannel_pkp_pin_peer_pubkey(struct Curl_cfilter *cf, + + do { + SECURITY_STATUS sspi_status; +- const char *x509_der; ++ uint8_t *x509_der; + DWORD x509_der_len; + struct Curl_X509certificate x509_parsed; + struct Curl_asn1Element *pubkey; +@@ -1129,7 +1129,7 @@ static CURLcode schannel_pkp_pin_peer_pubkey(struct Curl_cfilter *cf, + (pCertContextServer->cbCertEncoded > 0))) + break; + +- x509_der = (const char *)pCertContextServer->pbCertEncoded; ++ x509_der = (uint8_t *)pCertContextServer->pbCertEncoded; + x509_der_len = pCertContextServer->cbCertEncoded; + memset(&x509_parsed, 0, sizeof(x509_parsed)); + if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len)) +@@ -1543,12 +1543,12 @@ static bool add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, + struct Adder_args *args = (struct Adder_args *)raw_arg; + args->result = CURLE_OK; + if(valid_cert_encoding(ccert_context)) { +- const char *beg = (const char *)ccert_context->pbCertEncoded; +- const char *end = beg + ccert_context->cbCertEncoded; + int insert_index = reverse_order ? (args->certs_count - 1) - args->idx : + args->idx; + args->result = Curl_extract_certinfo(args->data, insert_index, +- beg, end); ++ ccert_context->pbCertEncoded, ++ ccert_context->pbCertEncoded + ++ ccert_context->cbCertEncoded); + args->idx++; + } + return args->result == CURLE_OK; +diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c +index c901ebfe1e..5a2967d275 100644 +--- a/lib/vtls/wolfssl.c ++++ b/lib/vtls/wolfssl.c +@@ -1545,7 +1545,7 @@ CURLcode Curl_wssl_verify_pinned(struct Curl_cfilter *cf, + + if(pinnedpubkey) { + #ifdef KEEP_PEER_CERT +- const char *x509_der; ++ const uint8_t *x509_der; + int x509_der_len; + struct Curl_X509certificate x509_parsed; + struct Curl_asn1Element *pubkey; +@@ -1558,7 +1558,7 @@ CURLcode Curl_wssl_verify_pinned(struct Curl_cfilter *cf, + goto end; + } + +- x509_der = (const char *)wolfSSL_X509_get_der(x509, &x509_der_len); ++ x509_der = wolfSSL_X509_get_der(x509, &x509_der_len); + if(!x509_der) { + failf(data, "SSL: failed retrieving ASN.1 server certificate"); + goto end; +diff --git a/lib/vtls/x509asn1.c b/lib/vtls/x509asn1.c +index b687a60193..65f2d9229d 100644 +--- a/lib/vtls/x509asn1.c ++++ b/lib/vtls/x509asn1.c +@@ -160,17 +160,19 @@ static const struct Curl_OID OIDtable[] = { + * Please note there is no pretension here to rewrite a full SSL library. + */ + +-static const char *getASN1Element(struct Curl_asn1Element *elem, +- const char *beg, const char *end) ++#ifndef UNITTESTS ++static const uint8_t *getASN1Element(struct Curl_asn1Element *elem, ++ const uint8_t *beg, const uint8_t *end) + WARN_UNUSED_RESULT; ++#endif + + #define CURL_ASN1_MAX_RECURSIONS 16 + +-static const char *getASN1Element_(struct Curl_asn1Element *elem, +- const char *beg, const char *end, ++static const uint8_t *getASN1Element_(struct Curl_asn1Element *elem, ++ const uint8_t *beg, const uint8_t *end, + size_t lvl) + { +- unsigned char b; ++ uint8_t b; + size_t len; + struct Curl_asn1Element lelem; + +@@ -185,7 +187,7 @@ static const char *getASN1Element_(struct Curl_asn1Element *elem, + + /* Process header byte. */ + elem->header = beg; +- b = (unsigned char)*beg++; ++ b = *beg++; + elem->constructed = (b & 0x20) != 0; + elem->eclass = (b >> 6) & 3; + b &= 0x1F; +@@ -196,7 +198,7 @@ static const char *getASN1Element_(struct Curl_asn1Element *elem, + /* Process length. */ + if(beg >= end) + return NULL; +- b = (unsigned char)*beg++; ++ b = *beg++; + if(!(b & 0x80)) + len = b; + else if(!(b &= 0x7F)) { +@@ -215,7 +217,7 @@ static const char *getASN1Element_(struct Curl_asn1Element *elem, + elem->end = beg; + return beg + 1; + } +- else if((unsigned)b > (size_t)(end - beg)) ++ else if(b > (size_t)(end - beg)) + return NULL; /* Does not fit in source. */ + else { + /* Get long length. */ +@@ -223,7 +225,7 @@ static const char *getASN1Element_(struct Curl_asn1Element *elem, + do { + if(len & 0xFF000000L) + return NULL; /* Lengths > 32 bits are not supported. */ +- len = (len << 8) | (unsigned char) *beg++; ++ len = (len << 8) | *beg++; + } while(--b); + } + if(len > (size_t)(end - beg)) +@@ -233,8 +235,11 @@ static const char *getASN1Element_(struct Curl_asn1Element *elem, + return elem->end; + } + +-static const char *getASN1Element(struct Curl_asn1Element *elem, +- const char *beg, const char *end) ++/* ++ * @unittest 1657 ++ */ ++UNITTEST const uint8_t *getASN1Element(struct Curl_asn1Element *elem, ++ const uint8_t *beg, const uint8_t *end) + { + return getASN1Element_(elem, beg, end, 0); + } +@@ -255,17 +260,6 @@ static const struct Curl_OID *searchOID(const char *oid) + return NULL; + } + +-#ifdef UNITTESTS +-/* used by unit1657.c */ +-CURLcode Curl_x509_getASN1Element(struct Curl_asn1Element *elem, +- const char *beg, const char *end) +-{ +- if(getASN1Element(elem, beg, end)) +- return CURLE_OK; +- return CURLE_BAD_FUNCTION_ARGUMENT; +-} +-#endif +- + /* + * Convert an ASN.1 Boolean value into its string representation. + * +@@ -273,7 +267,7 @@ CURLcode Curl_x509_getASN1Element(struct Curl_asn1Element *elem, + */ + + static CURLcode bool2str(struct dynbuf *store, +- const char *beg, const char *end) ++ const uint8_t *beg, const uint8_t *end) + { + if(end - beg != 1) + return CURLE_BAD_FUNCTION_ARGUMENT; +@@ -286,17 +280,18 @@ static CURLcode bool2str(struct dynbuf *store, + * Return error code. + */ + static CURLcode octet2str(struct dynbuf *store, +- const char *beg, const char *end) ++ const uint8_t *beg, const uint8_t *end) + { + CURLcode result = CURLE_OK; + + while(!result && beg < end) +- result = curlx_dyn_addf(store, "%02x:", (unsigned char)*beg++); ++ result = curlx_dyn_addf(store, "%02x:", *beg++); + + return result; + } + +-static CURLcode bit2str(struct dynbuf *store, const char *beg, const char *end) ++static CURLcode bit2str(struct dynbuf *store, ++ const uint8_t *beg, const uint8_t *end) + { + /* Convert an ASN.1 bit string to a printable string. */ + +@@ -310,7 +305,8 @@ static CURLcode bit2str(struct dynbuf *store, const char *beg, const char *end) + * + * Returns error. + */ +-static CURLcode int2str(struct dynbuf *store, const char *beg, const char *end) ++static CURLcode int2str(struct dynbuf *store, ++ const uint8_t *beg, const uint8_t *end) + { + unsigned int val = 0; + size_t n = end - beg; +@@ -326,7 +322,7 @@ static CURLcode int2str(struct dynbuf *store, const char *beg, const char *end) + val = ~val; + + do +- val = (val << 8) | *(const unsigned char *)beg++; ++ val = (val << 8) | *beg++; + while(beg < end); + return curlx_dyn_addf(store, "%s%x", val >= 10 ? "0x" : "", val); + } +@@ -339,8 +335,8 @@ static CURLcode int2str(struct dynbuf *store, const char *beg, const char *end) + * + * Returns error. + */ +-static CURLcode utf8asn1str(struct dynbuf *to, int type, const char *from, +- const char *end) ++static CURLcode utf8asn1str(struct dynbuf *to, int type, ++ const uint8_t *from, const uint8_t *end) + { + size_t inlength = end - from; + int size = 1; +@@ -381,14 +377,14 @@ static CURLcode utf8asn1str(struct dynbuf *to, int type, const char *from, + + switch(size) { + case 4: +- wc = (wc << 8) | *(const unsigned char *)from++; +- wc = (wc << 8) | *(const unsigned char *)from++; ++ wc = (wc << 8) | *from++; ++ wc = (wc << 8) | *from++; + FALLTHROUGH(); + case 2: +- wc = (wc << 8) | *(const unsigned char *)from++; ++ wc = (wc << 8) | *from++; + FALLTHROUGH(); + default: /* case 1: */ +- wc = (wc << 8) | *(const unsigned char *)from++; ++ wc = (wc << 8) | *from++; + } + if(wc >= 0x00000080) { + if(wc >= 0x00000800) { +@@ -422,14 +418,14 @@ static CURLcode utf8asn1str(struct dynbuf *to, int type, const char *from, + * Return error code. + */ + static CURLcode encodeOID(struct dynbuf *store, +- const char *beg, const char *end) ++ const uint8_t *beg, const uint8_t *end) + { + unsigned int x; + unsigned int y; + CURLcode result = CURLE_OK; + + /* Process the first two numbers. */ +- y = *(const unsigned char *)beg++; ++ y = *beg++; + x = y / 40; + y -= x * 40; + +@@ -445,7 +441,7 @@ static CURLcode encodeOID(struct dynbuf *store, + return CURLE_OK; + else if(beg == end) + return CURLE_BAD_FUNCTION_ARGUMENT; +- y = *(const unsigned char *)beg++; ++ y = *beg++; + x = (x << 7) | (y & 0x7F); + } while(y & 0x80); + result = curlx_dyn_addf(store, ".%u", x); +@@ -460,7 +456,7 @@ static CURLcode encodeOID(struct dynbuf *store, + */ + + static CURLcode OID2str(struct dynbuf *store, +- const char *beg, const char *end, bool symbolic) ++ const uint8_t *beg, const uint8_t *end, bool symbolic) + { + CURLcode result = CURLE_OK; + if(beg < end) { +@@ -650,10 +646,12 @@ static CURLcode ASN1tostr(struct dynbuf *store, + result = OID2str(store, elem->beg, elem->end, TRUE); + break; + case CURL_ASN1_UTC_TIME: +- result = UTime2str(store, elem->beg, elem->end); ++ result = UTime2str(store, (const char *)elem->beg, ++ (const char *)elem->end); + break; + case CURL_ASN1_GENERALIZED_TIME: +- result = GTime2str(store, elem->beg, elem->end); ++ result = GTime2str(store, (const char *)elem->beg, ++ (const char *)elem->end); + break; + case CURL_ASN1_UTF8_STRING: + case CURL_ASN1_NUMERIC_STRING: +@@ -681,10 +679,10 @@ static CURLcode encodeDN(struct dynbuf *store, struct Curl_asn1Element *dn) + struct Curl_asn1Element atv; + struct Curl_asn1Element oid; + struct Curl_asn1Element value; +- const char *p1; +- const char *p2; +- const char *p3; +- const char *str; ++ const uint8_t *p1; ++ const uint8_t *p2; ++ const uint8_t *p3; ++ const uint8_t *str; + CURLcode result = CURLE_OK; + bool added = FALSE; + struct dynbuf temp; +@@ -716,7 +714,7 @@ static CURLcode encodeDN(struct dynbuf *store, struct Curl_asn1Element *dn) + if(result) + goto error; + +- str = curlx_dyn_ptr(&temp); ++ str = curlx_dyn_uptr(&temp); + + if(!str) { + result = CURLE_BAD_FUNCTION_ARGUMENT; +@@ -737,7 +735,7 @@ static CURLcode encodeDN(struct dynbuf *store, struct Curl_asn1Element *dn) + } + + /* Encode attribute name. */ +- result = curlx_dyn_add(store, str); ++ result = curlx_dyn_add(store, (const char *)str); + if(result) + goto error; + +@@ -769,13 +767,14 @@ error: + * See RFC 5280. + */ + int Curl_parseX509(struct Curl_X509certificate *cert, +- const char *beg, const char *end) ++ const uint8_t *beg, const uint8_t *end) + { + struct Curl_asn1Element elem; + struct Curl_asn1Element tbsCertificate; +- const char *ccp; +- static const char defaultVersion = 0; /* v1. */ ++ const uint8_t *ccp; ++ static const uint8_t defaultVersion = 0; /* v1. */ + ++ memset(cert, 0, sizeof(*cert)); + cert->certificate.header = NULL; + cert->certificate.beg = beg; + cert->certificate.end = end; +@@ -831,6 +830,9 @@ int Curl_parseX509(struct Curl_X509certificate *cert, + return -1; + if(!getASN1Element(&cert->notAfter, ccp, elem.end)) + return -1; ++ /* These two fields MUST consume all of the validity elem */ ++ if(elem.end != cert->notAfter.end) ++ return -1; + /* Get subject. */ + beg = getASN1Element(&cert->subject, beg, end); + if(!beg) +@@ -851,10 +853,10 @@ int Curl_parseX509(struct Curl_X509certificate *cert, + cert->issuerUniqueID.tag = cert->subjectUniqueID.tag = 0; + cert->extensions.tag = elem.tag = 0; + cert->issuerUniqueID.header = cert->subjectUniqueID.header = NULL; +- cert->issuerUniqueID.beg = cert->issuerUniqueID.end = ""; +- cert->subjectUniqueID.beg = cert->subjectUniqueID.end = ""; ++ cert->issuerUniqueID.beg = cert->issuerUniqueID.end = beg; ++ cert->subjectUniqueID.beg = cert->subjectUniqueID.end = beg; + cert->extensions.header = NULL; +- cert->extensions.beg = cert->extensions.end = ""; ++ cert->extensions.beg = cert->extensions.end = beg; + if(beg < end) { + beg = getASN1Element(&elem, beg, end); + if(!beg) +@@ -888,7 +890,7 @@ int Curl_parseX509(struct Curl_X509certificate *cert, + + static CURLcode dumpAlgo(struct dynbuf *store, + struct Curl_asn1Element *param, +- const char *beg, const char *end) ++ const uint8_t *beg, const uint8_t *end) + { + struct Curl_asn1Element oid; + +@@ -901,7 +903,7 @@ static CURLcode dumpAlgo(struct dynbuf *store, + param->tag = 0; + param->beg = param->end = end; + if(beg < end) { +- const char *p = getASN1Element(param, beg, end); ++ const uint8_t *p = getASN1Element(param, beg, end); + if(!p) + return CURLE_BAD_FUNCTION_ARGUMENT; + } +@@ -972,7 +974,7 @@ static int do_pubkey(struct Curl_easy *data, int certnum, const char *algo, + { + struct Curl_asn1Element elem; + struct Curl_asn1Element pk; +- const char *p; ++ const uint8_t *p; + + /* Generate all information records for the public key. */ + +@@ -1004,7 +1006,7 @@ static int do_pubkey(struct Curl_easy *data, int certnum, const char *algo, + return 1; + + if(curl_strequal(algo, "rsaEncryption")) { +- const char *q; ++ const uint8_t *q; + size_t len; + + p = getASN1Element(&elem, pk.beg, pk.end); +@@ -1017,7 +1019,7 @@ static int do_pubkey(struct Curl_easy *data, int certnum, const char *algo, + len = ((elem.end - q) * 8); + if(len) { + unsigned int i; +- for(i = *(const unsigned char *)q; !(i & 0x80); i <<= 1) ++ for(i = *q; !(i & 0x80); i <<= 1) + len--; + } + if(len > 32) +@@ -1083,8 +1085,8 @@ static CURLcode DNtostr(struct dynbuf *store, struct Curl_asn1Element *dn) + + CURLcode Curl_extract_certinfo(struct Curl_easy *data, + int certnum, +- const char *beg, +- const char *end) ++ const uint8_t *beg, ++ const uint8_t *end) + { + struct Curl_X509certificate cert; + struct Curl_asn1Element param; +@@ -1093,7 +1095,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data, + struct dynbuf out; + CURLcode result = CURLE_OK; + unsigned int version; +- const char *ptr; ++ const uint8_t *ptr; + int rc; + + if(!data->set.ssl.certinfo) +@@ -1132,7 +1134,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data, + /* Version (always fits in less than 32 bits). */ + version = 0; + for(ptr = cert.version.beg; ptr < cert.version.end; ptr++) +- version = (version << 8) | *(const unsigned char *)ptr; ++ version = (version << 8) | *ptr; + if(data->set.ssl.certinfo) { + result = curlx_dyn_addf(&out, "%x", version); + if(result) +diff --git a/lib/vtls/x509asn1.h b/lib/vtls/x509asn1.h +index 829dfd884f..e5374108e5 100644 +--- a/lib/vtls/x509asn1.h ++++ b/lib/vtls/x509asn1.h +@@ -38,11 +38,11 @@ + + /* ASN.1 parsed element. */ + struct Curl_asn1Element { +- const char *header; /* Pointer to header byte. */ +- const char *beg; /* Pointer to element data. */ +- const char *end; /* Pointer to 1st byte after element. */ +- unsigned char eclass; /* ASN.1 element class. */ +- unsigned char tag; /* ASN.1 element tag. */ ++ const uint8_t *header; /* Pointer to header byte. */ ++ const uint8_t *beg; /* Pointer to element data. */ ++ const uint8_t *end; /* Pointer to 1st byte after element. */ ++ uint8_t eclass; /* ASN.1 element class. */ ++ uint8_t tag; /* ASN.1 element tag. */ + BIT(constructed); /* Element is constructed. */ + }; + +@@ -70,22 +70,22 @@ struct Curl_X509certificate { + */ + + int Curl_parseX509(struct Curl_X509certificate *cert, +- const char *beg, const char *end); ++ const uint8_t *beg, const uint8_t *end); + CURLcode Curl_extract_certinfo(struct Curl_easy *data, int certnum, +- const char *beg, const char *end); ++ const uint8_t *beg, const uint8_t *end); + CURLcode Curl_verifyhost(struct Curl_cfilter *cf, struct Curl_easy *data, +- const char *beg, const char *end); ++ const uint8_t *beg, const uint8_t *end); + + #ifdef UNITTESTS ++const uint8_t *getASN1Element(struct Curl_asn1Element *elem, ++ const uint8_t *beg, const uint8_t *end) ++ WARN_UNUSED_RESULT; + #if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_MBEDTLS) || \ + defined(USE_RUSTLS) + + /* used by unit1656.c */ + CURLcode Curl_x509_GTime2str(struct dynbuf *store, + const char *beg, const char *end); +-/* used by unit1657.c */ +-CURLcode Curl_x509_getASN1Element(struct Curl_asn1Element *elem, +- const char *beg, const char *end); + #endif /* USE_GNUTLS || USE_SCHANNEL || USE_MBEDTLS || RUSTLS */ + #endif /* UNITTESTS */ + +diff --git a/tests/unit/unit1651.c b/tests/unit/unit1651.c +index 10fc979724..ce8cbaedc5 100644 +--- a/tests/unit/unit1651.c ++++ b/tests/unit/unit1651.c +@@ -33,7 +33,7 @@ static CURLcode test_unit1651(const char *arg) + + /* cert captured from gdb when connecting to curl.se on October 26 + 2018. */ +- static unsigned char cert[] = { ++ static uint8_t cert[] = { + 0x30, 0x82, 0x0F, 0x5B, 0x30, 0x82, 0x0E, 0x43, 0xA0, 0x03, 0x02, 0x01, + 0x02, 0x02, 0x0C, 0x08, 0x77, 0x99, 0x2C, 0x6B, 0x67, 0xE1, 0x18, 0xD6, + 0x66, 0x66, 0x9E, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, +@@ -365,8 +365,8 @@ static CURLcode test_unit1651(const char *arg) + }; + + CURLcode result; +- const char *beg = (const char *)&cert[0]; +- const char *end = (const char *)&cert[sizeof(cert)]; ++ const uint8_t *beg = &cert[0]; ++ const uint8_t *end = &cert[sizeof(cert)]; + struct Curl_easy *data; + int i; + int byte; +diff --git a/tests/unit/unit1657.c b/tests/unit/unit1657.c +index 7c769e78da..716df1856c 100644 +--- a/tests/unit/unit1657.c ++++ b/tests/unit/unit1657.c +@@ -23,7 +23,8 @@ + ***************************************************************************/ + #include "unitcheck.h" + +-#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_MBEDTLS) ++#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || \ ++ defined(USE_MBEDTLS) || defined(USE_RUSTLS) + + #include "vtls/x509asn1.h" + +@@ -38,8 +39,8 @@ static CURLcode make1657_nested(const struct test1657_spec *spec, + { + CURLcode result; + size_t i; +- unsigned char open_undef[] = { 0x32, 0x80 }; +- unsigned char close_undef[] = { 0x00, 0x00 }; ++ uint8_t open_undef[] = { 0x32, 0x80 }; ++ uint8_t close_undef[] = { 0x00, 0x00 }; + + for(i = 0; i < spec->n; ++i) { + result = curlx_dyn_addn(buf, open_undef, sizeof(open_undef)); +@@ -66,7 +67,8 @@ static bool do_test1657(const struct test1657_spec *spec, size_t i, + { + CURLcode result; + struct Curl_asn1Element elem; +- const char *in; ++ const uint8_t *in; ++ const uint8_t *ptr; + + memset(&elem, 0, sizeof(elem)); + curlx_dyn_reset(buf); +@@ -75,8 +77,9 @@ static bool do_test1657(const struct test1657_spec *spec, size_t i, + curl_mfprintf(stderr, "test %zu: error setting buf %d\n", i, result); + return FALSE; + } +- in = curlx_dyn_ptr(buf); +- result = Curl_x509_getASN1Element(&elem, in, in + curlx_dyn_len(buf)); ++ in = curlx_dyn_uptr(buf); ++ ptr = getASN1Element(&elem, in, in + curlx_dyn_len(buf)); ++ result = ptr ? CURLE_OK : CURLE_BAD_FUNCTION_ARGUMENT; + if(result != spec->result_exp) { + curl_mfprintf(stderr, "test %zu: expect result %d, got %d\n", + i, spec->result_exp, result); +@@ -85,6 +88,59 @@ static bool do_test1657(const struct test1657_spec *spec, size_t i, + return TRUE; + } + ++struct test1657_cert_spec { ++ const char * const pem; ++ bool exp_success; ++}; ++ ++static const struct test1657_cert_spec test1657_certs[] = { ++ { /* a valid certificate */ ++ "MIIBGTCBzKADAgECAhQ8Ssn8BaVsqlKKccv81NFuKY1vATAFBgMrZXAwADAeFw0y" ++ "NjA5MDIwNDU0MjZaFw0yNjEwMDIwNDU0MjZaMAAwKjAFBgMrZXADIQBeG0S343s9" ++ "5yRmIK8xZmGvUmiiYvRH5ZMcPq6rvHHKwqNYMFYwNQYDKgMEBC4wADAqMAUGAytl" ++ "cAMhAPP5TXSe2WHt/bebbP8eHPXrG3LNxYz8TnHNgpwTFsT7MB0GA1UdDgQWBBR6" ++ "aqL9LrZiIpgYCy0X4fNrhgFQsTAFBgMrZXADQQALU0OHGcIvfTwyin/+u9csJ9hZ" ++ "W0c+XdHJY5uDdCR1O92K4Vnozf/QCe7ITOJ8aUnCs7Jgf5xrDgyXZNdum04A", ++ TRUE ++ }, ++ { /* a certificate with "validity" element that has too long length */ ++ "MIIBGTCBzKADAgECAhQ8Ssn8BaVsqlKKccv81NFuKY1vATAFBgMrZXAwADBZFw0y" ++ "NjA5MDIwNDU0MjZaFw0yNjEwMDIwNDU0MjZaMAAwKjAFBgMrZXADIQBeG0S343s9" ++ "5yRmIK8xZmGvUmiiYvRH5ZMcPq6rvHHKwqNYMFYwNQYDKgMEBC4wADAqMAUGAytl" ++ "cAMhAPP5TXSe2WHt/bebbP8eHPXrG3LNxYz8TnHNgpwTFsT7MB0GA1UdDgQWBBR6" ++ "aqL9LrZiIpgYCy0X4fNrhgFQsTAFBgMrZXADQQALU0OHGcIvfTwyin/+u9csJ9hZ" ++ "W0c+XdHJY5uDdCR1O92K4Vnozf/QCe7ITOJ8aUnCs7Jgf5xrDgyXZNdum04A", ++ FALSE ++ } ++}; ++ ++static bool test1657_parse_cert(size_t i, ++ const struct test1657_cert_spec *spec) ++{ ++ struct Curl_X509certificate cert; ++ CURLcode result; ++ uint8_t *cert_der; ++ size_t cert_der_len; ++ bool success; ++ ++ result = curlx_base64_decode(spec->pem, &cert_der, &cert_der_len); ++ if(result) { ++ curl_mfprintf(stderr, "cert %zu: base64 decoding failed: %d\n", ++ i, (int)result); ++ return FALSE; ++ } ++ ++ success = !Curl_parseX509(&cert, cert_der, cert_der + cert_der_len); ++ if(success != spec->exp_success) { ++ curl_mfprintf(stderr, "cert %zu: parsing DER %sfailed\n", i, ++ spec->exp_success ? "" : "should have "); ++ return FALSE; ++ } ++ ++ curlx_free(cert_der); ++ return TRUE; ++} ++ + static CURLcode test_unit1657(const char *arg) + { + UNITTEST_BEGIN_SIMPLE +@@ -104,7 +160,14 @@ static CURLcode test_unit1657(const char *arg) + if(!do_test1657(&test1657_specs[i], i, &dbuf)) + all_ok = FALSE; + } +- fail_unless(all_ok, "some tests of Curl_x509_getASN1Element() fails"); ++ fail_unless(all_ok, "some getASN1Element() tests failed"); ++ ++ all_ok = TRUE; ++ for(i = 0; i < CURL_ARRAYSIZE(test1657_certs); ++i) { ++ if(!test1657_parse_cert(i, &test1657_certs[i])) ++ all_ok = FALSE; ++ } ++ fail_unless(all_ok, "some certificate tests failed"); + + curlx_dyn_free(&dbuf); + curl_global_cleanup(); +@@ -117,7 +180,7 @@ static CURLcode test_unit1657(const char *arg) + static CURLcode test_unit1657(const char *arg) + { + UNITTEST_BEGIN_SIMPLE +- puts("not tested since Curl_x509_getASN1Element() is not built in"); ++ puts("not tested since getASN1Element() is not built in"); + UNITTEST_END_SIMPLE + } + +-- +2.35.6 diff --git a/meta/recipes-support/curl/curl_8.19.0.bb b/meta/recipes-support/curl/curl_8.19.0.bb index 026b5a3638..51479d8b6a 100644 --- a/meta/recipes-support/curl/curl_8.19.0.bb +++ b/meta/recipes-support/curl/curl_8.19.0.bb @@ -71,6 +71,7 @@ SRC_URI = "https://curl.se/download/${BP}.tar.xz \ file://CVE-2026-94266_p1.patch \ file://CVE-2026-94266_p2.patch \ file://CVE-2026-107929.patch \ + file://CVE-2026-87866.patch \ " SRC_URI:append:class-nativesdk = " \