From patchwork Mon Dec 29 23:07:35 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steve Sakoman X-Patchwork-Id: 77639 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 68B25E92FF7 for ; Mon, 29 Dec 2025 23:08:06 +0000 (UTC) Received: from mail-pf1-f169.google.com (mail-pf1-f169.google.com [209.85.210.169]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.53859.1767049684714898092 for ; Mon, 29 Dec 2025 15:08:04 -0800 Authentication-Results: mx.groups.io; dkim=pass header.i=@sakoman-com.20230601.gappssmtp.com header.s=20230601 header.b=q0LFPKla; spf=softfail (domain: sakoman.com, ip: 209.85.210.169, mailfrom: steve@sakoman.com) Received: by mail-pf1-f169.google.com with SMTP id d2e1a72fcca58-7aab061e7cbso12820578b3a.1 for ; Mon, 29 Dec 2025 15:08:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sakoman-com.20230601.gappssmtp.com; s=20230601; t=1767049684; x=1767654484; darn=lists.openembedded.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=wkFcORmZxfiLQtT/MaR0seYyw1IEVw6XfLUpxcATQSQ=; b=q0LFPKla+RTBzeV4NJ9ArD9tgv5vi5xYaW2/rHwueSoUi0tbD+JQ7UZtae2Z/ecJ6Y fhsLwz4mLPVUbYaI8ble77oCCm8UnY4+jekyBsMWf3je5I0vdoVeo7qcIj2F4B8z4d5y 44m8bHvWCMl/IJPH8QNSfkAqLs+ZfrRQIUd3rvjRmy7WqkLojLjjQCgjRaeLIe8SNX2b 21JocHLsMttva4Xz4KYBRrDnBQsRDk2oeaAMPdRJjGwTEEe7Q+gNIVZiDsacgGt+3jcQ csa6nin+8SH0Ui6+czQLWdu/BKf99U0WhBYBKTHBjgVDVIMXjEGvzcAjjNmp7tZioOSz zZGA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767049684; x=1767654484; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=wkFcORmZxfiLQtT/MaR0seYyw1IEVw6XfLUpxcATQSQ=; b=nXuvzymOZDpMpBpqljGISTcR+1QlwyCg6qvLLoYmFE08HEb4rhaib6ZCF5rW/z7FfW e75oq0upKWdiLZV2grchMmBvhJ8COjNjNO+0whYCGiAxkeEOlXponKC49G4TaojRkWeZ pkEgujJWffbBxc4ZAz15oMqEc+Bq78lXX6x40YwRQ7u6yE+xvkvdX0tdMckMN+zu1J6i ScSFeLuycoedxlBqGqZESX1dbYX2u2ETDbRYkXPICsIon1ZUkfKSMMsHoXZooBjBTUzc xK9q/T/pdRmSTXLokldjvgPgbTSyEf0ap8cS74OmYGKr+3PZPjqcxk13xHy4pj+5syqg kzkw== X-Gm-Message-State: AOJu0YwMQB/VRcagMIRxgZJZlcp60SQG4CdIBskCnelXxhbmSijVpv/p Jq/kX15aT9vdM2ekdjSD5dGXKrN6LmHERiVkRsOePsU53hQrac6bpXSNpL0OCcdFpU2hqO3JxgB cz/xn X-Gm-Gg: AY/fxX4ePrpJkcPm25IGzPH6Hob/KKoJ9qhdva4dq8fI+kFx3NWm3n/S5ifWTuBZgIL 6WBxwZ+iK9fCFmJU+8018UlbByb6m4MSWRcmEeOuaOlRVDBc55hGGRs253F1bZoW1o3/JO9BxLm 7Iy12ZHf2vCeffAr0u2VHsPudhj0WvpPqyTF9ZC5kj66dXryZltNAwDHVxuGbzylLvG+3J4NTMo jXxBTEPKJEGmM3bdf4Y/dTa6CgPFTIpe6ZssSd/Pz8UvDYaS201AbxV8nDi7Fg4eGtwV8BXDsbC h6UqaxA60S533jZWrb2xKZHWBX7XeB2zxiveFT4cGxbYcfQAH916HBAJgt16/Z6AW1bM56c52xz ub6HCiQHfelmyyqbFLGpBIvW5Vd6TSE6MerM7PPJ03VgWKxPNn0W4c6j2Q9oSWKBTspB1r/Deri 2yNQ== X-Google-Smtp-Source: AGHT+IFxi6a82j3aOiesnW0bDwxqpYUh+Q/BLBjlRIV7aP4nmrHKNKxJlJuD7V5RCzPpnQMKmdIMxg== X-Received: by 2002:a05:6a00:288f:b0:7f7:13bb:8f20 with SMTP id d2e1a72fcca58-7ff6667c961mr24389327b3a.50.1767049683900; Mon, 29 Dec 2025 15:08:03 -0800 (PST) Received: from hexa.. ([2602:feb4:3b:2100:c013:8f5c:baf3:22c3]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7ff7e493123sm30340938b3a.50.2025.12.29.15.08.03 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Dec 2025 15:08:03 -0800 (PST) From: Steve Sakoman To: openembedded-core@lists.openembedded.org Subject: [OE-core][scarthgap 1/5] grub: fix CVE-2025-54770 CVE-2025-61661 CVE-2025-61662 CVE-2025-61663 CVE-2025-61664 Date: Mon, 29 Dec 2025 15:07:35 -0800 Message-ID: X-Mailer: git-send-email 2.43.0 In-Reply-To: References: MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Mon, 29 Dec 2025 23:08:06 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/228622 From: Jiaying Song References: https://nvd.nist.gov/vuln/detail/CVE-2025-54770 https://nvd.nist.gov/vuln/detail/CVE-2025-61661 https://nvd.nist.gov/vuln/detail/CVE-2025-61662 https://nvd.nist.gov/vuln/detail/CVE-2025-61663 https://nvd.nist.gov/vuln/detail/CVE-2025-61664 Signed-off-by: Jiaying Song Signed-off-by: Steve Sakoman --- .../grub/files/CVE-2025-54770.patch | 41 +++++++++++ .../grub/files/CVE-2025-61661.patch | 40 +++++++++++ .../grub/files/CVE-2025-61662.patch | 72 +++++++++++++++++++ .../grub/files/CVE-2025-61663_61664.patch | 64 +++++++++++++++++ meta/recipes-bsp/grub/grub2.inc | 4 ++ 5 files changed, 221 insertions(+) create mode 100644 meta/recipes-bsp/grub/files/CVE-2025-54770.patch create mode 100644 meta/recipes-bsp/grub/files/CVE-2025-61661.patch create mode 100644 meta/recipes-bsp/grub/files/CVE-2025-61662.patch create mode 100644 meta/recipes-bsp/grub/files/CVE-2025-61663_61664.patch diff --git a/meta/recipes-bsp/grub/files/CVE-2025-54770.patch b/meta/recipes-bsp/grub/files/CVE-2025-54770.patch new file mode 100644 index 0000000000..7df1d8534b --- /dev/null +++ b/meta/recipes-bsp/grub/files/CVE-2025-54770.patch @@ -0,0 +1,41 @@ +From 80e0e9b2558c40fb108ae7a869362566eb4c1ead Mon Sep 17 00:00:00 2001 +From: Thomas Frauendorfer | Miray Software +Date: Fri, 9 May 2025 14:20:47 +0200 +Subject: [PATCH] net/net: Unregister net_set_vlan command on unload + +The commit 954c48b9c (net/net: Add net_set_vlan command) added command +net_set_vlan to the net module. Unfortunately the commit only added the +grub_register_command() call on module load but missed the +grub_unregister_command() on unload. Let's fix this. + +Fixes: CVE-2025-54770 +Fixes: 954c48b9c (net/net: Add net_set_vlan command) + +CVE: CVE-2025-54770 + +Upstream-Status: Backport +[https://gitweb.git.savannah.gnu.org/gitweb/?p=grub.git;a=commit;h=10e58a14db20e17d1b6a39abe38df01fef98e29d] + +Reported-by: Thomas Frauendorfer | Miray Software +Signed-off-by: Thomas Frauendorfer | Miray Software +Reviewed-by: Daniel Kiper +Signed-off-by: Jiaying Song +--- + grub-core/net/net.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index 2b45c27d1..05f11be08 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -2080,6 +2080,7 @@ GRUB_MOD_FINI(net) + grub_unregister_command (cmd_deladdr); + grub_unregister_command (cmd_addroute); + grub_unregister_command (cmd_delroute); ++ grub_unregister_command (cmd_setvlan); + grub_unregister_command (cmd_lsroutes); + grub_unregister_command (cmd_lscards); + grub_unregister_command (cmd_lsaddr); +-- +2.34.1 + diff --git a/meta/recipes-bsp/grub/files/CVE-2025-61661.patch b/meta/recipes-bsp/grub/files/CVE-2025-61661.patch new file mode 100644 index 0000000000..9f6cf68e4b --- /dev/null +++ b/meta/recipes-bsp/grub/files/CVE-2025-61661.patch @@ -0,0 +1,40 @@ +From c24e11d87f8ee8cefd615e0c30eb71ff6149ee50 Mon Sep 17 00:00:00 2001 +From: Jamie +Date: Mon, 14 Jul 2025 09:52:59 +0100 +Subject: [PATCH 2/4] commands/usbtest: Use correct string length field + +An incorrect length field is used for buffer allocation. This leads to +grub_utf16_to_utf8() receiving an incorrect/different length and possibly +causing OOB write. This makes sure to use the correct length. + +Fixes: CVE-2025-61661 + +CVE: CVE-2025-61661 + +Upstream-Status: Backport +[https://gitweb.git.savannah.gnu.org/gitweb/?p=grub.git;a=commit;h=549a9cc372fd0b96a4ccdfad0e12140476cc62a3] + +Reported-by: Jamie +Signed-off-by: Jamie +Reviewed-by: Daniel Kiper +Signed-off-by: Jiaying Song +--- + grub-core/commands/usbtest.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/commands/usbtest.c b/grub-core/commands/usbtest.c +index 2c6d93fe6..8ef187a9a 100644 +--- a/grub-core/commands/usbtest.c ++++ b/grub-core/commands/usbtest.c +@@ -99,7 +99,7 @@ grub_usb_get_string (grub_usb_device_t dev, grub_uint8_t index, int langid, + return GRUB_USB_ERR_NONE; + } + +- *string = grub_malloc (descstr.length * 2 + 1); ++ *string = grub_malloc (descstrp->length * 2 + 1); + if (! *string) + { + grub_free (descstrp); +-- +2.34.1 + diff --git a/meta/recipes-bsp/grub/files/CVE-2025-61662.patch b/meta/recipes-bsp/grub/files/CVE-2025-61662.patch new file mode 100644 index 0000000000..f04a52fe76 --- /dev/null +++ b/meta/recipes-bsp/grub/files/CVE-2025-61662.patch @@ -0,0 +1,72 @@ +From 498dc73aa661bb1cae4b06572b5cef154dcb1fb7 Mon Sep 17 00:00:00 2001 +From: Alec Brown +Date: Thu, 21 Aug 2025 21:14:06 +0000 +Subject: [PATCH 3/4] gettext/gettext: Unregister gettext command on module + unload + +When the gettext module is loaded, the gettext command is registered but +isn't unregistered when the module is unloaded. We need to add a call to +grub_unregister_command() when unloading the module. + +Fixes: CVE-2025-61662 + +CVE: CVE-2025-61662 + +Upstream-Status: Backport +[https://gitweb.git.savannah.gnu.org/gitweb/?p=grub.git;a=commit;h=8ed78fd9f0852ab218cc1f991c38e5a229e43807] + +Reported-by: Alec Brown +Signed-off-by: Alec Brown +Reviewed-by: Daniel Kiper +Signed-off-by: Jiaying Song +--- + grub-core/gettext/gettext.c | 19 ++++++++++++------- + 1 file changed, 12 insertions(+), 7 deletions(-) + +diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c +index 9ffc73428..edebed998 100644 +--- a/grub-core/gettext/gettext.c ++++ b/grub-core/gettext/gettext.c +@@ -502,6 +502,8 @@ grub_cmd_translate (grub_command_t cmd __attribute__ ((unused)), + return 0; + } + ++static grub_command_t cmd; ++ + GRUB_MOD_INIT (gettext) + { + const char *lang; +@@ -521,13 +523,14 @@ GRUB_MOD_INIT (gettext) + grub_register_variable_hook ("locale_dir", NULL, read_main); + grub_register_variable_hook ("secondary_locale_dir", NULL, read_secondary); + +- grub_register_command_p1 ("gettext", grub_cmd_translate, +- N_("STRING"), +- /* TRANSLATORS: It refers to passing the string through gettext. +- So it's "translate" in the same meaning as in what you're +- doing now. +- */ +- N_("Translates the string with the current settings.")); ++ cmd = grub_register_command_p1 ("gettext", grub_cmd_translate, ++ N_("STRING"), ++ /* ++ * TRANSLATORS: It refers to passing the string through gettext. ++ * So it's "translate" in the same meaning as in what you're ++ * doing now. ++ */ ++ N_("Translates the string with the current settings.")); + + /* Reload .mo file information if lang changes. */ + grub_register_variable_hook ("lang", NULL, grub_gettext_env_write_lang); +@@ -544,6 +547,8 @@ GRUB_MOD_FINI (gettext) + grub_register_variable_hook ("secondary_locale_dir", NULL, NULL); + grub_register_variable_hook ("lang", NULL, NULL); + ++ grub_unregister_command (cmd); ++ + grub_gettext_delete_list (&main_context); + grub_gettext_delete_list (&secondary_context); + +-- +2.34.1 + diff --git a/meta/recipes-bsp/grub/files/CVE-2025-61663_61664.patch b/meta/recipes-bsp/grub/files/CVE-2025-61663_61664.patch new file mode 100644 index 0000000000..bfc05008bf --- /dev/null +++ b/meta/recipes-bsp/grub/files/CVE-2025-61663_61664.patch @@ -0,0 +1,64 @@ +From 8368c026562a72a005bea320cfde9fd7d62d3850 Mon Sep 17 00:00:00 2001 +From: Alec Brown +Date: Thu, 21 Aug 2025 21:14:07 +0000 +Subject: [PATCH 4/4] normal/main: Unregister commands on module unload + +When the normal module is loaded, the normal and normal_exit commands +are registered but aren't unregistered when the module is unloaded. We +need to add calls to grub_unregister_command() when unloading the module +for these commands. + +Fixes: CVE-2025-61663 +Fixes: CVE-2025-61664 + +CVE: CVE-2025-61663 CVE-2025-61664 + +Upstream-Status: Backport +[https://gitweb.git.savannah.gnu.org/gitweb/?p=grub.git;a=commit;h=05d3698b8b03eccc49e53491bbd75dba15f40917] + +Reported-by: Alec Brown +Signed-off-by: Alec Brown +Reviewed-by: Daniel Kiper +Signed-off-by: Jiaying Song +--- + grub-core/normal/main.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c +index dad25e7d2..a810858c3 100644 +--- a/grub-core/normal/main.c ++++ b/grub-core/normal/main.c +@@ -500,7 +500,7 @@ grub_mini_cmd_clear (struct grub_command *cmd __attribute__ ((unused)), + return 0; + } + +-static grub_command_t cmd_clear; ++static grub_command_t cmd_clear, cmd_normal, cmd_normal_exit; + + static void (*grub_xputs_saved) (const char *str); + static const char *features[] = { +@@ -542,10 +542,10 @@ GRUB_MOD_INIT(normal) + grub_env_export ("pager"); + + /* Register a command "normal" for the rescue mode. */ +- grub_register_command ("normal", grub_cmd_normal, +- 0, N_("Enter normal mode.")); +- grub_register_command ("normal_exit", grub_cmd_normal_exit, +- 0, N_("Exit from normal mode.")); ++ cmd_normal = grub_register_command ("normal", grub_cmd_normal, ++ 0, N_("Enter normal mode.")); ++ cmd_normal_exit = grub_register_command ("normal_exit", grub_cmd_normal_exit, ++ 0, N_("Exit from normal mode.")); + + /* Reload terminal colors when these variables are written to. */ + grub_register_variable_hook ("color_normal", NULL, grub_env_write_color_normal); +@@ -587,4 +587,6 @@ GRUB_MOD_FINI(normal) + grub_register_variable_hook ("color_highlight", NULL, NULL); + grub_fs_autoload_hook = 0; + grub_unregister_command (cmd_clear); ++ grub_unregister_command (cmd_normal); ++ grub_unregister_command (cmd_normal_exit); + } +-- +2.34.1 + diff --git a/meta/recipes-bsp/grub/grub2.inc b/meta/recipes-bsp/grub/grub2.inc index edb87ef2ea..3160708113 100644 --- a/meta/recipes-bsp/grub/grub2.inc +++ b/meta/recipes-bsp/grub/grub2.inc @@ -38,6 +38,10 @@ SRC_URI = "${GNU_MIRROR}/grub/grub-${PV}.tar.gz \ file://CVE-2025-0677_CVE-2025-0684_CVE-2025-0685_CVE-2025-0686_CVE-2025-0689.patch \ file://CVE-2025-0678_CVE-2025-1125.patch \ file://CVE-2024-56738.patch \ + file://CVE-2025-54770.patch \ + file://CVE-2025-61661.patch \ + file://CVE-2025-61662.patch \ + file://CVE-2025-61663_61664.patch \ " SRC_URI[sha256sum] = "b30919fa5be280417c17ac561bb1650f60cfb80cc6237fa1e2b6f56154cb9c91" From patchwork Mon Dec 29 23:07:36 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steve Sakoman X-Patchwork-Id: 77640 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4B00FE92FFF for ; Mon, 29 Dec 2025 23:08:16 +0000 (UTC) Received: from mail-pf1-f172.google.com (mail-pf1-f172.google.com [209.85.210.172]) by mx.groups.io with SMTP id smtpd.msgproc02-g2.53841.1767049686361120352 for ; Mon, 29 Dec 2025 15:08:06 -0800 Authentication-Results: mx.groups.io; dkim=pass header.i=@sakoman-com.20230601.gappssmtp.com header.s=20230601 header.b=JLNvcaxQ; spf=softfail (domain: sakoman.com, ip: 209.85.210.172, mailfrom: steve@sakoman.com) Received: by mail-pf1-f172.google.com with SMTP id d2e1a72fcca58-7aa2170adf9so7024057b3a.0 for ; Mon, 29 Dec 2025 15:08:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sakoman-com.20230601.gappssmtp.com; s=20230601; t=1767049685; x=1767654485; darn=lists.openembedded.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=BQX8JCTy5Qi2l4o33YRQ6g4rKFoDlJakafklbNwH6OY=; b=JLNvcaxQwjPBj+qX4GILMHNfcoXJ6H5p8JqLnQz2/dsuQLfM3i9HojnVGj9HZ3akZH KKMnTEkMnMaF3Bolj4Ba72iok870tGlhuPUFHvR/VEZ6Cy3r+kUcd4JYAFv35gma/Bkw NV6q+Lv005whB0vd0+cW9sVV+wGzmB8DGtj53/TIXqde8jHqKeiatJB/CK5Tzxup0Ms0 ZYRwvJrB2s8JBJaZX7rZhoU1pqWwwkJBtlQSKmJIb8UQvH/1Ktm4JbTgWmMV71KyivGs rhz+9Y5RBWYqDcUt/o5MNU3eazEVJwq6zR9MBIcgNTqjwbCFrd2yxmTVmi1ZfW6RvqS6 AeBw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767049685; x=1767654485; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=BQX8JCTy5Qi2l4o33YRQ6g4rKFoDlJakafklbNwH6OY=; b=PifIWQrRvgANxZzwkSXrywA26fcBuIkluCG/GN9uBOg+36Uxf/zkj4tKaRz7eq7G+Y OVeGSQkISuiO1Tf+DpvpW5pp6FuuTncdR0twW8cvLmECtl8BYPfjxSFgU9uAwbOCk7DC YWQenTguWYOfO5YYgwmXjLKWyZsvUNoETm/ViZmsU3m2OjTj4xlDsZKxGWXaY2xFi0rx U0Bs05zRb84ZKbT+bBfKGvZbKtxKJo5SeRUKAePq3vKVOYzkOxMMJPeS6OKLM5TV+FQ0 bqbEveiw0MbBx4QfacGso6oI1di1a+MUlFcLNSd+h161/m7uvSc8URaqotR0kWQpBnEb 82iQ== X-Gm-Message-State: AOJu0Yz1pjLC19jfeEzMQ8kbvsWXw7mC4/DhwLe/wZnOghQ1WsaGy5iN 1sjY+8qfQwyyp4L6/+OJuseA/B3qDb2MvI8UfbLihKky22IFlUX7d10EPOZTr/PBPgh/vtYKKbK U4oDR X-Gm-Gg: AY/fxX7WZU3eA7UKbo0ON6ldZxSxQbkHWm3+wKFOqjUt9UtvRBH1pXMrNdUhoCCz8iW ubtNCZrK3YTN0BiUqrTXvPvEACiCtPXQkLtaCtW+Q3lz4Xyl6Ksa0/9MGmYkE0sTM/OKKlrTe3z A5HjlxBMGYMNXh2kLPw3AL4UjczJGWXd4IuK5mzegJvRHtflOzC+ntjLhwC7rPYsjwCiHzHMOH7 fjItUA6zluet1QNDcvAIBCtd4cJ1Nv+AC+DB4g20TGJAcFlUa9k5FnNC7sRyJKx1GWw1FOjtuDC KwjI0s7hdDz/CLGscgmbh7SDRzOSE0fiCj25BERf13yELWoqA1RGlREYNDXSS6EeboOzUQLONNS oeuTC4o7wbICTCnJaqLdEsjrob8D0u3rH4Yb3zZO5VusegEhYErGktIqsjIdGXnTvEUJwEcjpEp tRsQ== X-Google-Smtp-Source: AGHT+IHIEGcjRtXeVCl037RPnf73SK8aWqRY/nGj7SW5WVEry0+viK0NK0H3jO9sMxMk6L4aT7+Avw== X-Received: by 2002:a05:6a00:3286:b0:7ee:f5d7:cd9a with SMTP id d2e1a72fcca58-7ff6725628cmr24336895b3a.46.1767049685554; Mon, 29 Dec 2025 15:08:05 -0800 (PST) Received: from hexa.. ([2602:feb4:3b:2100:c013:8f5c:baf3:22c3]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7ff7e493123sm30340938b3a.50.2025.12.29.15.08.04 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Dec 2025 15:08:05 -0800 (PST) From: Steve Sakoman To: openembedded-core@lists.openembedded.org Subject: [OE-core][scarthgap 2/5] libsoup: fix CVE-2025-12105 Date: Mon, 29 Dec 2025 15:07:36 -0800 Message-ID: <1ac9ad3faf022684ae709f4494a430aee5fb9906.1767049440.git.steve@sakoman.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: References: MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Mon, 29 Dec 2025 23:08:16 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/228623 From: Changqing Li Refer: https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/481 Signed-off-by: Changqing Li Signed-off-by: Steve Sakoman --- .../libsoup-3.4.4/CVE-2025-12105.patch | 34 +++++++++++++++++++ meta/recipes-support/libsoup/libsoup_3.4.4.bb | 1 + 2 files changed, 35 insertions(+) create mode 100644 meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-12105.patch diff --git a/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-12105.patch b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-12105.patch new file mode 100644 index 0000000000..a460554d6f --- /dev/null +++ b/meta/recipes-support/libsoup/libsoup-3.4.4/CVE-2025-12105.patch @@ -0,0 +1,34 @@ +From 4cbb31f5bf083442325692ff16559fed73f3a6cf Mon Sep 17 00:00:00 2001 +From: Eugene Mutavchi +Date: Fri, 10 Oct 2025 16:24:27 +0000 +Subject: [PATCH] fix 'heap-use-after-free' caused by 'finishing' queue item + twice + +CVE: CVE-2025-12105 +Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/9ba1243a24e442fa5ec44684617a4480027da960] + +Signed-off-by: Changqing Li +--- + libsoup/soup-session.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c +index 9f00b05..649902f 100644 +--- a/libsoup/soup-session.c ++++ b/libsoup/soup-session.c +@@ -2822,8 +2822,10 @@ run_until_read_done (SoupMessage *msg, + if (soup_message_io_in_progress (msg)) + soup_message_io_finished (msg); + item->paused = FALSE; +- item->state = SOUP_MESSAGE_FINISHING; +- soup_session_process_queue_item (item->session, item, FALSE); ++ if (item->state != SOUP_MESSAGE_FINISHED) { ++ item->state = SOUP_MESSAGE_FINISHING; ++ soup_session_process_queue_item (item->session, item, FALSE); ++ } + } + async_send_request_return_result (item, NULL, error); + } +-- +2.34.1 + diff --git a/meta/recipes-support/libsoup/libsoup_3.4.4.bb b/meta/recipes-support/libsoup/libsoup_3.4.4.bb index f64d0d6745..c09b06fec2 100644 --- a/meta/recipes-support/libsoup/libsoup_3.4.4.bb +++ b/meta/recipes-support/libsoup/libsoup_3.4.4.bb @@ -45,6 +45,7 @@ SRC_URI = "${GNOME_MIRROR}/libsoup/${SHRT_VER}/libsoup-${PV}.tar.xz \ file://CVE-2025-4948.patch \ file://CVE-2025-2784.patch \ file://CVE-2025-4945.patch \ + file://CVE-2025-12105.patch \ " SRC_URI[sha256sum] = "291c67725f36ed90ea43efff25064b69c5a2d1981488477c05c481a3b4b0c5aa" From patchwork Mon Dec 29 23:07:37 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Steve Sakoman X-Patchwork-Id: 77641 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 45F57E94100 for ; Mon, 29 Dec 2025 23:08:16 +0000 (UTC) Received: from mail-pf1-f179.google.com (mail-pf1-f179.google.com [209.85.210.179]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.53860.1767049688336249084 for ; Mon, 29 Dec 2025 15:08:08 -0800 Authentication-Results: mx.groups.io; dkim=pass header.i=@sakoman-com.20230601.gappssmtp.com header.s=20230601 header.b=E1soyyko; spf=softfail (domain: sakoman.com, ip: 209.85.210.179, mailfrom: steve@sakoman.com) Received: by mail-pf1-f179.google.com with SMTP id d2e1a72fcca58-7b8bbf16b71so9441973b3a.2 for ; Mon, 29 Dec 2025 15:08:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sakoman-com.20230601.gappssmtp.com; s=20230601; t=1767049687; x=1767654487; darn=lists.openembedded.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=PYh5JgZcehazHMP6ZQBRtmGin0rYtEKRUUNg54baMSA=; b=E1soyykoBecYjQ6IctVO158zd4lIiAAnnLqpnw34PC2JFn3j2WPcIva9WZOBig+U1y tM8lLYJUwdPWtktvfmi2zLQJz4U1zYtJN/yiPQcXAff/wr0z4vb3hZVCZldANlGJ4ZeB DHGTmlVxbX++dlp3iA3/MB9PCvnyWSi6AWKO7Sl5EGEkNRnnolIQ09mNwTEscXFg64CY YKGWeyVeR24xxKYfxx3k5OEnSo/uHais65LJdARjf6fMNWdAp8atEfRwyTiuP5X8RuS9 2QlKbGmp9TYSU1al9S4hGLbEnR6vPW3B5AoCbT1Zunigsj+XmvkqjuHUenzwdr3aoKwv 29Dg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767049687; x=1767654487; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=PYh5JgZcehazHMP6ZQBRtmGin0rYtEKRUUNg54baMSA=; b=LBpydACO7jEhQA8bYdLEZhbShI1hwbPGYgifjEcqBVf/6nv5uIuhF+cLhlOu9VH7t6 B3Ucyf63fFZVlsYjNcTIrIQQbBpUnL8hjLVuUF8UhwmbHGNq1pLw3qpeDnB0ngrNrhz9 ytrB2ounbP2mwp7JZ0nN1HNtb4vsW8lsdv6rFzH+IyKUJcQKuPd5i0MROMGcA3/KNRtt 1iBr7L6Efed/9yi2ye5F9zbzESJ3Y4iuIh1Q7oBk6cNV5kpzAw4KtN0c4mQtSQYyjLnK /JvoimACEsh8PyR9f2qP7UyMc1lw1uXxuywFQKp7CF1yvlaHzDR9NsE6HryJl0vj0rtp afvw== X-Gm-Message-State: AOJu0Yxr6Dcy8ahRaK5ulobUTjJzoe67FSglgmdU/imqEhoiLmftLUdf Xq5QyrYp4tPsOJ73JjVPi0A40BzVfI0gIXSewejWM+4X1roTjm5kIDafeW+JUdy9NvkJc0xD6DI 899b6 X-Gm-Gg: AY/fxX7sSHHvoI7h0DMpjywXwr1VSO7mhD/YaIl3iWtwL29Bl1zk0hUsPv2x2xPFkxh /qEJUy3r6m2Ehktw7cG4LFKjvk1wtlCJDLr1F6lCsxZoR6ZJ2M+bNnY2UNjriyurOkVrvy+zdHR 5xLAN99AIKTa0Z30kOm9y2VgqSe9oaLT+syIpUvIrJxQRytsJfjJSnRZOjmU6qG/GucIsDwrJIU mcssOKN/q14tLHF7keij4FwFKFdpOvyzIbIFf+5/TYcJE9rKFAFInYN6iojEiybCsMcOxt5RQt2 dnrTFWI0IBAKmQ5xUvbDPXVnaJBafg0Ouk2WM8HVHVvZC8R2/1/BSmLxv7V1ZEqJZzN4/Z+/E2l Z2hwOjnkEfJfWnYSE3U4sWAi4QOF8K+N5rMkGfM97NDZ7RvrqZy9IQwaJahdW92dhRFkGbFXp+2 RgcW21LVfSVZJP X-Google-Smtp-Source: AGHT+IEr1lmEgLe5YjWcEfmO67W6mzE49SOFtyqqLf9/mPsdseNJ8DvvIcZ5azCnTJet4cbwWYkbjw== X-Received: by 2002:a05:6a00:3284:b0:7b8:d12f:90ae with SMTP id d2e1a72fcca58-7ff649e44fdmr28645710b3a.21.1767049687317; Mon, 29 Dec 2025 15:08:07 -0800 (PST) Received: from hexa.. ([2602:feb4:3b:2100:c013:8f5c:baf3:22c3]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7ff7e493123sm30340938b3a.50.2025.12.29.15.08.06 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Dec 2025 15:08:06 -0800 (PST) From: Steve Sakoman To: openembedded-core@lists.openembedded.org Subject: [OE-core][scarthgap 3/5] go: Update CVE-2025-58187 Date: Mon, 29 Dec 2025 15:07:37 -0800 Message-ID: <2d6b089de3ef5e062d852eb93e3ff16997e796ef.1767049440.git.steve@sakoman.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: References: MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Mon, 29 Dec 2025 23:08:16 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/228624 From: Vijay Anusuri Upstream-Status: Backport from https://github.com/golang/go/commit/ca6a5545ba18844a97c88a90a385eb6335bb7526 Signed-off-by: Vijay Anusuri Signed-off-by: Steve Sakoman --- meta/recipes-devtools/go/go-1.22.12.inc | 3 +- ...025-58187.patch => CVE-2025-58187-1.patch} | 0 .../go/go/CVE-2025-58187-2.patch | 516 ++++++++++++++++++ 3 files changed, 518 insertions(+), 1 deletion(-) rename meta/recipes-devtools/go/go/{CVE-2025-58187.patch => CVE-2025-58187-1.patch} (100%) create mode 100644 meta/recipes-devtools/go/go/CVE-2025-58187-2.patch diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc index 825b8f4d68..0729b5eec0 100644 --- a/meta/recipes-devtools/go/go-1.22.12.inc +++ b/meta/recipes-devtools/go/go-1.22.12.inc @@ -22,7 +22,8 @@ SRC_URI += "\ file://CVE-2025-47907.patch \ file://CVE-2025-47906.patch \ file://CVE-2025-58185.patch \ - file://CVE-2025-58187.patch \ + file://CVE-2025-58187-1.patch \ + file://CVE-2025-58187-2.patch \ file://CVE-2025-58188.patch \ file://CVE-2025-58189.patch \ file://CVE-2025-47912.patch \ diff --git a/meta/recipes-devtools/go/go/CVE-2025-58187.patch b/meta/recipes-devtools/go/go/CVE-2025-58187-1.patch similarity index 100% rename from meta/recipes-devtools/go/go/CVE-2025-58187.patch rename to meta/recipes-devtools/go/go/CVE-2025-58187-1.patch diff --git a/meta/recipes-devtools/go/go/CVE-2025-58187-2.patch b/meta/recipes-devtools/go/go/CVE-2025-58187-2.patch new file mode 100644 index 0000000000..b55dac2dc2 --- /dev/null +++ b/meta/recipes-devtools/go/go/CVE-2025-58187-2.patch @@ -0,0 +1,516 @@ +From ca6a5545ba18844a97c88a90a385eb6335bb7526 Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker +Date: Thu, 9 Oct 2025 13:35:24 -0700 +Subject: [PATCH] [release-branch.go1.24] crypto/x509: rework fix for + CVE-2025-58187 + +In CL 709854 we enabled strict validation for a number of properties of +domain names (and their constraints). This caused significant breakage, +since we didn't previously disallow the creation of certificates which +contained these malformed domains. + +Rollback a number of the properties we enforced, making domainNameValid +only enforce the same properties that domainToReverseLabels does. Since +this also undoes some of the DoS protections our initial fix enabled, +this change also adds caching of constraints in isValid (which perhaps +is the fix we should've initially chosen). + +Updates #75835 +Updates #75828 +Fixes #75860 + +Change-Id: Ie6ca6b4f30e9b8a143692b64757f7bbf4671ed0e +Reviewed-on: https://go-review.googlesource.com/c/go/+/710735 +LUCI-TryBot-Result: Go LUCI +Reviewed-by: Damien Neil +(cherry picked from commit 1cd71689f2ed8f07031a0cc58fc3586ca501839f) +Reviewed-on: https://go-review.googlesource.com/c/go/+/710879 +Reviewed-by: Michael Pratt +Auto-Submit: Michael Pratt + +Upstream-Status: Backport [https://github.com/golang/go/commit/ca6a5545ba18844a97c88a90a385eb6335bb7526] +CVE: CVE-2025-58187 +Signed-off-by: Vijay Anusuri +--- + src/crypto/x509/name_constraints_test.go | 66 +++++++++++++++++-- + src/crypto/x509/parser.go | 57 +++++++++++----- + src/crypto/x509/parser_test.go | 84 +++++++++++++++++++++--- + src/crypto/x509/verify.go | 53 ++++++++++----- + src/crypto/x509/verify_test.go | 2 +- + 5 files changed, 213 insertions(+), 49 deletions(-) + +diff --git a/src/crypto/x509/name_constraints_test.go b/src/crypto/x509/name_constraints_test.go +index 9aaa6d7..78263fc 100644 +--- a/src/crypto/x509/name_constraints_test.go ++++ b/src/crypto/x509/name_constraints_test.go +@@ -1456,7 +1456,63 @@ var nameConstraintsTests = []nameConstraintsTest{ + expectedError: "incompatible key usage", + }, + +- // #77: if several EKUs are requested, satisfying any of them is sufficient. ++ // An invalid DNS SAN should be detected only at validation time so ++ // that we can process CA certificates in the wild that have invalid SANs. ++ // See https://github.com/golang/go/issues/23995 ++ ++ // #77: an invalid DNS or mail SAN will not be detected if name constraint ++ // checking is not triggered. ++ { ++ roots: make([]constraintsSpec, 1), ++ intermediates: [][]constraintsSpec{ ++ { ++ {}, ++ }, ++ }, ++ leaf: leafSpec{ ++ sans: []string{"dns:this is invalid", "email:this @ is invalid"}, ++ }, ++ }, ++ ++ // #78: an invalid DNS SAN will be detected if any name constraint checking ++ // is triggered. ++ { ++ roots: []constraintsSpec{ ++ { ++ bad: []string{"uri:"}, ++ }, ++ }, ++ intermediates: [][]constraintsSpec{ ++ { ++ {}, ++ }, ++ }, ++ leaf: leafSpec{ ++ sans: []string{"dns:this is invalid"}, ++ }, ++ expectedError: "cannot parse dnsName", ++ }, ++ ++ // #79: an invalid email SAN will be detected if any name constraint ++ // checking is triggered. ++ { ++ roots: []constraintsSpec{ ++ { ++ bad: []string{"uri:"}, ++ }, ++ }, ++ intermediates: [][]constraintsSpec{ ++ { ++ {}, ++ }, ++ }, ++ leaf: leafSpec{ ++ sans: []string{"email:this @ is invalid"}, ++ }, ++ expectedError: "cannot parse rfc822Name", ++ }, ++ ++ // #80: if several EKUs are requested, satisfying any of them is sufficient. + { + roots: make([]constraintsSpec, 1), + intermediates: [][]constraintsSpec{ +@@ -1471,7 +1527,7 @@ var nameConstraintsTests = []nameConstraintsTest{ + requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageEmailProtection}, + }, + +- // #78: EKUs that are not asserted in VerifyOpts are not required to be ++ // #81: EKUs that are not asserted in VerifyOpts are not required to be + // nested. + { + roots: make([]constraintsSpec, 1), +@@ -1490,7 +1546,7 @@ var nameConstraintsTests = []nameConstraintsTest{ + }, + }, + +- // #79: a certificate without SANs and CN is accepted in a constrained chain. ++ // #82: a certificate without SANs and CN is accepted in a constrained chain. + { + roots: []constraintsSpec{ + { +@@ -1507,7 +1563,7 @@ var nameConstraintsTests = []nameConstraintsTest{ + }, + }, + +- // #80: a certificate without SANs and with a CN that does not parse as a ++ // #83: a certificate without SANs and with a CN that does not parse as a + // hostname is accepted in a constrained chain. + { + roots: []constraintsSpec{ +@@ -1526,7 +1582,7 @@ var nameConstraintsTests = []nameConstraintsTest{ + }, + }, + +- // #81: a certificate with SANs and CN is accepted in a constrained chain. ++ // #84: a certificate with SANs and CN is accepted in a constrained chain. + { + roots: []constraintsSpec{ + { +diff --git a/src/crypto/x509/parser.go b/src/crypto/x509/parser.go +index 9a3bcd6..f8beff7 100644 +--- a/src/crypto/x509/parser.go ++++ b/src/crypto/x509/parser.go +@@ -378,14 +378,10 @@ func parseSANExtension(der cryptobyte.String) (dnsNames, emailAddresses []string + if err := isIA5String(email); err != nil { + return errors.New("x509: SAN rfc822Name is malformed") + } +- parsed, ok := parseRFC2821Mailbox(email) +- if !ok || (ok && !domainNameValid(parsed.domain, false)) { +- return errors.New("x509: SAN rfc822Name is malformed") +- } + emailAddresses = append(emailAddresses, email) + case nameTypeDNS: + name := string(data) +- if err := isIA5String(name); err != nil || (err == nil && !domainNameValid(name, false)) { ++ if err := isIA5String(name); err != nil { + return errors.New("x509: SAN dNSName is malformed") + } + dnsNames = append(dnsNames, string(name)) +@@ -395,9 +391,12 @@ func parseSANExtension(der cryptobyte.String) (dnsNames, emailAddresses []string + return errors.New("x509: SAN uniformResourceIdentifier is malformed") + } + uri, err := url.Parse(uriStr) +- if err != nil || (err == nil && uri.Host != "" && !domainNameValid(uri.Host, false)) { ++ if err != nil { + return fmt.Errorf("x509: cannot parse URI %q: %s", uriStr, err) + } ++ if len(uri.Host) > 0 && !domainNameValid(uri.Host, false) { ++ return fmt.Errorf("x509: cannot parse URI %q: invalid domain", uriStr) ++ } + uris = append(uris, uri) + case nameTypeIP: + switch len(data) { +@@ -1176,36 +1175,58 @@ func ParseRevocationList(der []byte) (*RevocationList, error) { + return rl, nil + } + +-// domainNameValid does minimal domain name validity checking. In particular it +-// enforces the following properties: +-// - names cannot have the trailing period +-// - names can only have a leading period if constraint is true +-// - names must be <= 253 characters +-// - names cannot have empty labels +-// - names cannot labels that are longer than 63 characters +-// +-// Note that this does not enforce the LDH requirements for domain names. ++// domainNameValid is an alloc-less version of the checks that ++// domainToReverseLabels does. + func domainNameValid(s string, constraint bool) bool { +- if len(s) == 0 && constraint { ++ // TODO(#75835): This function omits a number of checks which we ++ // really should be doing to enforce that domain names are valid names per ++ // RFC 1034. We previously enabled these checks, but this broke a ++ // significant number of certificates we previously considered valid, and we ++ // happily create via CreateCertificate (et al). We should enable these ++ // checks, but will need to gate them behind a GODEBUG. ++ // ++ // I have left the checks we previously enabled, noted with "TODO(#75835)" so ++ // that we can easily re-enable them once we unbreak everyone. ++ ++ // TODO(#75835): this should only be true for constraints. ++ if len(s) == 0 { + return true + } +- if len(s) == 0 || (!constraint && s[0] == '.') || s[len(s)-1] == '.' || len(s) > 253 { ++ ++ // Do not allow trailing period (FQDN format is not allowed in SANs or ++ // constraints). ++ if s[len(s)-1] == '.' { + return false + } ++ ++ // TODO(#75835): domains must have at least one label, cannot have ++ // a leading empty label, and cannot be longer than 253 characters. ++ // if len(s) == 0 || (!constraint && s[0] == '.') || len(s) > 253 { ++ // return false ++ // } ++ + lastDot := -1 + if constraint && s[0] == '.' { + s = s[1:] + } + + for i := 0; i <= len(s); i++ { ++ if i < len(s) && (s[i] < 33 || s[i] > 126) { ++ // Invalid character. ++ return false ++ } + if i == len(s) || s[i] == '.' { + labelLen := i + if lastDot >= 0 { + labelLen -= lastDot + 1 + } +- if labelLen == 0 || labelLen > 63 { ++ if labelLen == 0 { + return false + } ++ // TODO(#75835): labels cannot be longer than 63 characters. ++ // if labelLen > 63 { ++ // return false ++ // } + lastDot = i + } + } +diff --git a/src/crypto/x509/parser_test.go b/src/crypto/x509/parser_test.go +index a6cdfb8..35f872a 100644 +--- a/src/crypto/x509/parser_test.go ++++ b/src/crypto/x509/parser_test.go +@@ -5,6 +5,9 @@ + package x509 + + import ( ++ "crypto/ecdsa" ++ "crypto/elliptic" ++ "crypto/rand" + "encoding/asn1" + "strings" + "testing" +@@ -110,7 +113,31 @@ func TestDomainNameValid(t *testing.T) { + constraint bool + valid bool + }{ +- {"empty name, name", "", false, false}, ++ // TODO(#75835): these tests are for stricter name validation, which we ++ // had to disable. Once we reenable these strict checks, behind a ++ // GODEBUG, we should add them back in. ++ // {"empty name, name", "", false, false}, ++ // {"254 char label, name", strings.Repeat("a.a", 84) + "aaa", false, false}, ++ // {"254 char label, constraint", strings.Repeat("a.a", 84) + "aaa", true, false}, ++ // {"253 char label, name", strings.Repeat("a.a", 84) + "aa", false, false}, ++ // {"253 char label, constraint", strings.Repeat("a.a", 84) + "aa", true, false}, ++ // {"64 char single label, name", strings.Repeat("a", 64), false, false}, ++ // {"64 char single label, constraint", strings.Repeat("a", 64), true, false}, ++ // {"64 char label, name", "a." + strings.Repeat("a", 64), false, false}, ++ // {"64 char label, constraint", "a." + strings.Repeat("a", 64), true, false}, ++ ++ // TODO(#75835): these are the inverse of the tests above, they should be removed ++ // once the strict checking is enabled. ++ {"254 char label, name", strings.Repeat("a.a", 84) + "aaa", false, true}, ++ {"254 char label, constraint", strings.Repeat("a.a", 84) + "aaa", true, true}, ++ {"253 char label, name", strings.Repeat("a.a", 84) + "aa", false, true}, ++ {"253 char label, constraint", strings.Repeat("a.a", 84) + "aa", true, true}, ++ {"64 char single label, name", strings.Repeat("a", 64), false, true}, ++ {"64 char single label, constraint", strings.Repeat("a", 64), true, true}, ++ {"64 char label, name", "a." + strings.Repeat("a", 64), false, true}, ++ {"64 char label, constraint", "a." + strings.Repeat("a", 64), true, true}, ++ ++ // Check we properly enforce properties of domain names. + {"empty name, constraint", "", true, true}, + {"empty label, name", "a..a", false, false}, + {"empty label, constraint", "a..a", true, false}, +@@ -124,23 +151,60 @@ func TestDomainNameValid(t *testing.T) { + {"trailing period, constraint", "a.", true, false}, + {"bare label, name", "a", false, true}, + {"bare label, constraint", "a", true, true}, +- {"254 char label, name", strings.Repeat("a.a", 84) + "aaa", false, false}, +- {"254 char label, constraint", strings.Repeat("a.a", 84) + "aaa", true, false}, +- {"253 char label, name", strings.Repeat("a.a", 84) + "aa", false, false}, +- {"253 char label, constraint", strings.Repeat("a.a", 84) + "aa", true, false}, +- {"64 char single label, name", strings.Repeat("a", 64), false, false}, +- {"64 char single label, constraint", strings.Repeat("a", 64), true, false}, + {"63 char single label, name", strings.Repeat("a", 63), false, true}, + {"63 char single label, constraint", strings.Repeat("a", 63), true, true}, +- {"64 char label, name", "a." + strings.Repeat("a", 64), false, false}, +- {"64 char label, constraint", "a." + strings.Repeat("a", 64), true, false}, + {"63 char label, name", "a." + strings.Repeat("a", 63), false, true}, + {"63 char label, constraint", "a." + strings.Repeat("a", 63), true, true}, + } { + t.Run(tc.name, func(t *testing.T) { +- if tc.valid != domainNameValid(tc.dnsName, tc.constraint) { ++ valid := domainNameValid(tc.dnsName, tc.constraint) ++ if tc.valid != valid { + t.Errorf("domainNameValid(%q, %t) = %v; want %v", tc.dnsName, tc.constraint, !tc.valid, tc.valid) + } ++ // Also check that we enforce the same properties as domainToReverseLabels ++ trimmedName := tc.dnsName ++ if tc.constraint && len(trimmedName) > 1 && trimmedName[0] == '.' { ++ trimmedName = trimmedName[1:] ++ } ++ _, revValid := domainToReverseLabels(trimmedName) ++ if valid != revValid { ++ t.Errorf("domainNameValid(%q, %t) = %t != domainToReverseLabels(%q) = %t", tc.dnsName, tc.constraint, valid, trimmedName, revValid) ++ } + }) + } + } ++ ++func TestRoundtripWeirdSANs(t *testing.T) { ++ // TODO(#75835): check that certificates we create with CreateCertificate that have malformed SAN values ++ // can be parsed by ParseCertificate. We should eventually restrict this, but for now we have to maintain ++ // this property as people have been relying on it. ++ k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) ++ if err != nil { ++ t.Fatal(err) ++ } ++ badNames := []string{ ++ "baredomain", ++ "baredomain.", ++ strings.Repeat("a", 255), ++ strings.Repeat("a", 65) + ".com", ++ } ++ tmpl := &Certificate{ ++ EmailAddresses: badNames, ++ DNSNames: badNames, ++ } ++ b, err := CreateCertificate(rand.Reader, tmpl, tmpl, &k.PublicKey, k) ++ if err != nil { ++ t.Fatal(err) ++ } ++ _, err = ParseCertificate(b) ++ if err != nil { ++ t.Fatalf("Couldn't roundtrip certificate: %v", err) ++ } ++} ++ ++func FuzzDomainNameValid(f *testing.F) { ++ f.Fuzz(func(t *testing.T, data string) { ++ domainNameValid(data, false) ++ domainNameValid(data, true) ++ }) ++} +diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go +index 14cd23f..e670786 100644 +--- a/src/crypto/x509/verify.go ++++ b/src/crypto/x509/verify.go +@@ -393,7 +393,7 @@ func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) { + return reverseLabels, true + } + +-func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string) (bool, error) { ++func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]string) (bool, error) { + // If the constraint contains an @, then it specifies an exact mailbox + // name. + if strings.Contains(constraint, "@") { +@@ -406,10 +406,10 @@ func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string) (bool, erro + + // Otherwise the constraint is like a DNS constraint of the domain part + // of the mailbox. +- return matchDomainConstraint(mailbox.domain, constraint) ++ return matchDomainConstraint(mailbox.domain, constraint, reversedDomainsCache, reversedConstraintsCache) + } + +-func matchURIConstraint(uri *url.URL, constraint string) (bool, error) { ++func matchURIConstraint(uri *url.URL, constraint string, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]string) (bool, error) { + // From RFC 5280, Section 4.2.1.10: + // “a uniformResourceIdentifier that does not include an authority + // component with a host name specified as a fully qualified domain +@@ -438,7 +438,7 @@ func matchURIConstraint(uri *url.URL, constraint string) (bool, error) { + return false, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", uri.String()) + } + +- return matchDomainConstraint(host, constraint) ++ return matchDomainConstraint(host, constraint, reversedDomainsCache, reversedConstraintsCache) + } + + func matchIPConstraint(ip net.IP, constraint *net.IPNet) (bool, error) { +@@ -455,16 +455,21 @@ func matchIPConstraint(ip net.IP, constraint *net.IPNet) (bool, error) { + return true, nil + } + +-func matchDomainConstraint(domain, constraint string) (bool, error) { ++func matchDomainConstraint(domain, constraint string, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]string) (bool, error) { + // The meaning of zero length constraints is not specified, but this + // code follows NSS and accepts them as matching everything. + if len(constraint) == 0 { + return true, nil + } + +- domainLabels, ok := domainToReverseLabels(domain) +- if !ok { +- return false, fmt.Errorf("x509: internal error: cannot parse domain %q", domain) ++ domainLabels, found := reversedDomainsCache[domain] ++ if !found { ++ var ok bool ++ domainLabels, ok = domainToReverseLabels(domain) ++ if !ok { ++ return false, fmt.Errorf("x509: internal error: cannot parse domain %q", domain) ++ } ++ reversedDomainsCache[domain] = domainLabels + } + + // RFC 5280 says that a leading period in a domain name means that at +@@ -478,9 +483,14 @@ func matchDomainConstraint(domain, constraint string) (bool, error) { + constraint = constraint[1:] + } + +- constraintLabels, ok := domainToReverseLabels(constraint) +- if !ok { +- return false, fmt.Errorf("x509: internal error: cannot parse domain %q", constraint) ++ constraintLabels, found := reversedConstraintsCache[constraint] ++ if !found { ++ var ok bool ++ constraintLabels, ok = domainToReverseLabels(constraint) ++ if !ok { ++ return false, fmt.Errorf("x509: internal error: cannot parse domain %q", constraint) ++ } ++ reversedConstraintsCache[constraint] = constraintLabels + } + + if len(domainLabels) < len(constraintLabels) || +@@ -601,6 +611,19 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V + } + } + ++ // Each time we do constraint checking, we need to check the constraints in ++ // the current certificate against all of the names that preceded it. We ++ // reverse these names using domainToReverseLabels, which is a relatively ++ // expensive operation. Since we check each name against each constraint, ++ // this requires us to do N*C calls to domainToReverseLabels (where N is the ++ // total number of names that preceed the certificate, and C is the total ++ // number of constraints in the certificate). By caching the results of ++ // calling domainToReverseLabels, we can reduce that to N+C calls at the ++ // cost of keeping all of the parsed names and constraints in memory until ++ // we return from isValid. ++ reversedDomainsCache := map[string][]string{} ++ reversedConstraintsCache := map[string][]string{} ++ + if (certType == intermediateCertificate || certType == rootCertificate) && + c.hasNameConstraints() { + toCheck := []*Certificate{} +@@ -621,20 +644,20 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V + + if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "email address", name, mailbox, + func(parsedName, constraint any) (bool, error) { +- return matchEmailConstraint(parsedName.(rfc2821Mailbox), constraint.(string)) ++ return matchEmailConstraint(parsedName.(rfc2821Mailbox), constraint.(string), reversedDomainsCache, reversedConstraintsCache) + }, c.PermittedEmailAddresses, c.ExcludedEmailAddresses); err != nil { + return err + } + + case nameTypeDNS: + name := string(data) +- if _, ok := domainToReverseLabels(name); !ok { ++ if !domainNameValid(name, false) { + return fmt.Errorf("x509: cannot parse dnsName %q", name) + } + + if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "DNS name", name, name, + func(parsedName, constraint any) (bool, error) { +- return matchDomainConstraint(parsedName.(string), constraint.(string)) ++ return matchDomainConstraint(parsedName.(string), constraint.(string), reversedDomainsCache, reversedConstraintsCache) + }, c.PermittedDNSDomains, c.ExcludedDNSDomains); err != nil { + return err + } +@@ -648,7 +671,7 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V + + if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "URI", name, uri, + func(parsedName, constraint any) (bool, error) { +- return matchURIConstraint(parsedName.(*url.URL), constraint.(string)) ++ return matchURIConstraint(parsedName.(*url.URL), constraint.(string), reversedDomainsCache, reversedConstraintsCache) + }, c.PermittedURIDomains, c.ExcludedURIDomains); err != nil { + return err + } +diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go +index 4a7d8da..ba5c392 100644 +--- a/src/crypto/x509/verify_test.go ++++ b/src/crypto/x509/verify_test.go +@@ -1549,7 +1549,7 @@ var nameConstraintTests = []struct { + + func TestNameConstraints(t *testing.T) { + for i, test := range nameConstraintTests { +- result, err := matchDomainConstraint(test.domain, test.constraint) ++ result, err := matchDomainConstraint(test.domain, test.constraint, map[string][]string{}, map[string][]string{}) + + if err != nil && !test.expectError { + t.Errorf("unexpected error for test #%d: domain=%s, constraint=%s, err=%s", i, test.domain, test.constraint, err) +-- +2.43.0 + From patchwork Mon Dec 29 23:07:38 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Steve Sakoman X-Patchwork-Id: 77643 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 52F3AE94102 for ; Mon, 29 Dec 2025 23:08:16 +0000 (UTC) Received: from mail-pf1-f178.google.com (mail-pf1-f178.google.com [209.85.210.178]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.53862.1767049689851047975 for ; Mon, 29 Dec 2025 15:08:09 -0800 Authentication-Results: mx.groups.io; dkim=pass header.i=@sakoman-com.20230601.gappssmtp.com header.s=20230601 header.b=N4lh5LlN; spf=softfail (domain: sakoman.com, ip: 209.85.210.178, mailfrom: steve@sakoman.com) Received: by mail-pf1-f178.google.com with SMTP id d2e1a72fcca58-7ba55660769so7378149b3a.1 for ; Mon, 29 Dec 2025 15:08:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sakoman-com.20230601.gappssmtp.com; s=20230601; t=1767049689; x=1767654489; darn=lists.openembedded.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=QMScY1eopowI61GVfNwZKwTLzXYiMSRKP9J8MFZQj7o=; b=N4lh5LlN+EINgQ6JAkW4oHjqPxiP9C6UJ7gvYFovZd8JfvgLTTt9+mZ2NiVGyxkH9x RRPBdYlQG52PR1P+FxhMGnR0850E+imwdj0NCStVvLVb2x4Oz+1I/vJCjvLm8fRqxCQ3 0o8BZRec0CzjdoGDOdmDbwWY9hiSadAqD5IcYPVqcYjJt8bUJxc/ClR+fDutvyrNcGcM c9R2FC2U9BcwIbG21M5V3Pn+os8QbyCa146YrZshn6y6VSob5OMjYJL5ohT7NzAn0iCV rVPisNNjVgLqPeKjZeBtwLXIZ7NcsJS+iRJ2RbdV9q7NCafiCzKWn400F1bxDoqrtysg oJ/g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767049689; x=1767654489; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=QMScY1eopowI61GVfNwZKwTLzXYiMSRKP9J8MFZQj7o=; b=ZTVQ6wO1oF/Uen22h/iA7gyUYW5DE5vhlfjl0byLLRc/g3i1InCOb3R0FqPYPUZint xcW0u2LVUnXyhYUXhmeW3PwocorizRGv+TU5N+GwlJKz7XChWECzSvBzpySCWa/YTID2 HjnvaQclrKh1BkJYmI06KJaydzKgKkDJkh+nuLFSZNtBA6SgtMIxw7sWR7Vsucgsv4LH 5DL/OZ8dVMO6ZdB2g/AS7B0BWfJxwh+9BwfKCPn5I5X9IIDb0fFvc+FxgIyi8+tXXLxD BcXEBAmyAN9l4K4zLcFHyJYX5RehRbVaza/89J1E3jx/BXN7H3I6vNb7JPO9jhQBkf2+ WtTQ== X-Gm-Message-State: AOJu0YwI3TjAhsyTHUo8A5wgqmvY/KcCTiVpRPpCPBAZWpYakLKQRr7b y18whPoBu/hys/tut62x5B0ou0SuURRLt2fNwVTqeFZ9P54XyxM9lfjIElovuAWpoPlk0j7JrtO K0skp X-Gm-Gg: AY/fxX6me4i0ORbcIEOrLK0Wc7UFCuuEISb9PeRS/sze+7+3exNzDVmE1jv5BFg9BCW gok7C46gIXKrwd+rKp2nRnu4b4xTPJgDW5dl2BDSMFhht4k1zqhYo1xcjPBU9NqAOgxpWvzlee2 jIHkrXNJL2CSOtyGOymvkFdeF+yNkoiw9wT6jed0Ew1ni4Xv/HDjh70ePb5rJHieK0i2GmAM/n2 oYKfifpgGys26nIK5T4Fya0dj60MZoFTXipJLZVZfEqX+jXFHRZlGBEkBK7gHydO8eF+/bKe+ct ERM8fwgYSoEby7wy5dZUn4TN+mNUB3YwzK2TzT56AyTTIVa/M/kefV2UNMEluK+wu4VZ4LS2bFU TKsXH/cHzM7d0Nq8FTOgtt6kXa0Zoy/4tuJmISd1q40xFNtVHRrtFZ+DiUZSwDiou+wSbZE0nqB W0Tg== X-Google-Smtp-Source: AGHT+IGFGURwggZAQhUYdrvP+kelulJiUAE2WA9k1ZPrisKTQvvr1HLX2kbG26oY/qgLzWuKieaOBg== X-Received: by 2002:a05:6a00:aa04:b0:7e8:4471:8c0 with SMTP id d2e1a72fcca58-7ff6627a1damr30384008b3a.33.1767049689001; Mon, 29 Dec 2025 15:08:09 -0800 (PST) Received: from hexa.. ([2602:feb4:3b:2100:c013:8f5c:baf3:22c3]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7ff7e493123sm30340938b3a.50.2025.12.29.15.08.08 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Dec 2025 15:08:08 -0800 (PST) From: Steve Sakoman To: openembedded-core@lists.openembedded.org Subject: [OE-core][scarthgap 4/5] go: Fix CVE-2025-61727 Date: Mon, 29 Dec 2025 15:07:38 -0800 Message-ID: <647e151485bd10a8bbbdbae4825791723c9a5d8e.1767049440.git.steve@sakoman.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: References: MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Mon, 29 Dec 2025 23:08:16 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/228625 From: Vijay Anusuri Upstream-Status: Backport from https://github.com/golang/go/commit/04db77a423cac75bb82cc9a6859991ae9c016344 Signed-off-by: Vijay Anusuri Signed-off-by: Steve Sakoman --- meta/recipes-devtools/go/go-1.22.12.inc | 1 + .../go/go/CVE-2025-61727.patch | 226 ++++++++++++++++++ 2 files changed, 227 insertions(+) create mode 100644 meta/recipes-devtools/go/go/CVE-2025-61727.patch diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc index 0729b5eec0..664ccf3edc 100644 --- a/meta/recipes-devtools/go/go-1.22.12.inc +++ b/meta/recipes-devtools/go/go-1.22.12.inc @@ -29,6 +29,7 @@ SRC_URI += "\ file://CVE-2025-47912.patch \ file://CVE-2025-61723.patch \ file://CVE-2025-61724.patch \ + file://CVE-2025-61727.patch \ " SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71" diff --git a/meta/recipes-devtools/go/go/CVE-2025-61727.patch b/meta/recipes-devtools/go/go/CVE-2025-61727.patch new file mode 100644 index 0000000000..e87621ef99 --- /dev/null +++ b/meta/recipes-devtools/go/go/CVE-2025-61727.patch @@ -0,0 +1,226 @@ +From 04db77a423cac75bb82cc9a6859991ae9c016344 Mon Sep 17 00:00:00 2001 +From: Roland Shoemaker +Date: Mon, 24 Nov 2025 08:46:08 -0800 +Subject: [PATCH] [release-branch.go1.24] crypto/x509: excluded subdomain + constraints preclude wildcard SANs + +When evaluating name constraints in a certificate chain, the presence of +an excluded subdomain constraint (e.g., excluding "test.example.com") +should preclude the use of a wildcard SAN (e.g., "*.example.com"). + +Fixes #76442 +Fixes #76463 +Fixes CVE-2025-61727 + +Change-Id: I42a0da010cb36d2ec9d1239ae3f61cf25eb78bba +Reviewed-on: https://go-review.googlesource.com/c/go/+/724401 +Reviewed-by: Nicholas Husin +Reviewed-by: Daniel McCarney +LUCI-TryBot-Result: Go LUCI +Reviewed-by: Nicholas Husin +Reviewed-by: Neal Patel + +Upstream-Status: Backport [https://github.com/golang/go/commit/04db77a423cac75bb82cc9a6859991ae9c016344] +CVE: CVE-2025-61727 +Signed-off-by: Vijay Anusuri +--- + src/crypto/x509/name_constraints_test.go | 34 ++++++++++++++++++++ + src/crypto/x509/verify.go | 40 +++++++++++++++--------- + src/crypto/x509/verify_test.go | 2 +- + 3 files changed, 60 insertions(+), 16 deletions(-) + +diff --git a/src/crypto/x509/name_constraints_test.go b/src/crypto/x509/name_constraints_test.go +index a5851845164d10..bc91b28401fce5 100644 +--- a/src/crypto/x509/name_constraints_test.go ++++ b/src/crypto/x509/name_constraints_test.go +@@ -1624,6 +1624,40 @@ var nameConstraintsTests = []nameConstraintsTest{ + }, + expectedError: "URI with IP", + }, ++ // #87: subdomain excluded constraints preclude wildcard names ++ { ++ roots: []constraintsSpec{ ++ { ++ bad: []string{"dns:foo.example.com"}, ++ }, ++ }, ++ intermediates: [][]constraintsSpec{ ++ { ++ {}, ++ }, ++ }, ++ leaf: leafSpec{ ++ sans: []string{"dns:*.example.com"}, ++ }, ++ expectedError: "\"*.example.com\" is excluded by constraint \"foo.example.com\"", ++ }, ++ // #88: wildcard names are not matched by subdomain permitted constraints ++ { ++ roots: []constraintsSpec{ ++ { ++ ok: []string{"dns:foo.example.com"}, ++ }, ++ }, ++ intermediates: [][]constraintsSpec{ ++ { ++ {}, ++ }, ++ }, ++ leaf: leafSpec{ ++ sans: []string{"dns:*.example.com"}, ++ }, ++ expectedError: "\"*.example.com\" is not permitted", ++ }, + } + + func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) { +diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go +index bf7e7ec058db2b..9175fa4dc147a2 100644 +--- a/src/crypto/x509/verify.go ++++ b/src/crypto/x509/verify.go +@@ -429,7 +429,7 @@ func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) { + return reverseLabels, true + } + +-func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]string) (bool, error) { ++func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string, excluded bool, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]string) (bool, error) { + // If the constraint contains an @, then it specifies an exact mailbox + // name. + if strings.Contains(constraint, "@") { +@@ -442,10 +442,10 @@ func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string, reversedDom + + // Otherwise the constraint is like a DNS constraint of the domain part + // of the mailbox. +- return matchDomainConstraint(mailbox.domain, constraint, reversedDomainsCache, reversedConstraintsCache) ++ return matchDomainConstraint(mailbox.domain, constraint, excluded, reversedDomainsCache, reversedConstraintsCache) + } + +-func matchURIConstraint(uri *url.URL, constraint string, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]string) (bool, error) { ++func matchURIConstraint(uri *url.URL, constraint string, excluded bool, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]string) (bool, error) { + // From RFC 5280, Section 4.2.1.10: + // “a uniformResourceIdentifier that does not include an authority + // component with a host name specified as a fully qualified domain +@@ -474,7 +474,7 @@ func matchURIConstraint(uri *url.URL, constraint string, reversedDomainsCache ma + return false, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", uri.String()) + } + +- return matchDomainConstraint(host, constraint, reversedDomainsCache, reversedConstraintsCache) ++ return matchDomainConstraint(host, constraint, excluded, reversedDomainsCache, reversedConstraintsCache) + } + + func matchIPConstraint(ip net.IP, constraint *net.IPNet) (bool, error) { +@@ -491,7 +491,7 @@ func matchIPConstraint(ip net.IP, constraint *net.IPNet) (bool, error) { + return true, nil + } + +-func matchDomainConstraint(domain, constraint string, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]string) (bool, error) { ++func matchDomainConstraint(domain, constraint string, excluded bool, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]string) (bool, error) { + // The meaning of zero length constraints is not specified, but this + // code follows NSS and accepts them as matching everything. + if len(constraint) == 0 { +@@ -508,6 +508,11 @@ func matchDomainConstraint(domain, constraint string, reversedDomainsCache map[s + reversedDomainsCache[domain] = domainLabels + } + ++ wildcardDomain := false ++ if len(domain) > 0 && domain[0] == '*' { ++ wildcardDomain = true ++ } ++ + // RFC 5280 says that a leading period in a domain name means that at + // least one label must be prepended, but only for URI and email + // constraints, not DNS constraints. The code also supports that +@@ -534,6 +539,11 @@ func matchDomainConstraint(domain, constraint string, reversedDomainsCache map[s + return false, nil + } + ++ if excluded && wildcardDomain && len(domainLabels) > 1 && len(constraintLabels) > 0 { ++ domainLabels = domainLabels[:len(domainLabels)-1] ++ constraintLabels = constraintLabels[:len(constraintLabels)-1] ++ } ++ + for i, constraintLabel := range constraintLabels { + if !strings.EqualFold(constraintLabel, domainLabels[i]) { + return false, nil +@@ -553,7 +563,7 @@ func (c *Certificate) checkNameConstraints(count *int, + nameType string, + name string, + parsedName any, +- match func(parsedName, constraint any) (match bool, err error), ++ match func(parsedName, constraint any, excluded bool) (match bool, err error), + permitted, excluded any) error { + + excludedValue := reflect.ValueOf(excluded) +@@ -565,7 +575,7 @@ func (c *Certificate) checkNameConstraints(count *int, + + for i := 0; i < excludedValue.Len(); i++ { + constraint := excludedValue.Index(i).Interface() +- match, err := match(parsedName, constraint) ++ match, err := match(parsedName, constraint, true) + if err != nil { + return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()} + } +@@ -587,7 +597,7 @@ func (c *Certificate) checkNameConstraints(count *int, + constraint := permittedValue.Index(i).Interface() + + var err error +- if ok, err = match(parsedName, constraint); err != nil { ++ if ok, err = match(parsedName, constraint, false); err != nil { + return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()} + } + +@@ -679,8 +689,8 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V + } + + if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "email address", name, mailbox, +- func(parsedName, constraint any) (bool, error) { +- return matchEmailConstraint(parsedName.(rfc2821Mailbox), constraint.(string), reversedDomainsCache, reversedConstraintsCache) ++ func(parsedName, constraint any, excluded bool) (bool, error) { ++ return matchEmailConstraint(parsedName.(rfc2821Mailbox), constraint.(string), excluded, reversedDomainsCache, reversedConstraintsCache) + }, c.PermittedEmailAddresses, c.ExcludedEmailAddresses); err != nil { + return err + } +@@ -692,8 +702,8 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V + } + + if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "DNS name", name, name, +- func(parsedName, constraint any) (bool, error) { +- return matchDomainConstraint(parsedName.(string), constraint.(string), reversedDomainsCache, reversedConstraintsCache) ++ func(parsedName, constraint any, excluded bool) (bool, error) { ++ return matchDomainConstraint(parsedName.(string), constraint.(string), excluded, reversedDomainsCache, reversedConstraintsCache) + }, c.PermittedDNSDomains, c.ExcludedDNSDomains); err != nil { + return err + } +@@ -706,8 +716,8 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V + } + + if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "URI", name, uri, +- func(parsedName, constraint any) (bool, error) { +- return matchURIConstraint(parsedName.(*url.URL), constraint.(string), reversedDomainsCache, reversedConstraintsCache) ++ func(parsedName, constraint any, excluded bool) (bool, error) { ++ return matchURIConstraint(parsedName.(*url.URL), constraint.(string), excluded, reversedDomainsCache, reversedConstraintsCache) + }, c.PermittedURIDomains, c.ExcludedURIDomains); err != nil { + return err + } +@@ -719,7 +729,7 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V + } + + if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "IP address", ip.String(), ip, +- func(parsedName, constraint any) (bool, error) { ++ func(parsedName, constraint any, _ bool) (bool, error) { + return matchIPConstraint(parsedName.(net.IP), constraint.(*net.IPNet)) + }, c.PermittedIPRanges, c.ExcludedIPRanges); err != nil { + return err +diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go +index 60a4cea9146adf..6a394e46e94f5a 100644 +--- a/src/crypto/x509/verify_test.go ++++ b/src/crypto/x509/verify_test.go +@@ -1352,7 +1352,7 @@ var nameConstraintTests = []struct { + + func TestNameConstraints(t *testing.T) { + for i, test := range nameConstraintTests { +- result, err := matchDomainConstraint(test.domain, test.constraint, map[string][]string{}, map[string][]string{}) ++ result, err := matchDomainConstraint(test.domain, test.constraint, false, map[string][]string{}, map[string][]string{}) + + if err != nil && !test.expectError { + t.Errorf("unexpected error for test #%d: domain=%s, constraint=%s, err=%s", i, test.domain, test.constraint, err) From patchwork Mon Dec 29 23:07:39 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steve Sakoman X-Patchwork-Id: 77642 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 57926E94106 for ; Mon, 29 Dec 2025 23:08:16 +0000 (UTC) Received: from mail-pf1-f174.google.com (mail-pf1-f174.google.com [209.85.210.174]) by mx.groups.io with SMTP id smtpd.msgproc01-g2.53864.1767049691548103103 for ; Mon, 29 Dec 2025 15:08:11 -0800 Authentication-Results: mx.groups.io; dkim=pass header.i=@sakoman-com.20230601.gappssmtp.com header.s=20230601 header.b=ndZS8FtF; spf=softfail (domain: sakoman.com, ip: 209.85.210.174, mailfrom: steve@sakoman.com) Received: by mail-pf1-f174.google.com with SMTP id d2e1a72fcca58-7b89c1ce9easo10621191b3a.2 for ; Mon, 29 Dec 2025 15:08:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sakoman-com.20230601.gappssmtp.com; s=20230601; t=1767049691; x=1767654491; darn=lists.openembedded.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=Xrx+fZKMSeO/kIADwn9oUviEtWaWdBpTAkIbWgvYgGE=; b=ndZS8FtFmtgU6yyZH+zGExk2OYfEpMkTeGQfT2jRCFDLF4EcEC0F4Tmmy6agVgzcNc DHNgCjcqT0tANKuA2Gm4cqS0Bd81EUwaJEIgKLLKtH/JnVGP6quoOB9xzLEIFRoXog7Z vB4KC4m9b2eW0pmVkdaJpeX44CqcF+eIIMFsjGM/MaYZqtFk0TS+xnpIeDefHJlwKwW0 hVkVpa3plqNyl2nr9/yK/e34McGNuyC2cGqkV3/pJVlTm/7NASmKAqZAaC7yaoHhHrES 7/aQKHXkI0RTBNicdCIiOppsfEkMfmAc/Re8LhGGiR5M5OnbyAXU4Cr28F8SgukN24gx vdZg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767049691; x=1767654491; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=Xrx+fZKMSeO/kIADwn9oUviEtWaWdBpTAkIbWgvYgGE=; b=I6PJAcHLZpocHuo8/LKuiCLuuggLJUDrPn3NF7C05IJ6oqGfCsmtm0+O0oVAO+Fk1a iDj51GajLfKyx02HJq6zqR02iN76723xKmlWk+AfCzW+qFyLB9wtnGL0e44VVIoTTEkb JbSnZeizTUL/sDQ0TJ4M/AbOHKdjo7eLbbWIIDt24Gk/2sGB9I5GRF1U/KfhxaS3GhaU T4AFxVLLGUbbqcc/TatisZe33MfxCLv/WmeZjiKK8DReaLU7V2eZKf797IDE4oxhmIDA 30b+7mycdpSZ+dUAdobhvWTDdyKT4qcZvWNrUG+A3sXQ+oE1Rg73KbJjBjn3lbA2kd4z 1rQg== X-Gm-Message-State: AOJu0Yy36vw3vG1P5cfQtNPbyxXF2PARbuZQoA6P4eEehMwrcQGx1lky k/l1Y2KWseCobE0rnZDWmCSQ9TtH5CEwuvr6rWG+U4xQ4baAeKyHgyATPBU8nWlJzye+5VbYQyN djEgC X-Gm-Gg: AY/fxX6Xh/0wknQ27IjNlMi0CpclE9R/Gk+AsFRIXBPXRmjL4/4jozq+cTQCS9dS8j+ xovt9p31U49DIe/tuRSHOIz8ZS6YYS+fkrX3qlccjmZiSrCOypyzuFrfliPypNIEnPzgykudI+l 44ZJcSo6nM71LZfLILbbk3xmFDLXQt6Y5dxYVzXYFQQmb8iGANlCcg9IP0hq8VxTC6OaFwmMC8z DTXfTgKFXtG2Biic9VT3lb1gZTSXBDTIDAqshr6WhOG8kksm7oM6RoQr4NHN4YdCnfZNVV9ld/9 jltXQ9Y35kmWeu4VHleBUOprRMsXc6LvqbE9xypAA+9jqU6mOBGWDGj7r/5AgLsIa9KCBoC8j+E nKy+qGg/zHpJcsMUuT6ziDbQ5LXMmaocgxK5zpD0/HYL8vwrK6FAQXmZMzZvCpCuzH8gb1+6cS4 3ARw== X-Google-Smtp-Source: AGHT+IHSHanDKbfTUxIH3gq2za/1o3DG4FCgbI6yGgBDAynCLuo/M5Rr7wHrKKfag3Oej6Hre9LCrA== X-Received: by 2002:a05:6a00:6ca2:b0:7a9:c738:5e88 with SMTP id d2e1a72fcca58-7ff657a1298mr27039066b3a.8.1767049690702; Mon, 29 Dec 2025 15:08:10 -0800 (PST) Received: from hexa.. ([2602:feb4:3b:2100:c013:8f5c:baf3:22c3]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7ff7e493123sm30340938b3a.50.2025.12.29.15.08.09 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 29 Dec 2025 15:08:10 -0800 (PST) From: Steve Sakoman To: openembedded-core@lists.openembedded.org Subject: [OE-core][scarthgap 5/5] go: Fix CVE-2025-61729 Date: Mon, 29 Dec 2025 15:07:39 -0800 Message-ID: <2d6d68e46a430a1dbba7bd8b7d37ff56f4f5a0e6.1767049440.git.steve@sakoman.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: References: MIME-Version: 1.0 List-Id: X-Webhook-Received: from 45-33-107-173.ip.linodeusercontent.com [45.33.107.173] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Mon, 29 Dec 2025 23:08:16 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-core/message/228626 From: Vijay Anusuri Upstream-Status: Backport from https://github.com/golang/go/commit/3a842bd5c6aa8eefa13c0174de3ab361e50bd672 Signed-off-by: Vijay Anusuri Signed-off-by: Steve Sakoman --- meta/recipes-devtools/go/go-1.22.12.inc | 1 + .../go/go/CVE-2025-61729.patch | 174 ++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 meta/recipes-devtools/go/go/CVE-2025-61729.patch diff --git a/meta/recipes-devtools/go/go-1.22.12.inc b/meta/recipes-devtools/go/go-1.22.12.inc index 664ccf3edc..ca5016c2f5 100644 --- a/meta/recipes-devtools/go/go-1.22.12.inc +++ b/meta/recipes-devtools/go/go-1.22.12.inc @@ -30,6 +30,7 @@ SRC_URI += "\ file://CVE-2025-61723.patch \ file://CVE-2025-61724.patch \ file://CVE-2025-61727.patch \ + file://CVE-2025-61729.patch \ " SRC_URI[main.sha256sum] = "012a7e1f37f362c0918c1dfa3334458ac2da1628c4b9cf4d9ca02db986e17d71" diff --git a/meta/recipes-devtools/go/go/CVE-2025-61729.patch b/meta/recipes-devtools/go/go/CVE-2025-61729.patch new file mode 100644 index 0000000000..08859e5729 --- /dev/null +++ b/meta/recipes-devtools/go/go/CVE-2025-61729.patch @@ -0,0 +1,174 @@ +From 3a842bd5c6aa8eefa13c0174de3ab361e50bd672 Mon Sep 17 00:00:00 2001 +From: "Nicholas S. Husin" +Date: Mon, 24 Nov 2025 14:56:23 -0500 +Subject: [PATCH] [release-branch.go1.24] crypto/x509: prevent + HostnameError.Error() from consuming excessive resource + +Constructing HostnameError.Error() takes O(N^2) runtime due to using a +string concatenation in a loop. Additionally, there is no limit on how +many names are included in the error message. As a result, a malicious +attacker could craft a certificate with an infinite amount of names to +unfairly consume resource. + +To remediate this, we will now use strings.Builder to construct the +error message, preventing O(N^2) runtime. When a certificate has 100 or +more names, we will also not print each name individually. + +Thanks to Philippe Antoine (Catena cyber) for reporting this issue. + +Updates #76445 +Fixes #76460 +Fixes CVE-2025-61729 + +Change-Id: I6343776ec3289577abc76dad71766c491c1a7c81 +Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3000 +Reviewed-by: Neal Patel +Reviewed-by: Damien Neil +Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3220 +Reviewed-by: Roland Shoemaker +Reviewed-on: https://go-review.googlesource.com/c/go/+/725820 +Reviewed-by: Dmitri Shuralyov +TryBot-Bypass: Dmitri Shuralyov +Auto-Submit: Dmitri Shuralyov +Reviewed-by: Mark Freeman + +Upstream-Status: Backport [https://github.com/golang/go/commit/3a842bd5c6aa8eefa13c0174de3ab361e50bd672] +CVE: CVE-2025-61729 +Signed-off-by: Vijay Anusuri +--- + src/crypto/x509/verify.go | 21 ++++++++++----- + src/crypto/x509/verify_test.go | 47 ++++++++++++++++++++++++++++++++++ + 2 files changed, 61 insertions(+), 7 deletions(-) + +diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go +index 3fdf65f..0ae8aef 100644 +--- a/src/crypto/x509/verify.go ++++ b/src/crypto/x509/verify.go +@@ -100,31 +100,38 @@ type HostnameError struct { + + func (h HostnameError) Error() string { + c := h.Certificate ++ maxNamesIncluded := 100 + + if !c.hasSANExtension() && matchHostnames(c.Subject.CommonName, h.Host) { + return "x509: certificate relies on legacy Common Name field, use SANs instead" + } + +- var valid string ++ var valid strings.Builder + if ip := net.ParseIP(h.Host); ip != nil { + // Trying to validate an IP + if len(c.IPAddresses) == 0 { + return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs" + } ++ if len(c.IPAddresses) >= maxNamesIncluded { ++ return fmt.Sprintf("x509: certificate is valid for %d IP SANs, but none matched %s", len(c.IPAddresses), h.Host) ++ } + for _, san := range c.IPAddresses { +- if len(valid) > 0 { +- valid += ", " ++ if valid.Len() > 0 { ++ valid.WriteString(", ") + } +- valid += san.String() ++ valid.WriteString(san.String()) + } + } else { +- valid = strings.Join(c.DNSNames, ", ") ++ if len(c.DNSNames) >= maxNamesIncluded { ++ return fmt.Sprintf("x509: certificate is valid for %d names, but none matched %s", len(c.DNSNames), h.Host) ++ } ++ valid.WriteString(strings.Join(c.DNSNames, ", ")) + } + +- if len(valid) == 0 { ++ if valid.Len() == 0 { + return "x509: certificate is not valid for any names, but wanted to match " + h.Host + } +- return "x509: certificate is valid for " + valid + ", not " + h.Host ++ return "x509: certificate is valid for " + valid.String() + ", not " + h.Host + } + + // UnknownAuthorityError results when the certificate issuer is unknown +diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go +index df9b0a2..223c250 100644 +--- a/src/crypto/x509/verify_test.go ++++ b/src/crypto/x509/verify_test.go +@@ -10,13 +10,16 @@ import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" ++ "crypto/rsa" + "crypto/x509/pkix" + "encoding/asn1" + "encoding/pem" + "errors" + "fmt" + "internal/testenv" ++ "log" + "math/big" ++ "net" + "os/exec" + "reflect" + "runtime" +@@ -89,6 +92,26 @@ var verifyTests = []verifyTest{ + + errorCallback: expectHostnameError("certificate is valid for"), + }, ++ { ++ name: "TooManyDNS", ++ leaf: generatePEMCertWithRepeatSAN(1677615892, 200, "fake.dns"), ++ roots: []string{generatePEMCertWithRepeatSAN(1677615892, 200, "fake.dns")}, ++ currentTime: 1677615892, ++ dnsName: "www.example.com", ++ systemSkip: true, // does not chain to a system root ++ ++ errorCallback: expectHostnameError("certificate is valid for 200 names, but none matched"), ++ }, ++ { ++ name: "TooManyIPs", ++ leaf: generatePEMCertWithRepeatSAN(1677615892, 150, "4.3.2.1"), ++ roots: []string{generatePEMCertWithRepeatSAN(1677615892, 150, "4.3.2.1")}, ++ currentTime: 1677615892, ++ dnsName: "1.2.3.4", ++ systemSkip: true, // does not chain to a system root ++ ++ errorCallback: expectHostnameError("certificate is valid for 150 IP SANs, but none matched"), ++ }, + { + name: "IPMissing", + leaf: googleLeaf, +@@ -595,6 +618,30 @@ func nameToKey(name *pkix.Name) string { + return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName + } + ++func generatePEMCertWithRepeatSAN(currentTime int64, count int, san string) string { ++ cert := Certificate{ ++ NotBefore: time.Unix(currentTime, 0), ++ NotAfter: time.Unix(currentTime, 0), ++ } ++ if ip := net.ParseIP(san); ip != nil { ++ cert.IPAddresses = slices.Repeat([]net.IP{ip}, count) ++ } else { ++ cert.DNSNames = slices.Repeat([]string{san}, count) ++ } ++ privKey, err := rsa.GenerateKey(rand.Reader, 4096) ++ if err != nil { ++ log.Fatal(err) ++ } ++ certBytes, err := CreateCertificate(rand.Reader, &cert, &cert, &privKey.PublicKey, privKey) ++ if err != nil { ++ log.Fatal(err) ++ } ++ return string(pem.EncodeToMemory(&pem.Block{ ++ Type: "CERTIFICATE", ++ Bytes: certBytes, ++ })) ++} ++ + const gtsIntermediate = `-----BEGIN CERTIFICATE----- + MIIFljCCA36gAwIBAgINAgO8U1lrNMcY9QFQZjANBgkqhkiG9w0BAQsFADBHMQsw + CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +-- +2.43.0 +