diff options
Diffstat (limited to 'meta')
67 files changed, 5261 insertions, 122 deletions
diff --git a/meta/classes/cross.bbclass b/meta/classes/cross.bbclass index 9d951076a7..a292a98335 100644 --- a/meta/classes/cross.bbclass +++ b/meta/classes/cross.bbclass | |||
| @@ -95,3 +95,39 @@ addtask addto_recipe_sysroot after do_populate_sysroot | |||
| 95 | do_addto_recipe_sysroot[deptask] = "do_populate_sysroot" | 95 | do_addto_recipe_sysroot[deptask] = "do_populate_sysroot" |
| 96 | 96 | ||
| 97 | PATH:prepend = "${COREBASE}/scripts/cross-intercept:" | 97 | PATH:prepend = "${COREBASE}/scripts/cross-intercept:" |
| 98 | |||
| 99 | # | ||
| 100 | # Cross task outputs can call native dependencies and even when cross | ||
| 101 | # recipe output doesn't change it might produce different results when | ||
| 102 | # the called native dependency is changed, e.g. clang-cross-${TARGET_ARCH} | ||
| 103 | # contains symlink to clang binary from clang-native, but when clang-native | ||
| 104 | # outhash is changed, clang-cross-${TARGET_ARCH} will still be considered | ||
| 105 | # equivalent and target recipes aren't rebuilt with new clang binary, see | ||
| 106 | # work around in https://github.com/kraj/meta-clang/pull/1140 to make target | ||
| 107 | # recipes to depend directly not only on clang-cross-${TARGET_ARCH} but | ||
| 108 | # clang-native as well. | ||
| 109 | # | ||
| 110 | # This can cause poor interactions with hash equivalence, since this recipes | ||
| 111 | # output-changing dependency is "hidden" and downstream task only see that this | ||
| 112 | # recipe has the same outhash and therefore is equivalent. This can result in | ||
| 113 | # different output in different cases. | ||
| 114 | # | ||
| 115 | # To resolve this, unhide the output-changing dependency by adding its unihash | ||
| 116 | # to this tasks outhash calculation. Unfortunately, don't know specifically | ||
| 117 | # know which dependencies are output-changing, so we have to add all of them. | ||
| 118 | # | ||
| 119 | python cross_add_do_populate_sysroot_deps () { | ||
| 120 | current_task = "do_" + d.getVar("BB_CURRENTTASK") | ||
| 121 | if current_task != "do_populate_sysroot": | ||
| 122 | return | ||
| 123 | |||
| 124 | taskdepdata = d.getVar("BB_TASKDEPDATA", False) | ||
| 125 | pn = d.getVar("PN") | ||
| 126 | deps = { | ||
| 127 | dep[0]:dep[6] for dep in taskdepdata.values() if | ||
| 128 | dep[1] == current_task and dep[0] != pn | ||
| 129 | } | ||
| 130 | |||
| 131 | d.setVar("HASHEQUIV_EXTRA_SIGDATA", "\n".join("%s: %s" % (k, deps[k]) for k in sorted(deps.keys()))) | ||
| 132 | } | ||
| 133 | SSTATECREATEFUNCS += "cross_add_do_populate_sysroot_deps" | ||
diff --git a/meta/lib/oeqa/runtime/cases/buildcpio.py b/meta/lib/oeqa/runtime/cases/buildcpio.py index e29bf16ccb..90abd98c40 100644 --- a/meta/lib/oeqa/runtime/cases/buildcpio.py +++ b/meta/lib/oeqa/runtime/cases/buildcpio.py | |||
| @@ -12,7 +12,7 @@ class BuildCpioTest(OERuntimeTestCase): | |||
| 12 | 12 | ||
| 13 | @classmethod | 13 | @classmethod |
| 14 | def setUpClass(cls): | 14 | def setUpClass(cls): |
| 15 | uri = 'https://downloads.yoctoproject.org/mirror/sources/cpio-2.13.tar.gz' | 15 | uri = 'https://downloads.yoctoproject.org/mirror/sources/cpio-2.14.tar.gz' |
| 16 | cls.project = TargetBuildProject(cls.tc.target, | 16 | cls.project = TargetBuildProject(cls.tc.target, |
| 17 | uri, | 17 | uri, |
| 18 | dl_dir = cls.tc.td['DL_DIR']) | 18 | dl_dir = cls.tc.td['DL_DIR']) |
diff --git a/meta/lib/oeqa/sdk/cases/buildcpio.py b/meta/lib/oeqa/sdk/cases/buildcpio.py index 00088d0ea0..2e9d4f5f18 100644 --- a/meta/lib/oeqa/sdk/cases/buildcpio.py +++ b/meta/lib/oeqa/sdk/cases/buildcpio.py | |||
| @@ -17,10 +17,10 @@ class BuildCpioTest(OESDKTestCase): | |||
| 17 | """ | 17 | """ |
| 18 | def test_cpio(self): | 18 | def test_cpio(self): |
| 19 | with tempfile.TemporaryDirectory(prefix="cpio-", dir=self.tc.sdk_dir) as testdir: | 19 | with tempfile.TemporaryDirectory(prefix="cpio-", dir=self.tc.sdk_dir) as testdir: |
| 20 | tarball = self.fetch(testdir, self.td["DL_DIR"], "https://ftpmirror.gnu.org/gnu/cpio/cpio-2.13.tar.gz") | 20 | tarball = self.fetch(testdir, self.td["DL_DIR"], "https://ftpmirror.gnu.org/gnu/cpio/cpio-2.14.tar.gz") |
| 21 | 21 | ||
| 22 | dirs = {} | 22 | dirs = {} |
| 23 | dirs["source"] = os.path.join(testdir, "cpio-2.13") | 23 | dirs["source"] = os.path.join(testdir, "cpio-2.14") |
| 24 | dirs["build"] = os.path.join(testdir, "build") | 24 | dirs["build"] = os.path.join(testdir, "build") |
| 25 | dirs["install"] = os.path.join(testdir, "install") | 25 | dirs["install"] = os.path.join(testdir, "install") |
| 26 | 26 | ||
diff --git a/meta/lib/oeqa/selftest/cases/meta_ide.py b/meta/lib/oeqa/selftest/cases/meta_ide.py index 3dc81b20a7..1432736b7e 100644 --- a/meta/lib/oeqa/selftest/cases/meta_ide.py +++ b/meta/lib/oeqa/selftest/cases/meta_ide.py | |||
| @@ -40,7 +40,7 @@ class MetaIDE(OESelftestTestCase): | |||
| 40 | def test_meta_ide_can_build_cpio_project(self): | 40 | def test_meta_ide_can_build_cpio_project(self): |
| 41 | dl_dir = self.td.get('DL_DIR', None) | 41 | dl_dir = self.td.get('DL_DIR', None) |
| 42 | self.project = SDKBuildProject(self.tmpdir_metaideQA + "/cpio/", self.environment_script_path, | 42 | self.project = SDKBuildProject(self.tmpdir_metaideQA + "/cpio/", self.environment_script_path, |
| 43 | "https://ftpmirror.gnu.org/gnu/cpio/cpio-2.13.tar.gz", | 43 | "https://ftpmirror.gnu.org/gnu/cpio/cpio-2.14.tar.gz", |
| 44 | self.tmpdir_metaideQA, self.td['DATETIME'], dl_dir=dl_dir) | 44 | self.tmpdir_metaideQA, self.td['DATETIME'], dl_dir=dl_dir) |
| 45 | self.project.download_archive() | 45 | self.project.download_archive() |
| 46 | self.assertEqual(self.project.run_configure('$CONFIGURE_FLAGS --disable-maintainer-mode','sed -i -e "/char \*program_name/d" src/global.c;'), 0, | 46 | self.assertEqual(self.project.run_configure('$CONFIGURE_FLAGS --disable-maintainer-mode','sed -i -e "/char \*program_name/d" src/global.c;'), 0, |
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..9ae4f3b307 --- /dev/null +++ b/meta/recipes-bsp/grub/files/CVE-2025-61661.patch | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | From 9c2ae73b549a653f5f1bd5d4edebc50a764bad06 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Jamie <volticks@gmail.com> | ||
| 3 | Date: Mon, 14 Jul 2025 09:52:59 +0100 | ||
| 4 | Subject: [PATCH 1/3] commands/usbtest: Use correct string length field | ||
| 5 | |||
| 6 | An incorrect length field is used for buffer allocation. This leads to | ||
| 7 | grub_utf16_to_utf8() receiving an incorrect/different length and possibly | ||
| 8 | causing OOB write. This makes sure to use the correct length. | ||
| 9 | |||
| 10 | Fixes: CVE-2025-61661 | ||
| 11 | |||
| 12 | CVE: CVE-2025-61661 | ||
| 13 | |||
| 14 | Upstream-Status: Backport | ||
| 15 | [https://gitweb.git.savannah.gnu.org/gitweb/?p=grub.git;a=commit;h=549a9cc372fd0b96a4ccdfad0e12140476cc62a3] | ||
| 16 | |||
| 17 | Reported-by: Jamie <volticks@gmail.com> | ||
| 18 | Signed-off-by: Jamie <volticks@gmail.com> | ||
| 19 | Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> | ||
| 20 | Signed-off-by: Jiaying Song <jiaying.song.cn@windriver.com> | ||
| 21 | --- | ||
| 22 | grub-core/commands/usbtest.c | 2 +- | ||
| 23 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
| 24 | |||
| 25 | diff --git a/grub-core/commands/usbtest.c b/grub-core/commands/usbtest.c | ||
| 26 | index 2c6d93fe6..8ef187a9a 100644 | ||
| 27 | --- a/grub-core/commands/usbtest.c | ||
| 28 | +++ b/grub-core/commands/usbtest.c | ||
| 29 | @@ -99,7 +99,7 @@ grub_usb_get_string (grub_usb_device_t dev, grub_uint8_t index, int langid, | ||
| 30 | return GRUB_USB_ERR_NONE; | ||
| 31 | } | ||
| 32 | |||
| 33 | - *string = grub_malloc (descstr.length * 2 + 1); | ||
| 34 | + *string = grub_malloc (descstrp->length * 2 + 1); | ||
| 35 | if (! *string) | ||
| 36 | { | ||
| 37 | grub_free (descstrp); | ||
| 38 | -- | ||
| 39 | 2.34.1 | ||
| 40 | |||
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..1614b00d53 --- /dev/null +++ b/meta/recipes-bsp/grub/files/CVE-2025-61662.patch | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | From c47760a907c91283bac9a8400d6975574b1d3986 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Alec Brown <alec.r.brown@oracle.com> | ||
| 3 | Date: Thu, 21 Aug 2025 21:14:06 +0000 | ||
| 4 | Subject: [PATCH 2/3] gettext/gettext: Unregister gettext command on module | ||
| 5 | unload | ||
| 6 | |||
| 7 | When the gettext module is loaded, the gettext command is registered but | ||
| 8 | isn't unregistered when the module is unloaded. We need to add a call to | ||
| 9 | grub_unregister_command() when unloading the module. | ||
| 10 | |||
| 11 | Fixes: CVE-2025-61662 | ||
| 12 | |||
| 13 | CVE: CVE-2025-61662 | ||
| 14 | |||
| 15 | Upstream-Status: Backport | ||
| 16 | [https://gitweb.git.savannah.gnu.org/gitweb/?p=grub.git;a=commit;h=8ed78fd9f0852ab218cc1f991c38e5a229e43807] | ||
| 17 | |||
| 18 | Reported-by: Alec Brown <alec.r.brown@oracle.com> | ||
| 19 | Signed-off-by: Alec Brown <alec.r.brown@oracle.com> | ||
| 20 | Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> | ||
| 21 | Signed-off-by: Jiaying Song <jiaying.song.cn@windriver.com> | ||
| 22 | --- | ||
| 23 | grub-core/gettext/gettext.c | 19 ++++++++++++------- | ||
| 24 | 1 file changed, 12 insertions(+), 7 deletions(-) | ||
| 25 | |||
| 26 | diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c | ||
| 27 | index 7a25c9d67..ef1258ee0 100644 | ||
| 28 | --- a/grub-core/gettext/gettext.c | ||
| 29 | +++ b/grub-core/gettext/gettext.c | ||
| 30 | @@ -502,6 +502,8 @@ grub_cmd_translate (grub_command_t cmd __attribute__ ((unused)), | ||
| 31 | return 0; | ||
| 32 | } | ||
| 33 | |||
| 34 | +static grub_command_t cmd; | ||
| 35 | + | ||
| 36 | GRUB_MOD_INIT (gettext) | ||
| 37 | { | ||
| 38 | const char *lang; | ||
| 39 | @@ -521,13 +523,14 @@ GRUB_MOD_INIT (gettext) | ||
| 40 | grub_register_variable_hook ("locale_dir", NULL, read_main); | ||
| 41 | grub_register_variable_hook ("secondary_locale_dir", NULL, read_secondary); | ||
| 42 | |||
| 43 | - grub_register_command_p1 ("gettext", grub_cmd_translate, | ||
| 44 | - N_("STRING"), | ||
| 45 | - /* TRANSLATORS: It refers to passing the string through gettext. | ||
| 46 | - So it's "translate" in the same meaning as in what you're | ||
| 47 | - doing now. | ||
| 48 | - */ | ||
| 49 | - N_("Translates the string with the current settings.")); | ||
| 50 | + cmd = grub_register_command_p1 ("gettext", grub_cmd_translate, | ||
| 51 | + N_("STRING"), | ||
| 52 | + /* | ||
| 53 | + * TRANSLATORS: It refers to passing the string through gettext. | ||
| 54 | + * So it's "translate" in the same meaning as in what you're | ||
| 55 | + * doing now. | ||
| 56 | + */ | ||
| 57 | + N_("Translates the string with the current settings.")); | ||
| 58 | |||
| 59 | /* Reload .mo file information if lang changes. */ | ||
| 60 | grub_register_variable_hook ("lang", NULL, grub_gettext_env_write_lang); | ||
| 61 | @@ -544,6 +547,8 @@ GRUB_MOD_FINI (gettext) | ||
| 62 | grub_register_variable_hook ("secondary_locale_dir", NULL, NULL); | ||
| 63 | grub_register_variable_hook ("lang", NULL, NULL); | ||
| 64 | |||
| 65 | + grub_unregister_command (cmd); | ||
| 66 | + | ||
| 67 | grub_gettext_delete_list (&main_context); | ||
| 68 | grub_gettext_delete_list (&secondary_context); | ||
| 69 | |||
| 70 | -- | ||
| 71 | 2.34.1 | ||
| 72 | |||
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..cdf1e4ca36 --- /dev/null +++ b/meta/recipes-bsp/grub/files/CVE-2025-61663_61664.patch | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | From a182bd873e4aa93205ecbb7845ef7f0eda99dcf5 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Alec Brown <alec.r.brown@oracle.com> | ||
| 3 | Date: Thu, 21 Aug 2025 21:14:07 +0000 | ||
| 4 | Subject: [PATCH 3/3] normal/main: Unregister commands on module unload | ||
| 5 | |||
| 6 | When the normal module is loaded, the normal and normal_exit commands | ||
| 7 | are registered but aren't unregistered when the module is unloaded. We | ||
| 8 | need to add calls to grub_unregister_command() when unloading the module | ||
| 9 | for these commands. | ||
| 10 | |||
| 11 | Fixes: CVE-2025-61663 | ||
| 12 | Fixes: CVE-2025-61664 | ||
| 13 | |||
| 14 | CVE: CVE-2025-61663 CVE-2025-61664 | ||
| 15 | |||
| 16 | Upstream-Status: Backport | ||
| 17 | [https://gitweb.git.savannah.gnu.org/gitweb/?p=grub.git;a=commit;h=05d3698b8b03eccc49e53491bbd75dba15f40917] | ||
| 18 | |||
| 19 | Reported-by: Alec Brown <alec.r.brown@oracle.com> | ||
| 20 | Signed-off-by: Alec Brown <alec.r.brown@oracle.com> | ||
| 21 | Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> | ||
| 22 | Signed-off-by: Jiaying Song <jiaying.song.cn@windriver.com> | ||
| 23 | --- | ||
| 24 | grub-core/normal/main.c | 12 +++++++----- | ||
| 25 | 1 file changed, 7 insertions(+), 5 deletions(-) | ||
| 26 | |||
| 27 | diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c | ||
| 28 | index a95c25e5f..9d576de7a 100644 | ||
| 29 | --- a/grub-core/normal/main.c | ||
| 30 | +++ b/grub-core/normal/main.c | ||
| 31 | @@ -499,7 +499,7 @@ grub_mini_cmd_clear (struct grub_command *cmd __attribute__ ((unused)), | ||
| 32 | return 0; | ||
| 33 | } | ||
| 34 | |||
| 35 | -static grub_command_t cmd_clear; | ||
| 36 | +static grub_command_t cmd_clear, cmd_normal, cmd_normal_exit; | ||
| 37 | |||
| 38 | static void (*grub_xputs_saved) (const char *str); | ||
| 39 | static const char *features[] = { | ||
| 40 | @@ -541,10 +541,10 @@ GRUB_MOD_INIT(normal) | ||
| 41 | grub_env_export ("pager"); | ||
| 42 | |||
| 43 | /* Register a command "normal" for the rescue mode. */ | ||
| 44 | - grub_register_command ("normal", grub_cmd_normal, | ||
| 45 | - 0, N_("Enter normal mode.")); | ||
| 46 | - grub_register_command ("normal_exit", grub_cmd_normal_exit, | ||
| 47 | - 0, N_("Exit from normal mode.")); | ||
| 48 | + cmd_normal = grub_register_command ("normal", grub_cmd_normal, | ||
| 49 | + 0, N_("Enter normal mode.")); | ||
| 50 | + cmd_normal_exit = grub_register_command ("normal_exit", grub_cmd_normal_exit, | ||
| 51 | + 0, N_("Exit from normal mode.")); | ||
| 52 | |||
| 53 | /* Reload terminal colors when these variables are written to. */ | ||
| 54 | grub_register_variable_hook ("color_normal", NULL, grub_env_write_color_normal); | ||
| 55 | @@ -586,4 +586,6 @@ GRUB_MOD_FINI(normal) | ||
| 56 | grub_register_variable_hook ("color_highlight", NULL, NULL); | ||
| 57 | grub_fs_autoload_hook = 0; | ||
| 58 | grub_unregister_command (cmd_clear); | ||
| 59 | + grub_unregister_command (cmd_normal); | ||
| 60 | + grub_unregister_command (cmd_normal_exit); | ||
| 61 | } | ||
| 62 | -- | ||
| 63 | 2.34.1 | ||
| 64 | |||
diff --git a/meta/recipes-bsp/grub/grub2.inc b/meta/recipes-bsp/grub/grub2.inc index 94eeadfb99..4744e26693 100644 --- a/meta/recipes-bsp/grub/grub2.inc +++ b/meta/recipes-bsp/grub/grub2.inc | |||
| @@ -60,6 +60,9 @@ SRC_URI = "${GNU_MIRROR}/grub/grub-${PV}.tar.gz \ | |||
| 60 | file://CVE-2025-0690.patch \ | 60 | file://CVE-2025-0690.patch \ |
| 61 | file://CVE-2025-1118.patch \ | 61 | file://CVE-2025-1118.patch \ |
| 62 | file://CVE-2024-56738.patch \ | 62 | file://CVE-2024-56738.patch \ |
| 63 | file://CVE-2025-61661.patch \ | ||
| 64 | file://CVE-2025-61662.patch \ | ||
| 65 | file://CVE-2025-61663_61664.patch \ | ||
| 63 | " | 66 | " |
| 64 | 67 | ||
| 65 | SRC_URI[sha256sum] = "23b64b4c741569f9426ed2e3d0e6780796fca081bee4c99f62aa3f53ae803f5f" | 68 | SRC_URI[sha256sum] = "23b64b4c741569f9426ed2e3d0e6780796fca081bee4c99f62aa3f53ae803f5f" |
diff --git a/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-01.patch b/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-01.patch new file mode 100644 index 0000000000..73c3ab3f5c --- /dev/null +++ b/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-01.patch | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | From 7224be0fe2f4beb916b7b69141f478facd0f0634 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Denis Ovsienko <denis@ovsienko.info> | ||
| 3 | Date: Sat, 27 Dec 2025 21:36:11 +0000 | ||
| 4 | Subject: [PATCH] Rename one of the xdtoi() copies to simplify backporting. | ||
| 5 | |||
| 6 | CVE: CVE-2025-11961 | ||
| 7 | Upstream-Status: Backport [https://github.com/the-tcpdump-group/libpcap/commit/7224be0fe2f4beb916b7b69141f478facd0f0634] | ||
| 8 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 9 | --- | ||
| 10 | nametoaddr.c | 6 +++--- | ||
| 11 | 1 file changed, 3 insertions(+), 3 deletions(-) | ||
| 12 | |||
| 13 | diff --git a/nametoaddr.c b/nametoaddr.c | ||
| 14 | index dc75495c..bdaacbf1 100644 | ||
| 15 | --- a/nametoaddr.c | ||
| 16 | +++ b/nametoaddr.c | ||
| 17 | @@ -646,7 +646,7 @@ pcap_nametollc(const char *s) | ||
| 18 | |||
| 19 | /* Hex digit to 8-bit unsigned integer. */ | ||
| 20 | static inline u_char | ||
| 21 | -xdtoi(u_char c) | ||
| 22 | +pcapint_xdtoi(u_char c) | ||
| 23 | { | ||
| 24 | if (c >= '0' && c <= '9') | ||
| 25 | return (u_char)(c - '0'); | ||
| 26 | @@ -728,10 +728,10 @@ pcap_ether_aton(const char *s) | ||
| 27 | while (*s) { | ||
| 28 | if (*s == ':' || *s == '.' || *s == '-') | ||
| 29 | s += 1; | ||
| 30 | - d = xdtoi(*s++); | ||
| 31 | + d = pcapint_xdtoi(*s++); | ||
| 32 | if (PCAP_ISXDIGIT(*s)) { | ||
| 33 | d <<= 4; | ||
| 34 | - d |= xdtoi(*s++); | ||
| 35 | + d |= pcapint_xdtoi(*s++); | ||
| 36 | } | ||
| 37 | *ep++ = d; | ||
| 38 | } | ||
diff --git a/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-02.patch b/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-02.patch new file mode 100644 index 0000000000..0b0dc5ac40 --- /dev/null +++ b/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11961-02.patch | |||
| @@ -0,0 +1,433 @@ | |||
| 1 | From b2d2f9a9a0581c40780bde509f7cc715920f1c02 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Denis Ovsienko <denis@ovsienko.info> | ||
| 3 | Date: Fri, 19 Dec 2025 17:31:13 +0000 | ||
| 4 | Subject: [PATCH] CVE-2025-11961: Fix OOBR and OOBW in pcap_ether_aton(). | ||
| 5 | |||
| 6 | pcap_ether_aton() has for a long time required its string argument to be | ||
| 7 | a well-formed MAC-48 address, which is always the case when the argument | ||
| 8 | comes from other libpcap code, so the function has never validated the | ||
| 9 | input and used a simple loop to parse any of the three common MAC-48 | ||
| 10 | address formats. However, the function has also been a part of the | ||
| 11 | public API, so calling it directly with a malformed address can cause | ||
| 12 | the loop to read beyond the end of the input string and/or to write | ||
| 13 | beyond the end of the allocated output buffer. | ||
| 14 | |||
| 15 | To handle invalid input more appropriately, replace the simple loop with | ||
| 16 | new functions and require the input to match a supported address format. | ||
| 17 | |||
| 18 | This problem was reported by Jin Wei, Kunwei Qian and Ping Chen. | ||
| 19 | |||
| 20 | (backported from commit dd08e53e9380e217ae7c7768da9cc3d7bf37bf83) | ||
| 21 | |||
| 22 | CVE: CVE-2025-11961 | ||
| 23 | Upstream-Status: Backport [https://github.com/the-tcpdump-group/libpcap/commit/b2d2f9a9a0581c40780bde509f7cc715920f1c02] | ||
| 24 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 25 | --- | ||
| 26 | gencode.c | 5 + | ||
| 27 | nametoaddr.c | 367 +++++++++++++++++++++++++++++++++++++++++++++++---- | ||
| 28 | 2 files changed, 349 insertions(+), 23 deletions(-) | ||
| 29 | |||
| 30 | diff --git a/gencode.c b/gencode.c | ||
| 31 | index 3ddd15f8..76fb2d82 100644 | ||
| 32 | --- a/gencode.c | ||
| 33 | +++ b/gencode.c | ||
| 34 | @@ -7206,6 +7206,11 @@ gen_ecode(compiler_state_t *cstate, const char *s, struct qual q) | ||
| 35 | return (NULL); | ||
| 36 | |||
| 37 | if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK) { | ||
| 38 | + /* | ||
| 39 | + * Because the lexer guards the input string format, in this | ||
| 40 | + * context the function returns NULL iff the implicit malloc() | ||
| 41 | + * has failed. | ||
| 42 | + */ | ||
| 43 | cstate->e = pcap_ether_aton(s); | ||
| 44 | if (cstate->e == NULL) | ||
| 45 | bpf_error(cstate, "malloc"); | ||
| 46 | diff --git a/nametoaddr.c b/nametoaddr.c | ||
| 47 | index f9fcd288..f50d0da5 100644 | ||
| 48 | --- a/nametoaddr.c | ||
| 49 | +++ b/nametoaddr.c | ||
| 50 | @@ -703,39 +703,360 @@ __pcap_atodn(const char *s, bpf_u_int32 *addr) | ||
| 51 | return(32); | ||
| 52 | } | ||
| 53 | |||
| 54 | +// Man page: "xxxxxxxxxxxx", regexp: "^[0-9a-fA-F]{12}$". | ||
| 55 | +static u_char | ||
| 56 | +pcapint_atomac48_xxxxxxxxxxxx(const char *s, uint8_t *addr) | ||
| 57 | +{ | ||
| 58 | + if (strlen(s) == 12 && | ||
| 59 | + PCAP_ISXDIGIT(s[0]) && | ||
| 60 | + PCAP_ISXDIGIT(s[1]) && | ||
| 61 | + PCAP_ISXDIGIT(s[2]) && | ||
| 62 | + PCAP_ISXDIGIT(s[3]) && | ||
| 63 | + PCAP_ISXDIGIT(s[4]) && | ||
| 64 | + PCAP_ISXDIGIT(s[5]) && | ||
| 65 | + PCAP_ISXDIGIT(s[6]) && | ||
| 66 | + PCAP_ISXDIGIT(s[7]) && | ||
| 67 | + PCAP_ISXDIGIT(s[8]) && | ||
| 68 | + PCAP_ISXDIGIT(s[9]) && | ||
| 69 | + PCAP_ISXDIGIT(s[10]) && | ||
| 70 | + PCAP_ISXDIGIT(s[11])) { | ||
| 71 | + addr[0] = pcapint_xdtoi(s[0]) << 4 | pcapint_xdtoi(s[1]); | ||
| 72 | + addr[1] = pcapint_xdtoi(s[2]) << 4 | pcapint_xdtoi(s[3]); | ||
| 73 | + addr[2] = pcapint_xdtoi(s[4]) << 4 | pcapint_xdtoi(s[5]); | ||
| 74 | + addr[3] = pcapint_xdtoi(s[6]) << 4 | pcapint_xdtoi(s[7]); | ||
| 75 | + addr[4] = pcapint_xdtoi(s[8]) << 4 | pcapint_xdtoi(s[9]); | ||
| 76 | + addr[5] = pcapint_xdtoi(s[10]) << 4 | pcapint_xdtoi(s[11]); | ||
| 77 | + return 1; | ||
| 78 | + } | ||
| 79 | + return 0; | ||
| 80 | +} | ||
| 81 | + | ||
| 82 | +// Man page: "xxxx.xxxx.xxxx", regexp: "^[0-9a-fA-F]{4}(\.[0-9a-fA-F]{4}){2}$". | ||
| 83 | +static u_char | ||
| 84 | +pcapint_atomac48_xxxx_3_times(const char *s, uint8_t *addr) | ||
| 85 | +{ | ||
| 86 | + const char sep = '.'; | ||
| 87 | + if (strlen(s) == 14 && | ||
| 88 | + PCAP_ISXDIGIT(s[0]) && | ||
| 89 | + PCAP_ISXDIGIT(s[1]) && | ||
| 90 | + PCAP_ISXDIGIT(s[2]) && | ||
| 91 | + PCAP_ISXDIGIT(s[3]) && | ||
| 92 | + s[4] == sep && | ||
| 93 | + PCAP_ISXDIGIT(s[5]) && | ||
| 94 | + PCAP_ISXDIGIT(s[6]) && | ||
| 95 | + PCAP_ISXDIGIT(s[7]) && | ||
| 96 | + PCAP_ISXDIGIT(s[8]) && | ||
| 97 | + s[9] == sep && | ||
| 98 | + PCAP_ISXDIGIT(s[10]) && | ||
| 99 | + PCAP_ISXDIGIT(s[11]) && | ||
| 100 | + PCAP_ISXDIGIT(s[12]) && | ||
| 101 | + PCAP_ISXDIGIT(s[13])) { | ||
| 102 | + addr[0] = pcapint_xdtoi(s[0]) << 4 | pcapint_xdtoi(s[1]); | ||
| 103 | + addr[1] = pcapint_xdtoi(s[2]) << 4 | pcapint_xdtoi(s[3]); | ||
| 104 | + addr[2] = pcapint_xdtoi(s[5]) << 4 | pcapint_xdtoi(s[6]); | ||
| 105 | + addr[3] = pcapint_xdtoi(s[7]) << 4 | pcapint_xdtoi(s[8]); | ||
| 106 | + addr[4] = pcapint_xdtoi(s[10]) << 4 | pcapint_xdtoi(s[11]); | ||
| 107 | + addr[5] = pcapint_xdtoi(s[12]) << 4 | pcapint_xdtoi(s[13]); | ||
| 108 | + return 1; | ||
| 109 | + } | ||
| 110 | + return 0; | ||
| 111 | +} | ||
| 112 | + | ||
| 113 | /* | ||
| 114 | - * Convert 's', which can have the one of the forms: | ||
| 115 | + * Man page: "xx:xx:xx:xx:xx:xx", regexp: "^[0-9a-fA-F]{1,2}(:[0-9a-fA-F]{1,2}){5}$". | ||
| 116 | + * Man page: "xx-xx-xx-xx-xx-xx", regexp: "^[0-9a-fA-F]{1,2}(-[0-9a-fA-F]{1,2}){5}$". | ||
| 117 | + * Man page: "xx.xx.xx.xx.xx.xx", regexp: "^[0-9a-fA-F]{1,2}(\.[0-9a-fA-F]{1,2}){5}$". | ||
| 118 | + * (Any "xx" above can be "x", which is equivalent to "0x".) | ||
| 119 | * | ||
| 120 | - * "xx:xx:xx:xx:xx:xx" | ||
| 121 | - * "xx.xx.xx.xx.xx.xx" | ||
| 122 | - * "xx-xx-xx-xx-xx-xx" | ||
| 123 | - * "xxxx.xxxx.xxxx" | ||
| 124 | - * "xxxxxxxxxxxx" | ||
| 125 | + * An equivalent (and parametrisable for EUI-64) FSM could be implemented using | ||
| 126 | + * a smaller graph, but that graph would be neither acyclic nor planar nor | ||
| 127 | + * trivial to verify. | ||
| 128 | * | ||
| 129 | - * (or various mixes of ':', '.', and '-') into a new | ||
| 130 | - * ethernet address. Assumes 's' is well formed. | ||
| 131 | + * | | ||
| 132 | + * [.] v | ||
| 133 | + * +<---------- START | ||
| 134 | + * | | | ||
| 135 | + * | | [0-9a-fA-F] | ||
| 136 | + * | [.] v | ||
| 137 | + * +<--------- BYTE0_X ----------+ | ||
| 138 | + * | | | | ||
| 139 | + * | | [0-9a-fA-F] | | ||
| 140 | + * | [.] v | | ||
| 141 | + * +<--------- BYTE0_XX | [:\.-] | ||
| 142 | + * | | | | ||
| 143 | + * | | [:\.-] | | ||
| 144 | + * | [.] v | | ||
| 145 | + * +<----- BYTE0_SEP_BYTE1 <-----+ | ||
| 146 | + * | | | ||
| 147 | + * | | [0-9a-fA-F] | ||
| 148 | + * | [.] v | ||
| 149 | + * +<--------- BYTE1_X ----------+ | ||
| 150 | + * | | | | ||
| 151 | + * | | [0-9a-fA-F] | | ||
| 152 | + * | [.] v | | ||
| 153 | + * +<--------- BYTE1_XX | <sep> | ||
| 154 | + * | | | | ||
| 155 | + * | | <sep> | | ||
| 156 | + * | [.] v | | ||
| 157 | + * +<----- BYTE1_SEP_BYTE2 <-----+ | ||
| 158 | + * | | | ||
| 159 | + * | | [0-9a-fA-F] | ||
| 160 | + * | [.] v | ||
| 161 | + * +<--------- BYTE2_X ----------+ | ||
| 162 | + * | | | | ||
| 163 | + * | | [0-9a-fA-F] | | ||
| 164 | + * | [.] v | | ||
| 165 | + * +<--------- BYTE2_XX | <sep> | ||
| 166 | + * | | | | ||
| 167 | + * | | <sep> | | ||
| 168 | + * | [.] v | | ||
| 169 | + * +<----- BYTE2_SEP_BYTE3 <-----+ | ||
| 170 | + * | | | ||
| 171 | + * | | [0-9a-fA-F] | ||
| 172 | + * | [.] v | ||
| 173 | + * +<--------- BYTE3_X ----------+ | ||
| 174 | + * | | | | ||
| 175 | + * | | [0-9a-fA-F] | | ||
| 176 | + * | [.] v | | ||
| 177 | + * +<--------- BYTE3_XX | <sep> | ||
| 178 | + * | | | | ||
| 179 | + * | | <sep> | | ||
| 180 | + * | [.] v | | ||
| 181 | + * +<----- BYTE3_SEP_BYTE4 <-----+ | ||
| 182 | + * | | | ||
| 183 | + * | | [0-9a-fA-F] | ||
| 184 | + * | [.] v | ||
| 185 | + * +<--------- BYTE4_X ----------+ | ||
| 186 | + * | | | | ||
| 187 | + * | | [0-9a-fA-F] | | ||
| 188 | + * | [.] v | | ||
| 189 | + * +<--------- BYTE4_XX | <sep> | ||
| 190 | + * | | | | ||
| 191 | + * | | <sep> | | ||
| 192 | + * | [.] v | | ||
| 193 | + * +<----- BYTE4_SEP_BYTE5 <-----+ | ||
| 194 | + * | | | ||
| 195 | + * | | [0-9a-fA-F] | ||
| 196 | + * | [.] v | ||
| 197 | + * +<--------- BYTE5_X ----------+ | ||
| 198 | + * | | | | ||
| 199 | + * | | [0-9a-fA-F] | | ||
| 200 | + * | [.] v | | ||
| 201 | + * +<--------- BYTE5_XX | \0 | ||
| 202 | + * | | | | ||
| 203 | + * | | \0 | | ||
| 204 | + * | | v | ||
| 205 | + * +--> (reject) +---------> (accept) | ||
| 206 | + * | ||
| 207 | + */ | ||
| 208 | +static u_char | ||
| 209 | +pcapint_atomac48_x_xx_6_times(const char *s, uint8_t *addr) | ||
| 210 | +{ | ||
| 211 | + enum { | ||
| 212 | + START, | ||
| 213 | + BYTE0_X, | ||
| 214 | + BYTE0_XX, | ||
| 215 | + BYTE0_SEP_BYTE1, | ||
| 216 | + BYTE1_X, | ||
| 217 | + BYTE1_XX, | ||
| 218 | + BYTE1_SEP_BYTE2, | ||
| 219 | + BYTE2_X, | ||
| 220 | + BYTE2_XX, | ||
| 221 | + BYTE2_SEP_BYTE3, | ||
| 222 | + BYTE3_X, | ||
| 223 | + BYTE3_XX, | ||
| 224 | + BYTE3_SEP_BYTE4, | ||
| 225 | + BYTE4_X, | ||
| 226 | + BYTE4_XX, | ||
| 227 | + BYTE4_SEP_BYTE5, | ||
| 228 | + BYTE5_X, | ||
| 229 | + BYTE5_XX, | ||
| 230 | + } fsm_state = START; | ||
| 231 | + uint8_t buf[6]; | ||
| 232 | + const char *seplist = ":.-"; | ||
| 233 | + char sep; | ||
| 234 | + | ||
| 235 | + while (*s) { | ||
| 236 | + switch (fsm_state) { | ||
| 237 | + case START: | ||
| 238 | + if (PCAP_ISXDIGIT(*s)) { | ||
| 239 | + buf[0] = pcapint_xdtoi(*s); | ||
| 240 | + fsm_state = BYTE0_X; | ||
| 241 | + break; | ||
| 242 | + } | ||
| 243 | + goto reject; | ||
| 244 | + case BYTE0_X: | ||
| 245 | + if (strchr(seplist, *s)) { | ||
| 246 | + sep = *s; | ||
| 247 | + fsm_state = BYTE0_SEP_BYTE1; | ||
| 248 | + break; | ||
| 249 | + } | ||
| 250 | + if (PCAP_ISXDIGIT(*s)) { | ||
| 251 | + buf[0] = buf[0] << 4 | pcapint_xdtoi(*s); | ||
| 252 | + fsm_state = BYTE0_XX; | ||
| 253 | + break; | ||
| 254 | + } | ||
| 255 | + goto reject; | ||
| 256 | + case BYTE0_XX: | ||
| 257 | + if (strchr(seplist, *s)) { | ||
| 258 | + sep = *s; | ||
| 259 | + fsm_state = BYTE0_SEP_BYTE1; | ||
| 260 | + break; | ||
| 261 | + } | ||
| 262 | + goto reject; | ||
| 263 | + case BYTE0_SEP_BYTE1: | ||
| 264 | + if (PCAP_ISXDIGIT(*s)) { | ||
| 265 | + buf[1] = pcapint_xdtoi(*s); | ||
| 266 | + fsm_state = BYTE1_X; | ||
| 267 | + break; | ||
| 268 | + } | ||
| 269 | + goto reject; | ||
| 270 | + case BYTE1_X: | ||
| 271 | + if (*s == sep) { | ||
| 272 | + fsm_state = BYTE1_SEP_BYTE2; | ||
| 273 | + break; | ||
| 274 | + } | ||
| 275 | + if (PCAP_ISXDIGIT(*s)) { | ||
| 276 | + buf[1] = buf[1] << 4 | pcapint_xdtoi(*s); | ||
| 277 | + fsm_state = BYTE1_XX; | ||
| 278 | + break; | ||
| 279 | + } | ||
| 280 | + goto reject; | ||
| 281 | + case BYTE1_XX: | ||
| 282 | + if (*s == sep) { | ||
| 283 | + fsm_state = BYTE1_SEP_BYTE2; | ||
| 284 | + break; | ||
| 285 | + } | ||
| 286 | + goto reject; | ||
| 287 | + case BYTE1_SEP_BYTE2: | ||
| 288 | + if (PCAP_ISXDIGIT(*s)) { | ||
| 289 | + buf[2] = pcapint_xdtoi(*s); | ||
| 290 | + fsm_state = BYTE2_X; | ||
| 291 | + break; | ||
| 292 | + } | ||
| 293 | + goto reject; | ||
| 294 | + case BYTE2_X: | ||
| 295 | + if (*s == sep) { | ||
| 296 | + fsm_state = BYTE2_SEP_BYTE3; | ||
| 297 | + break; | ||
| 298 | + } | ||
| 299 | + if (PCAP_ISXDIGIT(*s)) { | ||
| 300 | + buf[2] = buf[2] << 4 | pcapint_xdtoi(*s); | ||
| 301 | + fsm_state = BYTE2_XX; | ||
| 302 | + break; | ||
| 303 | + } | ||
| 304 | + goto reject; | ||
| 305 | + case BYTE2_XX: | ||
| 306 | + if (*s == sep) { | ||
| 307 | + fsm_state = BYTE2_SEP_BYTE3; | ||
| 308 | + break; | ||
| 309 | + } | ||
| 310 | + goto reject; | ||
| 311 | + case BYTE2_SEP_BYTE3: | ||
| 312 | + if (PCAP_ISXDIGIT(*s)) { | ||
| 313 | + buf[3] = pcapint_xdtoi(*s); | ||
| 314 | + fsm_state = BYTE3_X; | ||
| 315 | + break; | ||
| 316 | + } | ||
| 317 | + goto reject; | ||
| 318 | + case BYTE3_X: | ||
| 319 | + if (*s == sep) { | ||
| 320 | + fsm_state = BYTE3_SEP_BYTE4; | ||
| 321 | + break; | ||
| 322 | + } | ||
| 323 | + if (PCAP_ISXDIGIT(*s)) { | ||
| 324 | + buf[3] = buf[3] << 4 | pcapint_xdtoi(*s); | ||
| 325 | + fsm_state = BYTE3_XX; | ||
| 326 | + break; | ||
| 327 | + } | ||
| 328 | + goto reject; | ||
| 329 | + case BYTE3_XX: | ||
| 330 | + if (*s == sep) { | ||
| 331 | + fsm_state = BYTE3_SEP_BYTE4; | ||
| 332 | + break; | ||
| 333 | + } | ||
| 334 | + goto reject; | ||
| 335 | + case BYTE3_SEP_BYTE4: | ||
| 336 | + if (PCAP_ISXDIGIT(*s)) { | ||
| 337 | + buf[4] = pcapint_xdtoi(*s); | ||
| 338 | + fsm_state = BYTE4_X; | ||
| 339 | + break; | ||
| 340 | + } | ||
| 341 | + goto reject; | ||
| 342 | + case BYTE4_X: | ||
| 343 | + if (*s == sep) { | ||
| 344 | + fsm_state = BYTE4_SEP_BYTE5; | ||
| 345 | + break; | ||
| 346 | + } | ||
| 347 | + if (PCAP_ISXDIGIT(*s)) { | ||
| 348 | + buf[4] = buf[4] << 4 | pcapint_xdtoi(*s); | ||
| 349 | + fsm_state = BYTE4_XX; | ||
| 350 | + break; | ||
| 351 | + } | ||
| 352 | + goto reject; | ||
| 353 | + case BYTE4_XX: | ||
| 354 | + if (*s == sep) { | ||
| 355 | + fsm_state = BYTE4_SEP_BYTE5; | ||
| 356 | + break; | ||
| 357 | + } | ||
| 358 | + goto reject; | ||
| 359 | + case BYTE4_SEP_BYTE5: | ||
| 360 | + if (PCAP_ISXDIGIT(*s)) { | ||
| 361 | + buf[5] = pcapint_xdtoi(*s); | ||
| 362 | + fsm_state = BYTE5_X; | ||
| 363 | + break; | ||
| 364 | + } | ||
| 365 | + goto reject; | ||
| 366 | + case BYTE5_X: | ||
| 367 | + if (PCAP_ISXDIGIT(*s)) { | ||
| 368 | + buf[5] = buf[5] << 4 | pcapint_xdtoi(*s); | ||
| 369 | + fsm_state = BYTE5_XX; | ||
| 370 | + break; | ||
| 371 | + } | ||
| 372 | + goto reject; | ||
| 373 | + case BYTE5_XX: | ||
| 374 | + goto reject; | ||
| 375 | + } // switch | ||
| 376 | + s++; | ||
| 377 | + } // while | ||
| 378 | + | ||
| 379 | + if (fsm_state == BYTE5_X || fsm_state == BYTE5_XX) { | ||
| 380 | + // accept | ||
| 381 | + memcpy(addr, buf, sizeof(buf)); | ||
| 382 | + return 1; | ||
| 383 | + } | ||
| 384 | + | ||
| 385 | +reject: | ||
| 386 | + return 0; | ||
| 387 | +} | ||
| 388 | + | ||
| 389 | +// The 'addr' argument must point to an array of at least 6 elements. | ||
| 390 | +static int | ||
| 391 | +pcapint_atomac48(const char *s, uint8_t *addr) | ||
| 392 | +{ | ||
| 393 | + return s && ( | ||
| 394 | + pcapint_atomac48_xxxxxxxxxxxx(s, addr) || | ||
| 395 | + pcapint_atomac48_xxxx_3_times(s, addr) || | ||
| 396 | + pcapint_atomac48_x_xx_6_times(s, addr) | ||
| 397 | + ); | ||
| 398 | +} | ||
| 399 | + | ||
| 400 | +/* | ||
| 401 | + * If 's' is a MAC-48 address in one of the forms documented in pcap-filter(7) | ||
| 402 | + * for "ether host", return a pointer to an allocated buffer with the binary | ||
| 403 | + * value of the address. Return NULL on any error. | ||
| 404 | */ | ||
| 405 | u_char * | ||
| 406 | pcap_ether_aton(const char *s) | ||
| 407 | { | ||
| 408 | - register u_char *ep, *e; | ||
| 409 | - register u_char d; | ||
| 410 | + uint8_t tmp[6]; | ||
| 411 | + if (! pcapint_atomac48(s, tmp)) | ||
| 412 | + return (NULL); | ||
| 413 | |||
| 414 | - e = ep = (u_char *)malloc(6); | ||
| 415 | + u_char *e = malloc(6); | ||
| 416 | if (e == NULL) | ||
| 417 | return (NULL); | ||
| 418 | - | ||
| 419 | - while (*s) { | ||
| 420 | - if (*s == ':' || *s == '.' || *s == '-') | ||
| 421 | - s += 1; | ||
| 422 | - d = pcapint_xdtoi(*s++); | ||
| 423 | - if (PCAP_ISXDIGIT(*s)) { | ||
| 424 | - d <<= 4; | ||
| 425 | - d |= pcapint_xdtoi(*s++); | ||
| 426 | - } | ||
| 427 | - *ep++ = d; | ||
| 428 | - } | ||
| 429 | - | ||
| 430 | + memcpy(e, tmp, sizeof(tmp)); | ||
| 431 | return (e); | ||
| 432 | } | ||
| 433 | |||
diff --git a/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11964.patch b/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11964.patch new file mode 100644 index 0000000000..003d21fb1f --- /dev/null +++ b/meta/recipes-connectivity/libpcap/libpcap/CVE-2025-11964.patch | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | From 7fabf607f2319a36a0bd78444247180acb838e69 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Guy Harris <gharris@sonic.net> | ||
| 3 | Date: Sun, 7 Sep 2025 12:51:56 -0700 | ||
| 4 | Subject: [PATCH] Fix a copy-and-pasteo in utf_16le_to_utf_8_truncated(). | ||
| 5 | |||
| 6 | For the four octets of UTF-8 case, it was decrementing the remaining | ||
| 7 | buffer length by 3, not 4. | ||
| 8 | |||
| 9 | Thanks to a team of developers from the Univesity of Waterloo for | ||
| 10 | reporting this. | ||
| 11 | |||
| 12 | (cherry picked from commit aebfca1aea2fc8c177760a26e8f4de27b51d1b3b) | ||
| 13 | |||
| 14 | CVE: CVE-2025-11964 | ||
| 15 | Upstream-Status: Backport [https://github.com/the-tcpdump-group/libpcap/commit/7fabf607f2319a36a0bd78444247180acb838e69] | ||
| 16 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 17 | --- | ||
| 18 | fmtutils.c | 2 +- | ||
| 19 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
| 20 | |||
| 21 | diff --git a/fmtutils.c b/fmtutils.c | ||
| 22 | index a5a4fe62..78a0f8b7 100644 | ||
| 23 | --- a/fmtutils.c | ||
| 24 | +++ b/fmtutils.c | ||
| 25 | @@ -235,7 +235,7 @@ utf_16le_to_utf_8_truncated(const wchar_t *utf_16, char *utf_8, | ||
| 26 | *utf_8++ = ((uc >> 12) & 0x3F) | 0x80; | ||
| 27 | *utf_8++ = ((uc >> 6) & 0x3F) | 0x80; | ||
| 28 | *utf_8++ = ((uc >> 0) & 0x3F) | 0x80; | ||
| 29 | - utf_8_len -= 3; | ||
| 30 | + utf_8_len -= 4; | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
diff --git a/meta/recipes-connectivity/libpcap/libpcap_1.10.1.bb b/meta/recipes-connectivity/libpcap/libpcap_1.10.1.bb index 584e98c76d..5e136e3b1a 100644 --- a/meta/recipes-connectivity/libpcap/libpcap_1.10.1.bb +++ b/meta/recipes-connectivity/libpcap/libpcap_1.10.1.bb | |||
| @@ -17,6 +17,9 @@ SRC_URI = "https://www.tcpdump.org/release/${BP}.tar.gz \ | |||
| 17 | file://CVE-2023-7256-pre4.patch \ | 17 | file://CVE-2023-7256-pre4.patch \ |
| 18 | file://CVE-2023-7256.patch \ | 18 | file://CVE-2023-7256.patch \ |
| 19 | file://CVE-2024-8006.patch \ | 19 | file://CVE-2024-8006.patch \ |
| 20 | file://CVE-2025-11961-01.patch \ | ||
| 21 | file://CVE-2025-11961-02.patch \ | ||
| 22 | file://CVE-2025-11964.patch \ | ||
| 20 | " | 23 | " |
| 21 | 24 | ||
| 22 | SRC_URI[sha256sum] = "ed285f4accaf05344f90975757b3dbfe772ba41d1c401c2648b7fa45b711bdd4" | 25 | SRC_URI[sha256sum] = "ed285f4accaf05344f90975757b3dbfe772ba41d1c401c2648b7fa45b711bdd4" |
diff --git a/meta/recipes-core/dropbear/dropbear.inc b/meta/recipes-core/dropbear/dropbear.inc index 94059df258..cebb1e49c9 100644 --- a/meta/recipes-core/dropbear/dropbear.inc +++ b/meta/recipes-core/dropbear/dropbear.inc | |||
| @@ -34,6 +34,7 @@ SRC_URI = "http://matt.ucc.asn.au/dropbear/releases/dropbear-${PV}.tar.bz2 \ | |||
| 34 | file://0001-Add-m_snprintf-that-won-t-return-negative.patch \ | 34 | file://0001-Add-m_snprintf-that-won-t-return-negative.patch \ |
| 35 | file://0001-Handle-arbitrary-length-paths-and-commands-in-multih.patch \ | 35 | file://0001-Handle-arbitrary-length-paths-and-commands-in-multih.patch \ |
| 36 | file://CVE-2025-47203.patch \ | 36 | file://CVE-2025-47203.patch \ |
| 37 | file://CVE-2019-6111.patch \ | ||
| 37 | " | 38 | " |
| 38 | 39 | ||
| 39 | PAM_SRC_URI = "file://0005-dropbear-enable-pam.patch \ | 40 | PAM_SRC_URI = "file://0005-dropbear-enable-pam.patch \ |
diff --git a/meta/recipes-core/dropbear/dropbear/CVE-2019-6111.patch b/meta/recipes-core/dropbear/dropbear/CVE-2019-6111.patch new file mode 100644 index 0000000000..84224a5f57 --- /dev/null +++ b/meta/recipes-core/dropbear/dropbear/CVE-2019-6111.patch | |||
| @@ -0,0 +1,157 @@ | |||
| 1 | From 48a17cff6aa104b8e806ddb2191f83f1024060f1 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Matt Johnston <matt@ucc.asn.au> | ||
| 3 | Date: Tue, 9 Dec 2025 22:59:19 +0900 | ||
| 4 | Subject: [PATCH] scp CVE-2019-6111 fix | ||
| 5 | |||
| 6 | Cherry-pick from OpenSSH portable | ||
| 7 | |||
| 8 | 391ffc4b9d31 ("upstream: check in scp client that filenames sent during") | ||
| 9 | |||
| 10 | upstream: check in scp client that filenames sent during | ||
| 11 | |||
| 12 | remote->local directory copies satisfy the wildcard specified by the user. | ||
| 13 | |||
| 14 | This checking provides some protection against a malicious server | ||
| 15 | sending unexpected filenames, but it comes at a risk of rejecting wanted | ||
| 16 | files due to differences between client and server wildcard expansion rules. | ||
| 17 | |||
| 18 | For this reason, this also adds a new -T flag to disable the check. | ||
| 19 | |||
| 20 | reported by Harry Sintonen | ||
| 21 | fix approach suggested by markus@; | ||
| 22 | has been in snaps for ~1wk courtesy deraadt@ | ||
| 23 | |||
| 24 | CVE: CVE-2019-6111 | ||
| 25 | Upstream-Status: Backport [https://github.com/mkj/dropbear/commit/48a17cff6aa104b8e806ddb2191f83f1024060f1] | ||
| 26 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 27 | --- | ||
| 28 | scp.c | 38 +++++++++++++++++++++++++++++--------- | ||
| 29 | 1 file changed, 29 insertions(+), 9 deletions(-) | ||
| 30 | |||
| 31 | diff --git a/scp.c b/scp.c | ||
| 32 | index 384f2cb..bf98986 100644 | ||
| 33 | --- a/scp.c | ||
| 34 | +++ b/scp.c | ||
| 35 | @@ -76,6 +76,8 @@ | ||
| 36 | #include "includes.h" | ||
| 37 | /*RCSID("$OpenBSD: scp.c,v 1.130 2006/01/31 10:35:43 djm Exp $");*/ | ||
| 38 | |||
| 39 | +#include <fnmatch.h> | ||
| 40 | + | ||
| 41 | #include "atomicio.h" | ||
| 42 | #include "compat.h" | ||
| 43 | #include "scpmisc.h" | ||
| 44 | @@ -291,14 +293,14 @@ void verifydir(char *); | ||
| 45 | |||
| 46 | uid_t userid; | ||
| 47 | int errs, remin, remout; | ||
| 48 | -int pflag, iamremote, iamrecursive, targetshouldbedirectory; | ||
| 49 | +int Tflag, pflag, iamremote, iamrecursive, targetshouldbedirectory; | ||
| 50 | |||
| 51 | #define CMDNEEDS 64 | ||
| 52 | char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ | ||
| 53 | |||
| 54 | int response(void); | ||
| 55 | void rsource(char *, struct stat *); | ||
| 56 | -void sink(int, char *[]); | ||
| 57 | +void sink(int, char *[], const char *); | ||
| 58 | void source(int, char *[]); | ||
| 59 | void tolocal(int, char *[]); | ||
| 60 | void toremote(char *, int, char *[]); | ||
| 61 | @@ -325,8 +327,8 @@ main(int argc, char **argv) | ||
| 62 | args.list = NULL; | ||
| 63 | addargs(&args, "%s", ssh_program); | ||
| 64 | |||
| 65 | - fflag = tflag = 0; | ||
| 66 | - while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q1246S:o:F:")) != -1) | ||
| 67 | + fflag = Tflag = tflag = 0; | ||
| 68 | + while ((ch = getopt(argc, argv, "dfl:prtTvBCc:i:P:q1246S:o:F:")) != -1) | ||
| 69 | switch (ch) { | ||
| 70 | /* User-visible flags. */ | ||
| 71 | case '1': | ||
| 72 | @@ -389,9 +391,12 @@ main(int argc, char **argv) | ||
| 73 | setmode(0, O_BINARY); | ||
| 74 | #endif | ||
| 75 | break; | ||
| 76 | + case 'T': | ||
| 77 | + Tflag = 1; | ||
| 78 | + break; | ||
| 79 | default: | ||
| 80 | usage(); | ||
| 81 | - } | ||
| 82 | + } | ||
| 83 | argc -= optind; | ||
| 84 | argv += optind; | ||
| 85 | |||
| 86 | @@ -409,7 +414,7 @@ main(int argc, char **argv) | ||
| 87 | } | ||
| 88 | if (tflag) { | ||
| 89 | /* Receive data. */ | ||
| 90 | - sink(argc, argv); | ||
| 91 | + sink(argc, argv, NULL); | ||
| 92 | exit(errs != 0); | ||
| 93 | } | ||
| 94 | if (argc < 2) | ||
| 95 | @@ -590,7 +595,7 @@ tolocal(int argc, char **argv) | ||
| 96 | continue; | ||
| 97 | } | ||
| 98 | xfree(bp); | ||
| 99 | - sink(1, argv + argc - 1); | ||
| 100 | + sink(1, argv + argc - 1, src); | ||
| 101 | (void) close(remin); | ||
| 102 | remin = remout = -1; | ||
| 103 | } | ||
| 104 | @@ -823,7 +828,7 @@ bwlimit(int amount) | ||
| 105 | } | ||
| 106 | |||
| 107 | void | ||
| 108 | -sink(int argc, char **argv) | ||
| 109 | +sink(int argc, char **argv, const char *src) | ||
| 110 | { | ||
| 111 | static BUF buffer; | ||
| 112 | struct stat stb; | ||
| 113 | @@ -837,6 +842,7 @@ sink(int argc, char **argv) | ||
| 114 | off_t size, statbytes; | ||
| 115 | int setimes, targisdir, wrerrno = 0; | ||
| 116 | char ch, *cp, *np, *targ, *why, *vect[1], buf[2048]; | ||
| 117 | + char *src_copy = NULL, *restrict_pattern = NULL; | ||
| 118 | struct timeval tv[2]; | ||
| 119 | |||
| 120 | #define atime tv[0] | ||
| 121 | @@ -858,6 +864,17 @@ sink(int argc, char **argv) | ||
| 122 | (void) atomicio(vwrite, remout, "", 1); | ||
| 123 | if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) | ||
| 124 | targisdir = 1; | ||
| 125 | + if (src != NULL && !iamrecursive && !Tflag) { | ||
| 126 | + /* | ||
| 127 | + * Prepare to try to restrict incoming filenames to match | ||
| 128 | + * the requested destination file glob. | ||
| 129 | + */ | ||
| 130 | + if ((src_copy = strdup(src)) == NULL) | ||
| 131 | + fatal("strdup failed"); | ||
| 132 | + if ((restrict_pattern = strrchr(src_copy, '/')) != NULL) { | ||
| 133 | + *restrict_pattern++ = '\0'; | ||
| 134 | + } | ||
| 135 | + } | ||
| 136 | for (first = 1;; first = 0) { | ||
| 137 | cp = buf; | ||
| 138 | if (atomicio(read, remin, cp, 1) != 1) | ||
| 139 | @@ -940,6 +957,9 @@ sink(int argc, char **argv) | ||
| 140 | run_err("error: unexpected filename: %s", cp); | ||
| 141 | exit(1); | ||
| 142 | } | ||
| 143 | + if (restrict_pattern != NULL && | ||
| 144 | + fnmatch(restrict_pattern, cp, 0) != 0) | ||
| 145 | + SCREWUP("filename does not match request"); | ||
| 146 | if (targisdir) { | ||
| 147 | static char *namebuf = NULL; | ||
| 148 | static size_t cursize = 0; | ||
| 149 | @@ -978,7 +998,7 @@ sink(int argc, char **argv) | ||
| 150 | goto bad; | ||
| 151 | } | ||
| 152 | vect[0] = xstrdup(np); | ||
| 153 | - sink(1, vect); | ||
| 154 | + sink(1, vect, src); | ||
| 155 | if (setimes) { | ||
| 156 | setimes = 0; | ||
| 157 | if (utimes(vect[0], tv) < 0) | ||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2025-13601-01.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2025-13601-01.patch new file mode 100644 index 0000000000..7046d2405e --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2025-13601-01.patch | |||
| @@ -0,0 +1,125 @@ | |||
| 1 | From f28340ee62c655487972ad3c632d231ee098fb7f Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Philip Withnall <pwithnall@gnome.org> | ||
| 3 | Date: Thu, 13 Nov 2025 18:27:22 +0000 | ||
| 4 | Subject: [PATCH] gconvert: Error out if g_escape_uri_string() would overflow | ||
| 5 | |||
| 6 | If the string to escape contains a very large number of unacceptable | ||
| 7 | characters (which would need escaping), the calculation of the length of | ||
| 8 | the escaped string could overflow, leading to a potential write off the | ||
| 9 | end of the newly allocated string. | ||
| 10 | |||
| 11 | In addition to that, the number of unacceptable characters was counted | ||
| 12 | in a signed integer, which would overflow to become negative, making it | ||
| 13 | easier for an attacker to craft an input string which would cause an | ||
| 14 | out-of-bounds write. | ||
| 15 | |||
| 16 | Fix that by validating the allocation length, and using an unsigned | ||
| 17 | integer to count the number of unacceptable characters. | ||
| 18 | |||
| 19 | Spotted by treeplus. Thanks to the Sovereign Tech Resilience programme | ||
| 20 | from the Sovereign Tech Agency. ID: #YWH-PGM9867-134 | ||
| 21 | |||
| 22 | Signed-off-by: Philip Withnall <pwithnall@gnome.org> | ||
| 23 | |||
| 24 | Fixes: #3827 | ||
| 25 | |||
| 26 | CVE: CVE-2025-13601 | ||
| 27 | Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/f28340ee62c655487972ad3c632d231ee098fb7f] | ||
| 28 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 29 | --- | ||
| 30 | glib/gconvert.c | 36 +++++++++++++++++++++++++----------- | ||
| 31 | 1 file changed, 25 insertions(+), 11 deletions(-) | ||
| 32 | |||
| 33 | diff --git a/glib/gconvert.c b/glib/gconvert.c | ||
| 34 | index b066dd5a8..a02d2ea73 100644 | ||
| 35 | --- a/glib/gconvert.c | ||
| 36 | +++ b/glib/gconvert.c | ||
| 37 | @@ -1425,8 +1425,9 @@ static const gchar hex[] = "0123456789ABCDEF"; | ||
| 38 | /* Note: This escape function works on file: URIs, but if you want to | ||
| 39 | * escape something else, please read RFC-2396 */ | ||
| 40 | static gchar * | ||
| 41 | -g_escape_uri_string (const gchar *string, | ||
| 42 | - UnsafeCharacterSet mask) | ||
| 43 | +g_escape_uri_string (const gchar *string, | ||
| 44 | + UnsafeCharacterSet mask, | ||
| 45 | + GError **error) | ||
| 46 | { | ||
| 47 | #define ACCEPTABLE(a) ((a)>=32 && (a)<128 && (acceptable[(a)-32] & use_mask)) | ||
| 48 | |||
| 49 | @@ -1434,7 +1435,7 @@ g_escape_uri_string (const gchar *string, | ||
| 50 | gchar *q; | ||
| 51 | gchar *result; | ||
| 52 | int c; | ||
| 53 | - gint unacceptable; | ||
| 54 | + size_t unacceptable; | ||
| 55 | UnsafeCharacterSet use_mask; | ||
| 56 | |||
| 57 | g_return_val_if_fail (mask == UNSAFE_ALL | ||
| 58 | @@ -1451,7 +1452,14 @@ g_escape_uri_string (const gchar *string, | ||
| 59 | if (!ACCEPTABLE (c)) | ||
| 60 | unacceptable++; | ||
| 61 | } | ||
| 62 | - | ||
| 63 | + | ||
| 64 | + if (unacceptable >= (G_MAXSIZE - (p - string)) / 2) | ||
| 65 | + { | ||
| 66 | + g_set_error_literal (error, G_CONVERT_ERROR, G_CONVERT_ERROR_BAD_URI, | ||
| 67 | + _("The URI is too long")); | ||
| 68 | + return NULL; | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | result = g_malloc (p - string + unacceptable * 2 + 1); | ||
| 72 | |||
| 73 | use_mask = mask; | ||
| 74 | @@ -1476,12 +1484,13 @@ g_escape_uri_string (const gchar *string, | ||
| 75 | |||
| 76 | |||
| 77 | static gchar * | ||
| 78 | -g_escape_file_uri (const gchar *hostname, | ||
| 79 | - const gchar *pathname) | ||
| 80 | +g_escape_file_uri (const gchar *hostname, | ||
| 81 | + const gchar *pathname, | ||
| 82 | + GError **error) | ||
| 83 | { | ||
| 84 | char *escaped_hostname = NULL; | ||
| 85 | - char *escaped_path; | ||
| 86 | - char *res; | ||
| 87 | + char *escaped_path = NULL; | ||
| 88 | + char *res = NULL; | ||
| 89 | |||
| 90 | #ifdef G_OS_WIN32 | ||
| 91 | char *p, *backslash; | ||
| 92 | @@ -1502,10 +1511,14 @@ g_escape_file_uri (const gchar *hostname, | ||
| 93 | |||
| 94 | if (hostname && *hostname != '\0') | ||
| 95 | { | ||
| 96 | - escaped_hostname = g_escape_uri_string (hostname, UNSAFE_HOST); | ||
| 97 | + escaped_hostname = g_escape_uri_string (hostname, UNSAFE_HOST, error); | ||
| 98 | + if (escaped_hostname == NULL) | ||
| 99 | + goto out; | ||
| 100 | } | ||
| 101 | |||
| 102 | - escaped_path = g_escape_uri_string (pathname, UNSAFE_PATH); | ||
| 103 | + escaped_path = g_escape_uri_string (pathname, UNSAFE_PATH, error); | ||
| 104 | + if (escaped_path == NULL) | ||
| 105 | + goto out; | ||
| 106 | |||
| 107 | res = g_strconcat ("file://", | ||
| 108 | (escaped_hostname) ? escaped_hostname : "", | ||
| 109 | @@ -1513,6 +1526,7 @@ g_escape_file_uri (const gchar *hostname, | ||
| 110 | escaped_path, | ||
| 111 | NULL); | ||
| 112 | |||
| 113 | +out: | ||
| 114 | #ifdef G_OS_WIN32 | ||
| 115 | g_free ((char *) pathname); | ||
| 116 | #endif | ||
| 117 | @@ -1832,7 +1846,7 @@ g_filename_to_uri (const gchar *filename, | ||
| 118 | hostname = NULL; | ||
| 119 | #endif | ||
| 120 | |||
| 121 | - escaped_uri = g_escape_file_uri (hostname, filename); | ||
| 122 | + escaped_uri = g_escape_file_uri (hostname, filename, error); | ||
| 123 | |||
| 124 | return escaped_uri; | ||
| 125 | } | ||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2025-13601-02.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2025-13601-02.patch new file mode 100644 index 0000000000..4be8d0d947 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2025-13601-02.patch | |||
| @@ -0,0 +1,128 @@ | |||
| 1 | From 7bd3fc372040cdf8eada7f65c32c30da52a7461d Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Philip Withnall <pwithnall@gnome.org> | ||
| 3 | Date: Thu, 13 Nov 2025 18:31:43 +0000 | ||
| 4 | Subject: [PATCH] fuzzing: Add fuzz tests for g_filename_{to,from}_uri() | ||
| 5 | |||
| 6 | These functions could be called on untrusted input data, and since they | ||
| 7 | do URI escaping/unescaping, they have non-trivial string handling code. | ||
| 8 | |||
| 9 | Signed-off-by: Philip Withnall <pwithnall@gnome.org> | ||
| 10 | |||
| 11 | See: #3827 | ||
| 12 | |||
| 13 | CVE: CVE-2025-13601 | ||
| 14 | Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/7bd3fc372040cdf8eada7f65c32c30da52a7461d] | ||
| 15 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 16 | --- | ||
| 17 | fuzzing/fuzz_filename_from_uri.c | 40 ++++++++++++++++++++++++++++++++ | ||
| 18 | fuzzing/fuzz_filename_to_uri.c | 40 ++++++++++++++++++++++++++++++++ | ||
| 19 | fuzzing/meson.build | 2 ++ | ||
| 20 | 3 files changed, 82 insertions(+) | ||
| 21 | create mode 100644 fuzzing/fuzz_filename_from_uri.c | ||
| 22 | create mode 100644 fuzzing/fuzz_filename_to_uri.c | ||
| 23 | |||
| 24 | diff --git a/fuzzing/fuzz_filename_from_uri.c b/fuzzing/fuzz_filename_from_uri.c | ||
| 25 | new file mode 100644 | ||
| 26 | index 000000000..9b7a715f0 | ||
| 27 | --- /dev/null | ||
| 28 | +++ b/fuzzing/fuzz_filename_from_uri.c | ||
| 29 | @@ -0,0 +1,40 @@ | ||
| 30 | +/* | ||
| 31 | + * Copyright 2025 GNOME Foundation, Inc. | ||
| 32 | + * | ||
| 33 | + * SPDX-License-Identifier: LGPL-2.1-or-later | ||
| 34 | + * | ||
| 35 | + * This library is free software; you can redistribute it and/or | ||
| 36 | + * modify it under the terms of the GNU Lesser General Public | ||
| 37 | + * License as published by the Free Software Foundation; either | ||
| 38 | + * version 2.1 of the License, or (at your option) any later version. | ||
| 39 | + * | ||
| 40 | + * This library is distributed in the hope that it will be useful, | ||
| 41 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 42 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 43 | + * Lesser General Public License for more details. | ||
| 44 | + * | ||
| 45 | + * You should have received a copy of the GNU Lesser General Public | ||
| 46 | + * License along with this library; if not, see <http://www.gnu.org/licenses/>. | ||
| 47 | + */ | ||
| 48 | + | ||
| 49 | +#include "fuzz.h" | ||
| 50 | + | ||
| 51 | +int | ||
| 52 | +LLVMFuzzerTestOneInput (const unsigned char *data, size_t size) | ||
| 53 | +{ | ||
| 54 | + unsigned char *nul_terminated_data = NULL; | ||
| 55 | + char *filename = NULL; | ||
| 56 | + GError *local_error = NULL; | ||
| 57 | + | ||
| 58 | + fuzz_set_logging_func (); | ||
| 59 | + | ||
| 60 | + /* ignore @size (g_filename_from_uri() doesn’t support it); ensure @data is nul-terminated */ | ||
| 61 | + nul_terminated_data = (unsigned char *) g_strndup ((const char *) data, size); | ||
| 62 | + filename = g_filename_from_uri ((const char *) nul_terminated_data, NULL, &local_error); | ||
| 63 | + g_free (nul_terminated_data); | ||
| 64 | + | ||
| 65 | + g_free (filename); | ||
| 66 | + g_clear_error (&local_error); | ||
| 67 | + | ||
| 68 | + return 0; | ||
| 69 | +} | ||
| 70 | diff --git a/fuzzing/fuzz_filename_to_uri.c b/fuzzing/fuzz_filename_to_uri.c | ||
| 71 | new file mode 100644 | ||
| 72 | index 000000000..acb319203 | ||
| 73 | --- /dev/null | ||
| 74 | +++ b/fuzzing/fuzz_filename_to_uri.c | ||
| 75 | @@ -0,0 +1,40 @@ | ||
| 76 | +/* | ||
| 77 | + * Copyright 2025 GNOME Foundation, Inc. | ||
| 78 | + * | ||
| 79 | + * SPDX-License-Identifier: LGPL-2.1-or-later | ||
| 80 | + * | ||
| 81 | + * This library is free software; you can redistribute it and/or | ||
| 82 | + * modify it under the terms of the GNU Lesser General Public | ||
| 83 | + * License as published by the Free Software Foundation; either | ||
| 84 | + * version 2.1 of the License, or (at your option) any later version. | ||
| 85 | + * | ||
| 86 | + * This library is distributed in the hope that it will be useful, | ||
| 87 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 88 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 89 | + * Lesser General Public License for more details. | ||
| 90 | + * | ||
| 91 | + * You should have received a copy of the GNU Lesser General Public | ||
| 92 | + * License along with this library; if not, see <http://www.gnu.org/licenses/>. | ||
| 93 | + */ | ||
| 94 | + | ||
| 95 | +#include "fuzz.h" | ||
| 96 | + | ||
| 97 | +int | ||
| 98 | +LLVMFuzzerTestOneInput (const unsigned char *data, size_t size) | ||
| 99 | +{ | ||
| 100 | + unsigned char *nul_terminated_data = NULL; | ||
| 101 | + char *uri = NULL; | ||
| 102 | + GError *local_error = NULL; | ||
| 103 | + | ||
| 104 | + fuzz_set_logging_func (); | ||
| 105 | + | ||
| 106 | + /* ignore @size (g_filename_to_uri() doesn’t support it); ensure @data is nul-terminated */ | ||
| 107 | + nul_terminated_data = (unsigned char *) g_strndup ((const char *) data, size); | ||
| 108 | + uri = g_filename_to_uri ((const char *) nul_terminated_data, NULL, &local_error); | ||
| 109 | + g_free (nul_terminated_data); | ||
| 110 | + | ||
| 111 | + g_free (uri); | ||
| 112 | + g_clear_error (&local_error); | ||
| 113 | + | ||
| 114 | + return 0; | ||
| 115 | +} | ||
| 116 | diff --git a/fuzzing/meson.build b/fuzzing/meson.build | ||
| 117 | index addbe9071..05f936eeb 100644 | ||
| 118 | --- a/fuzzing/meson.build | ||
| 119 | +++ b/fuzzing/meson.build | ||
| 120 | @@ -4,6 +4,8 @@ fuzz_targets = [ | ||
| 121 | 'fuzz_date_parse', | ||
| 122 | 'fuzz_date_time_new_from_iso8601', | ||
| 123 | 'fuzz_dbus_message', | ||
| 124 | + 'fuzz_filename_from_uri', | ||
| 125 | + 'fuzz_filename_to_uri', | ||
| 126 | 'fuzz_inet_address_mask_new_from_string', | ||
| 127 | 'fuzz_inet_address_new_from_string', | ||
| 128 | 'fuzz_inet_socket_address_new_from_string', | ||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2025-14087-01.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2025-14087-01.patch new file mode 100644 index 0000000000..ec7b1fecaa --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2025-14087-01.patch | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | From 31f82e22e21bae520b7228f7f57d357fb20df8a4 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Philip Withnall <pwithnall@gnome.org> | ||
| 3 | Date: Tue, 25 Nov 2025 19:02:56 +0000 | ||
| 4 | Subject: [PATCH] gvariant-parser: Fix potential integer overflow parsing | ||
| 5 | (byte)strings | ||
| 6 | |||
| 7 | The termination condition for parsing string and bytestring literals in | ||
| 8 | GVariant text format input was subject to an integer overflow for input | ||
| 9 | string (or bytestring) literals longer than `INT_MAX`. | ||
| 10 | |||
| 11 | Fix that by counting as a `size_t` rather than as an `int`. The counter | ||
| 12 | can never correctly be negative. | ||
| 13 | |||
| 14 | Spotted by treeplus. Thanks to the Sovereign Tech Resilience programme | ||
| 15 | from the Sovereign Tech Agency. ID: #YWH-PGM9867-145 | ||
| 16 | |||
| 17 | Signed-off-by: Philip Withnall <pwithnall@gnome.org> | ||
| 18 | Fixes: #3834 | ||
| 19 | |||
| 20 | CVE: CVE-2025-14087 | ||
| 21 | Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/31f82e22e21bae520b7228f7f57d357fb20df8a4] | ||
| 22 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 23 | --- | ||
| 24 | glib/gvariant-parser.c | 10 +++++----- | ||
| 25 | 1 file changed, 5 insertions(+), 5 deletions(-) | ||
| 26 | |||
| 27 | diff --git a/glib/gvariant-parser.c b/glib/gvariant-parser.c | ||
| 28 | index 2f1d3db9f..2d6e9856f 100644 | ||
| 29 | --- a/glib/gvariant-parser.c | ||
| 30 | +++ b/glib/gvariant-parser.c | ||
| 31 | @@ -594,7 +594,7 @@ ast_resolve (AST *ast, | ||
| 32 | { | ||
| 33 | GVariant *value; | ||
| 34 | gchar *pattern; | ||
| 35 | - gint i, j = 0; | ||
| 36 | + size_t i, j = 0; | ||
| 37 | |||
| 38 | pattern = ast_get_pattern (ast, error); | ||
| 39 | |||
| 40 | @@ -1555,9 +1555,9 @@ string_free (AST *ast) | ||
| 41 | * No leading/trailing space allowed. */ | ||
| 42 | static gboolean | ||
| 43 | unicode_unescape (const gchar *src, | ||
| 44 | - gint *src_ofs, | ||
| 45 | + size_t *src_ofs, | ||
| 46 | gchar *dest, | ||
| 47 | - gint *dest_ofs, | ||
| 48 | + size_t *dest_ofs, | ||
| 49 | gsize length, | ||
| 50 | SourceRef *ref, | ||
| 51 | GError **error) | ||
| 52 | @@ -1618,7 +1618,7 @@ string_parse (TokenStream *stream, | ||
| 53 | gsize length; | ||
| 54 | gchar quote; | ||
| 55 | gchar *str; | ||
| 56 | - gint i, j; | ||
| 57 | + size_t i, j; | ||
| 58 | |||
| 59 | token_stream_start_ref (stream, &ref); | ||
| 60 | token = token_stream_get (stream); | ||
| 61 | @@ -1748,7 +1748,7 @@ bytestring_parse (TokenStream *stream, | ||
| 62 | gsize length; | ||
| 63 | gchar quote; | ||
| 64 | gchar *str; | ||
| 65 | - gint i, j; | ||
| 66 | + size_t i, j; | ||
| 67 | |||
| 68 | token_stream_start_ref (stream, &ref); | ||
| 69 | token = token_stream_get (stream); | ||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2025-14087-02.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2025-14087-02.patch new file mode 100644 index 0000000000..595f9c1b93 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2025-14087-02.patch | |||
| @@ -0,0 +1,240 @@ | |||
| 1 | From ac9de0871281cf734f6e269988f90a2521582a08 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Philip Withnall <pwithnall@gnome.org> | ||
| 3 | Date: Tue, 25 Nov 2025 19:19:16 +0000 | ||
| 4 | Subject: [PATCH] gvariant-parser: Use size_t to count numbers of child | ||
| 5 | elements | ||
| 6 | MIME-Version: 1.0 | ||
| 7 | Content-Type: text/plain; charset=UTF-8 | ||
| 8 | Content-Transfer-Encoding: 8bit | ||
| 9 | |||
| 10 | Rather than using `gint`, which could overflow for arrays (or dicts, or | ||
| 11 | tuples) longer than `INT_MAX`. There may be other limits which prevent | ||
| 12 | parsed containers becoming that long, but we might as well make the type | ||
| 13 | system reflect the programmer’s intention as best it can anyway. | ||
| 14 | |||
| 15 | For arrays and tuples this is straightforward. For dictionaries, it’s | ||
| 16 | slightly complicated by the fact that the code used | ||
| 17 | `dict->n_children == -1` to indicate that the `Dictionary` struct in | ||
| 18 | question actually represented a single freestanding dict entry. In | ||
| 19 | GVariant text format, that would be `{1, "one"}`. | ||
| 20 | |||
| 21 | The implementation previously didn’t define the semantics of | ||
| 22 | `dict->n_children < -1`. | ||
| 23 | |||
| 24 | Now, instead, change `Dictionary.n_children` to `size_t`, and define a | ||
| 25 | magic value `DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY` to indicate that | ||
| 26 | the `Dictionary` represents a single freestanding dict entry. | ||
| 27 | |||
| 28 | This magic value is `SIZE_MAX`, and given that a dictionary entry takes | ||
| 29 | more than one byte to represent in GVariant text format, that means it’s | ||
| 30 | not possible to have that many entries in a parsed dictionary, so this | ||
| 31 | magic value won’t be hit by a normal dictionary. An assertion checks | ||
| 32 | this anyway. | ||
| 33 | |||
| 34 | Spotted while working on #3834. | ||
| 35 | |||
| 36 | Signed-off-by: Philip Withnall <pwithnall@gnome.org> | ||
| 37 | |||
| 38 | CVE: CVE-2025-14087 | ||
| 39 | Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/ac9de0871281cf734f6e269988f90a2521582a08] | ||
| 40 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 41 | --- | ||
| 42 | glib/gvariant-parser.c | 58 ++++++++++++++++++++++++------------------ | ||
| 43 | 1 file changed, 33 insertions(+), 25 deletions(-) | ||
| 44 | |||
| 45 | diff --git a/glib/gvariant-parser.c b/glib/gvariant-parser.c | ||
| 46 | index 2d6e9856f..519baa3f3 100644 | ||
| 47 | --- a/glib/gvariant-parser.c | ||
| 48 | +++ b/glib/gvariant-parser.c | ||
| 49 | @@ -647,9 +647,9 @@ static AST *parse (TokenStream *stream, | ||
| 50 | GError **error); | ||
| 51 | |||
| 52 | static void | ||
| 53 | -ast_array_append (AST ***array, | ||
| 54 | - gint *n_items, | ||
| 55 | - AST *ast) | ||
| 56 | +ast_array_append (AST ***array, | ||
| 57 | + size_t *n_items, | ||
| 58 | + AST *ast) | ||
| 59 | { | ||
| 60 | if ((*n_items & (*n_items - 1)) == 0) | ||
| 61 | *array = g_renew (AST *, *array, *n_items ? 2 ** n_items : 1); | ||
| 62 | @@ -658,10 +658,10 @@ ast_array_append (AST ***array, | ||
| 63 | } | ||
| 64 | |||
| 65 | static void | ||
| 66 | -ast_array_free (AST **array, | ||
| 67 | - gint n_items) | ||
| 68 | +ast_array_free (AST **array, | ||
| 69 | + size_t n_items) | ||
| 70 | { | ||
| 71 | - gint i; | ||
| 72 | + size_t i; | ||
| 73 | |||
| 74 | for (i = 0; i < n_items; i++) | ||
| 75 | ast_free (array[i]); | ||
| 76 | @@ -670,11 +670,11 @@ ast_array_free (AST **array, | ||
| 77 | |||
| 78 | static gchar * | ||
| 79 | ast_array_get_pattern (AST **array, | ||
| 80 | - gint n_items, | ||
| 81 | + size_t n_items, | ||
| 82 | GError **error) | ||
| 83 | { | ||
| 84 | gchar *pattern; | ||
| 85 | - gint i; | ||
| 86 | + size_t i; | ||
| 87 | |||
| 88 | /* Find the pattern which applies to all children in the array, by l-folding a | ||
| 89 | * coalesce operation. | ||
| 90 | @@ -706,7 +706,7 @@ ast_array_get_pattern (AST **array, | ||
| 91 | * pair of values. | ||
| 92 | */ | ||
| 93 | { | ||
| 94 | - int j = 0; | ||
| 95 | + size_t j = 0; | ||
| 96 | |||
| 97 | while (TRUE) | ||
| 98 | { | ||
| 99 | @@ -891,7 +891,7 @@ typedef struct | ||
| 100 | AST ast; | ||
| 101 | |||
| 102 | AST **children; | ||
| 103 | - gint n_children; | ||
| 104 | + size_t n_children; | ||
| 105 | } Array; | ||
| 106 | |||
| 107 | static gchar * | ||
| 108 | @@ -924,7 +924,7 @@ array_get_value (AST *ast, | ||
| 109 | Array *array = (Array *) ast; | ||
| 110 | const GVariantType *childtype; | ||
| 111 | GVariantBuilder builder; | ||
| 112 | - gint i; | ||
| 113 | + size_t i; | ||
| 114 | |||
| 115 | if (!g_variant_type_is_array (type)) | ||
| 116 | return ast_type_error (ast, type, error); | ||
| 117 | @@ -1010,7 +1010,7 @@ typedef struct | ||
| 118 | AST ast; | ||
| 119 | |||
| 120 | AST **children; | ||
| 121 | - gint n_children; | ||
| 122 | + size_t n_children; | ||
| 123 | } Tuple; | ||
| 124 | |||
| 125 | static gchar * | ||
| 126 | @@ -1020,7 +1020,7 @@ tuple_get_pattern (AST *ast, | ||
| 127 | Tuple *tuple = (Tuple *) ast; | ||
| 128 | gchar *result = NULL; | ||
| 129 | gchar **parts; | ||
| 130 | - gint i; | ||
| 131 | + size_t i; | ||
| 132 | |||
| 133 | parts = g_new (gchar *, tuple->n_children + 4); | ||
| 134 | parts[tuple->n_children + 1] = (gchar *) ")"; | ||
| 135 | @@ -1050,7 +1050,7 @@ tuple_get_value (AST *ast, | ||
| 136 | Tuple *tuple = (Tuple *) ast; | ||
| 137 | const GVariantType *childtype; | ||
| 138 | GVariantBuilder builder; | ||
| 139 | - gint i; | ||
| 140 | + size_t i; | ||
| 141 | |||
| 142 | if (!g_variant_type_is_tuple (type)) | ||
| 143 | return ast_type_error (ast, type, error); | ||
| 144 | @@ -1242,9 +1242,16 @@ typedef struct | ||
| 145 | |||
| 146 | AST **keys; | ||
| 147 | AST **values; | ||
| 148 | - gint n_children; | ||
| 149 | + | ||
| 150 | + /* Iff this is DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY then this struct | ||
| 151 | + * represents a single freestanding dict entry (`{1, "one"}`) rather than a | ||
| 152 | + * full dict. In the freestanding case, @keys and @values have exactly one | ||
| 153 | + * member each. */ | ||
| 154 | + size_t n_children; | ||
| 155 | } Dictionary; | ||
| 156 | |||
| 157 | +#define DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY ((size_t) -1) | ||
| 158 | + | ||
| 159 | static gchar * | ||
| 160 | dictionary_get_pattern (AST *ast, | ||
| 161 | GError **error) | ||
| 162 | @@ -1259,7 +1266,7 @@ dictionary_get_pattern (AST *ast, | ||
| 163 | return g_strdup ("Ma{**}"); | ||
| 164 | |||
| 165 | key_pattern = ast_array_get_pattern (dict->keys, | ||
| 166 | - abs (dict->n_children), | ||
| 167 | + (dict->n_children == DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY) ? 1 : dict->n_children, | ||
| 168 | error); | ||
| 169 | |||
| 170 | if (key_pattern == NULL) | ||
| 171 | @@ -1290,7 +1297,7 @@ dictionary_get_pattern (AST *ast, | ||
| 172 | return NULL; | ||
| 173 | |||
| 174 | result = g_strdup_printf ("M%s{%c%s}", | ||
| 175 | - dict->n_children > 0 ? "a" : "", | ||
| 176 | + (dict->n_children > 0 && dict->n_children != DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY) ? "a" : "", | ||
| 177 | key_char, value_pattern); | ||
| 178 | g_free (value_pattern); | ||
| 179 | |||
| 180 | @@ -1304,7 +1311,7 @@ dictionary_get_value (AST *ast, | ||
| 181 | { | ||
| 182 | Dictionary *dict = (Dictionary *) ast; | ||
| 183 | |||
| 184 | - if (dict->n_children == -1) | ||
| 185 | + if (dict->n_children == DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY) | ||
| 186 | { | ||
| 187 | const GVariantType *subtype; | ||
| 188 | GVariantBuilder builder; | ||
| 189 | @@ -1337,7 +1344,7 @@ dictionary_get_value (AST *ast, | ||
| 190 | { | ||
| 191 | const GVariantType *entry, *key, *val; | ||
| 192 | GVariantBuilder builder; | ||
| 193 | - gint i; | ||
| 194 | + size_t i; | ||
| 195 | |||
| 196 | if (!g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_DICTIONARY)) | ||
| 197 | return ast_type_error (ast, type, error); | ||
| 198 | @@ -1378,12 +1385,12 @@ static void | ||
| 199 | dictionary_free (AST *ast) | ||
| 200 | { | ||
| 201 | Dictionary *dict = (Dictionary *) ast; | ||
| 202 | - gint n_children; | ||
| 203 | + size_t n_children; | ||
| 204 | |||
| 205 | - if (dict->n_children > -1) | ||
| 206 | - n_children = dict->n_children; | ||
| 207 | - else | ||
| 208 | + if (dict->n_children == DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY) | ||
| 209 | n_children = 1; | ||
| 210 | + else | ||
| 211 | + n_children = dict->n_children; | ||
| 212 | |||
| 213 | ast_array_free (dict->keys, n_children); | ||
| 214 | ast_array_free (dict->values, n_children); | ||
| 215 | @@ -1401,7 +1408,7 @@ dictionary_parse (TokenStream *stream, | ||
| 216 | maybe_wrapper, dictionary_get_value, | ||
| 217 | dictionary_free | ||
| 218 | }; | ||
| 219 | - gint n_keys, n_values; | ||
| 220 | + size_t n_keys, n_values; | ||
| 221 | gboolean only_one; | ||
| 222 | Dictionary *dict; | ||
| 223 | AST *first; | ||
| 224 | @@ -1444,7 +1451,7 @@ dictionary_parse (TokenStream *stream, | ||
| 225 | goto error; | ||
| 226 | |||
| 227 | g_assert (n_keys == 1 && n_values == 1); | ||
| 228 | - dict->n_children = -1; | ||
| 229 | + dict->n_children = DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY; | ||
| 230 | |||
| 231 | return (AST *) dict; | ||
| 232 | } | ||
| 233 | @@ -1477,6 +1484,7 @@ dictionary_parse (TokenStream *stream, | ||
| 234 | } | ||
| 235 | |||
| 236 | g_assert (n_keys == n_values); | ||
| 237 | + g_assert (n_keys != DICTIONARY_N_CHILDREN_FREESTANDING_ENTRY); | ||
| 238 | dict->n_children = n_keys; | ||
| 239 | |||
| 240 | return (AST *) dict; | ||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2025-14087-03.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2025-14087-03.patch new file mode 100644 index 0000000000..4a474f39fc --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2025-14087-03.patch | |||
| @@ -0,0 +1,150 @@ | |||
| 1 | From acaabfedff42e974334dd5368e6103d2845aaba6 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Philip Withnall <pwithnall@gnome.org> | ||
| 3 | Date: Tue, 25 Nov 2025 19:25:58 +0000 | ||
| 4 | Subject: [PATCH] gvariant-parser: Convert error handling code to use size_t | ||
| 5 | |||
| 6 | The error handling code allows for printing out the range of input bytes | ||
| 7 | related to a parsing error. This was previously done using `gint`, but | ||
| 8 | the input could be longer than `INT_MAX`, so it should really be done | ||
| 9 | using `size_t`. | ||
| 10 | |||
| 11 | Spotted while working on #3834. | ||
| 12 | |||
| 13 | Signed-off-by: Philip Withnall <pwithnall@gnome.org> | ||
| 14 | |||
| 15 | CVE: CVE-2025-14087 | ||
| 16 | Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/acaabfedff42e974334dd5368e6103d2845aaba6] | ||
| 17 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 18 | --- | ||
| 19 | glib/gvariant-parser.c | 36 +++++++++++++++++++++++------------- | ||
| 20 | 1 file changed, 23 insertions(+), 13 deletions(-) | ||
| 21 | |||
| 22 | diff --git a/glib/gvariant-parser.c b/glib/gvariant-parser.c | ||
| 23 | index 519baa3f3..1b1ddd654 100644 | ||
| 24 | --- a/glib/gvariant-parser.c | ||
| 25 | +++ b/glib/gvariant-parser.c | ||
| 26 | @@ -88,7 +88,9 @@ g_variant_parser_get_error_quark (void) | ||
| 27 | |||
| 28 | typedef struct | ||
| 29 | { | ||
| 30 | - gint start, end; | ||
| 31 | + /* Offsets from the start of the input, in bytes. Can be equal when referring | ||
| 32 | + * to a point rather than a range. The invariant `end >= start` always holds. */ | ||
| 33 | + size_t start, end; | ||
| 34 | } SourceRef; | ||
| 35 | |||
| 36 | G_GNUC_PRINTF(5, 0) | ||
| 37 | @@ -103,14 +105,16 @@ parser_set_error_va (GError **error, | ||
| 38 | GString *msg = g_string_new (NULL); | ||
| 39 | |||
| 40 | if (location->start == location->end) | ||
| 41 | - g_string_append_printf (msg, "%d", location->start); | ||
| 42 | + g_string_append_printf (msg, "%" G_GSIZE_FORMAT, location->start); | ||
| 43 | else | ||
| 44 | - g_string_append_printf (msg, "%d-%d", location->start, location->end); | ||
| 45 | + g_string_append_printf (msg, "%" G_GSIZE_FORMAT "-%" G_GSIZE_FORMAT, | ||
| 46 | + location->start, location->end); | ||
| 47 | |||
| 48 | if (other != NULL) | ||
| 49 | { | ||
| 50 | g_assert (other->start != other->end); | ||
| 51 | - g_string_append_printf (msg, ",%d-%d", other->start, other->end); | ||
| 52 | + g_string_append_printf (msg, ",%" G_GSIZE_FORMAT "-%" G_GSIZE_FORMAT, | ||
| 53 | + other->start, other->end); | ||
| 54 | } | ||
| 55 | g_string_append_c (msg, ':'); | ||
| 56 | |||
| 57 | @@ -137,11 +141,15 @@ parser_set_error (GError **error, | ||
| 58 | |||
| 59 | typedef struct | ||
| 60 | { | ||
| 61 | + /* We should always have the following ordering constraint: | ||
| 62 | + * start <= this <= stream <= end | ||
| 63 | + * Additionally, unless in an error or EOF state, `this < stream`. | ||
| 64 | + */ | ||
| 65 | const gchar *start; | ||
| 66 | const gchar *stream; | ||
| 67 | const gchar *end; | ||
| 68 | |||
| 69 | - const gchar *this; | ||
| 70 | + const gchar *this; /* (nullable) */ | ||
| 71 | } TokenStream; | ||
| 72 | |||
| 73 | |||
| 74 | @@ -172,7 +180,7 @@ token_stream_set_error (TokenStream *stream, | ||
| 75 | static gboolean | ||
| 76 | token_stream_prepare (TokenStream *stream) | ||
| 77 | { | ||
| 78 | - gint brackets = 0; | ||
| 79 | + gssize brackets = 0; | ||
| 80 | const gchar *end; | ||
| 81 | |||
| 82 | if (stream->this != NULL) | ||
| 83 | @@ -402,7 +410,7 @@ static void | ||
| 84 | pattern_copy (gchar **out, | ||
| 85 | const gchar **in) | ||
| 86 | { | ||
| 87 | - gint brackets = 0; | ||
| 88 | + gssize brackets = 0; | ||
| 89 | |||
| 90 | while (**in == 'a' || **in == 'm' || **in == 'M') | ||
| 91 | *(*out)++ = *(*in)++; | ||
| 92 | @@ -2666,7 +2674,7 @@ g_variant_builder_add_parsed (GVariantBuilder *builder, | ||
| 93 | static gboolean | ||
| 94 | parse_num (const gchar *num, | ||
| 95 | const gchar *limit, | ||
| 96 | - guint *result) | ||
| 97 | + size_t *result) | ||
| 98 | { | ||
| 99 | gchar *endptr; | ||
| 100 | gint64 bignum; | ||
| 101 | @@ -2676,10 +2684,12 @@ parse_num (const gchar *num, | ||
| 102 | if (endptr != limit) | ||
| 103 | return FALSE; | ||
| 104 | |||
| 105 | + /* The upper bound here is more restrictive than it technically needs to be, | ||
| 106 | + * but should be enough for any practical situation: */ | ||
| 107 | if (bignum < 0 || bignum > G_MAXINT) | ||
| 108 | return FALSE; | ||
| 109 | |||
| 110 | - *result = (guint) bignum; | ||
| 111 | + *result = (size_t) bignum; | ||
| 112 | |||
| 113 | return TRUE; | ||
| 114 | } | ||
| 115 | @@ -2690,7 +2700,7 @@ add_last_line (GString *err, | ||
| 116 | { | ||
| 117 | const gchar *last_nl; | ||
| 118 | gchar *chomped; | ||
| 119 | - gint i; | ||
| 120 | + size_t i; | ||
| 121 | |||
| 122 | /* This is an error at the end of input. If we have a file | ||
| 123 | * with newlines, that's probably the empty string after the | ||
| 124 | @@ -2835,7 +2845,7 @@ g_variant_parse_error_print_context (GError *error, | ||
| 125 | |||
| 126 | if (dash == NULL || colon < dash) | ||
| 127 | { | ||
| 128 | - guint point; | ||
| 129 | + size_t point; | ||
| 130 | |||
| 131 | /* we have a single point */ | ||
| 132 | if (!parse_num (error->message, colon, &point)) | ||
| 133 | @@ -2853,7 +2863,7 @@ g_variant_parse_error_print_context (GError *error, | ||
| 134 | /* We have one or two ranges... */ | ||
| 135 | if (comma && comma < colon) | ||
| 136 | { | ||
| 137 | - guint start1, end1, start2, end2; | ||
| 138 | + size_t start1, end1, start2, end2; | ||
| 139 | const gchar *dash2; | ||
| 140 | |||
| 141 | /* Two ranges */ | ||
| 142 | @@ -2869,7 +2879,7 @@ g_variant_parse_error_print_context (GError *error, | ||
| 143 | } | ||
| 144 | else | ||
| 145 | { | ||
| 146 | - guint start, end; | ||
| 147 | + size_t start, end; | ||
| 148 | |||
| 149 | /* One range */ | ||
| 150 | if (!parse_num (error->message, dash, &start) || !parse_num (dash + 1, colon, &end)) | ||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0/CVE-2025-14512.patch b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2025-14512.patch new file mode 100644 index 0000000000..fd3ba765b1 --- /dev/null +++ b/meta/recipes-core/glib-2.0/glib-2.0/CVE-2025-14512.patch | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | From 1909d8ea9297287f1ff6862968608dcf06e60523 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Philip Withnall <pwithnall@gnome.org> | ||
| 3 | Date: Thu, 4 Dec 2025 16:37:19 +0000 | ||
| 4 | Subject: [PATCH] gfileattribute: Fix integer overflow calculating escaping for | ||
| 5 | byte strings | ||
| 6 | |||
| 7 | The number of invalid characters in the byte string (characters which | ||
| 8 | would have to be percent-encoded) was only stored in an `int`, which | ||
| 9 | gave the possibility of a long string largely full of invalid | ||
| 10 | characters overflowing this and allowing an attacker-controlled buffer | ||
| 11 | size to be allocated. | ||
| 12 | |||
| 13 | This could be triggered by an attacker controlled file attribute (of | ||
| 14 | type `G_FILE_ATTRIBUTE_TYPE_BYTE_STRING`), such as | ||
| 15 | `G_FILE_ATTRIBUTE_THUMBNAIL_PATH` or `G_FILE_ATTRIBUTE_STANDARD_NAME`, | ||
| 16 | being read by user code. | ||
| 17 | |||
| 18 | Spotted by Codean Labs. | ||
| 19 | |||
| 20 | Signed-off-by: Philip Withnall <pwithnall@gnome.org> | ||
| 21 | |||
| 22 | Fixes: #3845 | ||
| 23 | |||
| 24 | CVE: CVE-2025-14512 | ||
| 25 | Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/glib/-/commit/1909d8ea9297287f1ff6862968608dcf06e60523] | ||
| 26 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 27 | --- | ||
| 28 | gio/gfileattribute.c | 11 +++++++++-- | ||
| 29 | 1 file changed, 9 insertions(+), 2 deletions(-) | ||
| 30 | |||
| 31 | diff --git a/gio/gfileattribute.c b/gio/gfileattribute.c | ||
| 32 | index c6fde60fa..d3083e5bd 100644 | ||
| 33 | --- a/gio/gfileattribute.c | ||
| 34 | +++ b/gio/gfileattribute.c | ||
| 35 | @@ -20,6 +20,7 @@ | ||
| 36 | |||
| 37 | #include "config.h" | ||
| 38 | |||
| 39 | +#include <stdint.h> | ||
| 40 | #include <string.h> | ||
| 41 | |||
| 42 | #include "gfileattribute.h" | ||
| 43 | @@ -271,11 +272,12 @@ valid_char (char c) | ||
| 44 | return c >= 32 && c <= 126 && c != '\\'; | ||
| 45 | } | ||
| 46 | |||
| 47 | +/* Returns NULL on error */ | ||
| 48 | static char * | ||
| 49 | escape_byte_string (const char *str) | ||
| 50 | { | ||
| 51 | size_t i, len; | ||
| 52 | - int num_invalid; | ||
| 53 | + size_t num_invalid; | ||
| 54 | char *escaped_val, *p; | ||
| 55 | unsigned char c; | ||
| 56 | const char hex_digits[] = "0123456789abcdef"; | ||
| 57 | @@ -293,7 +295,12 @@ escape_byte_string (const char *str) | ||
| 58 | return g_strdup (str); | ||
| 59 | else | ||
| 60 | { | ||
| 61 | - escaped_val = g_malloc (len + num_invalid*3 + 1); | ||
| 62 | + /* Check for overflow. We want to check the inequality: | ||
| 63 | + * !(len + num_invalid * 3 + 1 > SIZE_MAX) */ | ||
| 64 | + if (num_invalid >= (SIZE_MAX - len) / 3) | ||
| 65 | + return NULL; | ||
| 66 | + | ||
| 67 | + escaped_val = g_malloc (len + num_invalid * 3 + 1); | ||
| 68 | |||
| 69 | p = escaped_val; | ||
| 70 | for (i = 0; i < len; i++) | ||
diff --git a/meta/recipes-core/glib-2.0/glib-2.0_2.72.3.bb b/meta/recipes-core/glib-2.0/glib-2.0_2.72.3.bb index 7ba52b5c79..50701be3d0 100644 --- a/meta/recipes-core/glib-2.0/glib-2.0_2.72.3.bb +++ b/meta/recipes-core/glib-2.0/glib-2.0_2.72.3.bb | |||
| @@ -64,6 +64,12 @@ SRC_URI = "${GNOME_MIRROR}/glib/${SHRT_VER}/glib-${PV}.tar.xz \ | |||
| 64 | file://CVE-2025-4373-02.patch \ | 64 | file://CVE-2025-4373-02.patch \ |
| 65 | file://CVE-2025-7039-01.patch \ | 65 | file://CVE-2025-7039-01.patch \ |
| 66 | file://CVE-2025-7039-02.patch \ | 66 | file://CVE-2025-7039-02.patch \ |
| 67 | file://CVE-2025-13601-01.patch \ | ||
| 68 | file://CVE-2025-13601-02.patch \ | ||
| 69 | file://CVE-2025-14087-01.patch \ | ||
| 70 | file://CVE-2025-14087-02.patch \ | ||
| 71 | file://CVE-2025-14087-03.patch \ | ||
| 72 | file://CVE-2025-14512.patch \ | ||
| 67 | " | 73 | " |
| 68 | SRC_URI:append:class-native = " file://relocate-modules.patch" | 74 | SRC_URI:append:class-native = " file://relocate-modules.patch" |
| 69 | 75 | ||
diff --git a/meta/recipes-core/images/build-appliance-image_15.0.0.bb b/meta/recipes-core/images/build-appliance-image_15.0.0.bb index 37328be02a..5b74c10a9a 100644 --- a/meta/recipes-core/images/build-appliance-image_15.0.0.bb +++ b/meta/recipes-core/images/build-appliance-image_15.0.0.bb | |||
| @@ -24,7 +24,7 @@ IMAGE_FSTYPES = "wic.vmdk wic.vhd wic.vhdx" | |||
| 24 | 24 | ||
| 25 | inherit core-image setuptools3 | 25 | inherit core-image setuptools3 |
| 26 | 26 | ||
| 27 | SRCREV ?= "8d5cd4a310e1807e841b25aaa46261dc24cea1eb" | 27 | SRCREV ?= "ff118ede826a9ae45eb35025a5f7f612880fba01" |
| 28 | SRC_URI = "git://git.yoctoproject.org/poky;branch=kirkstone \ | 28 | SRC_URI = "git://git.yoctoproject.org/poky;branch=kirkstone \ |
| 29 | file://Yocto_Build_Appliance.vmx \ | 29 | file://Yocto_Build_Appliance.vmx \ |
| 30 | file://Yocto_Build_Appliance.vmxf \ | 30 | file://Yocto_Build_Appliance.vmxf \ |
diff --git a/meta/recipes-core/util-linux/util-linux.inc b/meta/recipes-core/util-linux/util-linux.inc index c62c6d70c3..a8b505a122 100644 --- a/meta/recipes-core/util-linux/util-linux.inc +++ b/meta/recipes-core/util-linux/util-linux.inc | |||
| @@ -42,6 +42,8 @@ SRC_URI = "${KERNELORG_MIRROR}/linux/utils/util-linux/v${MAJOR_VERSION}/util-lin | |||
| 42 | file://CVE-2024-28085-0004.patch \ | 42 | file://CVE-2024-28085-0004.patch \ |
| 43 | file://CVE-2024-28085-0005.patch \ | 43 | file://CVE-2024-28085-0005.patch \ |
| 44 | file://fstab-isolation.patch \ | 44 | file://fstab-isolation.patch \ |
| 45 | file://CVE-2025-14104-01.patch \ | ||
| 46 | file://CVE-2025-14104-02.patch \ | ||
| 45 | " | 47 | " |
| 46 | 48 | ||
| 47 | SRC_URI[sha256sum] = "634e6916ad913366c3536b6468e7844769549b99a7b2bf80314de78ab5655b83" | 49 | SRC_URI[sha256sum] = "634e6916ad913366c3536b6468e7844769549b99a7b2bf80314de78ab5655b83" |
diff --git a/meta/recipes-core/util-linux/util-linux/CVE-2025-14104-01.patch b/meta/recipes-core/util-linux/util-linux/CVE-2025-14104-01.patch new file mode 100644 index 0000000000..23677345c9 --- /dev/null +++ b/meta/recipes-core/util-linux/util-linux/CVE-2025-14104-01.patch | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | From aaa9e718c88d6916b003da7ebcfe38a3c88df8e6 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Mohamed Maatallah <hotelsmaatallahrecemail@gmail.com> | ||
| 3 | Date: Sat, 24 May 2025 03:16:09 +0100 | ||
| 4 | Subject: [PATCH] Update setpwnam.c | ||
| 5 | |||
| 6 | CVE: CVE-2025-14104 | ||
| 7 | Upstream-Status: Backport [https://github.com/util-linux/util-linux/commit/aaa9e718c88d6916b003da7ebcfe38a3c88df8e6] | ||
| 8 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 9 | --- | ||
| 10 | login-utils/setpwnam.c | 10 ++++++---- | ||
| 11 | 1 file changed, 6 insertions(+), 4 deletions(-) | ||
| 12 | |||
| 13 | diff --git a/login-utils/setpwnam.c b/login-utils/setpwnam.c | ||
| 14 | index 3e3c1abde..95e470b5a 100644 | ||
| 15 | --- a/login-utils/setpwnam.c | ||
| 16 | +++ b/login-utils/setpwnam.c | ||
| 17 | @@ -126,10 +126,12 @@ int setpwnam(struct passwd *pwd, const char *prefix) | ||
| 18 | } | ||
| 19 | |||
| 20 | /* Is this the username we were sent to change? */ | ||
| 21 | - if (!found && linebuf[namelen] == ':' && | ||
| 22 | - !strncmp(linebuf, pwd->pw_name, namelen)) { | ||
| 23 | - /* Yes! So go forth in the name of the Lord and | ||
| 24 | - * change it! */ | ||
| 25 | + if (!found && | ||
| 26 | + strncmp(linebuf, pwd->pw_name, namelen) == 0 && | ||
| 27 | + strlen(linebuf) > namelen && | ||
| 28 | + linebuf[namelen] == ':') { | ||
| 29 | + /* Yes! But this time let’s not walk past the end of the buffer | ||
| 30 | + * in the name of the Lord, SUID, or anything else. */ | ||
| 31 | if (putpwent(pwd, fp) < 0) | ||
| 32 | goto fail; | ||
| 33 | found = 1; | ||
diff --git a/meta/recipes-core/util-linux/util-linux/CVE-2025-14104-02.patch b/meta/recipes-core/util-linux/util-linux/CVE-2025-14104-02.patch new file mode 100644 index 0000000000..9d21db2743 --- /dev/null +++ b/meta/recipes-core/util-linux/util-linux/CVE-2025-14104-02.patch | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | From 9a36d77012c4c771f8d51eba46b6e62c29bf572a Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Mohamed Maatallah <hotelsmaatallahrecemail@gmail.com> | ||
| 3 | Date: Mon, 26 May 2025 10:06:02 +0100 | ||
| 4 | Subject: [PATCH] Update bufflen | ||
| 5 | |||
| 6 | Update buflen | ||
| 7 | |||
| 8 | CVE: CVE-2025-14104 | ||
| 9 | Upstream-Status: Backport [https://github.com/util-linux/util-linux/commit/9a36d77012c4c771f8d51eba46b6e62c29bf572a] | ||
| 10 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 11 | --- | ||
| 12 | login-utils/setpwnam.c | 3 ++- | ||
| 13 | 1 file changed, 2 insertions(+), 1 deletion(-) | ||
| 14 | |||
| 15 | diff --git a/login-utils/setpwnam.c b/login-utils/setpwnam.c | ||
| 16 | index 95e470b5a..7778e98f7 100644 | ||
| 17 | --- a/login-utils/setpwnam.c | ||
| 18 | +++ b/login-utils/setpwnam.c | ||
| 19 | @@ -99,7 +99,8 @@ int setpwnam(struct passwd *pwd, const char *prefix) | ||
| 20 | goto fail; | ||
| 21 | |||
| 22 | namelen = strlen(pwd->pw_name); | ||
| 23 | - | ||
| 24 | + if (namelen > buflen) | ||
| 25 | + buflen += namelen; | ||
| 26 | linebuf = malloc(buflen); | ||
| 27 | if (!linebuf) | ||
| 28 | goto fail; | ||
diff --git a/meta/recipes-devtools/binutils/binutils-2.38.inc b/meta/recipes-devtools/binutils/binutils-2.38.inc index d5ad3c0ecb..36f9c7ce27 100644 --- a/meta/recipes-devtools/binutils/binutils-2.38.inc +++ b/meta/recipes-devtools/binutils/binutils-2.38.inc | |||
| @@ -86,5 +86,10 @@ SRC_URI = "\ | |||
| 86 | file://0047-CVE-2025-8225.patch \ | 86 | file://0047-CVE-2025-8225.patch \ |
| 87 | file://CVE-2025-11412.patch \ | 87 | file://CVE-2025-11412.patch \ |
| 88 | file://CVE-2025-11413.patch \ | 88 | file://CVE-2025-11413.patch \ |
| 89 | file://0048-CVE-2025-11494.patch \ | ||
| 90 | file://0049-CVE-2025-11839.patch \ | ||
| 91 | file://0050-CVE-2025-11840.patch \ | ||
| 92 | file://CVE-2025-1181-pre.patch \ | ||
| 93 | file://CVE-2025-1181.patch \ | ||
| 89 | " | 94 | " |
| 90 | S = "${WORKDIR}/git" | 95 | S = "${WORKDIR}/git" |
diff --git a/meta/recipes-devtools/binutils/binutils/0048-CVE-2025-11494.patch b/meta/recipes-devtools/binutils/binutils/0048-CVE-2025-11494.patch new file mode 100644 index 0000000000..dc4b413658 --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/0048-CVE-2025-11494.patch | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | From: "H.J. Lu" <hjl.tools@gmail.com> | ||
| 2 | Date: Tue, 30 Sep 2025 08:13:56 +0800 | ||
| 3 | |||
| 4 | Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=patch;h=b6ac5a8a5b82f0ae6a4642c8d7149b325f4cc60a] | ||
| 5 | CVE: CVE-2025-11494 | ||
| 6 | |||
| 7 | Since x86 .eh_frame section may reference _GLOBAL_OFFSET_TABLE_, keep | ||
| 8 | _GLOBAL_OFFSET_TABLE_ if there is dynamic section and the output | ||
| 9 | .eh_frame section is non-empty. | ||
| 10 | |||
| 11 | PR ld/33499 | ||
| 12 | * elfxx-x86.c (_bfd_x86_elf_late_size_sections): Keep | ||
| 13 | _GLOBAL_OFFSET_TABLE_ if there is dynamic section and the | ||
| 14 | output .eh_frame section is non-empty. | ||
| 15 | |||
| 16 | Signed-off-by: Deepesh Varatharajan <Deepesh.Varatharajan@windriver.com> | ||
| 17 | |||
| 18 | diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c | ||
| 19 | index c054f7cd..ddc15945 100644 | ||
| 20 | --- a/bfd/elfxx-x86.c | ||
| 21 | +++ b/bfd/elfxx-x86.c | ||
| 22 | @@ -2447,6 +2447,8 @@ _bfd_x86_elf_late_size_sections (bfd *output_bfd, | ||
| 23 | |||
| 24 | if (htab->elf.sgotplt) | ||
| 25 | { | ||
| 26 | + asection *eh_frame; | ||
| 27 | + | ||
| 28 | /* Don't allocate .got.plt section if there are no GOT nor PLT | ||
| 29 | entries and there is no reference to _GLOBAL_OFFSET_TABLE_. */ | ||
| 30 | if ((htab->elf.hgot == NULL | ||
| 31 | @@ -2459,7 +2461,11 @@ _bfd_x86_elf_late_size_sections (bfd *output_bfd, | ||
| 32 | && (htab->elf.iplt == NULL | ||
| 33 | || htab->elf.iplt->size == 0) | ||
| 34 | && (htab->elf.igotplt == NULL | ||
| 35 | - || htab->elf.igotplt->size == 0)) | ||
| 36 | + || htab->elf.igotplt->size == 0) | ||
| 37 | + && (!htab->elf.dynamic_sections_created | ||
| 38 | + || (eh_frame = bfd_get_section_by_name (output_bfd, | ||
| 39 | + ".eh_frame")) == NULL | ||
| 40 | + || eh_frame->rawsize == 0)) | ||
| 41 | { | ||
| 42 | htab->elf.sgotplt->size = 0; | ||
| 43 | /* Solaris requires to keep _GLOBAL_OFFSET_TABLE_ even if it | ||
diff --git a/meta/recipes-devtools/binutils/binutils/0049-CVE-2025-11839.patch b/meta/recipes-devtools/binutils/binutils/0049-CVE-2025-11839.patch new file mode 100644 index 0000000000..7f2f6d553d --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/0049-CVE-2025-11839.patch | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | From 12ef7d5b7b02d0023db645d86eb9d0797bc747fe Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Nick Clifton <nickc@redhat.com> | ||
| 3 | Date: Mon, 3 Nov 2025 11:49:02 +0000 | ||
| 4 | Subject: [PATCH] Remove call to abort in the DGB debug format printing code, | ||
| 5 | thus allowing the display of a fuzzed input file to complete without | ||
| 6 | triggering an abort. | ||
| 7 | |||
| 8 | PR 33448 | ||
| 9 | --- | ||
| 10 | binutils/prdbg.c | 1 - | ||
| 11 | 1 file changed, 1 deletion(-) | ||
| 12 | |||
| 13 | Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=12ef7d5b7b02d0023db645d86eb9d0797bc747fe] | ||
| 14 | CVE: CVE-2025-11839 | ||
| 15 | |||
| 16 | Signed-off-by: Yash Shinde <Yash.Shinde@windriver.com> | ||
| 17 | |||
| 18 | diff --git a/binutils/prdbg.c b/binutils/prdbg.c | ||
| 19 | index c239aeb1a79..5d405c48e3d 100644 | ||
| 20 | --- a/binutils/prdbg.c | ||
| 21 | +++ b/binutils/prdbg.c | ||
| 22 | @@ -2449,7 +2449,6 @@ tg_tag_type (void *p, const char *name, unsigned int id, | ||
| 23 | t = "union class "; | ||
| 24 | break; | ||
| 25 | default: | ||
| 26 | - abort (); | ||
| 27 | return false; | ||
| 28 | } | ||
| 29 | |||
| 30 | -- | ||
| 31 | 2.43.7 | ||
| 32 | |||
diff --git a/meta/recipes-devtools/binutils/binutils/0050-CVE-2025-11840.patch b/meta/recipes-devtools/binutils/binutils/0050-CVE-2025-11840.patch new file mode 100644 index 0000000000..3fb4db880e --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/0050-CVE-2025-11840.patch | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | From f6b0f53a36820da91eadfa9f466c22f92e4256e0 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Alan Modra <amodra@gmail.com> | ||
| 3 | Date: Mon, 3 Nov 2025 09:03:37 +1030 | ||
| 4 | Subject: [PATCH] PR 33455 SEGV in vfinfo at ldmisc.c:527 | ||
| 5 | |||
| 6 | A reloc howto set up with EMPTY_HOWTO has a NULL name. More than one | ||
| 7 | place emitting diagnostics assumes a reloc howto won't have a NULL | ||
| 8 | name. | ||
| 9 | |||
| 10 | PR 33455 | ||
| 11 | * coffcode.h (coff_slurp_reloc_table): Don't allow a howto with | ||
| 12 | a NULL name. | ||
| 13 | --- | ||
| 14 | bfd/coffcode.h | 2 +- | ||
| 15 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
| 16 | |||
| 17 | Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=f6b0f53a36820da91eadfa9f466c22f92e4256e0] | ||
| 18 | CVE: CVE-2025-11840 | ||
| 19 | |||
| 20 | Signed-off-by: Yash Shinde <Yash.Shinde@windriver.com> | ||
| 21 | |||
| 22 | diff --git a/bfd/coffcode.h b/bfd/coffcode.h | ||
| 23 | index 1e5acc0032c..ce1e39131b4 100644 | ||
| 24 | --- a/bfd/coffcode.h | ||
| 25 | +++ b/bfd/coffcode.h | ||
| 26 | @@ -5345,7 +5345,7 @@ coff_slurp_reloc_table (bfd * abfd, sec_ptr asect, asymbol ** symbols) | ||
| 27 | RTYPE2HOWTO (cache_ptr, &dst); | ||
| 28 | #endif /* RELOC_PROCESSING */ | ||
| 29 | |||
| 30 | - if (cache_ptr->howto == NULL) | ||
| 31 | + if (cache_ptr->howto == NULL || cache_ptr->howto->name == NULL) | ||
| 32 | { | ||
| 33 | _bfd_error_handler | ||
| 34 | /* xgettext:c-format */ | ||
| 35 | -- | ||
| 36 | 2.43.7 | ||
| 37 | |||
diff --git a/meta/recipes-devtools/binutils/binutils/CVE-2025-1181-pre.patch b/meta/recipes-devtools/binutils/binutils/CVE-2025-1181-pre.patch new file mode 100644 index 0000000000..ffad871657 --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/CVE-2025-1181-pre.patch | |||
| @@ -0,0 +1,149 @@ | |||
| 1 | Backported of: | ||
| 2 | |||
| 3 | From 18cc11a2771d9e40180485da9a4fb660c03efac3 Mon Sep 17 00:00:00 2001 | ||
| 4 | From: Nick Clifton <nickc@redhat.com> | ||
| 5 | Date: Wed, 5 Feb 2025 14:31:10 +0000 | ||
| 6 | Subject: [PATCH] Prevent illegal memory access when checking relocs in a | ||
| 7 | corrupt ELF binary. | ||
| 8 | |||
| 9 | PR 32641 | ||
| 10 | |||
| 11 | Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/binutils/tree/debian/patches/CVE-2025-1181-pre.patch?h=ubuntu/jammy-security | ||
| 12 | Upstream commit https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=18cc11a2771d9e40180485da9a4fb660c03efac3] | ||
| 13 | CVE: CVE-2025-1181 | ||
| 14 | Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> | ||
| 15 | --- | ||
| 16 | bfd/elf-bfd.h | 3 +++ | ||
| 17 | bfd/elf64-x86-64.c | 10 +++++----- | ||
| 18 | bfd/elflink.c | 24 ++++++++++++++++++++++++ | ||
| 19 | bfd/elfxx-x86.c | 20 +++++++------------- | ||
| 20 | 4 files changed, 39 insertions(+), 18 deletions(-) | ||
| 21 | Index: binutils-2.38/bfd/elf-bfd.h | ||
| 22 | =================================================================== | ||
| 23 | --- binutils-2.38.orig/bfd/elf-bfd.h | ||
| 24 | +++ binutils-2.38/bfd/elf-bfd.h | ||
| 25 | @@ -3007,6 +3007,9 @@ extern bool _bfd_elf_maybe_set_textrel | ||
| 26 | extern bool _bfd_elf_add_dynamic_tags | ||
| 27 | (bfd *, struct bfd_link_info *, bool); | ||
| 28 | |||
| 29 | +extern struct elf_link_hash_entry * _bfd_elf_get_link_hash_entry | ||
| 30 | + (struct elf_link_hash_entry **, unsigned int, Elf_Internal_Shdr *); | ||
| 31 | + | ||
| 32 | /* Large common section. */ | ||
| 33 | extern asection _bfd_elf_large_com_section; | ||
| 34 | |||
| 35 | Index: binutils-2.38/bfd/elf64-x86-64.c | ||
| 36 | =================================================================== | ||
| 37 | --- binutils-2.38.orig/bfd/elf64-x86-64.c | ||
| 38 | +++ binutils-2.38/bfd/elf64-x86-64.c | ||
| 39 | @@ -1484,7 +1484,7 @@ elf_x86_64_convert_load_reloc (bfd *abfd | ||
| 40 | bool to_reloc_pc32; | ||
| 41 | bool abs_symbol; | ||
| 42 | bool local_ref; | ||
| 43 | - asection *tsec; | ||
| 44 | + asection *tsec = NULL; | ||
| 45 | bfd_signed_vma raddend; | ||
| 46 | unsigned int opcode; | ||
| 47 | unsigned int modrm; | ||
| 48 | @@ -1639,6 +1639,9 @@ elf_x86_64_convert_load_reloc (bfd *abfd | ||
| 49 | return true; | ||
| 50 | } | ||
| 51 | |||
| 52 | + if (tsec == NULL) | ||
| 53 | + return false; | ||
| 54 | + | ||
| 55 | /* Don't convert GOTPCREL relocation against large section. */ | ||
| 56 | if (elf_section_data (tsec) != NULL | ||
| 57 | && (elf_section_flags (tsec) & SHF_X86_64_LARGE) != 0) | ||
| 58 | @@ -1915,10 +1918,7 @@ elf_x86_64_scan_relocs (bfd *abfd, struc | ||
| 59 | else | ||
| 60 | { | ||
| 61 | isym = NULL; | ||
| 62 | - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; | ||
| 63 | - while (h->root.type == bfd_link_hash_indirect | ||
| 64 | - || h->root.type == bfd_link_hash_warning) | ||
| 65 | - h = (struct elf_link_hash_entry *) h->root.u.i.link; | ||
| 66 | + h = _bfd_elf_get_link_hash_entry (sym_hashes, r_symndx, symtab_hdr); | ||
| 67 | } | ||
| 68 | |||
| 69 | /* Check invalid x32 relocations. */ | ||
| 70 | Index: binutils-2.38/bfd/elflink.c | ||
| 71 | =================================================================== | ||
| 72 | --- binutils-2.38.orig/bfd/elflink.c | ||
| 73 | +++ binutils-2.38/bfd/elflink.c | ||
| 74 | @@ -62,6 +62,27 @@ struct elf_find_verdep_info | ||
| 75 | static bool _bfd_elf_fix_symbol_flags | ||
| 76 | (struct elf_link_hash_entry *, struct elf_info_failed *); | ||
| 77 | |||
| 78 | +struct elf_link_hash_entry * | ||
| 79 | +_bfd_elf_get_link_hash_entry (struct elf_link_hash_entry ** sym_hashes, | ||
| 80 | + unsigned int symndx, | ||
| 81 | + Elf_Internal_Shdr * symtab_hdr) | ||
| 82 | +{ | ||
| 83 | + if (symndx < symtab_hdr->sh_info) | ||
| 84 | + return NULL; | ||
| 85 | + | ||
| 86 | + struct elf_link_hash_entry *h = sym_hashes[symndx - symtab_hdr->sh_info]; | ||
| 87 | + | ||
| 88 | + /* The hash might be empty. See PR 32641 for an example of this. */ | ||
| 89 | + if (h == NULL) | ||
| 90 | + return NULL; | ||
| 91 | + | ||
| 92 | + while (h->root.type == bfd_link_hash_indirect | ||
| 93 | + || h->root.type == bfd_link_hash_warning) | ||
| 94 | + h = (struct elf_link_hash_entry *) h->root.u.i.link; | ||
| 95 | + | ||
| 96 | + return h; | ||
| 97 | +} | ||
| 98 | + | ||
| 99 | static struct elf_link_hash_entry * | ||
| 100 | get_ext_sym_hash (struct elf_reloc_cookie *cookie, unsigned long r_symndx) | ||
| 101 | { | ||
| 102 | @@ -75,6 +96,9 @@ get_ext_sym_hash (struct elf_reloc_cooki | ||
| 103 | |||
| 104 | h = cookie->sym_hashes[r_symndx - cookie->extsymoff]; | ||
| 105 | |||
| 106 | + if (h == NULL) | ||
| 107 | + return NULL; | ||
| 108 | + | ||
| 109 | while (h->root.type == bfd_link_hash_indirect | ||
| 110 | || h->root.type == bfd_link_hash_warning) | ||
| 111 | h = (struct elf_link_hash_entry *) h->root.u.i.link; | ||
| 112 | Index: binutils-2.38/bfd/elfxx-x86.c | ||
| 113 | =================================================================== | ||
| 114 | --- binutils-2.38.orig/bfd/elfxx-x86.c | ||
| 115 | +++ binutils-2.38/bfd/elfxx-x86.c | ||
| 116 | @@ -973,15 +973,7 @@ _bfd_x86_elf_check_relocs (bfd *abfd, | ||
| 117 | goto error_return; | ||
| 118 | } | ||
| 119 | |||
| 120 | - if (r_symndx < symtab_hdr->sh_info) | ||
| 121 | - h = NULL; | ||
| 122 | - else | ||
| 123 | - { | ||
| 124 | - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; | ||
| 125 | - while (h->root.type == bfd_link_hash_indirect | ||
| 126 | - || h->root.type == bfd_link_hash_warning) | ||
| 127 | - h = (struct elf_link_hash_entry *) h->root.u.i.link; | ||
| 128 | - } | ||
| 129 | + h = _bfd_elf_get_link_hash_entry (sym_hashes, r_symndx, symtab_hdr); | ||
| 130 | |||
| 131 | if (X86_NEED_DYNAMIC_RELOC_TYPE_P (is_x86_64, r_type) | ||
| 132 | && NEED_DYNAMIC_RELOCATION_P (is_x86_64, info, true, h, sec, | ||
| 133 | @@ -1200,10 +1192,12 @@ _bfd_x86_elf_link_relax_section (bfd *ab | ||
| 134 | else | ||
| 135 | { | ||
| 136 | /* Get H and SEC for GENERATE_DYNAMIC_RELOCATION_P below. */ | ||
| 137 | - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; | ||
| 138 | - while (h->root.type == bfd_link_hash_indirect | ||
| 139 | - || h->root.type == bfd_link_hash_warning) | ||
| 140 | - h = (struct elf_link_hash_entry *) h->root.u.i.link; | ||
| 141 | + h = _bfd_elf_get_link_hash_entry (sym_hashes, r_symndx, symtab_hdr); | ||
| 142 | + if (h == NULL) | ||
| 143 | + { | ||
| 144 | + /* FIXMEL: Issue an error message ? */ | ||
| 145 | + continue; | ||
| 146 | + } | ||
| 147 | |||
| 148 | if (h->root.type == bfd_link_hash_defined | ||
| 149 | || h->root.type == bfd_link_hash_defweak) | ||
diff --git a/meta/recipes-devtools/binutils/binutils/CVE-2025-1181.patch b/meta/recipes-devtools/binutils/binutils/CVE-2025-1181.patch new file mode 100644 index 0000000000..2bcd55795d --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/CVE-2025-1181.patch | |||
| @@ -0,0 +1,342 @@ | |||
| 1 | Backported of: | ||
| 2 | |||
| 3 | From 931494c9a89558acb36a03a340c01726545eef24 Mon Sep 17 00:00:00 2001 | ||
| 4 | From: Nick Clifton <nickc@redhat.com> | ||
| 5 | Date: Wed, 5 Feb 2025 15:43:04 +0000 | ||
| 6 | Subject: [PATCH] Add even more checks for corrupt input when processing | ||
| 7 | relocations for ELF files. | ||
| 8 | |||
| 9 | PR 32643 | ||
| 10 | |||
| 11 | Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/binutils/tree/debian/patches/CVE-2025-1181.patch?h=ubuntu/jammy-security | ||
| 12 | Upstream commit https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=931494c9a89558acb36a03a340c01726545eef24] | ||
| 13 | CVE: CVE-2025-1181 | ||
| 14 | Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> | ||
| 15 | |||
| 16 | Index: binutils-2.38/bfd/elflink.c | ||
| 17 | =================================================================== | ||
| 18 | --- binutils-2.38.orig/bfd/elflink.c | ||
| 19 | +++ binutils-2.38/bfd/elflink.c | ||
| 20 | @@ -62,15 +62,17 @@ struct elf_find_verdep_info | ||
| 21 | static bool _bfd_elf_fix_symbol_flags | ||
| 22 | (struct elf_link_hash_entry *, struct elf_info_failed *); | ||
| 23 | |||
| 24 | -struct elf_link_hash_entry * | ||
| 25 | -_bfd_elf_get_link_hash_entry (struct elf_link_hash_entry ** sym_hashes, | ||
| 26 | - unsigned int symndx, | ||
| 27 | - Elf_Internal_Shdr * symtab_hdr) | ||
| 28 | +static struct elf_link_hash_entry * | ||
| 29 | +get_link_hash_entry (struct elf_link_hash_entry ** sym_hashes, | ||
| 30 | + unsigned int symndx, | ||
| 31 | + unsigned int ext_sym_start) | ||
| 32 | { | ||
| 33 | - if (symndx < symtab_hdr->sh_info) | ||
| 34 | + if (sym_hashes == NULL | ||
| 35 | + /* Guard against corrupt input. See PR 32636 for an example. */ | ||
| 36 | + || symndx < ext_sym_start) | ||
| 37 | return NULL; | ||
| 38 | |||
| 39 | - struct elf_link_hash_entry *h = sym_hashes[symndx - symtab_hdr->sh_info]; | ||
| 40 | + struct elf_link_hash_entry *h = sym_hashes[symndx - ext_sym_start]; | ||
| 41 | |||
| 42 | /* The hash might be empty. See PR 32641 for an example of this. */ | ||
| 43 | if (h == NULL) | ||
| 44 | @@ -83,29 +85,28 @@ _bfd_elf_get_link_hash_entry (struct elf | ||
| 45 | return h; | ||
| 46 | } | ||
| 47 | |||
| 48 | -static struct elf_link_hash_entry * | ||
| 49 | -get_ext_sym_hash (struct elf_reloc_cookie *cookie, unsigned long r_symndx) | ||
| 50 | +struct elf_link_hash_entry * | ||
| 51 | +_bfd_elf_get_link_hash_entry (struct elf_link_hash_entry ** sym_hashes, | ||
| 52 | + unsigned int symndx, | ||
| 53 | + Elf_Internal_Shdr * symtab_hdr) | ||
| 54 | { | ||
| 55 | - struct elf_link_hash_entry *h = NULL; | ||
| 56 | - | ||
| 57 | - if ((r_symndx >= cookie->locsymcount | ||
| 58 | - || ELF_ST_BIND (cookie->locsyms[r_symndx].st_info) != STB_LOCAL) | ||
| 59 | - /* Guard against corrupt input. See PR 32636 for an example. */ | ||
| 60 | - && r_symndx >= cookie->extsymoff) | ||
| 61 | - { | ||
| 62 | - | ||
| 63 | - h = cookie->sym_hashes[r_symndx - cookie->extsymoff]; | ||
| 64 | - | ||
| 65 | - if (h == NULL) | ||
| 66 | - return NULL; | ||
| 67 | + if (symtab_hdr == NULL) | ||
| 68 | + return NULL; | ||
| 69 | |||
| 70 | - while (h->root.type == bfd_link_hash_indirect | ||
| 71 | - || h->root.type == bfd_link_hash_warning) | ||
| 72 | - h = (struct elf_link_hash_entry *) h->root.u.i.link; | ||
| 73 | + return get_link_hash_entry (sym_hashes, symndx, symtab_hdr->sh_info); | ||
| 74 | +} | ||
| 75 | |||
| 76 | - } | ||
| 77 | +static struct elf_link_hash_entry * | ||
| 78 | +get_ext_sym_hash_from_cookie (struct elf_reloc_cookie *cookie, unsigned long r_symndx) | ||
| 79 | +{ | ||
| 80 | + if (cookie == NULL || cookie->sym_hashes == NULL) | ||
| 81 | + return NULL; | ||
| 82 | + | ||
| 83 | + if (r_symndx >= cookie->locsymcount | ||
| 84 | + || ELF_ST_BIND (cookie->locsyms[r_symndx].st_info) != STB_LOCAL) | ||
| 85 | + return get_link_hash_entry (cookie->sym_hashes, r_symndx, cookie->extsymoff); | ||
| 86 | |||
| 87 | - return h; | ||
| 88 | + return NULL; | ||
| 89 | } | ||
| 90 | |||
| 91 | asection * | ||
| 92 | @@ -115,7 +116,7 @@ _bfd_elf_section_for_symbol (struct elf_ | ||
| 93 | { | ||
| 94 | struct elf_link_hash_entry *h; | ||
| 95 | |||
| 96 | - h = get_ext_sym_hash (cookie, r_symndx); | ||
| 97 | + h = get_ext_sym_hash_from_cookie (cookie, r_symndx); | ||
| 98 | |||
| 99 | if (h != NULL) | ||
| 100 | { | ||
| 101 | @@ -8783,7 +8784,6 @@ set_symbol_value (bfd *bfd_with_globals, | ||
| 102 | size_t symidx, | ||
| 103 | bfd_vma val) | ||
| 104 | { | ||
| 105 | - struct elf_link_hash_entry **sym_hashes; | ||
| 106 | struct elf_link_hash_entry *h; | ||
| 107 | size_t extsymoff = locsymcount; | ||
| 108 | |||
| 109 | @@ -8806,12 +8806,12 @@ set_symbol_value (bfd *bfd_with_globals, | ||
| 110 | |||
| 111 | /* It is a global symbol: set its link type | ||
| 112 | to "defined" and give it a value. */ | ||
| 113 | - | ||
| 114 | - sym_hashes = elf_sym_hashes (bfd_with_globals); | ||
| 115 | - h = sym_hashes [symidx - extsymoff]; | ||
| 116 | - while (h->root.type == bfd_link_hash_indirect | ||
| 117 | - || h->root.type == bfd_link_hash_warning) | ||
| 118 | - h = (struct elf_link_hash_entry *) h->root.u.i.link; | ||
| 119 | + h = get_link_hash_entry (elf_sym_hashes (bfd_with_globals), symidx, extsymoff); | ||
| 120 | + if (h == NULL) | ||
| 121 | + { | ||
| 122 | + /* FIXMEL What should we do ? */ | ||
| 123 | + return; | ||
| 124 | + } | ||
| 125 | h->root.type = bfd_link_hash_defined; | ||
| 126 | h->root.u.def.value = val; | ||
| 127 | h->root.u.def.section = bfd_abs_section_ptr; | ||
| 128 | @@ -11281,10 +11281,19 @@ elf_link_input_bfd (struct elf_final_lin | ||
| 129 | || (elf_bad_symtab (input_bfd) | ||
| 130 | && flinfo->sections[symndx] == NULL)) | ||
| 131 | { | ||
| 132 | - struct elf_link_hash_entry *h = sym_hashes[symndx - extsymoff]; | ||
| 133 | - while (h->root.type == bfd_link_hash_indirect | ||
| 134 | - || h->root.type == bfd_link_hash_warning) | ||
| 135 | - h = (struct elf_link_hash_entry *) h->root.u.i.link; | ||
| 136 | + struct elf_link_hash_entry *h; | ||
| 137 | + | ||
| 138 | + h = get_link_hash_entry (sym_hashes, symndx, extsymoff); | ||
| 139 | + if (h == NULL) | ||
| 140 | + { | ||
| 141 | + _bfd_error_handler | ||
| 142 | + /* xgettext:c-format */ | ||
| 143 | + (_("error: %pB: unable to create group section symbol"), | ||
| 144 | + input_bfd); | ||
| 145 | + bfd_set_error (bfd_error_bad_value); | ||
| 146 | + return false; | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | /* Arrange for symbol to be output. */ | ||
| 150 | h->indx = -2; | ||
| 151 | elf_section_data (osec)->this_hdr.sh_info = -2; | ||
| 152 | @@ -11411,7 +11420,7 @@ elf_link_input_bfd (struct elf_final_lin | ||
| 153 | || (elf_bad_symtab (input_bfd) | ||
| 154 | && flinfo->sections[r_symndx] == NULL)) | ||
| 155 | { | ||
| 156 | - h = sym_hashes[r_symndx - extsymoff]; | ||
| 157 | + h = get_link_hash_entry (sym_hashes, r_symndx, extsymoff); | ||
| 158 | |||
| 159 | /* Badly formatted input files can contain relocs that | ||
| 160 | reference non-existant symbols. Check here so that | ||
| 161 | @@ -11420,17 +11429,13 @@ elf_link_input_bfd (struct elf_final_lin | ||
| 162 | { | ||
| 163 | _bfd_error_handler | ||
| 164 | /* xgettext:c-format */ | ||
| 165 | - (_("error: %pB contains a reloc (%#" PRIx64 ") for section %pA " | ||
| 166 | + (_("error: %pB contains a reloc (%#" PRIx64 ") for section '%pA' " | ||
| 167 | "that references a non-existent global symbol"), | ||
| 168 | input_bfd, (uint64_t) rel->r_info, o); | ||
| 169 | bfd_set_error (bfd_error_bad_value); | ||
| 170 | return false; | ||
| 171 | } | ||
| 172 | |||
| 173 | - while (h->root.type == bfd_link_hash_indirect | ||
| 174 | - || h->root.type == bfd_link_hash_warning) | ||
| 175 | - h = (struct elf_link_hash_entry *) h->root.u.i.link; | ||
| 176 | - | ||
| 177 | s_type = h->type; | ||
| 178 | |||
| 179 | /* If a plugin symbol is referenced from a non-IR file, | ||
| 180 | @@ -11646,7 +11651,6 @@ elf_link_input_bfd (struct elf_final_lin | ||
| 181 | && flinfo->sections[r_symndx] == NULL)) | ||
| 182 | { | ||
| 183 | struct elf_link_hash_entry *rh; | ||
| 184 | - unsigned long indx; | ||
| 185 | |||
| 186 | /* This is a reloc against a global symbol. We | ||
| 187 | have not yet output all the local symbols, so | ||
| 188 | @@ -11655,15 +11659,16 @@ elf_link_input_bfd (struct elf_final_lin | ||
| 189 | reloc to point to the global hash table entry | ||
| 190 | for this symbol. The symbol index is then | ||
| 191 | set at the end of bfd_elf_final_link. */ | ||
| 192 | - indx = r_symndx - extsymoff; | ||
| 193 | - rh = elf_sym_hashes (input_bfd)[indx]; | ||
| 194 | - while (rh->root.type == bfd_link_hash_indirect | ||
| 195 | - || rh->root.type == bfd_link_hash_warning) | ||
| 196 | - rh = (struct elf_link_hash_entry *) rh->root.u.i.link; | ||
| 197 | - | ||
| 198 | - /* Setting the index to -2 tells | ||
| 199 | - elf_link_output_extsym that this symbol is | ||
| 200 | - used by a reloc. */ | ||
| 201 | + rh = get_link_hash_entry (elf_sym_hashes (input_bfd), | ||
| 202 | + r_symndx, extsymoff); | ||
| 203 | + if (rh == NULL) | ||
| 204 | + { | ||
| 205 | + /* FIXME: Generate an error ? */ | ||
| 206 | + continue; | ||
| 207 | + } | ||
| 208 | + | ||
| 209 | + /* Setting the index to -2 tells elf_link_output_extsym | ||
| 210 | + that this symbol is used by a reloc. */ | ||
| 211 | BFD_ASSERT (rh->indx < 0); | ||
| 212 | rh->indx = -2; | ||
| 213 | *rel_hash = rh; | ||
| 214 | @@ -13615,25 +13620,21 @@ _bfd_elf_gc_mark_hook (asection *sec, | ||
| 215 | struct elf_link_hash_entry *h, | ||
| 216 | Elf_Internal_Sym *sym) | ||
| 217 | { | ||
| 218 | - if (h != NULL) | ||
| 219 | + if (h == NULL) | ||
| 220 | + return bfd_section_from_elf_index (sec->owner, sym->st_shndx); | ||
| 221 | + | ||
| 222 | + switch (h->root.type) | ||
| 223 | { | ||
| 224 | - switch (h->root.type) | ||
| 225 | - { | ||
| 226 | - case bfd_link_hash_defined: | ||
| 227 | - case bfd_link_hash_defweak: | ||
| 228 | - return h->root.u.def.section; | ||
| 229 | + case bfd_link_hash_defined: | ||
| 230 | + case bfd_link_hash_defweak: | ||
| 231 | + return h->root.u.def.section; | ||
| 232 | |||
| 233 | - case bfd_link_hash_common: | ||
| 234 | - return h->root.u.c.p->section; | ||
| 235 | + case bfd_link_hash_common: | ||
| 236 | + return h->root.u.c.p->section; | ||
| 237 | |||
| 238 | - default: | ||
| 239 | - break; | ||
| 240 | - } | ||
| 241 | + default: | ||
| 242 | + return NULL; | ||
| 243 | } | ||
| 244 | - else | ||
| 245 | - return bfd_section_from_elf_index (sec->owner, sym->st_shndx); | ||
| 246 | - | ||
| 247 | - return NULL; | ||
| 248 | } | ||
| 249 | |||
| 250 | /* Return the debug definition section. */ | ||
| 251 | @@ -13682,46 +13683,49 @@ _bfd_elf_gc_mark_rsec (struct bfd_link_i | ||
| 252 | if (r_symndx == STN_UNDEF) | ||
| 253 | return NULL; | ||
| 254 | |||
| 255 | - h = get_ext_sym_hash (cookie, r_symndx); | ||
| 256 | - | ||
| 257 | - if (h != NULL) | ||
| 258 | + h = get_ext_sym_hash_from_cookie (cookie, r_symndx); | ||
| 259 | + if (h == NULL) | ||
| 260 | { | ||
| 261 | - bool was_marked; | ||
| 262 | + /* A corrup tinput file can lead to a situation where the index | ||
| 263 | + does not reference either a local or an external symbol. */ | ||
| 264 | + if (r_symndx >= cookie->locsymcount) | ||
| 265 | + return NULL; | ||
| 266 | |||
| 267 | - was_marked = h->mark; | ||
| 268 | - h->mark = 1; | ||
| 269 | - /* Keep all aliases of the symbol too. If an object symbol | ||
| 270 | - needs to be copied into .dynbss then all of its aliases | ||
| 271 | - should be present as dynamic symbols, not just the one used | ||
| 272 | - on the copy relocation. */ | ||
| 273 | - hw = h; | ||
| 274 | - while (hw->is_weakalias) | ||
| 275 | - { | ||
| 276 | - hw = hw->u.alias; | ||
| 277 | - hw->mark = 1; | ||
| 278 | - } | ||
| 279 | + return (*gc_mark_hook) (sec, info, cookie->rel, NULL, | ||
| 280 | + &cookie->locsyms[r_symndx]); | ||
| 281 | + } | ||
| 282 | |||
| 283 | - if (!was_marked && h->start_stop && !h->root.ldscript_def) | ||
| 284 | - { | ||
| 285 | - if (info->start_stop_gc) | ||
| 286 | - return NULL; | ||
| 287 | + bool was_marked = h->mark; | ||
| 288 | |||
| 289 | - /* To work around a glibc bug, mark XXX input sections | ||
| 290 | - when there is a reference to __start_XXX or __stop_XXX | ||
| 291 | - symbols. */ | ||
| 292 | - else if (start_stop != NULL) | ||
| 293 | - { | ||
| 294 | - asection *s = h->u2.start_stop_section; | ||
| 295 | - *start_stop = true; | ||
| 296 | - return s; | ||
| 297 | - } | ||
| 298 | - } | ||
| 299 | + h->mark = 1; | ||
| 300 | + /* Keep all aliases of the symbol too. If an object symbol | ||
| 301 | + needs to be copied into .dynbss then all of its aliases | ||
| 302 | + should be present as dynamic symbols, not just the one used | ||
| 303 | + on the copy relocation. */ | ||
| 304 | + hw = h; | ||
| 305 | + while (hw->is_weakalias) | ||
| 306 | + { | ||
| 307 | + hw = hw->u.alias; | ||
| 308 | + hw->mark = 1; | ||
| 309 | + } | ||
| 310 | |||
| 311 | - return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL); | ||
| 312 | + if (!was_marked && h->start_stop && !h->root.ldscript_def) | ||
| 313 | + { | ||
| 314 | + if (info->start_stop_gc) | ||
| 315 | + return NULL; | ||
| 316 | + | ||
| 317 | + /* To work around a glibc bug, mark XXX input sections | ||
| 318 | + when there is a reference to __start_XXX or __stop_XXX | ||
| 319 | + symbols. */ | ||
| 320 | + else if (start_stop != NULL) | ||
| 321 | + { | ||
| 322 | + asection *s = h->u2.start_stop_section; | ||
| 323 | + *start_stop = true; | ||
| 324 | + return s; | ||
| 325 | + } | ||
| 326 | } | ||
| 327 | |||
| 328 | - return (*gc_mark_hook) (sec, info, cookie->rel, NULL, | ||
| 329 | - &cookie->locsyms[r_symndx]); | ||
| 330 | + return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL); | ||
| 331 | } | ||
| 332 | |||
| 333 | /* COOKIE->rel describes a relocation against section SEC, which is | ||
| 334 | @@ -14735,7 +14739,7 @@ bfd_elf_reloc_symbol_deleted_p (bfd_vma | ||
| 335 | |||
| 336 | struct elf_link_hash_entry *h; | ||
| 337 | |||
| 338 | - h = get_ext_sym_hash (rcookie, r_symndx); | ||
| 339 | + h = get_ext_sym_hash_from_cookie (rcookie, r_symndx); | ||
| 340 | |||
| 341 | if (h != NULL) | ||
| 342 | { | ||
diff --git a/meta/recipes-devtools/go/go-1.17.13.inc b/meta/recipes-devtools/go/go-1.17.13.inc index bb5e839950..e95003db96 100644 --- a/meta/recipes-devtools/go/go-1.17.13.inc +++ b/meta/recipes-devtools/go/go-1.17.13.inc | |||
| @@ -69,10 +69,14 @@ SRC_URI = "https://golang.org/dl/go${PV}.src.tar.gz;name=main \ | |||
| 69 | file://CVE-2025-47907.patch \ | 69 | file://CVE-2025-47907.patch \ |
| 70 | file://CVE-2025-47906.patch \ | 70 | file://CVE-2025-47906.patch \ |
| 71 | file://CVE-2024-24783.patch \ | 71 | file://CVE-2024-24783.patch \ |
| 72 | file://CVE-2025-58187.patch \ | 72 | file://CVE-2025-58187-1.patch \ |
| 73 | file://CVE-2025-58187-2.patch \ | ||
| 73 | file://CVE-2025-58189.patch \ | 74 | file://CVE-2025-58189.patch \ |
| 74 | file://CVE-2025-61723.patch \ | 75 | file://CVE-2025-61723.patch \ |
| 75 | file://CVE-2025-61724.patch \ | 76 | file://CVE-2025-61724.patch \ |
| 77 | file://CVE-2023-39323.patch \ | ||
| 78 | file://CVE-2025-61727.patch \ | ||
| 79 | file://CVE-2025-61729.patch \ | ||
| 76 | " | 80 | " |
| 77 | SRC_URI[main.sha256sum] = "a1a48b23afb206f95e7bbaa9b898d965f90826f6f1d1fc0c1d784ada0cd300fd" | 81 | SRC_URI[main.sha256sum] = "a1a48b23afb206f95e7bbaa9b898d965f90826f6f1d1fc0c1d784ada0cd300fd" |
| 78 | 82 | ||
diff --git a/meta/recipes-devtools/go/go-1.18/CVE-2025-58187.patch b/meta/recipes-devtools/go/go-1.18/CVE-2025-58187-1.patch index 810487674c..810487674c 100644 --- a/meta/recipes-devtools/go/go-1.18/CVE-2025-58187.patch +++ b/meta/recipes-devtools/go/go-1.18/CVE-2025-58187-1.patch | |||
diff --git a/meta/recipes-devtools/go/go-1.18/CVE-2025-58187-2.patch b/meta/recipes-devtools/go/go-1.18/CVE-2025-58187-2.patch new file mode 100644 index 0000000000..65f176f027 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.18/CVE-2025-58187-2.patch | |||
| @@ -0,0 +1,516 @@ | |||
| 1 | From ca6a5545ba18844a97c88a90a385eb6335bb7526 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Roland Shoemaker <roland@golang.org> | ||
| 3 | Date: Thu, 9 Oct 2025 13:35:24 -0700 | ||
| 4 | Subject: [PATCH] [release-branch.go1.24] crypto/x509: rework fix for | ||
| 5 | CVE-2025-58187 | ||
| 6 | |||
| 7 | In CL 709854 we enabled strict validation for a number of properties of | ||
| 8 | domain names (and their constraints). This caused significant breakage, | ||
| 9 | since we didn't previously disallow the creation of certificates which | ||
| 10 | contained these malformed domains. | ||
| 11 | |||
| 12 | Rollback a number of the properties we enforced, making domainNameValid | ||
| 13 | only enforce the same properties that domainToReverseLabels does. Since | ||
| 14 | this also undoes some of the DoS protections our initial fix enabled, | ||
| 15 | this change also adds caching of constraints in isValid (which perhaps | ||
| 16 | is the fix we should've initially chosen). | ||
| 17 | |||
| 18 | Updates #75835 | ||
| 19 | Updates #75828 | ||
| 20 | Fixes #75860 | ||
| 21 | |||
| 22 | Change-Id: Ie6ca6b4f30e9b8a143692b64757f7bbf4671ed0e | ||
| 23 | Reviewed-on: https://go-review.googlesource.com/c/go/+/710735 | ||
| 24 | LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> | ||
| 25 | Reviewed-by: Damien Neil <dneil@google.com> | ||
| 26 | (cherry picked from commit 1cd71689f2ed8f07031a0cc58fc3586ca501839f) | ||
| 27 | Reviewed-on: https://go-review.googlesource.com/c/go/+/710879 | ||
| 28 | Reviewed-by: Michael Pratt <mpratt@google.com> | ||
| 29 | Auto-Submit: Michael Pratt <mpratt@google.com> | ||
| 30 | |||
| 31 | Upstream-Status: Backport [https://github.com/golang/go/commit/ca6a5545ba18844a97c88a90a385eb6335bb7526] | ||
| 32 | CVE: CVE-2025-58187 | ||
| 33 | Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> | ||
| 34 | --- | ||
| 35 | src/crypto/x509/name_constraints_test.go | 66 +++++++++++++++++-- | ||
| 36 | src/crypto/x509/parser.go | 57 +++++++++++----- | ||
| 37 | src/crypto/x509/parser_test.go | 84 +++++++++++++++++++++--- | ||
| 38 | src/crypto/x509/verify.go | 53 ++++++++++----- | ||
| 39 | src/crypto/x509/verify_test.go | 2 +- | ||
| 40 | 5 files changed, 213 insertions(+), 49 deletions(-) | ||
| 41 | |||
| 42 | diff --git a/src/crypto/x509/name_constraints_test.go b/src/crypto/x509/name_constraints_test.go | ||
| 43 | index d4f7d41..c59a7dc 100644 | ||
| 44 | --- a/src/crypto/x509/name_constraints_test.go | ||
| 45 | +++ b/src/crypto/x509/name_constraints_test.go | ||
| 46 | @@ -1452,7 +1452,63 @@ var nameConstraintsTests = []nameConstraintsTest{ | ||
| 47 | requestedEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}, | ||
| 48 | }, | ||
| 49 | |||
| 50 | - // #77: if several EKUs are requested, satisfying any of them is sufficient. | ||
| 51 | + // An invalid DNS SAN should be detected only at validation time so | ||
| 52 | + // that we can process CA certificates in the wild that have invalid SANs. | ||
| 53 | + // See https://github.com/golang/go/issues/23995 | ||
| 54 | + | ||
| 55 | + // #77: an invalid DNS or mail SAN will not be detected if name constraint | ||
| 56 | + // checking is not triggered. | ||
| 57 | + { | ||
| 58 | + roots: make([]constraintsSpec, 1), | ||
| 59 | + intermediates: [][]constraintsSpec{ | ||
| 60 | + { | ||
| 61 | + {}, | ||
| 62 | + }, | ||
| 63 | + }, | ||
| 64 | + leaf: leafSpec{ | ||
| 65 | + sans: []string{"dns:this is invalid", "email:this @ is invalid"}, | ||
| 66 | + }, | ||
| 67 | + }, | ||
| 68 | + | ||
| 69 | + // #78: an invalid DNS SAN will be detected if any name constraint checking | ||
| 70 | + // is triggered. | ||
| 71 | + { | ||
| 72 | + roots: []constraintsSpec{ | ||
| 73 | + { | ||
| 74 | + bad: []string{"uri:"}, | ||
| 75 | + }, | ||
| 76 | + }, | ||
| 77 | + intermediates: [][]constraintsSpec{ | ||
| 78 | + { | ||
| 79 | + {}, | ||
| 80 | + }, | ||
| 81 | + }, | ||
| 82 | + leaf: leafSpec{ | ||
| 83 | + sans: []string{"dns:this is invalid"}, | ||
| 84 | + }, | ||
| 85 | + expectedError: "cannot parse dnsName", | ||
| 86 | + }, | ||
| 87 | + | ||
| 88 | + // #79: an invalid email SAN will be detected if any name constraint | ||
| 89 | + // checking is triggered. | ||
| 90 | + { | ||
| 91 | + roots: []constraintsSpec{ | ||
| 92 | + { | ||
| 93 | + bad: []string{"uri:"}, | ||
| 94 | + }, | ||
| 95 | + }, | ||
| 96 | + intermediates: [][]constraintsSpec{ | ||
| 97 | + { | ||
| 98 | + {}, | ||
| 99 | + }, | ||
| 100 | + }, | ||
| 101 | + leaf: leafSpec{ | ||
| 102 | + sans: []string{"email:this @ is invalid"}, | ||
| 103 | + }, | ||
| 104 | + expectedError: "cannot parse rfc822Name", | ||
| 105 | + }, | ||
| 106 | + | ||
| 107 | + // #80: if several EKUs are requested, satisfying any of them is sufficient. | ||
| 108 | { | ||
| 109 | roots: make([]constraintsSpec, 1), | ||
| 110 | intermediates: [][]constraintsSpec{ | ||
| 111 | @@ -1467,7 +1523,7 @@ var nameConstraintsTests = []nameConstraintsTest{ | ||
| 112 | requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageEmailProtection}, | ||
| 113 | }, | ||
| 114 | |||
| 115 | - // #78: EKUs that are not asserted in VerifyOpts are not required to be | ||
| 116 | + // #81: EKUs that are not asserted in VerifyOpts are not required to be | ||
| 117 | // nested. | ||
| 118 | { | ||
| 119 | roots: make([]constraintsSpec, 1), | ||
| 120 | @@ -1486,7 +1542,7 @@ var nameConstraintsTests = []nameConstraintsTest{ | ||
| 121 | }, | ||
| 122 | }, | ||
| 123 | |||
| 124 | - // #79: a certificate without SANs and CN is accepted in a constrained chain. | ||
| 125 | + // #82: a certificate without SANs and CN is accepted in a constrained chain. | ||
| 126 | { | ||
| 127 | roots: []constraintsSpec{ | ||
| 128 | { | ||
| 129 | @@ -1503,7 +1559,7 @@ var nameConstraintsTests = []nameConstraintsTest{ | ||
| 130 | }, | ||
| 131 | }, | ||
| 132 | |||
| 133 | - // #80: a certificate without SANs and with a CN that does not parse as a | ||
| 134 | + // #83: a certificate without SANs and with a CN that does not parse as a | ||
| 135 | // hostname is accepted in a constrained chain. | ||
| 136 | { | ||
| 137 | roots: []constraintsSpec{ | ||
| 138 | @@ -1522,7 +1578,7 @@ var nameConstraintsTests = []nameConstraintsTest{ | ||
| 139 | }, | ||
| 140 | }, | ||
| 141 | |||
| 142 | - // #81: a certificate with SANs and CN is accepted in a constrained chain. | ||
| 143 | + // #84: a certificate with SANs and CN is accepted in a constrained chain. | ||
| 144 | { | ||
| 145 | roots: []constraintsSpec{ | ||
| 146 | { | ||
| 147 | diff --git a/src/crypto/x509/parser.go b/src/crypto/x509/parser.go | ||
| 148 | index 0788210..cfe4c86 100644 | ||
| 149 | --- a/src/crypto/x509/parser.go | ||
| 150 | +++ b/src/crypto/x509/parser.go | ||
| 151 | @@ -391,14 +391,10 @@ func parseSANExtension(der cryptobyte.String) (dnsNames, emailAddresses []string | ||
| 152 | if err := isIA5String(email); err != nil { | ||
| 153 | return errors.New("x509: SAN rfc822Name is malformed") | ||
| 154 | } | ||
| 155 | - parsed, ok := parseRFC2821Mailbox(email) | ||
| 156 | - if !ok || (ok && !domainNameValid(parsed.domain, false)) { | ||
| 157 | - return errors.New("x509: SAN rfc822Name is malformed") | ||
| 158 | - } | ||
| 159 | emailAddresses = append(emailAddresses, email) | ||
| 160 | case nameTypeDNS: | ||
| 161 | name := string(data) | ||
| 162 | - if err := isIA5String(name); err != nil || (err == nil && !domainNameValid(name, false)) { | ||
| 163 | + if err := isIA5String(name); err != nil { | ||
| 164 | return errors.New("x509: SAN dNSName is malformed") | ||
| 165 | } | ||
| 166 | dnsNames = append(dnsNames, string(name)) | ||
| 167 | @@ -408,9 +404,12 @@ func parseSANExtension(der cryptobyte.String) (dnsNames, emailAddresses []string | ||
| 168 | return errors.New("x509: SAN uniformResourceIdentifier is malformed") | ||
| 169 | } | ||
| 170 | uri, err := url.Parse(uriStr) | ||
| 171 | - if err != nil || (err == nil && uri.Host != "" && !domainNameValid(uri.Host, false)) { | ||
| 172 | + if err != nil { | ||
| 173 | return fmt.Errorf("x509: cannot parse URI %q: %s", uriStr, err) | ||
| 174 | } | ||
| 175 | + if len(uri.Host) > 0 && !domainNameValid(uri.Host, false) { | ||
| 176 | + return fmt.Errorf("x509: cannot parse URI %q: invalid domain", uriStr) | ||
| 177 | + } | ||
| 178 | uris = append(uris, uri) | ||
| 179 | case nameTypeIP: | ||
| 180 | switch len(data) { | ||
| 181 | @@ -990,36 +989,58 @@ func ParseCertificates(der []byte) ([]*Certificate, error) { | ||
| 182 | return certs, nil | ||
| 183 | } | ||
| 184 | |||
| 185 | -// domainNameValid does minimal domain name validity checking. In particular it | ||
| 186 | -// enforces the following properties: | ||
| 187 | -// - names cannot have the trailing period | ||
| 188 | -// - names can only have a leading period if constraint is true | ||
| 189 | -// - names must be <= 253 characters | ||
| 190 | -// - names cannot have empty labels | ||
| 191 | -// - names cannot labels that are longer than 63 characters | ||
| 192 | -// | ||
| 193 | -// Note that this does not enforce the LDH requirements for domain names. | ||
| 194 | +// domainNameValid is an alloc-less version of the checks that | ||
| 195 | +// domainToReverseLabels does. | ||
| 196 | func domainNameValid(s string, constraint bool) bool { | ||
| 197 | - if len(s) == 0 && constraint { | ||
| 198 | + // TODO(#75835): This function omits a number of checks which we | ||
| 199 | + // really should be doing to enforce that domain names are valid names per | ||
| 200 | + // RFC 1034. We previously enabled these checks, but this broke a | ||
| 201 | + // significant number of certificates we previously considered valid, and we | ||
| 202 | + // happily create via CreateCertificate (et al). We should enable these | ||
| 203 | + // checks, but will need to gate them behind a GODEBUG. | ||
| 204 | + // | ||
| 205 | + // I have left the checks we previously enabled, noted with "TODO(#75835)" so | ||
| 206 | + // that we can easily re-enable them once we unbreak everyone. | ||
| 207 | + | ||
| 208 | + // TODO(#75835): this should only be true for constraints. | ||
| 209 | + if len(s) == 0 { | ||
| 210 | return true | ||
| 211 | } | ||
| 212 | - if len(s) == 0 || (!constraint && s[0] == '.') || s[len(s)-1] == '.' || len(s) > 253 { | ||
| 213 | + | ||
| 214 | + // Do not allow trailing period (FQDN format is not allowed in SANs or | ||
| 215 | + // constraints). | ||
| 216 | + if s[len(s)-1] == '.' { | ||
| 217 | return false | ||
| 218 | } | ||
| 219 | + | ||
| 220 | + // TODO(#75835): domains must have at least one label, cannot have | ||
| 221 | + // a leading empty label, and cannot be longer than 253 characters. | ||
| 222 | + // if len(s) == 0 || (!constraint && s[0] == '.') || len(s) > 253 { | ||
| 223 | + // return false | ||
| 224 | + // } | ||
| 225 | + | ||
| 226 | lastDot := -1 | ||
| 227 | if constraint && s[0] == '.' { | ||
| 228 | s = s[1:] | ||
| 229 | } | ||
| 230 | |||
| 231 | for i := 0; i <= len(s); i++ { | ||
| 232 | + if i < len(s) && (s[i] < 33 || s[i] > 126) { | ||
| 233 | + // Invalid character. | ||
| 234 | + return false | ||
| 235 | + } | ||
| 236 | if i == len(s) || s[i] == '.' { | ||
| 237 | labelLen := i | ||
| 238 | if lastDot >= 0 { | ||
| 239 | labelLen -= lastDot + 1 | ||
| 240 | } | ||
| 241 | - if labelLen == 0 || labelLen > 63 { | ||
| 242 | + if labelLen == 0 { | ||
| 243 | return false | ||
| 244 | } | ||
| 245 | + // TODO(#75835): labels cannot be longer than 63 characters. | ||
| 246 | + // if labelLen > 63 { | ||
| 247 | + // return false | ||
| 248 | + // } | ||
| 249 | lastDot = i | ||
| 250 | } | ||
| 251 | } | ||
| 252 | diff --git a/src/crypto/x509/parser_test.go b/src/crypto/x509/parser_test.go | ||
| 253 | index 95ed116..662e305 100644 | ||
| 254 | --- a/src/crypto/x509/parser_test.go | ||
| 255 | +++ b/src/crypto/x509/parser_test.go | ||
| 256 | @@ -4,6 +4,9 @@ | ||
| 257 | package x509 | ||
| 258 | |||
| 259 | import ( | ||
| 260 | + "crypto/ecdsa" | ||
| 261 | + "crypto/elliptic" | ||
| 262 | + "crypto/rand" | ||
| 263 | "encoding/asn1" | ||
| 264 | "strings" | ||
| 265 | "testing" | ||
| 266 | @@ -109,7 +112,31 @@ func TestDomainNameValid(t *testing.T) { | ||
| 267 | constraint bool | ||
| 268 | valid bool | ||
| 269 | }{ | ||
| 270 | - {"empty name, name", "", false, false}, | ||
| 271 | + // TODO(#75835): these tests are for stricter name validation, which we | ||
| 272 | + // had to disable. Once we reenable these strict checks, behind a | ||
| 273 | + // GODEBUG, we should add them back in. | ||
| 274 | + // {"empty name, name", "", false, false}, | ||
| 275 | + // {"254 char label, name", strings.Repeat("a.a", 84) + "aaa", false, false}, | ||
| 276 | + // {"254 char label, constraint", strings.Repeat("a.a", 84) + "aaa", true, false}, | ||
| 277 | + // {"253 char label, name", strings.Repeat("a.a", 84) + "aa", false, false}, | ||
| 278 | + // {"253 char label, constraint", strings.Repeat("a.a", 84) + "aa", true, false}, | ||
| 279 | + // {"64 char single label, name", strings.Repeat("a", 64), false, false}, | ||
| 280 | + // {"64 char single label, constraint", strings.Repeat("a", 64), true, false}, | ||
| 281 | + // {"64 char label, name", "a." + strings.Repeat("a", 64), false, false}, | ||
| 282 | + // {"64 char label, constraint", "a." + strings.Repeat("a", 64), true, false}, | ||
| 283 | + | ||
| 284 | + // TODO(#75835): these are the inverse of the tests above, they should be removed | ||
| 285 | + // once the strict checking is enabled. | ||
| 286 | + {"254 char label, name", strings.Repeat("a.a", 84) + "aaa", false, true}, | ||
| 287 | + {"254 char label, constraint", strings.Repeat("a.a", 84) + "aaa", true, true}, | ||
| 288 | + {"253 char label, name", strings.Repeat("a.a", 84) + "aa", false, true}, | ||
| 289 | + {"253 char label, constraint", strings.Repeat("a.a", 84) + "aa", true, true}, | ||
| 290 | + {"64 char single label, name", strings.Repeat("a", 64), false, true}, | ||
| 291 | + {"64 char single label, constraint", strings.Repeat("a", 64), true, true}, | ||
| 292 | + {"64 char label, name", "a." + strings.Repeat("a", 64), false, true}, | ||
| 293 | + {"64 char label, constraint", "a." + strings.Repeat("a", 64), true, true}, | ||
| 294 | + | ||
| 295 | + // Check we properly enforce properties of domain names. | ||
| 296 | {"empty name, constraint", "", true, true}, | ||
| 297 | {"empty label, name", "a..a", false, false}, | ||
| 298 | {"empty label, constraint", "a..a", true, false}, | ||
| 299 | @@ -123,23 +150,60 @@ func TestDomainNameValid(t *testing.T) { | ||
| 300 | {"trailing period, constraint", "a.", true, false}, | ||
| 301 | {"bare label, name", "a", false, true}, | ||
| 302 | {"bare label, constraint", "a", true, true}, | ||
| 303 | - {"254 char label, name", strings.Repeat("a.a", 84) + "aaa", false, false}, | ||
| 304 | - {"254 char label, constraint", strings.Repeat("a.a", 84) + "aaa", true, false}, | ||
| 305 | - {"253 char label, name", strings.Repeat("a.a", 84) + "aa", false, false}, | ||
| 306 | - {"253 char label, constraint", strings.Repeat("a.a", 84) + "aa", true, false}, | ||
| 307 | - {"64 char single label, name", strings.Repeat("a", 64), false, false}, | ||
| 308 | - {"64 char single label, constraint", strings.Repeat("a", 64), true, false}, | ||
| 309 | {"63 char single label, name", strings.Repeat("a", 63), false, true}, | ||
| 310 | {"63 char single label, constraint", strings.Repeat("a", 63), true, true}, | ||
| 311 | - {"64 char label, name", "a." + strings.Repeat("a", 64), false, false}, | ||
| 312 | - {"64 char label, constraint", "a." + strings.Repeat("a", 64), true, false}, | ||
| 313 | {"63 char label, name", "a." + strings.Repeat("a", 63), false, true}, | ||
| 314 | {"63 char label, constraint", "a." + strings.Repeat("a", 63), true, true}, | ||
| 315 | } { | ||
| 316 | t.Run(tc.name, func(t *testing.T) { | ||
| 317 | - if tc.valid != domainNameValid(tc.dnsName, tc.constraint) { | ||
| 318 | + valid := domainNameValid(tc.dnsName, tc.constraint) | ||
| 319 | + if tc.valid != valid { | ||
| 320 | t.Errorf("domainNameValid(%q, %t) = %v; want %v", tc.dnsName, tc.constraint, !tc.valid, tc.valid) | ||
| 321 | } | ||
| 322 | + // Also check that we enforce the same properties as domainToReverseLabels | ||
| 323 | + trimmedName := tc.dnsName | ||
| 324 | + if tc.constraint && len(trimmedName) > 1 && trimmedName[0] == '.' { | ||
| 325 | + trimmedName = trimmedName[1:] | ||
| 326 | + } | ||
| 327 | + _, revValid := domainToReverseLabels(trimmedName) | ||
| 328 | + if valid != revValid { | ||
| 329 | + t.Errorf("domainNameValid(%q, %t) = %t != domainToReverseLabels(%q) = %t", tc.dnsName, tc.constraint, valid, trimmedName, revValid) | ||
| 330 | + } | ||
| 331 | }) | ||
| 332 | } | ||
| 333 | } | ||
| 334 | + | ||
| 335 | +func TestRoundtripWeirdSANs(t *testing.T) { | ||
| 336 | + // TODO(#75835): check that certificates we create with CreateCertificate that have malformed SAN values | ||
| 337 | + // can be parsed by ParseCertificate. We should eventually restrict this, but for now we have to maintain | ||
| 338 | + // this property as people have been relying on it. | ||
| 339 | + k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | ||
| 340 | + if err != nil { | ||
| 341 | + t.Fatal(err) | ||
| 342 | + } | ||
| 343 | + badNames := []string{ | ||
| 344 | + "baredomain", | ||
| 345 | + "baredomain.", | ||
| 346 | + strings.Repeat("a", 255), | ||
| 347 | + strings.Repeat("a", 65) + ".com", | ||
| 348 | + } | ||
| 349 | + tmpl := &Certificate{ | ||
| 350 | + EmailAddresses: badNames, | ||
| 351 | + DNSNames: badNames, | ||
| 352 | + } | ||
| 353 | + b, err := CreateCertificate(rand.Reader, tmpl, tmpl, &k.PublicKey, k) | ||
| 354 | + if err != nil { | ||
| 355 | + t.Fatal(err) | ||
| 356 | + } | ||
| 357 | + _, err = ParseCertificate(b) | ||
| 358 | + if err != nil { | ||
| 359 | + t.Fatalf("Couldn't roundtrip certificate: %v", err) | ||
| 360 | + } | ||
| 361 | +} | ||
| 362 | + | ||
| 363 | +func FuzzDomainNameValid(f *testing.F) { | ||
| 364 | + f.Fuzz(func(t *testing.T, data string) { | ||
| 365 | + domainNameValid(data, false) | ||
| 366 | + domainNameValid(data, true) | ||
| 367 | + }) | ||
| 368 | +} | ||
| 369 | diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go | ||
| 370 | index fb2f4b2..99f38a0 100644 | ||
| 371 | --- a/src/crypto/x509/verify.go | ||
| 372 | +++ b/src/crypto/x509/verify.go | ||
| 373 | @@ -390,7 +390,7 @@ func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) { | ||
| 374 | return reverseLabels, true | ||
| 375 | } | ||
| 376 | |||
| 377 | -func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string) (bool, error) { | ||
| 378 | +func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]string) (bool, error) { | ||
| 379 | // If the constraint contains an @, then it specifies an exact mailbox | ||
| 380 | // name. | ||
| 381 | if strings.Contains(constraint, "@") { | ||
| 382 | @@ -403,10 +403,10 @@ func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string) (bool, erro | ||
| 383 | |||
| 384 | // Otherwise the constraint is like a DNS constraint of the domain part | ||
| 385 | // of the mailbox. | ||
| 386 | - return matchDomainConstraint(mailbox.domain, constraint) | ||
| 387 | + return matchDomainConstraint(mailbox.domain, constraint, reversedDomainsCache, reversedConstraintsCache) | ||
| 388 | } | ||
| 389 | |||
| 390 | -func matchURIConstraint(uri *url.URL, constraint string) (bool, error) { | ||
| 391 | +func matchURIConstraint(uri *url.URL, constraint string, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]string) (bool, error) { | ||
| 392 | // From RFC 5280, Section 4.2.1.10: | ||
| 393 | // “a uniformResourceIdentifier that does not include an authority | ||
| 394 | // component with a host name specified as a fully qualified domain | ||
| 395 | @@ -433,7 +433,7 @@ func matchURIConstraint(uri *url.URL, constraint string) (bool, error) { | ||
| 396 | return false, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", uri.String()) | ||
| 397 | } | ||
| 398 | |||
| 399 | - return matchDomainConstraint(host, constraint) | ||
| 400 | + return matchDomainConstraint(host, constraint, reversedDomainsCache, reversedConstraintsCache) | ||
| 401 | } | ||
| 402 | |||
| 403 | func matchIPConstraint(ip net.IP, constraint *net.IPNet) (bool, error) { | ||
| 404 | @@ -450,16 +450,21 @@ func matchIPConstraint(ip net.IP, constraint *net.IPNet) (bool, error) { | ||
| 405 | return true, nil | ||
| 406 | } | ||
| 407 | |||
| 408 | -func matchDomainConstraint(domain, constraint string) (bool, error) { | ||
| 409 | +func matchDomainConstraint(domain, constraint string, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]string) (bool, error) { | ||
| 410 | // The meaning of zero length constraints is not specified, but this | ||
| 411 | // code follows NSS and accepts them as matching everything. | ||
| 412 | if len(constraint) == 0 { | ||
| 413 | return true, nil | ||
| 414 | } | ||
| 415 | |||
| 416 | - domainLabels, ok := domainToReverseLabels(domain) | ||
| 417 | - if !ok { | ||
| 418 | - return false, fmt.Errorf("x509: internal error: cannot parse domain %q", domain) | ||
| 419 | + domainLabels, found := reversedDomainsCache[domain] | ||
| 420 | + if !found { | ||
| 421 | + var ok bool | ||
| 422 | + domainLabels, ok = domainToReverseLabels(domain) | ||
| 423 | + if !ok { | ||
| 424 | + return false, fmt.Errorf("x509: internal error: cannot parse domain %q", domain) | ||
| 425 | + } | ||
| 426 | + reversedDomainsCache[domain] = domainLabels | ||
| 427 | } | ||
| 428 | |||
| 429 | // RFC 5280 says that a leading period in a domain name means that at | ||
| 430 | @@ -473,9 +478,14 @@ func matchDomainConstraint(domain, constraint string) (bool, error) { | ||
| 431 | constraint = constraint[1:] | ||
| 432 | } | ||
| 433 | |||
| 434 | - constraintLabels, ok := domainToReverseLabels(constraint) | ||
| 435 | - if !ok { | ||
| 436 | - return false, fmt.Errorf("x509: internal error: cannot parse domain %q", constraint) | ||
| 437 | + constraintLabels, found := reversedConstraintsCache[constraint] | ||
| 438 | + if !found { | ||
| 439 | + var ok bool | ||
| 440 | + constraintLabels, ok = domainToReverseLabels(constraint) | ||
| 441 | + if !ok { | ||
| 442 | + return false, fmt.Errorf("x509: internal error: cannot parse domain %q", constraint) | ||
| 443 | + } | ||
| 444 | + reversedConstraintsCache[constraint] = constraintLabels | ||
| 445 | } | ||
| 446 | |||
| 447 | if len(domainLabels) < len(constraintLabels) || | ||
| 448 | @@ -598,6 +608,19 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V | ||
| 449 | leaf = currentChain[0] | ||
| 450 | } | ||
| 451 | |||
| 452 | + // Each time we do constraint checking, we need to check the constraints in | ||
| 453 | + // the current certificate against all of the names that preceded it. We | ||
| 454 | + // reverse these names using domainToReverseLabels, which is a relatively | ||
| 455 | + // expensive operation. Since we check each name against each constraint, | ||
| 456 | + // this requires us to do N*C calls to domainToReverseLabels (where N is the | ||
| 457 | + // total number of names that preceed the certificate, and C is the total | ||
| 458 | + // number of constraints in the certificate). By caching the results of | ||
| 459 | + // calling domainToReverseLabels, we can reduce that to N+C calls at the | ||
| 460 | + // cost of keeping all of the parsed names and constraints in memory until | ||
| 461 | + // we return from isValid. | ||
| 462 | + reversedDomainsCache := map[string][]string{} | ||
| 463 | + reversedConstraintsCache := map[string][]string{} | ||
| 464 | + | ||
| 465 | if (certType == intermediateCertificate || certType == rootCertificate) && | ||
| 466 | c.hasNameConstraints() && leaf.hasSANExtension() { | ||
| 467 | err := forEachSAN(leaf.getSANExtension(), func(tag int, data []byte) error { | ||
| 468 | @@ -611,20 +634,20 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V | ||
| 469 | |||
| 470 | if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "email address", name, mailbox, | ||
| 471 | func(parsedName, constraint interface{}) (bool, error) { | ||
| 472 | - return matchEmailConstraint(parsedName.(rfc2821Mailbox), constraint.(string)) | ||
| 473 | + return matchEmailConstraint(parsedName.(rfc2821Mailbox), constraint.(string), reversedDomainsCache, reversedConstraintsCache) | ||
| 474 | }, c.PermittedEmailAddresses, c.ExcludedEmailAddresses); err != nil { | ||
| 475 | return err | ||
| 476 | } | ||
| 477 | |||
| 478 | case nameTypeDNS: | ||
| 479 | name := string(data) | ||
| 480 | - if _, ok := domainToReverseLabels(name); !ok { | ||
| 481 | + if !domainNameValid(name, false) { | ||
| 482 | return fmt.Errorf("x509: cannot parse dnsName %q", name) | ||
| 483 | } | ||
| 484 | |||
| 485 | if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "DNS name", name, name, | ||
| 486 | func(parsedName, constraint interface{}) (bool, error) { | ||
| 487 | - return matchDomainConstraint(parsedName.(string), constraint.(string)) | ||
| 488 | + return matchDomainConstraint(parsedName.(string), constraint.(string), reversedDomainsCache, reversedConstraintsCache) | ||
| 489 | }, c.PermittedDNSDomains, c.ExcludedDNSDomains); err != nil { | ||
| 490 | return err | ||
| 491 | } | ||
| 492 | @@ -638,7 +661,7 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V | ||
| 493 | |||
| 494 | if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "URI", name, uri, | ||
| 495 | func(parsedName, constraint interface{}) (bool, error) { | ||
| 496 | - return matchURIConstraint(parsedName.(*url.URL), constraint.(string)) | ||
| 497 | + return matchURIConstraint(parsedName.(*url.URL), constraint.(string), reversedDomainsCache, reversedConstraintsCache) | ||
| 498 | }, c.PermittedURIDomains, c.ExcludedURIDomains); err != nil { | ||
| 499 | return err | ||
| 500 | } | ||
| 501 | diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go | ||
| 502 | index 9da39ca..31e8149 100644 | ||
| 503 | --- a/src/crypto/x509/verify_test.go | ||
| 504 | +++ b/src/crypto/x509/verify_test.go | ||
| 505 | @@ -1648,7 +1648,7 @@ var nameConstraintTests = []struct { | ||
| 506 | |||
| 507 | func TestNameConstraints(t *testing.T) { | ||
| 508 | for i, test := range nameConstraintTests { | ||
| 509 | - result, err := matchDomainConstraint(test.domain, test.constraint) | ||
| 510 | + result, err := matchDomainConstraint(test.domain, test.constraint, map[string][]string{}, map[string][]string{}) | ||
| 511 | |||
| 512 | if err != nil && !test.expectError { | ||
| 513 | t.Errorf("unexpected error for test #%d: domain=%s, constraint=%s, err=%s", i, test.domain, test.constraint, err) | ||
| 514 | -- | ||
| 515 | 2.25.1 | ||
| 516 | |||
diff --git a/meta/recipes-devtools/go/go-1.18/CVE-2025-61727.patch b/meta/recipes-devtools/go/go-1.18/CVE-2025-61727.patch new file mode 100644 index 0000000000..23dc35b8b8 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.18/CVE-2025-61727.patch | |||
| @@ -0,0 +1,229 @@ | |||
| 1 | From 04db77a423cac75bb82cc9a6859991ae9c016344 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Roland Shoemaker <bracewell@google.com> | ||
| 3 | Date: Mon, 24 Nov 2025 08:46:08 -0800 | ||
| 4 | Subject: [PATCH] [release-branch.go1.24] crypto/x509: excluded subdomain | ||
| 5 | constraints preclude wildcard SANs | ||
| 6 | |||
| 7 | When evaluating name constraints in a certificate chain, the presence of | ||
| 8 | an excluded subdomain constraint (e.g., excluding "test.example.com") | ||
| 9 | should preclude the use of a wildcard SAN (e.g., "*.example.com"). | ||
| 10 | |||
| 11 | Fixes #76442 | ||
| 12 | Fixes #76463 | ||
| 13 | Fixes CVE-2025-61727 | ||
| 14 | |||
| 15 | Change-Id: I42a0da010cb36d2ec9d1239ae3f61cf25eb78bba | ||
| 16 | Reviewed-on: https://go-review.googlesource.com/c/go/+/724401 | ||
| 17 | Reviewed-by: Nicholas Husin <husin@google.com> | ||
| 18 | Reviewed-by: Daniel McCarney <daniel@binaryparadox.net> | ||
| 19 | LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> | ||
| 20 | Reviewed-by: Nicholas Husin <nsh@golang.org> | ||
| 21 | Reviewed-by: Neal Patel <nealpatel@google.com> | ||
| 22 | |||
| 23 | Upstream-Status: Backport [https://github.com/golang/go/commit/04db77a423cac75bb82cc9a6859991ae9c016344] | ||
| 24 | CVE: CVE-2025-61727 | ||
| 25 | Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> | ||
| 26 | --- | ||
| 27 | src/crypto/x509/name_constraints_test.go | 34 ++++++++++++++++++++ | ||
| 28 | src/crypto/x509/verify.go | 40 +++++++++++++++--------- | ||
| 29 | src/crypto/x509/verify_test.go | 2 +- | ||
| 30 | 3 files changed, 60 insertions(+), 16 deletions(-) | ||
| 31 | |||
| 32 | diff --git a/src/crypto/x509/name_constraints_test.go b/src/crypto/x509/name_constraints_test.go | ||
| 33 | index c59a7dc..963bc5a 100644 | ||
| 34 | --- a/src/crypto/x509/name_constraints_test.go | ||
| 35 | +++ b/src/crypto/x509/name_constraints_test.go | ||
| 36 | @@ -1595,6 +1595,40 @@ var nameConstraintsTests = []nameConstraintsTest{ | ||
| 37 | cn: "foo.bar", | ||
| 38 | }, | ||
| 39 | }, | ||
| 40 | + // #87: subdomain excluded constraints preclude wildcard names | ||
| 41 | + { | ||
| 42 | + roots: []constraintsSpec{ | ||
| 43 | + { | ||
| 44 | + bad: []string{"dns:foo.example.com"}, | ||
| 45 | + }, | ||
| 46 | + }, | ||
| 47 | + intermediates: [][]constraintsSpec{ | ||
| 48 | + { | ||
| 49 | + {}, | ||
| 50 | + }, | ||
| 51 | + }, | ||
| 52 | + leaf: leafSpec{ | ||
| 53 | + sans: []string{"dns:*.example.com"}, | ||
| 54 | + }, | ||
| 55 | + expectedError: "\"*.example.com\" is excluded by constraint \"foo.example.com\"", | ||
| 56 | + }, | ||
| 57 | + // #88: wildcard names are not matched by subdomain permitted constraints | ||
| 58 | + { | ||
| 59 | + roots: []constraintsSpec{ | ||
| 60 | + { | ||
| 61 | + ok: []string{"dns:foo.example.com"}, | ||
| 62 | + }, | ||
| 63 | + }, | ||
| 64 | + intermediates: [][]constraintsSpec{ | ||
| 65 | + { | ||
| 66 | + {}, | ||
| 67 | + }, | ||
| 68 | + }, | ||
| 69 | + leaf: leafSpec{ | ||
| 70 | + sans: []string{"dns:*.example.com"}, | ||
| 71 | + }, | ||
| 72 | + expectedError: "\"*.example.com\" is not permitted", | ||
| 73 | + }, | ||
| 74 | } | ||
| 75 | |||
| 76 | func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) { | ||
| 77 | diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go | ||
| 78 | index 99f38a0..88260ee 100644 | ||
| 79 | --- a/src/crypto/x509/verify.go | ||
| 80 | +++ b/src/crypto/x509/verify.go | ||
| 81 | @@ -390,7 +390,7 @@ func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) { | ||
| 82 | return reverseLabels, true | ||
| 83 | } | ||
| 84 | |||
| 85 | -func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]string) (bool, error) { | ||
| 86 | +func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string, excluded bool, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]string) (bool, error) { | ||
| 87 | // If the constraint contains an @, then it specifies an exact mailbox | ||
| 88 | // name. | ||
| 89 | if strings.Contains(constraint, "@") { | ||
| 90 | @@ -403,10 +403,10 @@ func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string, reversedDom | ||
| 91 | |||
| 92 | // Otherwise the constraint is like a DNS constraint of the domain part | ||
| 93 | // of the mailbox. | ||
| 94 | - return matchDomainConstraint(mailbox.domain, constraint, reversedDomainsCache, reversedConstraintsCache) | ||
| 95 | + return matchDomainConstraint(mailbox.domain, constraint, excluded, reversedDomainsCache, reversedConstraintsCache) | ||
| 96 | } | ||
| 97 | |||
| 98 | -func matchURIConstraint(uri *url.URL, constraint string, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]string) (bool, error) { | ||
| 99 | +func matchURIConstraint(uri *url.URL, constraint string, excluded bool, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]string) (bool, error) { | ||
| 100 | // From RFC 5280, Section 4.2.1.10: | ||
| 101 | // “a uniformResourceIdentifier that does not include an authority | ||
| 102 | // component with a host name specified as a fully qualified domain | ||
| 103 | @@ -433,7 +433,7 @@ func matchURIConstraint(uri *url.URL, constraint string, reversedDomainsCache ma | ||
| 104 | return false, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", uri.String()) | ||
| 105 | } | ||
| 106 | |||
| 107 | - return matchDomainConstraint(host, constraint, reversedDomainsCache, reversedConstraintsCache) | ||
| 108 | + return matchDomainConstraint(host, constraint, excluded, reversedDomainsCache, reversedConstraintsCache) | ||
| 109 | } | ||
| 110 | |||
| 111 | func matchIPConstraint(ip net.IP, constraint *net.IPNet) (bool, error) { | ||
| 112 | @@ -450,7 +450,7 @@ func matchIPConstraint(ip net.IP, constraint *net.IPNet) (bool, error) { | ||
| 113 | return true, nil | ||
| 114 | } | ||
| 115 | |||
| 116 | -func matchDomainConstraint(domain, constraint string, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]string) (bool, error) { | ||
| 117 | +func matchDomainConstraint(domain, constraint string, excluded bool, reversedDomainsCache map[string][]string, reversedConstraintsCache map[string][]string) (bool, error) { | ||
| 118 | // The meaning of zero length constraints is not specified, but this | ||
| 119 | // code follows NSS and accepts them as matching everything. | ||
| 120 | if len(constraint) == 0 { | ||
| 121 | @@ -467,6 +467,11 @@ func matchDomainConstraint(domain, constraint string, reversedDomainsCache map[s | ||
| 122 | reversedDomainsCache[domain] = domainLabels | ||
| 123 | } | ||
| 124 | |||
| 125 | + wildcardDomain := false | ||
| 126 | + if len(domain) > 0 && domain[0] == '*' { | ||
| 127 | + wildcardDomain = true | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | // RFC 5280 says that a leading period in a domain name means that at | ||
| 131 | // least one label must be prepended, but only for URI and email | ||
| 132 | // constraints, not DNS constraints. The code also supports that | ||
| 133 | @@ -493,6 +498,11 @@ func matchDomainConstraint(domain, constraint string, reversedDomainsCache map[s | ||
| 134 | return false, nil | ||
| 135 | } | ||
| 136 | |||
| 137 | + if excluded && wildcardDomain && len(domainLabels) > 1 && len(constraintLabels) > 0 { | ||
| 138 | + domainLabels = domainLabels[:len(domainLabels)-1] | ||
| 139 | + constraintLabels = constraintLabels[:len(constraintLabels)-1] | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | for i, constraintLabel := range constraintLabels { | ||
| 143 | if !strings.EqualFold(constraintLabel, domainLabels[i]) { | ||
| 144 | return false, nil | ||
| 145 | @@ -512,7 +522,7 @@ func (c *Certificate) checkNameConstraints(count *int, | ||
| 146 | nameType string, | ||
| 147 | name string, | ||
| 148 | parsedName interface{}, | ||
| 149 | - match func(parsedName, constraint interface{}) (match bool, err error), | ||
| 150 | + match func(parsedName, constraint interface{}, excluded bool) (match bool, err error), | ||
| 151 | permitted, excluded interface{}) error { | ||
| 152 | |||
| 153 | excludedValue := reflect.ValueOf(excluded) | ||
| 154 | @@ -524,7 +534,7 @@ func (c *Certificate) checkNameConstraints(count *int, | ||
| 155 | |||
| 156 | for i := 0; i < excludedValue.Len(); i++ { | ||
| 157 | constraint := excludedValue.Index(i).Interface() | ||
| 158 | - match, err := match(parsedName, constraint) | ||
| 159 | + match, err := match(parsedName, constraint, true) | ||
| 160 | if err != nil { | ||
| 161 | return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()} | ||
| 162 | } | ||
| 163 | @@ -546,7 +556,7 @@ func (c *Certificate) checkNameConstraints(count *int, | ||
| 164 | constraint := permittedValue.Index(i).Interface() | ||
| 165 | |||
| 166 | var err error | ||
| 167 | - if ok, err = match(parsedName, constraint); err != nil { | ||
| 168 | + if ok, err = match(parsedName, constraint, false); err != nil { | ||
| 169 | return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()} | ||
| 170 | } | ||
| 171 | |||
| 172 | @@ -633,8 +643,8 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V | ||
| 173 | } | ||
| 174 | |||
| 175 | if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "email address", name, mailbox, | ||
| 176 | - func(parsedName, constraint interface{}) (bool, error) { | ||
| 177 | - return matchEmailConstraint(parsedName.(rfc2821Mailbox), constraint.(string), reversedDomainsCache, reversedConstraintsCache) | ||
| 178 | + func(parsedName, constraint interface{}, excluded bool) (bool, error) { | ||
| 179 | + return matchEmailConstraint(parsedName.(rfc2821Mailbox), constraint.(string), excluded, reversedDomainsCache, reversedConstraintsCache) | ||
| 180 | }, c.PermittedEmailAddresses, c.ExcludedEmailAddresses); err != nil { | ||
| 181 | return err | ||
| 182 | } | ||
| 183 | @@ -646,8 +656,8 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V | ||
| 184 | } | ||
| 185 | |||
| 186 | if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "DNS name", name, name, | ||
| 187 | - func(parsedName, constraint interface{}) (bool, error) { | ||
| 188 | - return matchDomainConstraint(parsedName.(string), constraint.(string), reversedDomainsCache, reversedConstraintsCache) | ||
| 189 | + func(parsedName, constraint interface{}, excluded bool) (bool, error) { | ||
| 190 | + return matchDomainConstraint(parsedName.(string), constraint.(string), excluded, reversedDomainsCache, reversedConstraintsCache) | ||
| 191 | }, c.PermittedDNSDomains, c.ExcludedDNSDomains); err != nil { | ||
| 192 | return err | ||
| 193 | } | ||
| 194 | @@ -660,8 +670,8 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V | ||
| 195 | } | ||
| 196 | |||
| 197 | if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "URI", name, uri, | ||
| 198 | - func(parsedName, constraint interface{}) (bool, error) { | ||
| 199 | - return matchURIConstraint(parsedName.(*url.URL), constraint.(string), reversedDomainsCache, reversedConstraintsCache) | ||
| 200 | + func(parsedName, constraint interface{}, excluded bool) (bool, error) { | ||
| 201 | + return matchURIConstraint(parsedName.(*url.URL), constraint.(string), excluded, reversedDomainsCache, reversedConstraintsCache) | ||
| 202 | }, c.PermittedURIDomains, c.ExcludedURIDomains); err != nil { | ||
| 203 | return err | ||
| 204 | } | ||
| 205 | @@ -673,7 +683,7 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V | ||
| 206 | } | ||
| 207 | |||
| 208 | if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "IP address", ip.String(), ip, | ||
| 209 | - func(parsedName, constraint interface{}) (bool, error) { | ||
| 210 | + func(parsedName, constraint interface{}, _ bool) (bool, error) { | ||
| 211 | return matchIPConstraint(parsedName.(net.IP), constraint.(*net.IPNet)) | ||
| 212 | }, c.PermittedIPRanges, c.ExcludedIPRanges); err != nil { | ||
| 213 | return err | ||
| 214 | diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go | ||
| 215 | index 31e8149..5f7c834 100644 | ||
| 216 | --- a/src/crypto/x509/verify_test.go | ||
| 217 | +++ b/src/crypto/x509/verify_test.go | ||
| 218 | @@ -1648,7 +1648,7 @@ var nameConstraintTests = []struct { | ||
| 219 | |||
| 220 | func TestNameConstraints(t *testing.T) { | ||
| 221 | for i, test := range nameConstraintTests { | ||
| 222 | - result, err := matchDomainConstraint(test.domain, test.constraint, map[string][]string{}, map[string][]string{}) | ||
| 223 | + result, err := matchDomainConstraint(test.domain, test.constraint, false, map[string][]string{}, map[string][]string{}) | ||
| 224 | |||
| 225 | if err != nil && !test.expectError { | ||
| 226 | t.Errorf("unexpected error for test #%d: domain=%s, constraint=%s, err=%s", i, test.domain, test.constraint, err) | ||
| 227 | -- | ||
| 228 | 2.25.1 | ||
| 229 | |||
diff --git a/meta/recipes-devtools/go/go-1.18/CVE-2025-61729.patch b/meta/recipes-devtools/go/go-1.18/CVE-2025-61729.patch new file mode 100644 index 0000000000..6fdc2fd426 --- /dev/null +++ b/meta/recipes-devtools/go/go-1.18/CVE-2025-61729.patch | |||
| @@ -0,0 +1,172 @@ | |||
| 1 | From 3a842bd5c6aa8eefa13c0174de3ab361e50bd672 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: "Nicholas S. Husin" <nsh@golang.org> | ||
| 3 | Date: Mon, 24 Nov 2025 14:56:23 -0500 | ||
| 4 | Subject: [PATCH] [release-branch.go1.24] crypto/x509: prevent | ||
| 5 | HostnameError.Error() from consuming excessive resource | ||
| 6 | |||
| 7 | Constructing HostnameError.Error() takes O(N^2) runtime due to using a | ||
| 8 | string concatenation in a loop. Additionally, there is no limit on how | ||
| 9 | many names are included in the error message. As a result, a malicious | ||
| 10 | attacker could craft a certificate with an infinite amount of names to | ||
| 11 | unfairly consume resource. | ||
| 12 | |||
| 13 | To remediate this, we will now use strings.Builder to construct the | ||
| 14 | error message, preventing O(N^2) runtime. When a certificate has 100 or | ||
| 15 | more names, we will also not print each name individually. | ||
| 16 | |||
| 17 | Thanks to Philippe Antoine (Catena cyber) for reporting this issue. | ||
| 18 | |||
| 19 | Updates #76445 | ||
| 20 | Fixes #76460 | ||
| 21 | Fixes CVE-2025-61729 | ||
| 22 | |||
| 23 | Change-Id: I6343776ec3289577abc76dad71766c491c1a7c81 | ||
| 24 | Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3000 | ||
| 25 | Reviewed-by: Neal Patel <nealpatel@google.com> | ||
| 26 | Reviewed-by: Damien Neil <dneil@google.com> | ||
| 27 | Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3220 | ||
| 28 | Reviewed-by: Roland Shoemaker <bracewell@google.com> | ||
| 29 | Reviewed-on: https://go-review.googlesource.com/c/go/+/725820 | ||
| 30 | Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> | ||
| 31 | TryBot-Bypass: Dmitri Shuralyov <dmitshur@golang.org> | ||
| 32 | Auto-Submit: Dmitri Shuralyov <dmitshur@google.com> | ||
| 33 | Reviewed-by: Mark Freeman <markfreeman@google.com> | ||
| 34 | |||
| 35 | Upstream-Status: Backport [https://github.com/golang/go/commit/3a842bd5c6aa8eefa13c0174de3ab361e50bd672] | ||
| 36 | CVE: CVE-2025-61729 | ||
| 37 | Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> | ||
| 38 | --- | ||
| 39 | src/crypto/x509/verify.go | 21 ++++++++++----- | ||
| 40 | src/crypto/x509/verify_test.go | 47 ++++++++++++++++++++++++++++++++++ | ||
| 41 | 2 files changed, 61 insertions(+), 7 deletions(-) | ||
| 42 | |||
| 43 | diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go | ||
| 44 | index 88260ee..c167191 100644 | ||
| 45 | --- a/src/crypto/x509/verify.go | ||
| 46 | +++ b/src/crypto/x509/verify.go | ||
| 47 | @@ -97,31 +97,38 @@ type HostnameError struct { | ||
| 48 | |||
| 49 | func (h HostnameError) Error() string { | ||
| 50 | c := h.Certificate | ||
| 51 | + maxNamesIncluded := 100 | ||
| 52 | |||
| 53 | if !c.hasSANExtension() && matchHostnames(c.Subject.CommonName, h.Host) { | ||
| 54 | return "x509: certificate relies on legacy Common Name field, use SANs instead" | ||
| 55 | } | ||
| 56 | |||
| 57 | - var valid string | ||
| 58 | + var valid strings.Builder | ||
| 59 | if ip := net.ParseIP(h.Host); ip != nil { | ||
| 60 | // Trying to validate an IP | ||
| 61 | if len(c.IPAddresses) == 0 { | ||
| 62 | return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs" | ||
| 63 | } | ||
| 64 | + if len(c.IPAddresses) >= maxNamesIncluded { | ||
| 65 | + return fmt.Sprintf("x509: certificate is valid for %d IP SANs, but none matched %s", len(c.IPAddresses), h.Host) | ||
| 66 | + } | ||
| 67 | for _, san := range c.IPAddresses { | ||
| 68 | - if len(valid) > 0 { | ||
| 69 | - valid += ", " | ||
| 70 | + if valid.Len() > 0 { | ||
| 71 | + valid.WriteString(", ") | ||
| 72 | } | ||
| 73 | - valid += san.String() | ||
| 74 | + valid.WriteString(san.String()) | ||
| 75 | } | ||
| 76 | } else { | ||
| 77 | - valid = strings.Join(c.DNSNames, ", ") | ||
| 78 | + if len(c.DNSNames) >= maxNamesIncluded { | ||
| 79 | + return fmt.Sprintf("x509: certificate is valid for %d names, but none matched %s", len(c.DNSNames), h.Host) | ||
| 80 | + } | ||
| 81 | + valid.WriteString(strings.Join(c.DNSNames, ", ")) | ||
| 82 | } | ||
| 83 | |||
| 84 | - if len(valid) == 0 { | ||
| 85 | + if valid.Len() == 0 { | ||
| 86 | return "x509: certificate is not valid for any names, but wanted to match " + h.Host | ||
| 87 | } | ||
| 88 | - return "x509: certificate is valid for " + valid + ", not " + h.Host | ||
| 89 | + return "x509: certificate is valid for " + valid.String() + ", not " + h.Host | ||
| 90 | } | ||
| 91 | |||
| 92 | // UnknownAuthorityError results when the certificate issuer is unknown | ||
| 93 | diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go | ||
| 94 | index 5f7c834..c2c2025 100644 | ||
| 95 | --- a/src/crypto/x509/verify_test.go | ||
| 96 | +++ b/src/crypto/x509/verify_test.go | ||
| 97 | @@ -9,11 +9,14 @@ import ( | ||
| 98 | "crypto/ecdsa" | ||
| 99 | "crypto/elliptic" | ||
| 100 | "crypto/rand" | ||
| 101 | + "crypto/rsa" | ||
| 102 | "crypto/x509/pkix" | ||
| 103 | "encoding/pem" | ||
| 104 | "errors" | ||
| 105 | "fmt" | ||
| 106 | + "log" | ||
| 107 | "math/big" | ||
| 108 | + "net" | ||
| 109 | "runtime" | ||
| 110 | "strings" | ||
| 111 | "testing" | ||
| 112 | @@ -70,6 +73,26 @@ var verifyTests = []verifyTest{ | ||
| 113 | |||
| 114 | errorCallback: expectHostnameError("certificate is valid for"), | ||
| 115 | }, | ||
| 116 | + { | ||
| 117 | + name: "TooManyDNS", | ||
| 118 | + leaf: generatePEMCertWithRepeatSAN(1677615892, 200, "fake.dns"), | ||
| 119 | + roots: []string{generatePEMCertWithRepeatSAN(1677615892, 200, "fake.dns")}, | ||
| 120 | + currentTime: 1677615892, | ||
| 121 | + dnsName: "www.example.com", | ||
| 122 | + systemSkip: true, // does not chain to a system root | ||
| 123 | + | ||
| 124 | + errorCallback: expectHostnameError("certificate is valid for 200 names, but none matched"), | ||
| 125 | + }, | ||
| 126 | + { | ||
| 127 | + name: "TooManyIPs", | ||
| 128 | + leaf: generatePEMCertWithRepeatSAN(1677615892, 150, "4.3.2.1"), | ||
| 129 | + roots: []string{generatePEMCertWithRepeatSAN(1677615892, 150, "4.3.2.1")}, | ||
| 130 | + currentTime: 1677615892, | ||
| 131 | + dnsName: "1.2.3.4", | ||
| 132 | + systemSkip: true, // does not chain to a system root | ||
| 133 | + | ||
| 134 | + errorCallback: expectHostnameError("certificate is valid for 150 IP SANs, but none matched"), | ||
| 135 | + }, | ||
| 136 | { | ||
| 137 | name: "IPMissing", | ||
| 138 | leaf: googleLeaf, | ||
| 139 | @@ -584,6 +607,30 @@ func nameToKey(name *pkix.Name) string { | ||
| 140 | return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName | ||
| 141 | } | ||
| 142 | |||
| 143 | +func generatePEMCertWithRepeatSAN(currentTime int64, count int, san string) string { | ||
| 144 | + cert := Certificate{ | ||
| 145 | + NotBefore: time.Unix(currentTime, 0), | ||
| 146 | + NotAfter: time.Unix(currentTime, 0), | ||
| 147 | + } | ||
| 148 | + if ip := net.ParseIP(san); ip != nil { | ||
| 149 | + cert.IPAddresses = slices.Repeat([]net.IP{ip}, count) | ||
| 150 | + } else { | ||
| 151 | + cert.DNSNames = slices.Repeat([]string{san}, count) | ||
| 152 | + } | ||
| 153 | + privKey, err := rsa.GenerateKey(rand.Reader, 4096) | ||
| 154 | + if err != nil { | ||
| 155 | + log.Fatal(err) | ||
| 156 | + } | ||
| 157 | + certBytes, err := CreateCertificate(rand.Reader, &cert, &cert, &privKey.PublicKey, privKey) | ||
| 158 | + if err != nil { | ||
| 159 | + log.Fatal(err) | ||
| 160 | + } | ||
| 161 | + return string(pem.EncodeToMemory(&pem.Block{ | ||
| 162 | + Type: "CERTIFICATE", | ||
| 163 | + Bytes: certBytes, | ||
| 164 | + })) | ||
| 165 | +} | ||
| 166 | + | ||
| 167 | const geoTrustRoot = `-----BEGIN CERTIFICATE----- | ||
| 168 | MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT | ||
| 169 | MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i | ||
| 170 | -- | ||
| 171 | 2.25.1 | ||
| 172 | |||
diff --git a/meta/recipes-devtools/go/go-1.21/CVE-2023-39323.patch b/meta/recipes-devtools/go/go-1.21/CVE-2023-39323.patch new file mode 100644 index 0000000000..613c91706b --- /dev/null +++ b/meta/recipes-devtools/go/go-1.21/CVE-2023-39323.patch | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | From 5e0a62c44fbaff6443bffe67911370bc0ea25f6d Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Ian Lance Taylor <iant@golang.org> | ||
| 3 | Date: Wed, 20 Sep 2023 16:16:29 -0700 | ||
| 4 | Subject: [PATCH] cmd/compile: use absolute file name in isCgo check | ||
| 5 | |||
| 6 | For #23672 | ||
| 7 | Fixes #63211 | ||
| 8 | Fixes CVE-2023-39323 | ||
| 9 | |||
| 10 | Change-Id: I4586a69e1b2560036afec29d53e53cf25e6c7352 | ||
| 11 | Reviewed-on: https://team-review.git.corp.google.com/c/golang/go-private/+/2032884 | ||
| 12 | Reviewed-by: Matthew Dempsky <mdempsky@google.com> | ||
| 13 | Reviewed-by: Roland Shoemaker <bracewell@google.com> | ||
| 14 | Reviewed-on: https://go-review.googlesource.com/c/go/+/534158 | ||
| 15 | Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> | ||
| 16 | Reviewed-by: Ian Lance Taylor <iant@google.com> | ||
| 17 | LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> | ||
| 18 | Auto-Submit: Ian Lance Taylor <iant@google.com> | ||
| 19 | |||
| 20 | Upstream-Status: Backport | ||
| 21 | CVE: CVE-2023-39323 | ||
| 22 | |||
| 23 | Reference to upstream patch: | ||
| 24 | https://github.com/golang/go/commit/e7c142a19d8b3944c2f1b9ab7fd94c63d8d0c555 | ||
| 25 | |||
| 26 | Backport patch to fix CVE-2023-39323 and drop the modifications of test codes. | ||
| 27 | |||
| 28 | Signed-off-by: Libo Chen <libo.chen.cn@windriver.com> | ||
| 29 | --- | ||
| 30 | src/cmd/compile/internal/noder/noder.go | 8 +++++++- | ||
| 31 | 1 file changed, 7 insertions(+), 1 deletion(-) | ||
| 32 | |||
| 33 | diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go | ||
| 34 | index 5fcad096c2..f35e065a31 100644 | ||
| 35 | --- a/src/cmd/compile/internal/noder/noder.go | ||
| 36 | +++ b/src/cmd/compile/internal/noder/noder.go | ||
| 37 | @@ -1690,8 +1690,14 @@ func (p *noder) pragma(pos syntax.Pos, blankLine bool, text string, old syntax.P | ||
| 38 | // contain cgo directives, and for security reasons | ||
| 39 | // (primarily misuse of linker flags), other files are not. | ||
| 40 | // See golang.org/issue/23672. | ||
| 41 | +// Note that cmd/go ignores files whose names start with underscore, | ||
| 42 | +// so the only _cgo_ files we will see from cmd/go are generated by cgo. | ||
| 43 | +// It's easy to bypass this check by calling the compiler directly; | ||
| 44 | +// we only protect against uses by cmd/go. | ||
| 45 | func isCgoGeneratedFile(pos syntax.Pos) bool { | ||
| 46 | - return strings.HasPrefix(filepath.Base(filepath.Clean(fileh(pos.Base().Filename()))), "_cgo_") | ||
| 47 | + // We need the absolute file, independent of //line directives, | ||
| 48 | + // so we call pos.Base().Pos().Base(). | ||
| 49 | + return strings.HasPrefix(filepath.Base(filepath.Clean(fileh(pos.Base().Pos().Base().Filename()))), "_cgo_") | ||
| 50 | } | ||
| 51 | |||
| 52 | // safeArg reports whether arg is a "safe" command-line argument, | ||
| 53 | -- | ||
| 54 | 2.34.1 | ||
| 55 | |||
diff --git a/meta/recipes-devtools/pseudo/files/0001-configure-Prune-PIE-flags.patch b/meta/recipes-devtools/pseudo/files/0001-configure-Prune-PIE-flags.patch deleted file mode 100644 index 43504eaab9..0000000000 --- a/meta/recipes-devtools/pseudo/files/0001-configure-Prune-PIE-flags.patch +++ /dev/null | |||
| @@ -1,44 +0,0 @@ | |||
| 1 | From b5545c08e6c674c49aef14b47a56a3e92df4d2a7 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Khem Raj <raj.khem@gmail.com> | ||
| 3 | Date: Wed, 17 Feb 2016 07:36:34 +0000 | ||
| 4 | Subject: [pseudo][PATCH] configure: Prune PIE flags | ||
| 5 | |||
| 6 | LDFLAGS are not taken from environment and CFLAGS is used for LDFLAGS | ||
| 7 | however when using security options -fpie and -pie options are coming | ||
| 8 | as part of ARCH_FLAGS and they get into LDFLAGS of shared objects as | ||
| 9 | well so we end up with conflicting options -shared -pie, which gold | ||
| 10 | rejects outright and bfd linker lets the one appearning last in cmdline | ||
| 11 | take effect. This create quite a unpleasant situation in OE when | ||
| 12 | security flags are enabled and gold or not-gold options are used | ||
| 13 | it errors out but errors are not same. | ||
| 14 | |||
| 15 | Anyway, with this patch we filter pie options from ARCH_FLAGS | ||
| 16 | ouright and take control of generating PIC objects | ||
| 17 | |||
| 18 | Helps with errors like | ||
| 19 | |||
| 20 | | /mnt/oe/build/tmp-glibc/sysroots/x86_64-linux/usr/libexec/x86_64-oe-linux/gcc/x86_64-oe-linux/5.3.0/ld: pseudo_client.o: relocation R_X86_64_PC32 against symbol `pseudo_util_debug_flags' can not be used when making a shared object; recompile with -fPIC | ||
| 21 | | /mnt/oe/build/tmp-glibc/sysroots/x86_64-linux/usr/libexec/x86_64-oe-linux/gcc/x86_64-oe-linux/5.3.0/ld: final link failed: Bad value | ||
| 22 | | collect2: error: ld returned 1 exit status | ||
| 23 | | make: *** [lib/pseudo/lib64/libpseudo.so] Error 1 | ||
| 24 | |||
| 25 | Signed-off-by: Khem Raj <raj.khem@gmail.com> | ||
| 26 | --- | ||
| 27 | Upstream-Status: Submitted | ||
| 28 | |||
| 29 | configure | 2 ++ | ||
| 30 | 1 file changed, 2 insertions(+) | ||
| 31 | |||
| 32 | diff --git a/configure b/configure | ||
| 33 | index e5ef9ce..83b0890 100755 | ||
| 34 | --- a/configure | ||
| 35 | +++ b/configure | ||
| 36 | @@ -339,3 +339,5 @@ sed -e ' | ||
| 37 | s,@ARCH@,'"$opt_arch"',g | ||
| 38 | s,@BITS@,'"$opt_bits"',g | ||
| 39 | ' < Makefile.in > Makefile | ||
| 40 | + | ||
| 41 | +sed -i -e 's/\-[f]*pie//g' Makefile | ||
| 42 | -- | ||
| 43 | 1.8.3.1 | ||
| 44 | |||
diff --git a/meta/recipes-devtools/pseudo/files/glibc238.patch b/meta/recipes-devtools/pseudo/files/glibc238.patch deleted file mode 100644 index dfb5c283f6..0000000000 --- a/meta/recipes-devtools/pseudo/files/glibc238.patch +++ /dev/null | |||
| @@ -1,65 +0,0 @@ | |||
| 1 | glibc 2.38 would include __isoc23_strtol and similar symbols. This is trggerd by | ||
| 2 | _GNU_SOURCE but we have to set that for other definitions. Therefore play with defines | ||
| 3 | to turn this off within pseudo_wrappers.c. Elsewhere we can switch to _DEFAULT_SOURCE | ||
| 4 | rather than _GNU_SOURCE. | ||
| 5 | |||
| 6 | Upstream-Status: Pending | ||
| 7 | |||
| 8 | Index: git/pseudo_wrappers.c | ||
| 9 | =================================================================== | ||
| 10 | --- git.orig/pseudo_wrappers.c | ||
| 11 | +++ git/pseudo_wrappers.c | ||
| 12 | @@ -6,6 +6,18 @@ | ||
| 13 | * SPDX-License-Identifier: LGPL-2.1-only | ||
| 14 | * | ||
| 15 | */ | ||
| 16 | +/* glibc 2.38 would include __isoc23_strtol and similar symbols. This is trggerd by | ||
| 17 | + * _GNU_SOURCE but we have to set that for other definitions. Therefore play with defines | ||
| 18 | + * to turn this off. | ||
| 19 | + */ | ||
| 20 | +#include <features.h> | ||
| 21 | +#undef __GLIBC_USE_ISOC2X | ||
| 22 | +#undef __GLIBC_USE_C2X_STRTOL | ||
| 23 | +#define __GLIBC_USE_C2X_STRTOL 0 | ||
| 24 | +#undef __GLIBC_USE_ISOC23 | ||
| 25 | +#undef __GLIBC_USE_C23_STRTOL | ||
| 26 | +#define __GLIBC_USE_C23_STRTOL 0 | ||
| 27 | + | ||
| 28 | #include <assert.h> | ||
| 29 | #include <stdlib.h> | ||
| 30 | #include <limits.h> | ||
| 31 | Index: git/pseudo_util.c | ||
| 32 | =================================================================== | ||
| 33 | --- git.orig/pseudo_util.c | ||
| 34 | +++ git/pseudo_util.c | ||
| 35 | @@ -8,6 +8,17 @@ | ||
| 36 | */ | ||
| 37 | /* we need access to RTLD_NEXT for a horrible workaround */ | ||
| 38 | #define _GNU_SOURCE | ||
| 39 | +/* glibc 2.38 would include __isoc23_strtol and similar symbols. This is trggerd by | ||
| 40 | + * _GNU_SOURCE but we have to set that for other definitions. Therefore play with defines | ||
| 41 | + * to turn this off. | ||
| 42 | + */ | ||
| 43 | +#include <features.h> | ||
| 44 | +#undef __GLIBC_USE_ISOC2X | ||
| 45 | +#undef __GLIBC_USE_C2X_STRTOL | ||
| 46 | +#define __GLIBC_USE_C2X_STRTOL 0 | ||
| 47 | +#undef __GLIBC_USE_ISOC23 | ||
| 48 | +#undef __GLIBC_USE_C23_STRTOL | ||
| 49 | +#define __GLIBC_USE_C23_STRTOL 0 | ||
| 50 | |||
| 51 | #include <ctype.h> | ||
| 52 | #include <errno.h> | ||
| 53 | Index: git/pseudo_client.c | ||
| 54 | =================================================================== | ||
| 55 | --- git.orig/pseudo_client.c | ||
| 56 | +++ git/pseudo_client.c | ||
| 57 | @@ -6,7 +6,7 @@ | ||
| 58 | * SPDX-License-Identifier: LGPL-2.1-only | ||
| 59 | * | ||
| 60 | */ | ||
| 61 | -#define _GNU_SOURCE | ||
| 62 | +#define _DEFAULT_SOURCE | ||
| 63 | |||
| 64 | #include <stdio.h> | ||
| 65 | #include <signal.h> | ||
diff --git a/meta/recipes-devtools/pseudo/files/older-glibc-symbols.patch b/meta/recipes-devtools/pseudo/files/older-glibc-symbols.patch index c453b5f735..f42b32b8d9 100644 --- a/meta/recipes-devtools/pseudo/files/older-glibc-symbols.patch +++ b/meta/recipes-devtools/pseudo/files/older-glibc-symbols.patch | |||
| @@ -28,10 +28,10 @@ diff --git a/Makefile.in b/Makefile.in | |||
| 28 | @@ -120,7 +120,7 @@ $(PSEUDODB): pseudodb.o $(SHOBJS) $(DBOBJS) pseudo_ipc.o | $(BIN) | 28 | @@ -120,7 +120,7 @@ $(PSEUDODB): pseudodb.o $(SHOBJS) $(DBOBJS) pseudo_ipc.o | $(BIN) |
| 29 | libpseudo: $(LIBPSEUDO) | 29 | libpseudo: $(LIBPSEUDO) |
| 30 | 30 | ||
| 31 | $(LIBPSEUDO): $(WRAPOBJS) pseudo_client.o pseudo_ipc.o $(SHOBJS) | $(LIB) | 31 | $(LIBPSEUDO): $(WRAPOBJS) pseudo_client.o pseudo_client_scanf.o pseudo_ipc.o $(SHOBJS) | $(LIB) |
| 32 | - $(CC) $(CFLAGS) $(CFLAGS_PSEUDO) -shared -o $(LIBPSEUDO) \ | 32 | - $(CC) $(CFLAGS) $(CFLAGS_PSEUDO) -shared -o $(LIBPSEUDO) \ |
| 33 | + $(CC) $(CFLAGS) -Lprebuilt/$(shell uname -m)-linux/lib/ $(CFLAGS_PSEUDO) -shared -o $(LIBPSEUDO) \ | 33 | + $(CC) $(CFLAGS) -Lprebuilt/$(shell uname -m)-linux/lib/ $(CFLAGS_PSEUDO) -shared -o $(LIBPSEUDO) \ |
| 34 | pseudo_client.o pseudo_ipc.o \ | 34 | pseudo_client.o pseudo_client_scanf.o pseudo_ipc.o \ |
| 35 | $(WRAPOBJS) $(SHOBJS) $(LDFLAGS) $(CLIENT_LDFLAGS) | 35 | $(WRAPOBJS) $(SHOBJS) $(LDFLAGS) $(CLIENT_LDFLAGS) |
| 36 | 36 | ||
| 37 | diff --git a/pseudo_wrappers.c b/pseudo_wrappers.c | 37 | diff --git a/pseudo_wrappers.c b/pseudo_wrappers.c |
diff --git a/meta/recipes-devtools/pseudo/pseudo.inc b/meta/recipes-devtools/pseudo/pseudo.inc index 7e09b6d58c..9c191560fb 100644 --- a/meta/recipes-devtools/pseudo/pseudo.inc +++ b/meta/recipes-devtools/pseudo/pseudo.inc | |||
| @@ -156,3 +156,10 @@ do_install:append:class-nativesdk () { | |||
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | BBCLASSEXTEND = "native nativesdk" | 158 | BBCLASSEXTEND = "native nativesdk" |
| 159 | |||
| 160 | # Setscene tasks which run under fakeroot must not be executed before | ||
| 161 | # pseudo-native and *all* its runtime dependencies are available in the | ||
| 162 | # sysroot. | ||
| 163 | PSEUDO_SETSCENE_DEPS = "" | ||
| 164 | PSEUDO_SETSCENE_DEPS:class-native = "sqlite3-native:do_populate_sysroot" | ||
| 165 | do_populate_sysroot_setscene[depends] += "${PSEUDO_SETSCENE_DEPS}" | ||
diff --git a/meta/recipes-devtools/pseudo/pseudo_git.bb b/meta/recipes-devtools/pseudo/pseudo_git.bb index 405d2340ae..dae4f4bc84 100644 --- a/meta/recipes-devtools/pseudo/pseudo_git.bb +++ b/meta/recipes-devtools/pseudo/pseudo_git.bb | |||
| @@ -1,8 +1,6 @@ | |||
| 1 | require pseudo.inc | 1 | require pseudo.inc |
| 2 | 2 | ||
| 3 | SRC_URI = "git://git.yoctoproject.org/pseudo;branch=master \ | 3 | SRC_URI = "git://git.yoctoproject.org/pseudo;branch=master \ |
| 4 | file://0001-configure-Prune-PIE-flags.patch \ | ||
| 5 | file://glibc238.patch \ | ||
| 6 | file://fallback-passwd \ | 4 | file://fallback-passwd \ |
| 7 | file://fallback-group \ | 5 | file://fallback-group \ |
| 8 | " | 6 | " |
| @@ -14,9 +12,9 @@ SRC_URI:append:class-nativesdk = " \ | |||
| 14 | file://older-glibc-symbols.patch" | 12 | file://older-glibc-symbols.patch" |
| 15 | SRC_URI[prebuilt.sha256sum] = "ed9f456856e9d86359f169f46a70ad7be4190d6040282b84c8d97b99072485aa" | 13 | SRC_URI[prebuilt.sha256sum] = "ed9f456856e9d86359f169f46a70ad7be4190d6040282b84c8d97b99072485aa" |
| 16 | 14 | ||
| 17 | SRCREV = "28dcefb809ce95db997811b5662f0b893b9923e0" | 15 | SRCREV = "125b020dd2bc46baa37a80784704e382732357b4" |
| 18 | S = "${WORKDIR}/git" | 16 | S = "${WORKDIR}/git" |
| 19 | PV = "1.9.0+git${SRCPV}" | 17 | PV = "1.9.2+git" |
| 20 | 18 | ||
| 21 | # largefile and 64bit time_t support adds these macros via compiler flags globally | 19 | # largefile and 64bit time_t support adds these macros via compiler flags globally |
| 22 | # remove them for pseudo since pseudo intercepts some of the functions which will be | 20 | # remove them for pseudo since pseudo intercepts some of the functions which will be |
diff --git a/meta/recipes-devtools/python/python3-urllib3/CVE-2025-66418.patch b/meta/recipes-devtools/python/python3-urllib3/CVE-2025-66418.patch new file mode 100644 index 0000000000..b490019d87 --- /dev/null +++ b/meta/recipes-devtools/python/python3-urllib3/CVE-2025-66418.patch | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | From 24d7b67eac89f94e11003424bcf0d8f7b72222a8 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Illia Volochii <illia.volochii@gmail.com> | ||
| 3 | Date: Fri, 5 Dec 2025 16:41:33 +0200 | ||
| 4 | Subject: [PATCH] Merge commit from fork | ||
| 5 | |||
| 6 | * Add a hard-coded limit for the decompression chain | ||
| 7 | |||
| 8 | * Reuse new list | ||
| 9 | |||
| 10 | CVE: CVE-2025-66418 | ||
| 11 | Upstream-Status: Backport [https://github.com/urllib3/urllib3/commit/24d7b67eac89f94e11003424bcf0d8f7b72222a8] | ||
| 12 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 13 | --- | ||
| 14 | changelog/GHSA-gm62-xv2j-4w53.security.rst | 4 ++++ | ||
| 15 | src/urllib3/response.py | 12 +++++++++++- | ||
| 16 | test/test_response.py | 10 ++++++++++ | ||
| 17 | 3 files changed, 25 insertions(+), 1 deletion(-) | ||
| 18 | create mode 100644 changelog/GHSA-gm62-xv2j-4w53.security.rst | ||
| 19 | |||
| 20 | diff --git a/changelog/GHSA-gm62-xv2j-4w53.security.rst b/changelog/GHSA-gm62-xv2j-4w53.security.rst | ||
| 21 | new file mode 100644 | ||
| 22 | index 00000000..6646eaa3 | ||
| 23 | --- /dev/null | ||
| 24 | +++ b/changelog/GHSA-gm62-xv2j-4w53.security.rst | ||
| 25 | @@ -0,0 +1,4 @@ | ||
| 26 | +Fixed a security issue where an attacker could compose an HTTP response with | ||
| 27 | +virtually unlimited links in the ``Content-Encoding`` header, potentially | ||
| 28 | +leading to a denial of service (DoS) attack by exhausting system resources | ||
| 29 | +during decoding. The number of allowed chained encodings is now limited to 5. | ||
| 30 | diff --git a/src/urllib3/response.py b/src/urllib3/response.py | ||
| 31 | index 4ba42136..069f726c 100644 | ||
| 32 | --- a/src/urllib3/response.py | ||
| 33 | +++ b/src/urllib3/response.py | ||
| 34 | @@ -135,8 +135,18 @@ class MultiDecoder(object): | ||
| 35 | they were applied. | ||
| 36 | """ | ||
| 37 | |||
| 38 | + # Maximum allowed number of chained HTTP encodings in the | ||
| 39 | + # Content-Encoding header. | ||
| 40 | + max_decode_links = 5 | ||
| 41 | + | ||
| 42 | def __init__(self, modes): | ||
| 43 | - self._decoders = [_get_decoder(m.strip()) for m in modes.split(",")] | ||
| 44 | + encodings = [m.strip() for m in modes.split(",")] | ||
| 45 | + if len(encodings) > self.max_decode_links: | ||
| 46 | + raise DecodeError( | ||
| 47 | + "Too many content encodings in the chain: " | ||
| 48 | + f"{len(encodings)} > {self.max_decode_links}" | ||
| 49 | + ) | ||
| 50 | + self._decoders = [_get_decoder(e) for e in encodings] | ||
| 51 | |||
| 52 | def flush(self): | ||
| 53 | return self._decoders[0].flush() | ||
| 54 | diff --git a/test/test_response.py b/test/test_response.py | ||
| 55 | index 9592fdd9..d824ae70 100644 | ||
| 56 | --- a/test/test_response.py | ||
| 57 | +++ b/test/test_response.py | ||
| 58 | @@ -295,6 +295,16 @@ class TestResponse(object): | ||
| 59 | |||
| 60 | assert r.data == b"foo" | ||
| 61 | |||
| 62 | + def test_read_multi_decoding_too_many_links(self) -> None: | ||
| 63 | + fp = BytesIO(b"foo") | ||
| 64 | + with pytest.raises( | ||
| 65 | + DecodeError, match="Too many content encodings in the chain: 6 > 5" | ||
| 66 | + ): | ||
| 67 | + HTTPResponse( | ||
| 68 | + fp, | ||
| 69 | + headers={"content-encoding": "gzip, deflate, br, zstd, gzip, deflate"}, | ||
| 70 | + ) | ||
| 71 | + | ||
| 72 | def test_body_blob(self): | ||
| 73 | resp = HTTPResponse(b"foo") | ||
| 74 | assert resp.data == b"foo" | ||
diff --git a/meta/recipes-devtools/python/python3-urllib3_1.26.20.bb b/meta/recipes-devtools/python/python3-urllib3_1.26.20.bb index 58988e4205..1f1132d5b5 100644 --- a/meta/recipes-devtools/python/python3-urllib3_1.26.20.bb +++ b/meta/recipes-devtools/python/python3-urllib3_1.26.20.bb | |||
| @@ -9,6 +9,7 @@ inherit pypi setuptools3 | |||
| 9 | 9 | ||
| 10 | SRC_URI += " \ | 10 | SRC_URI += " \ |
| 11 | file://CVE-2025-50181.patch \ | 11 | file://CVE-2025-50181.patch \ |
| 12 | file://CVE-2025-66418.patch \ | ||
| 12 | " | 13 | " |
| 13 | 14 | ||
| 14 | RDEPENDS:${PN} += "\ | 15 | RDEPENDS:${PN} += "\ |
diff --git a/meta/recipes-devtools/python/python3/CVE-2025-13836.patch b/meta/recipes-devtools/python/python3/CVE-2025-13836.patch new file mode 100644 index 0000000000..c4387b6019 --- /dev/null +++ b/meta/recipes-devtools/python/python3/CVE-2025-13836.patch | |||
| @@ -0,0 +1,163 @@ | |||
| 1 | From 289f29b0fe38baf2d7cb5854f4bb573cc34a6a15 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: "Miss Islington (bot)" | ||
| 3 | <31488909+miss-islington@users.noreply.github.com> | ||
| 4 | Date: Fri, 5 Dec 2025 16:21:57 +0100 | ||
| 5 | Subject: [PATCH] [3.13] gh-119451: Fix a potential denial of service in | ||
| 6 | http.client (GH-119454) (#142139) | ||
| 7 | |||
| 8 | gh-119451: Fix a potential denial of service in http.client (GH-119454) | ||
| 9 | |||
| 10 | Reading the whole body of the HTTP response could cause OOM if | ||
| 11 | the Content-Length value is too large even if the server does not send | ||
| 12 | a large amount of data. Now the HTTP client reads large data by chunks, | ||
| 13 | therefore the amount of consumed memory is proportional to the amount | ||
| 14 | of sent data. | ||
| 15 | (cherry picked from commit 5a4c4a033a4a54481be6870aa1896fad732555b5) | ||
| 16 | |||
| 17 | CVE: CVE-2025-13836 | ||
| 18 | Upstream-Status: Backport [https://github.com/python/cpython/commit/289f29b0fe38baf2d7cb5854f4bb573cc34a6a15] | ||
| 19 | Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com> | ||
| 20 | --- | ||
| 21 | Lib/http/client.py | 28 ++++++-- | ||
| 22 | Lib/test/test_httplib.py | 66 +++++++++++++++++++ | ||
| 23 | ...-05-23-11-47-48.gh-issue-119451.qkJe9-.rst | 5 ++ | ||
| 24 | 3 files changed, 95 insertions(+), 4 deletions(-) | ||
| 25 | create mode 100644 Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst | ||
| 26 | |||
| 27 | diff --git a/Lib/http/client.py b/Lib/http/client.py | ||
| 28 | index d1b7b10..c8ab5b7 100644 | ||
| 29 | --- a/Lib/http/client.py | ||
| 30 | +++ b/Lib/http/client.py | ||
| 31 | @@ -111,6 +111,11 @@ responses = {v: v.phrase for v in http.HTTPStatus.__members__.values()} | ||
| 32 | _MAXLINE = 65536 | ||
| 33 | _MAXHEADERS = 100 | ||
| 34 | |||
| 35 | +# Data larger than this will be read in chunks, to prevent extreme | ||
| 36 | +# overallocation. | ||
| 37 | +_MIN_READ_BUF_SIZE = 1 << 20 | ||
| 38 | + | ||
| 39 | + | ||
| 40 | # Header name/value ABNF (http://tools.ietf.org/html/rfc7230#section-3.2) | ||
| 41 | # | ||
| 42 | # VCHAR = %x21-7E | ||
| 43 | @@ -628,10 +633,25 @@ class HTTPResponse(io.BufferedIOBase): | ||
| 44 | reading. If the bytes are truly not available (due to EOF), then the | ||
| 45 | IncompleteRead exception can be used to detect the problem. | ||
| 46 | """ | ||
| 47 | - data = self.fp.read(amt) | ||
| 48 | - if len(data) < amt: | ||
| 49 | - raise IncompleteRead(data, amt-len(data)) | ||
| 50 | - return data | ||
| 51 | + cursize = min(amt, _MIN_READ_BUF_SIZE) | ||
| 52 | + data = self.fp.read(cursize) | ||
| 53 | + if len(data) >= amt: | ||
| 54 | + return data | ||
| 55 | + if len(data) < cursize: | ||
| 56 | + raise IncompleteRead(data, amt - len(data)) | ||
| 57 | + | ||
| 58 | + data = io.BytesIO(data) | ||
| 59 | + data.seek(0, 2) | ||
| 60 | + while True: | ||
| 61 | + # This is a geometric increase in read size (never more than | ||
| 62 | + # doubling out the current length of data per loop iteration). | ||
| 63 | + delta = min(cursize, amt - cursize) | ||
| 64 | + data.write(self.fp.read(delta)) | ||
| 65 | + if data.tell() >= amt: | ||
| 66 | + return data.getvalue() | ||
| 67 | + cursize += delta | ||
| 68 | + if data.tell() < cursize: | ||
| 69 | + raise IncompleteRead(data.getvalue(), amt - data.tell()) | ||
| 70 | |||
| 71 | def _safe_readinto(self, b): | ||
| 72 | """Same as _safe_read, but for reading into a buffer.""" | ||
| 73 | diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py | ||
| 74 | index 77152cf..89ec5f6 100644 | ||
| 75 | --- a/Lib/test/test_httplib.py | ||
| 76 | +++ b/Lib/test/test_httplib.py | ||
| 77 | @@ -1226,6 +1226,72 @@ class BasicTest(TestCase): | ||
| 78 | thread.join() | ||
| 79 | self.assertEqual(result, b"proxied data\n") | ||
| 80 | |||
| 81 | + def test_large_content_length(self): | ||
| 82 | + serv = socket.create_server((HOST, 0)) | ||
| 83 | + self.addCleanup(serv.close) | ||
| 84 | + | ||
| 85 | + def run_server(): | ||
| 86 | + [conn, address] = serv.accept() | ||
| 87 | + with conn: | ||
| 88 | + while conn.recv(1024): | ||
| 89 | + conn.sendall( | ||
| 90 | + b"HTTP/1.1 200 Ok\r\n" | ||
| 91 | + b"Content-Length: %d\r\n" | ||
| 92 | + b"\r\n" % size) | ||
| 93 | + conn.sendall(b'A' * (size//3)) | ||
| 94 | + conn.sendall(b'B' * (size - size//3)) | ||
| 95 | + | ||
| 96 | + thread = threading.Thread(target=run_server) | ||
| 97 | + thread.start() | ||
| 98 | + self.addCleanup(thread.join, 1.0) | ||
| 99 | + | ||
| 100 | + conn = client.HTTPConnection(*serv.getsockname()) | ||
| 101 | + try: | ||
| 102 | + for w in range(15, 27): | ||
| 103 | + size = 1 << w | ||
| 104 | + conn.request("GET", "/") | ||
| 105 | + with conn.getresponse() as response: | ||
| 106 | + self.assertEqual(len(response.read()), size) | ||
| 107 | + finally: | ||
| 108 | + conn.close() | ||
| 109 | + thread.join(1.0) | ||
| 110 | + | ||
| 111 | + def test_large_content_length_truncated(self): | ||
| 112 | + serv = socket.create_server((HOST, 0)) | ||
| 113 | + self.addCleanup(serv.close) | ||
| 114 | + | ||
| 115 | + def run_server(): | ||
| 116 | + while True: | ||
| 117 | + [conn, address] = serv.accept() | ||
| 118 | + with conn: | ||
| 119 | + conn.recv(1024) | ||
| 120 | + if not size: | ||
| 121 | + break | ||
| 122 | + conn.sendall( | ||
| 123 | + b"HTTP/1.1 200 Ok\r\n" | ||
| 124 | + b"Content-Length: %d\r\n" | ||
| 125 | + b"\r\n" | ||
| 126 | + b"Text" % size) | ||
| 127 | + | ||
| 128 | + thread = threading.Thread(target=run_server) | ||
| 129 | + thread.start() | ||
| 130 | + self.addCleanup(thread.join, 1.0) | ||
| 131 | + | ||
| 132 | + conn = client.HTTPConnection(*serv.getsockname()) | ||
| 133 | + try: | ||
| 134 | + for w in range(18, 65): | ||
| 135 | + size = 1 << w | ||
| 136 | + conn.request("GET", "/") | ||
| 137 | + with conn.getresponse() as response: | ||
| 138 | + self.assertRaises(client.IncompleteRead, response.read) | ||
| 139 | + conn.close() | ||
| 140 | + finally: | ||
| 141 | + conn.close() | ||
| 142 | + size = 0 | ||
| 143 | + conn.request("GET", "/") | ||
| 144 | + conn.close() | ||
| 145 | + thread.join(1.0) | ||
| 146 | + | ||
| 147 | def test_putrequest_override_domain_validation(self): | ||
| 148 | """ | ||
| 149 | It should be possible to override the default validation | ||
| 150 | diff --git a/Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst b/Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst | ||
| 151 | new file mode 100644 | ||
| 152 | index 0000000..6d6f25c | ||
| 153 | --- /dev/null | ||
| 154 | +++ b/Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst | ||
| 155 | @@ -0,0 +1,5 @@ | ||
| 156 | +Fix a potential memory denial of service in the :mod:`http.client` module. | ||
| 157 | +When connecting to a malicious server, it could cause | ||
| 158 | +an arbitrary amount of memory to be allocated. | ||
| 159 | +This could have led to symptoms including a :exc:`MemoryError`, swapping, out | ||
| 160 | +of memory (OOM) killed processes or containers, or even system crashes. | ||
| 161 | -- | ||
| 162 | 2.50.1 | ||
| 163 | |||
diff --git a/meta/recipes-devtools/python/python3_3.10.19.bb b/meta/recipes-devtools/python/python3_3.10.19.bb index 6f23d258c1..5140445ad8 100644 --- a/meta/recipes-devtools/python/python3_3.10.19.bb +++ b/meta/recipes-devtools/python/python3_3.10.19.bb | |||
| @@ -38,6 +38,7 @@ SRC_URI = "http://www.python.org/ftp/python/${PV}/Python-${PV}.tar.xz \ | |||
| 38 | file://0001-test_storlines-skip-due-to-load-variability.patch \ | 38 | file://0001-test_storlines-skip-due-to-load-variability.patch \ |
| 39 | file://0001-gh-107811-tarfile-treat-overflow-in-UID-GID-as-failu.patch \ | 39 | file://0001-gh-107811-tarfile-treat-overflow-in-UID-GID-as-failu.patch \ |
| 40 | file://CVE-2025-6075.patch \ | 40 | file://CVE-2025-6075.patch \ |
| 41 | file://CVE-2025-13836.patch \ | ||
| 41 | " | 42 | " |
| 42 | 43 | ||
| 43 | SRC_URI:append:class-native = " \ | 44 | SRC_URI:append:class-native = " \ |
diff --git a/meta/recipes-devtools/qemu/qemu.inc b/meta/recipes-devtools/qemu/qemu.inc index fd1a8647df..764f0e110a 100644 --- a/meta/recipes-devtools/qemu/qemu.inc +++ b/meta/recipes-devtools/qemu/qemu.inc | |||
| @@ -129,6 +129,7 @@ SRC_URI = "https://download.qemu.org/${BPN}-${PV}.tar.xz \ | |||
| 129 | file://CVE-2024-3446-0006.patch \ | 129 | file://CVE-2024-3446-0006.patch \ |
| 130 | file://CVE-2024-3447.patch \ | 130 | file://CVE-2024-3447.patch \ |
| 131 | file://CVE-2024-8354.patch \ | 131 | file://CVE-2024-8354.patch \ |
| 132 | file://CVE-2025-12464.patch \ | ||
| 132 | " | 133 | " |
| 133 | UPSTREAM_CHECK_REGEX = "qemu-(?P<pver>\d+(\.\d+)+)\.tar" | 134 | UPSTREAM_CHECK_REGEX = "qemu-(?P<pver>\d+(\.\d+)+)\.tar" |
| 134 | 135 | ||
| @@ -168,6 +169,9 @@ CVE_CHECK_IGNORE += "CVE-2023-1386" | |||
| 168 | # virtio-snd was implemented in 8.2.0, so version 6.2.0 is not yet affected | 169 | # virtio-snd was implemented in 8.2.0, so version 6.2.0 is not yet affected |
| 169 | CVE_CHECK_IGNORE += "CVE-2024-7730" | 170 | CVE_CHECK_IGNORE += "CVE-2024-7730" |
| 170 | 171 | ||
| 172 | # These issues were introduced in v10.0.0-rc0 | ||
| 173 | CVE_CHECK_IGNORE += "CVE-2025-54566 CVE-2025-54567" | ||
| 174 | |||
| 171 | COMPATIBLE_HOST:mipsarchn32 = "null" | 175 | COMPATIBLE_HOST:mipsarchn32 = "null" |
| 172 | COMPATIBLE_HOST:mipsarchn64 = "null" | 176 | COMPATIBLE_HOST:mipsarchn64 = "null" |
| 173 | COMPATIBLE_HOST:riscv32 = "null" | 177 | COMPATIBLE_HOST:riscv32 = "null" |
diff --git a/meta/recipes-devtools/qemu/qemu/CVE-2025-12464.patch b/meta/recipes-devtools/qemu/qemu/CVE-2025-12464.patch new file mode 100644 index 0000000000..6099fc79cd --- /dev/null +++ b/meta/recipes-devtools/qemu/qemu/CVE-2025-12464.patch | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | From a01344d9d78089e9e585faaeb19afccff2050abf Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Peter Maydell <peter.maydell@linaro.org> | ||
| 3 | Date: Tue, 28 Oct 2025 16:00:42 +0000 | ||
| 4 | Subject: [PATCH] net: pad packets to minimum length in qemu_receive_packet() | ||
| 5 | |||
| 6 | In commits like 969e50b61a28 ("net: Pad short frames to minimum size | ||
| 7 | before sending from SLiRP/TAP") we switched away from requiring | ||
| 8 | network devices to handle short frames to instead having the net core | ||
| 9 | code do the padding of short frames out to the ETH_ZLEN minimum size. | ||
| 10 | We then dropped the code for handling short frames from the network | ||
| 11 | devices in a series of commits like 140eae9c8f7 ("hw/net: e1000: | ||
| 12 | Remove the logic of padding short frames in the receive path"). | ||
| 13 | |||
| 14 | This missed one route where the device's receive code can still see a | ||
| 15 | short frame: if the device is in loopback mode and it transmits a | ||
| 16 | short frame via the qemu_receive_packet() function, this will be fed | ||
| 17 | back into its own receive code without being padded. | ||
| 18 | |||
| 19 | Add the padding logic to qemu_receive_packet(). | ||
| 20 | |||
| 21 | This fixes a buffer overrun which can be triggered in the | ||
| 22 | e1000_receive_iov() logic via the loopback code path. | ||
| 23 | |||
| 24 | Other devices that use qemu_receive_packet() to implement loopback | ||
| 25 | are cadence_gem, dp8393x, lan9118, msf2-emac, pcnet, rtl8139 | ||
| 26 | and sungem. | ||
| 27 | |||
| 28 | Cc: qemu-stable@nongnu.org | ||
| 29 | Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3043 | ||
| 30 | Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> | ||
| 31 | Signed-off-by: Peter Maydell <peter.maydell@linaro.org> | ||
| 32 | Signed-off-by: Jason Wang <jasowang@redhat.com> | ||
| 33 | |||
| 34 | CVE: CVE-2025-12464 | ||
| 35 | |||
| 36 | Upstream-Status: Backport [https://gitlab.com/qemu-project/qemu/-/commit/a01344d9d7] | ||
| 37 | |||
| 38 | Signed-off-by: Kai Kang <kai.kang@windriver.com> | ||
| 39 | --- | ||
| 40 | net/net.c | 10 ++++++++++ | ||
| 41 | 1 file changed, 10 insertions(+) | ||
| 42 | |||
| 43 | diff --git a/net/net.c b/net/net.c | ||
| 44 | index 27e0d27807..8aefdb3424 100644 | ||
| 45 | --- a/net/net.c | ||
| 46 | +++ b/net/net.c | ||
| 47 | @@ -775,10 +775,20 @@ ssize_t qemu_send_packet(NetClientState *nc, const uint8_t *buf, int size) | ||
| 48 | |||
| 49 | ssize_t qemu_receive_packet(NetClientState *nc, const uint8_t *buf, int size) | ||
| 50 | { | ||
| 51 | + uint8_t min_pkt[ETH_ZLEN]; | ||
| 52 | + size_t min_pktsz = sizeof(min_pkt); | ||
| 53 | + | ||
| 54 | if (!qemu_can_receive_packet(nc)) { | ||
| 55 | return 0; | ||
| 56 | } | ||
| 57 | |||
| 58 | + if (net_peer_needs_padding(nc)) { | ||
| 59 | + if (eth_pad_short_frame(min_pkt, &min_pktsz, buf, size)) { | ||
| 60 | + buf = min_pkt; | ||
| 61 | + size = min_pktsz; | ||
| 62 | + } | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | return qemu_net_queue_receive(nc->incoming_queue, buf, size); | ||
| 66 | } | ||
| 67 | |||
| 68 | -- | ||
| 69 | 2.47.1 | ||
| 70 | |||
diff --git a/meta/recipes-devtools/rsync/files/CVE-2025-10158.patch b/meta/recipes-devtools/rsync/files/CVE-2025-10158.patch new file mode 100644 index 0000000000..cba7002870 --- /dev/null +++ b/meta/recipes-devtools/rsync/files/CVE-2025-10158.patch | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | From a8fabf850c3c5164520c307199e9abc5ded45e4c Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Andrew Tridgell <andrew@tridgell.net> | ||
| 3 | Date: Sat, 23 Aug 2025 17:26:53 +1000 | ||
| 4 | Subject: [PATCH] fixed an invalid access to files array | ||
| 5 | |||
| 6 | this was found by Calum Hutton from Rapid7. It is a real bug, but | ||
| 7 | analysis shows it can't be leverged into an exploit. Worth fixing | ||
| 8 | though. | ||
| 9 | |||
| 10 | Many thanks to Calum and Rapid7 for finding and reporting this | ||
| 11 | |||
| 12 | CVE: CVE-2025-10158 | ||
| 13 | |||
| 14 | Upstream-Status: Backport [https://github.com/RsyncProject/rsync/commit/797e17fc4a6f15e3b1756538a9f812b63942686f] | ||
| 15 | |||
| 16 | Signed-off-by: Liyin Zhang <liyin.zhang.cn@windriver.com> | ||
| 17 | --- | ||
| 18 | sender.c | 2 ++ | ||
| 19 | 1 file changed, 2 insertions(+) | ||
| 20 | |||
| 21 | diff --git a/sender.c b/sender.c | ||
| 22 | index a4d46c39..b1588b70 100644 | ||
| 23 | --- a/sender.c | ||
| 24 | +++ b/sender.c | ||
| 25 | @@ -262,6 +262,8 @@ void send_files(int f_in, int f_out) | ||
| 26 | |||
| 27 | if (ndx - cur_flist->ndx_start >= 0) | ||
| 28 | file = cur_flist->files[ndx - cur_flist->ndx_start]; | ||
| 29 | + else if (cur_flist->parent_ndx < 0) | ||
| 30 | + exit_cleanup(RERR_PROTOCOL); | ||
| 31 | else | ||
| 32 | file = dir_flist->files[cur_flist->parent_ndx]; | ||
| 33 | if (F_PATHNAME(file)) { | ||
| 34 | -- | ||
| 35 | 2.35.5 | ||
| 36 | |||
diff --git a/meta/recipes-devtools/rsync/rsync_3.2.7.bb b/meta/recipes-devtools/rsync/rsync_3.2.7.bb index 37e79e1e56..e3dd1702ec 100644 --- a/meta/recipes-devtools/rsync/rsync_3.2.7.bb +++ b/meta/recipes-devtools/rsync/rsync_3.2.7.bb | |||
| @@ -27,6 +27,7 @@ SRC_URI = "https://download.samba.org/pub/${BPN}/src/${BP}.tar.gz \ | |||
| 27 | file://CVE-2024-12087-0003.patch \ | 27 | file://CVE-2024-12087-0003.patch \ |
| 28 | file://CVE-2024-12088.patch \ | 28 | file://CVE-2024-12088.patch \ |
| 29 | file://CVE-2024-12747.patch \ | 29 | file://CVE-2024-12747.patch \ |
| 30 | file://CVE-2025-10158.patch \ | ||
| 30 | " | 31 | " |
| 31 | 32 | ||
| 32 | SRC_URI[sha256sum] = "4e7d9d3f6ed10878c58c5fb724a67dacf4b6aac7340b13e488fb2dc41346f2bb" | 33 | SRC_URI[sha256sum] = "4e7d9d3f6ed10878c58c5fb724a67dacf4b6aac7340b13e488fb2dc41346f2bb" |
diff --git a/meta/recipes-extended/cups/cups.inc b/meta/recipes-extended/cups/cups.inc index cba4406720..f70c4e7026 100644 --- a/meta/recipes-extended/cups/cups.inc +++ b/meta/recipes-extended/cups/cups.inc | |||
| @@ -27,6 +27,9 @@ SRC_URI = "https://github.com/OpenPrinting/cups/releases/download/v${PV}/cups-${ | |||
| 27 | file://CVE-2024-47175-5.patch \ | 27 | file://CVE-2024-47175-5.patch \ |
| 28 | file://CVE-2025-58060.patch \ | 28 | file://CVE-2025-58060.patch \ |
| 29 | file://CVE-2025-58364.patch \ | 29 | file://CVE-2025-58364.patch \ |
| 30 | file://CVE-2025-58436.patch \ | ||
| 31 | file://CVE-2025-61915.patch \ | ||
| 32 | file://0001-conf.c-Fix-stopping-scheduler-on-unknown-directive.patch \ | ||
| 30 | " | 33 | " |
| 31 | 34 | ||
| 32 | UPSTREAM_CHECK_URI = "https://github.com/OpenPrinting/cups/releases" | 35 | UPSTREAM_CHECK_URI = "https://github.com/OpenPrinting/cups/releases" |
diff --git a/meta/recipes-extended/cups/cups/0001-conf.c-Fix-stopping-scheduler-on-unknown-directive.patch b/meta/recipes-extended/cups/cups/0001-conf.c-Fix-stopping-scheduler-on-unknown-directive.patch new file mode 100644 index 0000000000..572a8941f4 --- /dev/null +++ b/meta/recipes-extended/cups/cups/0001-conf.c-Fix-stopping-scheduler-on-unknown-directive.patch | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | From 277d3b1c49895f070bbf4b73cada011d71fbf9f3 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Zdenek Dohnal <zdohnal@redhat.com> | ||
| 3 | Date: Thu, 4 Dec 2025 09:04:37 +0100 | ||
| 4 | Subject: [PATCH] conf.c: Fix stopping scheduler on unknown directive | ||
| 5 | |||
| 6 | Change the return value to do not trigger stopping the scheduler in case | ||
| 7 | of unknown directive, because stopping the scheduler on config errors | ||
| 8 | should only happen in case of syntax errors. | ||
| 9 | |||
| 10 | Upstream-Status: Backport [https://github.com/OpenPrinting/cups/commit/277d3b1c49895f070bbf4b73cada011d71fbf9f3] | ||
| 11 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 12 | --- | ||
| 13 | scheduler/conf.c | 14 +++++++------- | ||
| 14 | 1 file changed, 7 insertions(+), 7 deletions(-) | ||
| 15 | |||
| 16 | diff --git a/scheduler/conf.c b/scheduler/conf.c | ||
| 17 | index 7d6da0252..0e7be0ef4 100644 | ||
| 18 | --- a/scheduler/conf.c | ||
| 19 | +++ b/scheduler/conf.c | ||
| 20 | @@ -2695,16 +2695,16 @@ parse_variable( | ||
| 21 | { | ||
| 22 | /* | ||
| 23 | * Unknown directive! Output an error message and continue... | ||
| 24 | + * | ||
| 25 | + * Return value 1 is on purpose - we ignore unknown directives to log | ||
| 26 | + * error, but do not stop the scheduler in case error in configuration | ||
| 27 | + * is set to be fatal. | ||
| 28 | */ | ||
| 29 | |||
| 30 | - if (!value) | ||
| 31 | - cupsdLogMessage(CUPSD_LOG_ERROR, "Missing value for %s on line %d of %s.", | ||
| 32 | - line, linenum, filename); | ||
| 33 | - else | ||
| 34 | - cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown directive %s on line %d of %s.", | ||
| 35 | - line, linenum, filename); | ||
| 36 | + cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown directive %s on line %d of %s.", | ||
| 37 | + line, linenum, filename); | ||
| 38 | |||
| 39 | - return (0); | ||
| 40 | + return (1); | ||
| 41 | } | ||
| 42 | |||
| 43 | switch (var->type) | ||
diff --git a/meta/recipes-extended/cups/cups/CVE-2025-58436.patch b/meta/recipes-extended/cups/cups/CVE-2025-58436.patch new file mode 100644 index 0000000000..388c5e57b5 --- /dev/null +++ b/meta/recipes-extended/cups/cups/CVE-2025-58436.patch | |||
| @@ -0,0 +1,630 @@ | |||
| 1 | From 5d414f1f91bdca118413301b148f0b188eb1cdc6 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Zdenek Dohnal <zdohnal@redhat.com> | ||
| 3 | Date: Mon, 13 Oct 2025 10:16:48 +0200 | ||
| 4 | Subject: [PATCH] Fix unresponsive cupsd process caused by a slow client | ||
| 5 | |||
| 6 | If client is very slow, it will slow cupsd process for other clients. | ||
| 7 | The fix is the best effort without turning scheduler cupsd into | ||
| 8 | multithreaded process which would be too complex and error-prone when | ||
| 9 | backporting to 2.4.x series. | ||
| 10 | |||
| 11 | The fix for unencrypted communication is to follow up on communication | ||
| 12 | only if there is the whole line on input, and the waiting time is | ||
| 13 | guarded by timeout. | ||
| 14 | |||
| 15 | Encrypted communication now starts after we have the whole client hello | ||
| 16 | packet, which conflicts with optional upgrade support to HTTPS via | ||
| 17 | methods other than method OPTIONS, so this optional support defined in | ||
| 18 | RFC 2817, section 3.1 is removed. Too slow or incomplete requests are | ||
| 19 | handled by connection timeout. | ||
| 20 | |||
| 21 | Fixes CVE-2025-58436 | ||
| 22 | |||
| 23 | CVE: CVE-2025-58436 | ||
| 24 | Upstream-Status: Backport [https://github.com/OpenPrinting/cups/commit/5d414f1f91bdca118413301b148f0b188eb1cdc6] | ||
| 25 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 26 | --- | ||
| 27 | cups/http-private.h | 7 +- | ||
| 28 | cups/http.c | 80 +++++++++++++------- | ||
| 29 | cups/tls-openssl.c | 15 +++- | ||
| 30 | scheduler/client.c | 178 ++++++++++++++++++++++++++++---------------- | ||
| 31 | scheduler/client.h | 3 + | ||
| 32 | scheduler/select.c | 12 +++ | ||
| 33 | 6 files changed, 198 insertions(+), 97 deletions(-) | ||
| 34 | |||
| 35 | diff --git a/cups/http-private.h b/cups/http-private.h | ||
| 36 | index d9854faed..2d9035032 100644 | ||
| 37 | --- a/cups/http-private.h | ||
| 38 | +++ b/cups/http-private.h | ||
| 39 | @@ -120,6 +120,7 @@ extern "C" { | ||
| 40 | * Constants... | ||
| 41 | */ | ||
| 42 | |||
| 43 | +# define _HTTP_MAX_BUFFER 32768 /* Size of read buffer */ | ||
| 44 | # define _HTTP_MAX_SBUFFER 65536 /* Size of (de)compression buffer */ | ||
| 45 | # define _HTTP_RESOLVE_DEFAULT 0 /* Just resolve with default options */ | ||
| 46 | # define _HTTP_RESOLVE_STDERR 1 /* Log resolve progress to stderr */ | ||
| 47 | @@ -231,8 +232,8 @@ struct _http_s /**** HTTP connection structure ****/ | ||
| 48 | http_encoding_t data_encoding; /* Chunked or not */ | ||
| 49 | int _data_remaining;/* Number of bytes left (deprecated) */ | ||
| 50 | int used; /* Number of bytes used in buffer */ | ||
| 51 | - char buffer[HTTP_MAX_BUFFER]; | ||
| 52 | - /* Buffer for incoming data */ | ||
| 53 | + char _buffer[HTTP_MAX_BUFFER]; | ||
| 54 | + /* Old read buffer (deprecated) */ | ||
| 55 | int _auth_type; /* Authentication in use (deprecated) */ | ||
| 56 | unsigned char _md5_state[88]; /* MD5 state (deprecated) */ | ||
| 57 | char nonce[HTTP_MAX_VALUE]; | ||
| 58 | @@ -306,6 +307,8 @@ struct _http_s /**** HTTP connection structure ****/ | ||
| 59 | /* Allocated field values */ | ||
| 60 | *default_fields[HTTP_FIELD_MAX]; | ||
| 61 | /* Default field values, if any */ | ||
| 62 | + char buffer[_HTTP_MAX_BUFFER]; | ||
| 63 | + /* Read buffer */ | ||
| 64 | }; | ||
| 65 | # endif /* !_HTTP_NO_PRIVATE */ | ||
| 66 | |||
| 67 | diff --git a/cups/http.c b/cups/http.c | ||
| 68 | index 7a42cb3d6..214e45158 100644 | ||
| 69 | --- a/cups/http.c | ||
| 70 | +++ b/cups/http.c | ||
| 71 | @@ -53,7 +53,7 @@ static http_t *http_create(const char *host, int port, | ||
| 72 | static void http_debug_hex(const char *prefix, const char *buffer, | ||
| 73 | int bytes); | ||
| 74 | #endif /* DEBUG */ | ||
| 75 | -static ssize_t http_read(http_t *http, char *buffer, size_t length); | ||
| 76 | +static ssize_t http_read(http_t *http, char *buffer, size_t length, int timeout); | ||
| 77 | static ssize_t http_read_buffered(http_t *http, char *buffer, size_t length); | ||
| 78 | static ssize_t http_read_chunk(http_t *http, char *buffer, size_t length); | ||
| 79 | static int http_send(http_t *http, http_state_t request, | ||
| 80 | @@ -1188,7 +1188,7 @@ httpGets(char *line, /* I - Line to read into */ | ||
| 81 | return (NULL); | ||
| 82 | } | ||
| 83 | |||
| 84 | - bytes = http_read(http, http->buffer + http->used, (size_t)(HTTP_MAX_BUFFER - http->used)); | ||
| 85 | + bytes = http_read(http, http->buffer + http->used, (size_t)(_HTTP_MAX_BUFFER - http->used), http->wait_value); | ||
| 86 | |||
| 87 | DEBUG_printf(("4httpGets: read " CUPS_LLFMT " bytes.", CUPS_LLCAST bytes)); | ||
| 88 | |||
| 89 | @@ -1706,24 +1706,13 @@ httpPeek(http_t *http, /* I - HTTP connection */ | ||
| 90 | |||
| 91 | ssize_t buflen; /* Length of read for buffer */ | ||
| 92 | |||
| 93 | - if (!http->blocking) | ||
| 94 | - { | ||
| 95 | - while (!httpWait(http, http->wait_value)) | ||
| 96 | - { | ||
| 97 | - if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) | ||
| 98 | - continue; | ||
| 99 | - | ||
| 100 | - return (0); | ||
| 101 | - } | ||
| 102 | - } | ||
| 103 | - | ||
| 104 | if ((size_t)http->data_remaining > sizeof(http->buffer)) | ||
| 105 | buflen = sizeof(http->buffer); | ||
| 106 | else | ||
| 107 | buflen = (ssize_t)http->data_remaining; | ||
| 108 | |||
| 109 | DEBUG_printf(("2httpPeek: Reading %d bytes into buffer.", (int)buflen)); | ||
| 110 | - bytes = http_read(http, http->buffer, (size_t)buflen); | ||
| 111 | + bytes = http_read(http, http->buffer, (size_t)buflen, http->wait_value); | ||
| 112 | |||
| 113 | DEBUG_printf(("2httpPeek: Read " CUPS_LLFMT " bytes into buffer.", | ||
| 114 | CUPS_LLCAST bytes)); | ||
| 115 | @@ -1744,9 +1733,9 @@ httpPeek(http_t *http, /* I - HTTP connection */ | ||
| 116 | int zerr; /* Decompressor error */ | ||
| 117 | z_stream stream; /* Copy of decompressor stream */ | ||
| 118 | |||
| 119 | - if (http->used > 0 && ((z_stream *)http->stream)->avail_in < HTTP_MAX_BUFFER) | ||
| 120 | + if (http->used > 0 && ((z_stream *)http->stream)->avail_in < _HTTP_MAX_BUFFER) | ||
| 121 | { | ||
| 122 | - size_t buflen = HTTP_MAX_BUFFER - ((z_stream *)http->stream)->avail_in; | ||
| 123 | + size_t buflen = _HTTP_MAX_BUFFER - ((z_stream *)http->stream)->avail_in; | ||
| 124 | /* Number of bytes to copy */ | ||
| 125 | |||
| 126 | if (((z_stream *)http->stream)->avail_in > 0 && | ||
| 127 | @@ -2004,7 +1993,7 @@ httpRead2(http_t *http, /* I - HTTP connection */ | ||
| 128 | |||
| 129 | if (bytes == 0) | ||
| 130 | { | ||
| 131 | - ssize_t buflen = HTTP_MAX_BUFFER - (ssize_t)((z_stream *)http->stream)->avail_in; | ||
| 132 | + ssize_t buflen = _HTTP_MAX_BUFFER - (ssize_t)((z_stream *)http->stream)->avail_in; | ||
| 133 | /* Additional bytes for buffer */ | ||
| 134 | |||
| 135 | if (buflen > 0) | ||
| 136 | @@ -2754,7 +2743,7 @@ int /* O - 1 to continue, 0 to stop */ | ||
| 137 | _httpUpdate(http_t *http, /* I - HTTP connection */ | ||
| 138 | http_status_t *status) /* O - Current HTTP status */ | ||
| 139 | { | ||
| 140 | - char line[32768], /* Line from connection... */ | ||
| 141 | + char line[_HTTP_MAX_BUFFER], /* Line from connection... */ | ||
| 142 | *value; /* Pointer to value on line */ | ||
| 143 | http_field_t field; /* Field index */ | ||
| 144 | int major, minor; /* HTTP version numbers */ | ||
| 145 | @@ -2762,12 +2751,46 @@ _httpUpdate(http_t *http, /* I - HTTP connection */ | ||
| 146 | |||
| 147 | DEBUG_printf(("_httpUpdate(http=%p, status=%p), state=%s", (void *)http, (void *)status, httpStateString(http->state))); | ||
| 148 | |||
| 149 | + /* When doing non-blocking I/O, make sure we have a whole line... */ | ||
| 150 | + if (!http->blocking) | ||
| 151 | + { | ||
| 152 | + ssize_t bytes; /* Bytes "peeked" from connection */ | ||
| 153 | + | ||
| 154 | + /* See whether our read buffer is full... */ | ||
| 155 | + DEBUG_printf(("2_httpUpdate: used=%d", http->used)); | ||
| 156 | + | ||
| 157 | + if (http->used > 0 && !memchr(http->buffer, '\n', (size_t)http->used) && (size_t)http->used < sizeof(http->buffer)) | ||
| 158 | + { | ||
| 159 | + /* No, try filling in more data... */ | ||
| 160 | + if ((bytes = http_read(http, http->buffer + http->used, sizeof(http->buffer) - (size_t)http->used, /*timeout*/0)) > 0) | ||
| 161 | + { | ||
| 162 | + DEBUG_printf(("2_httpUpdate: Read %d bytes.", (int)bytes)); | ||
| 163 | + http->used += (int)bytes; | ||
| 164 | + } | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + /* Peek at the incoming data... */ | ||
| 168 | + if (!http->used || !memchr(http->buffer, '\n', (size_t)http->used)) | ||
| 169 | + { | ||
| 170 | + /* Don't have a full line, tell the reader to try again when there is more data... */ | ||
| 171 | + DEBUG_puts("1_htttpUpdate: No newline in buffer yet."); | ||
| 172 | + if ((size_t)http->used == sizeof(http->buffer)) | ||
| 173 | + *status = HTTP_STATUS_ERROR; | ||
| 174 | + else | ||
| 175 | + *status = HTTP_STATUS_CONTINUE; | ||
| 176 | + return (0); | ||
| 177 | + } | ||
| 178 | + | ||
| 179 | + DEBUG_puts("2_httpUpdate: Found newline in buffer."); | ||
| 180 | + } | ||
| 181 | + | ||
| 182 | /* | ||
| 183 | * Grab a single line from the connection... | ||
| 184 | */ | ||
| 185 | |||
| 186 | if (!httpGets(line, sizeof(line), http)) | ||
| 187 | { | ||
| 188 | + DEBUG_puts("1_httpUpdate: Error reading request line."); | ||
| 189 | *status = HTTP_STATUS_ERROR; | ||
| 190 | return (0); | ||
| 191 | } | ||
| 192 | @@ -4089,7 +4112,8 @@ http_debug_hex(const char *prefix, /* I - Prefix for line */ | ||
| 193 | static ssize_t /* O - Number of bytes read or -1 on error */ | ||
| 194 | http_read(http_t *http, /* I - HTTP connection */ | ||
| 195 | char *buffer, /* I - Buffer */ | ||
| 196 | - size_t length) /* I - Maximum bytes to read */ | ||
| 197 | + size_t length, /* I - Maximum bytes to read */ | ||
| 198 | + int timeout) /* I - Wait timeout */ | ||
| 199 | { | ||
| 200 | ssize_t bytes; /* Bytes read */ | ||
| 201 | |||
| 202 | @@ -4098,7 +4122,7 @@ http_read(http_t *http, /* I - HTTP connection */ | ||
| 203 | |||
| 204 | if (!http->blocking || http->timeout_value > 0.0) | ||
| 205 | { | ||
| 206 | - while (!httpWait(http, http->wait_value)) | ||
| 207 | + while (!_httpWait(http, timeout, 1)) | ||
| 208 | { | ||
| 209 | if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) | ||
| 210 | continue; | ||
| 211 | @@ -4201,7 +4225,7 @@ http_read_buffered(http_t *http, /* I - HTTP connection */ | ||
| 212 | else | ||
| 213 | bytes = (ssize_t)length; | ||
| 214 | |||
| 215 | - DEBUG_printf(("8http_read: Grabbing %d bytes from input buffer.", | ||
| 216 | + DEBUG_printf(("8http_read_buffered: Grabbing %d bytes from input buffer.", | ||
| 217 | (int)bytes)); | ||
| 218 | |||
| 219 | memcpy(buffer, http->buffer, (size_t)bytes); | ||
| 220 | @@ -4211,7 +4235,7 @@ http_read_buffered(http_t *http, /* I - HTTP connection */ | ||
| 221 | memmove(http->buffer, http->buffer + bytes, (size_t)http->used); | ||
| 222 | } | ||
| 223 | else | ||
| 224 | - bytes = http_read(http, buffer, length); | ||
| 225 | + bytes = http_read(http, buffer, length, http->wait_value); | ||
| 226 | |||
| 227 | return (bytes); | ||
| 228 | } | ||
| 229 | @@ -4557,15 +4581,15 @@ http_set_timeout(int fd, /* I - File descriptor */ | ||
| 230 | static void | ||
| 231 | http_set_wait(http_t *http) /* I - HTTP connection */ | ||
| 232 | { | ||
| 233 | - if (http->blocking) | ||
| 234 | - { | ||
| 235 | - http->wait_value = (int)(http->timeout_value * 1000); | ||
| 236 | + http->wait_value = (int)(http->timeout_value * 1000); | ||
| 237 | |||
| 238 | - if (http->wait_value <= 0) | ||
| 239 | + if (http->wait_value <= 0) | ||
| 240 | + { | ||
| 241 | + if (http->blocking) | ||
| 242 | http->wait_value = 60000; | ||
| 243 | + else | ||
| 244 | + http->wait_value = 1000; | ||
| 245 | } | ||
| 246 | - else | ||
| 247 | - http->wait_value = 10000; | ||
| 248 | } | ||
| 249 | |||
| 250 | |||
| 251 | diff --git a/cups/tls-openssl.c b/cups/tls-openssl.c | ||
| 252 | index 9fcbe0af3..f746f4cba 100644 | ||
| 253 | --- a/cups/tls-openssl.c | ||
| 254 | +++ b/cups/tls-openssl.c | ||
| 255 | @@ -180,12 +180,14 @@ cupsMakeServerCredentials( | ||
| 256 | // Save them... | ||
| 257 | if ((bio = BIO_new_file(keyfile, "wb")) == NULL) | ||
| 258 | { | ||
| 259 | + DEBUG_printf(("1cupsMakeServerCredentials: Unable to create private key file '%s': %s", keyfile, strerror(errno))); | ||
| 260 | _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); | ||
| 261 | goto done; | ||
| 262 | } | ||
| 263 | |||
| 264 | if (!PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL)) | ||
| 265 | { | ||
| 266 | + DEBUG_puts("1cupsMakeServerCredentials: PEM_write_bio_PrivateKey failed."); | ||
| 267 | _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to write private key."), 1); | ||
| 268 | BIO_free(bio); | ||
| 269 | goto done; | ||
| 270 | @@ -195,12 +197,14 @@ cupsMakeServerCredentials( | ||
| 271 | |||
| 272 | if ((bio = BIO_new_file(crtfile, "wb")) == NULL) | ||
| 273 | { | ||
| 274 | + DEBUG_printf(("1cupsMakeServerCredentials: Unable to create certificate file '%s': %s", crtfile, strerror(errno))); | ||
| 275 | _cupsSetError(IPP_STATUS_ERROR_INTERNAL, strerror(errno), 0); | ||
| 276 | goto done; | ||
| 277 | } | ||
| 278 | |||
| 279 | if (!PEM_write_bio_X509(bio, cert)) | ||
| 280 | { | ||
| 281 | + DEBUG_puts("1cupsMakeServerCredentials: PEM_write_bio_X509 failed."); | ||
| 282 | _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to write X.509 certificate."), 1); | ||
| 283 | BIO_free(bio); | ||
| 284 | goto done; | ||
| 285 | @@ -1044,10 +1048,10 @@ _httpTLSStart(http_t *http) // I - Connection to server | ||
| 286 | |||
| 287 | if (!cupsMakeServerCredentials(tls_keypath, cn, 0, NULL, time(NULL) + 365 * 86400)) | ||
| 288 | { | ||
| 289 | - DEBUG_puts("4_httpTLSStart: cupsMakeServerCredentials failed."); | ||
| 290 | + DEBUG_printf(("4_httpTLSStart: cupsMakeServerCredentials failed: %s", cupsLastErrorString())); | ||
| 291 | http->error = errno = EINVAL; | ||
| 292 | http->status = HTTP_STATUS_ERROR; | ||
| 293 | - _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create server credentials."), 1); | ||
| 294 | +// _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to create server credentials."), 1); | ||
| 295 | SSL_CTX_free(context); | ||
| 296 | |||
| 297 | return (-1); | ||
| 298 | @@ -1272,14 +1276,17 @@ http_bio_read(BIO *h, // I - BIO data | ||
| 299 | |||
| 300 | http = (http_t *)BIO_get_data(h); | ||
| 301 | |||
| 302 | - if (!http->blocking) | ||
| 303 | + if (!http->blocking || http->timeout_value > 0.0) | ||
| 304 | { | ||
| 305 | /* | ||
| 306 | * Make sure we have data before we read... | ||
| 307 | */ | ||
| 308 | |||
| 309 | - if (!_httpWait(http, 10000, 0)) | ||
| 310 | + while (!_httpWait(http, http->wait_value, 0)) | ||
| 311 | { | ||
| 312 | + if (http->timeout_cb && (*http->timeout_cb)(http, http->timeout_data)) | ||
| 313 | + continue; | ||
| 314 | + | ||
| 315 | #ifdef WIN32 | ||
| 316 | http->error = WSAETIMEDOUT; | ||
| 317 | #else | ||
| 318 | diff --git a/scheduler/client.c b/scheduler/client.c | ||
| 319 | index f0349a6c9..9593c9138 100644 | ||
| 320 | --- a/scheduler/client.c | ||
| 321 | +++ b/scheduler/client.c | ||
| 322 | @@ -34,11 +34,11 @@ | ||
| 323 | |||
| 324 | static int check_if_modified(cupsd_client_t *con, | ||
| 325 | struct stat *filestats); | ||
| 326 | +#ifdef HAVE_TLS | ||
| 327 | +static int check_start_tls(cupsd_client_t *con); | ||
| 328 | +#endif /* HAVE_TLS */ | ||
| 329 | static int compare_clients(cupsd_client_t *a, cupsd_client_t *b, | ||
| 330 | void *data); | ||
| 331 | -#ifdef HAVE_TLS | ||
| 332 | -static int cupsd_start_tls(cupsd_client_t *con, http_encryption_t e); | ||
| 333 | -#endif /* HAVE_TLS */ | ||
| 334 | static char *get_file(cupsd_client_t *con, struct stat *filestats, | ||
| 335 | char *filename, size_t len); | ||
| 336 | static http_status_t install_cupsd_conf(cupsd_client_t *con); | ||
| 337 | @@ -360,14 +360,20 @@ cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ | ||
| 338 | if (lis->encryption == HTTP_ENCRYPTION_ALWAYS) | ||
| 339 | { | ||
| 340 | /* | ||
| 341 | - * https connection; go secure... | ||
| 342 | + * HTTPS connection, force TLS negotiation... | ||
| 343 | */ | ||
| 344 | |||
| 345 | - if (cupsd_start_tls(con, HTTP_ENCRYPTION_ALWAYS)) | ||
| 346 | - cupsdCloseClient(con); | ||
| 347 | + con->tls_start = time(NULL); | ||
| 348 | + con->encryption = HTTP_ENCRYPTION_ALWAYS; | ||
| 349 | } | ||
| 350 | else | ||
| 351 | + { | ||
| 352 | + /* | ||
| 353 | + * HTTP connection, but check for HTTPS negotiation on first data... | ||
| 354 | + */ | ||
| 355 | + | ||
| 356 | con->auto_ssl = 1; | ||
| 357 | + } | ||
| 358 | #endif /* HAVE_TLS */ | ||
| 359 | } | ||
| 360 | |||
| 361 | @@ -597,17 +603,46 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ | ||
| 362 | |||
| 363 | con->auto_ssl = 0; | ||
| 364 | |||
| 365 | - if (recv(httpGetFd(con->http), buf, 1, MSG_PEEK) == 1 && | ||
| 366 | - (!buf[0] || !strchr("DGHOPT", buf[0]))) | ||
| 367 | + if (recv(httpGetFd(con->http), buf, 5, MSG_PEEK) == 5 && buf[0] == 0x16 && buf[1] == 3 && buf[2]) | ||
| 368 | { | ||
| 369 | /* | ||
| 370 | - * Encrypt this connection... | ||
| 371 | + * Client hello record, encrypt this connection... | ||
| 372 | */ | ||
| 373 | |||
| 374 | - cupsdLogClient(con, CUPSD_LOG_DEBUG2, "Saw first byte %02X, auto-negotiating SSL/TLS session.", buf[0] & 255); | ||
| 375 | + cupsdLogClient(con, CUPSD_LOG_DEBUG2, "Saw client hello record, auto-negotiating TLS session."); | ||
| 376 | + con->tls_start = time(NULL); | ||
| 377 | + con->encryption = HTTP_ENCRYPTION_ALWAYS; | ||
| 378 | + } | ||
| 379 | + } | ||
| 380 | |||
| 381 | - if (cupsd_start_tls(con, HTTP_ENCRYPTION_ALWAYS)) | ||
| 382 | - cupsdCloseClient(con); | ||
| 383 | + if (con->tls_start) | ||
| 384 | + { | ||
| 385 | + /* | ||
| 386 | + * Try negotiating TLS... | ||
| 387 | + */ | ||
| 388 | + | ||
| 389 | + int tls_status = check_start_tls(con); | ||
| 390 | + | ||
| 391 | + if (tls_status < 0) | ||
| 392 | + { | ||
| 393 | + /* | ||
| 394 | + * TLS negotiation failed, close the connection. | ||
| 395 | + */ | ||
| 396 | + | ||
| 397 | + cupsdCloseClient(con); | ||
| 398 | + return; | ||
| 399 | + } | ||
| 400 | + else if (tls_status == 0) | ||
| 401 | + { | ||
| 402 | + /* | ||
| 403 | + * Nothing to do yet... | ||
| 404 | + */ | ||
| 405 | + | ||
| 406 | + if ((time(NULL) - con->tls_start) > 5) | ||
| 407 | + { | ||
| 408 | + // Timeout, close the connection... | ||
| 409 | + cupsdCloseClient(con); | ||
| 410 | + } | ||
| 411 | |||
| 412 | return; | ||
| 413 | } | ||
| 414 | @@ -771,9 +806,7 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ | ||
| 415 | * Parse incoming parameters until the status changes... | ||
| 416 | */ | ||
| 417 | |||
| 418 | - while ((status = httpUpdate(con->http)) == HTTP_STATUS_CONTINUE) | ||
| 419 | - if (!httpGetReady(con->http)) | ||
| 420 | - break; | ||
| 421 | + status = httpUpdate(con->http); | ||
| 422 | |||
| 423 | if (status != HTTP_STATUS_OK && status != HTTP_STATUS_CONTINUE) | ||
| 424 | { | ||
| 425 | @@ -935,11 +968,10 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ | ||
| 426 | return; | ||
| 427 | } | ||
| 428 | |||
| 429 | - if (cupsd_start_tls(con, HTTP_ENCRYPTION_REQUIRED)) | ||
| 430 | - { | ||
| 431 | - cupsdCloseClient(con); | ||
| 432 | - return; | ||
| 433 | - } | ||
| 434 | + con->tls_start = time(NULL); | ||
| 435 | + con->tls_upgrade = 1; | ||
| 436 | + con->encryption = HTTP_ENCRYPTION_REQUIRED; | ||
| 437 | + return; | ||
| 438 | #else | ||
| 439 | if (!cupsdSendError(con, HTTP_STATUS_NOT_IMPLEMENTED, CUPSD_AUTH_NONE)) | ||
| 440 | { | ||
| 441 | @@ -978,32 +1010,11 @@ cupsdReadClient(cupsd_client_t *con) /* I - Client to read from */ | ||
| 442 | if (!_cups_strcasecmp(httpGetField(con->http, HTTP_FIELD_CONNECTION), | ||
| 443 | "Upgrade") && !httpIsEncrypted(con->http)) | ||
| 444 | { | ||
| 445 | -#ifdef HAVE_TLS | ||
| 446 | - /* | ||
| 447 | - * Do encryption stuff... | ||
| 448 | - */ | ||
| 449 | - | ||
| 450 | - httpClearFields(con->http); | ||
| 451 | - | ||
| 452 | - if (!cupsdSendHeader(con, HTTP_STATUS_SWITCHING_PROTOCOLS, NULL, | ||
| 453 | - CUPSD_AUTH_NONE)) | ||
| 454 | - { | ||
| 455 | - cupsdCloseClient(con); | ||
| 456 | - return; | ||
| 457 | - } | ||
| 458 | - | ||
| 459 | - if (cupsd_start_tls(con, HTTP_ENCRYPTION_REQUIRED)) | ||
| 460 | - { | ||
| 461 | - cupsdCloseClient(con); | ||
| 462 | - return; | ||
| 463 | - } | ||
| 464 | -#else | ||
| 465 | if (!cupsdSendError(con, HTTP_STATUS_NOT_IMPLEMENTED, CUPSD_AUTH_NONE)) | ||
| 466 | { | ||
| 467 | cupsdCloseClient(con); | ||
| 468 | return; | ||
| 469 | } | ||
| 470 | -#endif /* HAVE_TLS */ | ||
| 471 | } | ||
| 472 | |||
| 473 | if ((status = cupsdIsAuthorized(con, NULL)) != HTTP_STATUS_OK) | ||
| 474 | @@ -2631,6 +2642,69 @@ check_if_modified( | ||
| 475 | } | ||
| 476 | |||
| 477 | |||
| 478 | +#ifdef HAVE_TLS | ||
| 479 | +/* | ||
| 480 | + * 'check_start_tls()' - Start encryption on a connection. | ||
| 481 | + */ | ||
| 482 | + | ||
| 483 | +static int /* O - 0 to continue, 1 on success, -1 on error */ | ||
| 484 | +check_start_tls(cupsd_client_t *con) /* I - Client connection */ | ||
| 485 | +{ | ||
| 486 | + unsigned char chello[4096]; /* Client hello record */ | ||
| 487 | + ssize_t chello_bytes; /* Bytes read/peeked */ | ||
| 488 | + int chello_len; /* Length of record */ | ||
| 489 | + | ||
| 490 | + | ||
| 491 | + /* | ||
| 492 | + * See if we have a good and complete client hello record... | ||
| 493 | + */ | ||
| 494 | + | ||
| 495 | + if ((chello_bytes = recv(httpGetFd(con->http), (char *)chello, sizeof(chello), MSG_PEEK)) < 5) | ||
| 496 | + return (0); /* Not enough bytes (yet) */ | ||
| 497 | + | ||
| 498 | + if (chello[0] != 0x016 || chello[1] != 3 || chello[2] == 0) | ||
| 499 | + return (-1); /* Not a TLS Client Hello record */ | ||
| 500 | + | ||
| 501 | + chello_len = (chello[3] << 8) | chello[4]; | ||
| 502 | + | ||
| 503 | + if ((chello_len + 5) > chello_bytes) | ||
| 504 | + return (0); /* Not enough bytes yet */ | ||
| 505 | + | ||
| 506 | + /* | ||
| 507 | + * OK, we do, try negotiating... | ||
| 508 | + */ | ||
| 509 | + | ||
| 510 | + con->tls_start = 0; | ||
| 511 | + | ||
| 512 | + if (httpEncryption(con->http, con->encryption)) | ||
| 513 | + { | ||
| 514 | + cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to encrypt connection: %s", cupsLastErrorString()); | ||
| 515 | + return (-1); | ||
| 516 | + } | ||
| 517 | + | ||
| 518 | + cupsdLogClient(con, CUPSD_LOG_DEBUG, "Connection now encrypted."); | ||
| 519 | + | ||
| 520 | + if (con->tls_upgrade) | ||
| 521 | + { | ||
| 522 | + // Respond to the original OPTIONS command... | ||
| 523 | + con->tls_upgrade = 0; | ||
| 524 | + | ||
| 525 | + httpClearFields(con->http); | ||
| 526 | + httpClearCookie(con->http); | ||
| 527 | + httpSetField(con->http, HTTP_FIELD_CONTENT_LENGTH, "0"); | ||
| 528 | + | ||
| 529 | + if (!cupsdSendHeader(con, HTTP_STATUS_OK, NULL, CUPSD_AUTH_NONE)) | ||
| 530 | + { | ||
| 531 | + cupsdCloseClient(con); | ||
| 532 | + return (-1); | ||
| 533 | + } | ||
| 534 | + } | ||
| 535 | + | ||
| 536 | + return (1); | ||
| 537 | +} | ||
| 538 | +#endif /* HAVE_TLS */ | ||
| 539 | + | ||
| 540 | + | ||
| 541 | /* | ||
| 542 | * 'compare_clients()' - Compare two client connections. | ||
| 543 | */ | ||
| 544 | @@ -2651,28 +2725,6 @@ compare_clients(cupsd_client_t *a, /* I - First client */ | ||
| 545 | } | ||
| 546 | |||
| 547 | |||
| 548 | -#ifdef HAVE_TLS | ||
| 549 | -/* | ||
| 550 | - * 'cupsd_start_tls()' - Start encryption on a connection. | ||
| 551 | - */ | ||
| 552 | - | ||
| 553 | -static int /* O - 0 on success, -1 on error */ | ||
| 554 | -cupsd_start_tls(cupsd_client_t *con, /* I - Client connection */ | ||
| 555 | - http_encryption_t e) /* I - Encryption mode */ | ||
| 556 | -{ | ||
| 557 | - if (httpEncryption(con->http, e)) | ||
| 558 | - { | ||
| 559 | - cupsdLogClient(con, CUPSD_LOG_ERROR, "Unable to encrypt connection: %s", | ||
| 560 | - cupsLastErrorString()); | ||
| 561 | - return (-1); | ||
| 562 | - } | ||
| 563 | - | ||
| 564 | - cupsdLogClient(con, CUPSD_LOG_DEBUG, "Connection now encrypted."); | ||
| 565 | - return (0); | ||
| 566 | -} | ||
| 567 | -#endif /* HAVE_TLS */ | ||
| 568 | - | ||
| 569 | - | ||
| 570 | /* | ||
| 571 | * 'get_file()' - Get a filename and state info. | ||
| 572 | */ | ||
| 573 | diff --git a/scheduler/client.h b/scheduler/client.h | ||
| 574 | index 9fe4e2ea6..2939ce997 100644 | ||
| 575 | --- a/scheduler/client.h | ||
| 576 | +++ b/scheduler/client.h | ||
| 577 | @@ -51,6 +51,9 @@ struct cupsd_client_s | ||
| 578 | cups_lang_t *language; /* Language to use */ | ||
| 579 | #ifdef HAVE_TLS | ||
| 580 | int auto_ssl; /* Automatic test for SSL/TLS */ | ||
| 581 | + time_t tls_start; /* Do TLS negotiation? */ | ||
| 582 | + int tls_upgrade; /* Doing TLS upgrade via OPTIONS? */ | ||
| 583 | + http_encryption_t encryption; /* Type of TLS negotiation */ | ||
| 584 | #endif /* HAVE_TLS */ | ||
| 585 | http_addr_t clientaddr; /* Client's server address */ | ||
| 586 | char clientname[256];/* Client's server name for connection */ | ||
| 587 | diff --git a/scheduler/select.c b/scheduler/select.c | ||
| 588 | index 2e64f2a7e..ac6205c51 100644 | ||
| 589 | --- a/scheduler/select.c | ||
| 590 | +++ b/scheduler/select.c | ||
| 591 | @@ -408,6 +408,9 @@ cupsdDoSelect(long timeout) /* I - Timeout in seconds */ | ||
| 592 | |||
| 593 | cupsd_in_select = 1; | ||
| 594 | |||
| 595 | + // Prevent 100% CPU by releasing control before the kevent call... | ||
| 596 | + usleep(1); | ||
| 597 | + | ||
| 598 | if (timeout >= 0 && timeout < 86400) | ||
| 599 | { | ||
| 600 | ktimeout.tv_sec = timeout; | ||
| 601 | @@ -454,6 +457,9 @@ cupsdDoSelect(long timeout) /* I - Timeout in seconds */ | ||
| 602 | struct epoll_event *event; /* Current event */ | ||
| 603 | |||
| 604 | |||
| 605 | + // Prevent 100% CPU by releasing control before the epoll_wait call... | ||
| 606 | + usleep(1); | ||
| 607 | + | ||
| 608 | if (timeout >= 0 && timeout < 86400) | ||
| 609 | nfds = epoll_wait(cupsd_epoll_fd, cupsd_epoll_events, MaxFDs, | ||
| 610 | timeout * 1000); | ||
| 611 | @@ -546,6 +552,9 @@ cupsdDoSelect(long timeout) /* I - Timeout in seconds */ | ||
| 612 | } | ||
| 613 | } | ||
| 614 | |||
| 615 | + // Prevent 100% CPU by releasing control before the poll call... | ||
| 616 | + usleep(1); | ||
| 617 | + | ||
| 618 | if (timeout >= 0 && timeout < 86400) | ||
| 619 | nfds = poll(cupsd_pollfds, (nfds_t)count, timeout * 1000); | ||
| 620 | else | ||
| 621 | @@ -599,6 +608,9 @@ cupsdDoSelect(long timeout) /* I - Timeout in seconds */ | ||
| 622 | cupsd_current_input = cupsd_global_input; | ||
| 623 | cupsd_current_output = cupsd_global_output; | ||
| 624 | |||
| 625 | + // Prevent 100% CPU by releasing control before the select call... | ||
| 626 | + usleep(1); | ||
| 627 | + | ||
| 628 | if (timeout >= 0 && timeout < 86400) | ||
| 629 | { | ||
| 630 | stimeout.tv_sec = timeout; | ||
diff --git a/meta/recipes-extended/cups/cups/CVE-2025-61915.patch b/meta/recipes-extended/cups/cups/CVE-2025-61915.patch new file mode 100644 index 0000000000..bdab24e028 --- /dev/null +++ b/meta/recipes-extended/cups/cups/CVE-2025-61915.patch | |||
| @@ -0,0 +1,487 @@ | |||
| 1 | From db8d560262c22a21ee1e55dfd62fa98d9359bcb0 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Zdenek Dohnal <zdohnal@redhat.com> | ||
| 3 | Date: Fri, 21 Nov 2025 07:36:36 +0100 | ||
| 4 | Subject: [PATCH] Fix various issues in cupsd | ||
| 5 | |||
| 6 | Various issues were found by @SilverPlate3, recognized as CVE-2025-61915: | ||
| 7 | |||
| 8 | - out of bound write when handling IPv6 addresses, | ||
| 9 | - cupsd crash caused by null dereference when ErrorPolicy value is empty, | ||
| 10 | |||
| 11 | On the top of that, Mike Sweet noticed vulnerability via domain socket, | ||
| 12 | exploitable locally if attacker has access to domain socket and knows username | ||
| 13 | of user within a group which is present in CUPS system groups: | ||
| 14 | |||
| 15 | - rewrite of cupsd.conf via PeerCred authorization via domain socket | ||
| 16 | |||
| 17 | The last vulnerability is fixed by introducing PeerCred directive for cups-files.conf, | ||
| 18 | which controls whether PeerCred is enabled/disabled for user in CUPS system groups. | ||
| 19 | |||
| 20 | Fixes CVE-2025-61915 | ||
| 21 | |||
| 22 | CVE: CVE-2025-61915 | ||
| 23 | Upstream-Status: Backport [https://github.com/OpenPrinting/cups/commit/db8d560262c22a21ee1e55dfd62fa98d9359bcb0] | ||
| 24 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 25 | --- | ||
| 26 | conf/cups-files.conf.in | 3 ++ | ||
| 27 | config-scripts/cups-defaults.m4 | 9 +++++ | ||
| 28 | config.h.in | 7 ++++ | ||
| 29 | configure | 22 ++++++++++ | ||
| 30 | doc/help/man-cups-files.conf.html | 9 ++++- | ||
| 31 | man/cups-files.conf.5 | 17 ++++++-- | ||
| 32 | scheduler/auth.c | 8 +++- | ||
| 33 | scheduler/auth.h | 7 ++++ | ||
| 34 | scheduler/client.c | 2 +- | ||
| 35 | scheduler/conf.c | 60 ++++++++++++++++++++++++---- | ||
| 36 | test/run-stp-tests.sh | 2 +- | ||
| 37 | vcnet/config.h | 7 ++++ | ||
| 38 | xcode/CUPS.xcodeproj/project.pbxproj | 2 - | ||
| 39 | xcode/config.h | 7 ++++ | ||
| 40 | 14 files changed, 145 insertions(+), 17 deletions(-) | ||
| 41 | |||
| 42 | diff --git a/conf/cups-files.conf.in b/conf/cups-files.conf.in | ||
| 43 | index f96f745ae..6db139297 100644 | ||
| 44 | --- a/conf/cups-files.conf.in | ||
| 45 | +++ b/conf/cups-files.conf.in | ||
| 46 | @@ -19,6 +19,9 @@ | ||
| 47 | SystemGroup @CUPS_SYSTEM_GROUPS@ | ||
| 48 | @CUPS_SYSTEM_AUTHKEY@ | ||
| 49 | |||
| 50 | +# Are Unix domain socket peer credentials used for authorization? | ||
| 51 | +PeerCred @CUPS_PEER_CRED@ | ||
| 52 | + | ||
| 53 | # User that is substituted for unauthenticated (remote) root accesses... | ||
| 54 | #RemoteRoot remroot | ||
| 55 | |||
| 56 | diff --git a/config-scripts/cups-defaults.m4 b/config-scripts/cups-defaults.m4 | ||
| 57 | index 999a8849d..fc9ba4a02 100644 | ||
| 58 | --- a/config-scripts/cups-defaults.m4 | ||
| 59 | +++ b/config-scripts/cups-defaults.m4 | ||
| 60 | @@ -129,6 +129,15 @@ AC_ARG_WITH([log_level], AS_HELP_STRING([--with-log-level], [set default LogLeve | ||
| 61 | AC_SUBST([CUPS_LOG_LEVEL]) | ||
| 62 | AC_DEFINE_UNQUOTED([CUPS_DEFAULT_LOG_LEVEL], ["$CUPS_LOG_LEVEL"], [Default LogLevel value.]) | ||
| 63 | |||
| 64 | +dnl Default PeerCred | ||
| 65 | +AC_ARG_WITH([peer_cred], AS_HELP_STRING([--with-peer-cred], [set default PeerCred value (on/off/root-only), default=on]), [ | ||
| 66 | + CUPS_PEER_CRED="$withval" | ||
| 67 | +], [ | ||
| 68 | + CUPS_PEER_CRED="on" | ||
| 69 | +]) | ||
| 70 | +AC_SUBST([CUPS_PEER_CRED]) | ||
| 71 | +AC_DEFINE_UNQUOTED([CUPS_DEFAULT_PEER_CRED], ["$CUPS_PEER_CRED"], [Default PeerCred value.]) | ||
| 72 | + | ||
| 73 | dnl Default AccessLogLevel | ||
| 74 | AC_ARG_WITH(access_log_level, [ --with-access-log-level set default AccessLogLevel value, default=none], | ||
| 75 | CUPS_ACCESS_LOG_LEVEL="$withval", | ||
| 76 | diff --git a/config.h.in b/config.h.in | ||
| 77 | index 207df66a7..37c279088 100644 | ||
| 78 | --- a/config.h.in | ||
| 79 | +++ b/config.h.in | ||
| 80 | @@ -86,6 +86,13 @@ | ||
| 81 | #define CUPS_DEFAULT_ERROR_POLICY "stop-printer" | ||
| 82 | |||
| 83 | |||
| 84 | +/* | ||
| 85 | + * Default PeerCred value... | ||
| 86 | + */ | ||
| 87 | + | ||
| 88 | +#define CUPS_DEFAULT_PEER_CRED "on" | ||
| 89 | + | ||
| 90 | + | ||
| 91 | /* | ||
| 92 | * Default MaxCopies value... | ||
| 93 | */ | ||
| 94 | diff --git a/configure b/configure | ||
| 95 | index a38ebded9..1721634ba 100755 | ||
| 96 | --- a/configure | ||
| 97 | +++ b/configure | ||
| 98 | @@ -672,6 +672,7 @@ CUPS_BROWSING | ||
| 99 | CUPS_SYNC_ON_CLOSE | ||
| 100 | CUPS_PAGE_LOG_FORMAT | ||
| 101 | CUPS_ACCESS_LOG_LEVEL | ||
| 102 | +CUPS_PEER_CRED | ||
| 103 | CUPS_LOG_LEVEL | ||
| 104 | CUPS_FATAL_ERRORS | ||
| 105 | CUPS_ERROR_POLICY | ||
| 106 | @@ -925,6 +926,7 @@ with_max_log_size | ||
| 107 | with_error_policy | ||
| 108 | with_fatal_errors | ||
| 109 | with_log_level | ||
| 110 | +with_peer_cred | ||
| 111 | with_access_log_level | ||
| 112 | enable_page_logging | ||
| 113 | enable_sync_on_close | ||
| 114 | @@ -1659,6 +1661,8 @@ Optional Packages: | ||
| 115 | --with-error-policy set default ErrorPolicy value, default=stop-printer | ||
| 116 | --with-fatal-errors set default FatalErrors value, default=config | ||
| 117 | --with-log-level set default LogLevel value, default=warn | ||
| 118 | + --with-peer-cred set default PeerCred value (on/off/root-only), | ||
| 119 | + default=on | ||
| 120 | --with-access-log-level set default AccessLogLevel value, default=none | ||
| 121 | --with-local-protocols set default BrowseLocalProtocols, default="" | ||
| 122 | --with-cups-user set default user for CUPS | ||
| 123 | @@ -11652,6 +11656,24 @@ printf "%s\n" "#define CUPS_DEFAULT_LOG_LEVEL \"$CUPS_LOG_LEVEL\"" >>confdefs.h | ||
| 124 | |||
| 125 | |||
| 126 | |||
| 127 | +# Check whether --with-peer_cred was given. | ||
| 128 | +if test ${with_peer_cred+y} | ||
| 129 | +then : | ||
| 130 | + withval=$with_peer_cred; | ||
| 131 | + CUPS_PEER_CRED="$withval" | ||
| 132 | + | ||
| 133 | +else $as_nop | ||
| 134 | + | ||
| 135 | + CUPS_PEER_CRED="on" | ||
| 136 | + | ||
| 137 | +fi | ||
| 138 | + | ||
| 139 | + | ||
| 140 | + | ||
| 141 | +printf "%s\n" "#define CUPS_DEFAULT_PEER_CRED \"$CUPS_PEER_CRED\"" >>confdefs.h | ||
| 142 | + | ||
| 143 | + | ||
| 144 | + | ||
| 145 | # Check whether --with-access_log_level was given. | ||
| 146 | if test ${with_access_log_level+y} | ||
| 147 | then : | ||
| 148 | diff --git a/doc/help/man-cups-files.conf.html b/doc/help/man-cups-files.conf.html | ||
| 149 | index 440f033d5..5a9ddefeb 100644 | ||
| 150 | --- a/doc/help/man-cups-files.conf.html | ||
| 151 | +++ b/doc/help/man-cups-files.conf.html | ||
| 152 | @@ -119,6 +119,13 @@ The default is "/var/log/cups/page_log". | ||
| 153 | <dt><a name="PassEnv"></a><b>PassEnv </b><i>variable </i>[ ... <i>variable </i>] | ||
| 154 | <dd style="margin-left: 5.0em">Passes the specified environment variable(s) to child processes. | ||
| 155 | Note: the standard CUPS filter and backend environment variables cannot be overridden using this directive. | ||
| 156 | +<dt><a name="PeerCred"></a><b>PeerCred off</b> | ||
| 157 | +<dd style="margin-left: 5.0em"><dt><b>PeerCred on</b> | ||
| 158 | +<dd style="margin-left: 5.0em"><dt><b>PeerCred root-only</b> | ||
| 159 | +<dd style="margin-left: 5.0em">Specifies whether peer credentials are used for authorization when communicating over the UNIX domain socket. | ||
| 160 | +When <b>on</b>, the peer credentials of any user are accepted for authorization. | ||
| 161 | +The value <b>off</b> disables the use of peer credentials entirely, while the value <b>root-only</b> allows peer credentials only for the root user. | ||
| 162 | +Note: for security reasons, the <b>on</b> setting is reduced to <b>root-only</b> for authorization of PUT requests. | ||
| 163 | <dt><a name="RemoteRoot"></a><b>RemoteRoot </b><i>username</i> | ||
| 164 | <dd style="margin-left: 5.0em">Specifies the username that is associated with unauthenticated accesses by clients claiming to be the root user. | ||
| 165 | The default is "remroot". | ||
| 166 | @@ -199,7 +206,7 @@ command is used instead. | ||
| 167 | <a href="man-subscriptions.conf.html?TOPIC=Man+Pages"><b>subscriptions.conf</b>(5),</a> | ||
| 168 | CUPS Online Help (<a href="http://localhost:631/help">http://localhost:631/help</a>) | ||
| 169 | <h2 class="title"><a name="COPYRIGHT">Copyright</a></h2> | ||
| 170 | -Copyright © 2020-2022 by OpenPrinting. | ||
| 171 | +Copyright © 2020-2025 by OpenPrinting. | ||
| 172 | |||
| 173 | </body> | ||
| 174 | </html> | ||
| 175 | diff --git a/man/cups-files.conf.5 b/man/cups-files.conf.5 | ||
| 176 | index ec16c9e13..18ce2be00 100644 | ||
| 177 | --- a/man/cups-files.conf.5 | ||
| 178 | +++ b/man/cups-files.conf.5 | ||
| 179 | @@ -1,14 +1,14 @@ | ||
| 180 | .\" | ||
| 181 | .\" cups-files.conf man page for CUPS. | ||
| 182 | .\" | ||
| 183 | -.\" Copyright © 2020-2022 by OpenPrinting. | ||
| 184 | +.\" Copyright © 2020-2025 by OpenPrinting. | ||
| 185 | .\" Copyright © 2007-2019 by Apple Inc. | ||
| 186 | .\" Copyright © 1997-2006 by Easy Software Products. | ||
| 187 | .\" | ||
| 188 | .\" Licensed under Apache License v2.0. See the file "LICENSE" for more | ||
| 189 | .\" information. | ||
| 190 | .\" | ||
| 191 | -.TH cups-files.conf 5 "CUPS" "2021-03-06" "OpenPrinting" | ||
| 192 | +.TH cups-files.conf 5 "CUPS" "2025-10-08" "OpenPrinting" | ||
| 193 | .SH NAME | ||
| 194 | cups\-files.conf \- file and directory configuration file for cups | ||
| 195 | .SH DESCRIPTION | ||
| 196 | @@ -166,6 +166,17 @@ The default is "/var/log/cups/page_log". | ||
| 197 | \fBPassEnv \fIvariable \fR[ ... \fIvariable \fR] | ||
| 198 | Passes the specified environment variable(s) to child processes. | ||
| 199 | Note: the standard CUPS filter and backend environment variables cannot be overridden using this directive. | ||
| 200 | +.\"#PeerCred | ||
| 201 | +.TP 5 | ||
| 202 | +\fBPeerCred off\fR | ||
| 203 | +.TP 5 | ||
| 204 | +\fBPeerCred on\fR | ||
| 205 | +.TP 5 | ||
| 206 | +\fBPeerCred root-only\fR | ||
| 207 | +Specifies whether peer credentials are used for authorization when communicating over the UNIX domain socket. | ||
| 208 | +When \fBon\fR, the peer credentials of any user are accepted for authorization. | ||
| 209 | +The value \fBoff\fR disables the use of peer credentials entirely, while the value \fBroot-only\fR allows peer credentials only for the root user. | ||
| 210 | +Note: for security reasons, the \fBon\fR setting is reduced to \fBroot-only\fR for authorization of PUT requests. | ||
| 211 | .\"#RemoteRoot | ||
| 212 | .TP 5 | ||
| 213 | \fBRemoteRoot \fIusername\fR | ||
| 214 | @@ -278,4 +289,4 @@ command is used instead. | ||
| 215 | .BR subscriptions.conf (5), | ||
| 216 | CUPS Online Help (http://localhost:631/help) | ||
| 217 | .SH COPYRIGHT | ||
| 218 | -Copyright \[co] 2020-2022 by OpenPrinting. | ||
| 219 | +Copyright \[co] 2020-2025 by OpenPrinting. | ||
| 220 | diff --git a/scheduler/auth.c b/scheduler/auth.c | ||
| 221 | index 3c9aa72aa..bd0d28a0e 100644 | ||
| 222 | --- a/scheduler/auth.c | ||
| 223 | +++ b/scheduler/auth.c | ||
| 224 | @@ -398,7 +398,7 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ | ||
| 225 | } | ||
| 226 | #endif /* HAVE_AUTHORIZATION_H */ | ||
| 227 | #if defined(SO_PEERCRED) && defined(AF_LOCAL) | ||
| 228 | - else if (!strncmp(authorization, "PeerCred ", 9) && | ||
| 229 | + else if (PeerCred != CUPSD_PEERCRED_OFF && !strncmp(authorization, "PeerCred ", 9) && | ||
| 230 | con->http->hostaddr->addr.sa_family == AF_LOCAL && con->best) | ||
| 231 | { | ||
| 232 | /* | ||
| 233 | @@ -441,6 +441,12 @@ cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ | ||
| 234 | } | ||
| 235 | #endif /* HAVE_AUTHORIZATION_H */ | ||
| 236 | |||
| 237 | + if ((PeerCred == CUPSD_PEERCRED_ROOTONLY || httpGetState(con->http) == HTTP_STATE_PUT_RECV) && strcmp(authorization + 9, "root")) | ||
| 238 | + { | ||
| 239 | + cupsdLogClient(con, CUPSD_LOG_INFO, "User \"%s\" is not allowed to use peer credentials.", authorization + 9); | ||
| 240 | + return; | ||
| 241 | + } | ||
| 242 | + | ||
| 243 | if ((pwd = getpwnam(authorization + 9)) == NULL) | ||
| 244 | { | ||
| 245 | cupsdLogClient(con, CUPSD_LOG_ERROR, "User \"%s\" does not exist.", authorization + 9); | ||
| 246 | diff --git a/scheduler/auth.h b/scheduler/auth.h | ||
| 247 | index ee98e92c7..fdf71213f 100644 | ||
| 248 | --- a/scheduler/auth.h | ||
| 249 | +++ b/scheduler/auth.h | ||
| 250 | @@ -50,6 +50,10 @@ | ||
| 251 | #define CUPSD_AUTH_LIMIT_ALL 127 /* Limit all requests */ | ||
| 252 | #define CUPSD_AUTH_LIMIT_IPP 128 /* Limit IPP requests */ | ||
| 253 | |||
| 254 | +#define CUPSD_PEERCRED_OFF 0 /* Don't allow PeerCred authorization */ | ||
| 255 | +#define CUPSD_PEERCRED_ON 1 /* Allow PeerCred authorization for all users */ | ||
| 256 | +#define CUPSD_PEERCRED_ROOTONLY 2 /* Allow PeerCred authorization for root user */ | ||
| 257 | + | ||
| 258 | #define IPP_ANY_OPERATION (ipp_op_t)0 | ||
| 259 | /* Any IPP operation */ | ||
| 260 | #define IPP_BAD_OPERATION (ipp_op_t)-1 | ||
| 261 | @@ -107,6 +111,9 @@ typedef struct cupsd_client_s cupsd_client_t; | ||
| 262 | |||
| 263 | VAR cups_array_t *Locations VALUE(NULL); | ||
| 264 | /* Authorization locations */ | ||
| 265 | +VAR int PeerCred VALUE(CUPSD_PEERCRED_ON); | ||
| 266 | + /* Allow PeerCred authorization? */ | ||
| 267 | + | ||
| 268 | #ifdef HAVE_TLS | ||
| 269 | VAR http_encryption_t DefaultEncryption VALUE(HTTP_ENCRYPT_REQUIRED); | ||
| 270 | /* Default encryption for authentication */ | ||
| 271 | diff --git a/scheduler/client.c b/scheduler/client.c | ||
| 272 | index 9593c9138..d961c15db 100644 | ||
| 273 | --- a/scheduler/client.c | ||
| 274 | +++ b/scheduler/client.c | ||
| 275 | @@ -2143,7 +2143,7 @@ cupsdSendHeader( | ||
| 276 | auth_size = sizeof(auth_str) - (size_t)(auth_key - auth_str); | ||
| 277 | |||
| 278 | #if defined(SO_PEERCRED) && defined(AF_LOCAL) | ||
| 279 | - if (httpAddrFamily(httpGetAddress(con->http)) == AF_LOCAL) | ||
| 280 | + if (PeerCred != CUPSD_PEERCRED_OFF && httpAddrFamily(httpGetAddress(con->http)) == AF_LOCAL) | ||
| 281 | { | ||
| 282 | strlcpy(auth_key, ", PeerCred", auth_size); | ||
| 283 | auth_key += 10; | ||
| 284 | diff --git a/scheduler/conf.c b/scheduler/conf.c | ||
| 285 | index db4104ec5..7d6da0252 100644 | ||
| 286 | --- a/scheduler/conf.c | ||
| 287 | +++ b/scheduler/conf.c | ||
| 288 | @@ -47,6 +47,7 @@ typedef enum | ||
| 289 | { | ||
| 290 | CUPSD_VARTYPE_INTEGER, /* Integer option */ | ||
| 291 | CUPSD_VARTYPE_TIME, /* Time interval option */ | ||
| 292 | + CUPSD_VARTYPE_NULLSTRING, /* String option or NULL/empty string */ | ||
| 293 | CUPSD_VARTYPE_STRING, /* String option */ | ||
| 294 | CUPSD_VARTYPE_BOOLEAN, /* Boolean option */ | ||
| 295 | CUPSD_VARTYPE_PATHNAME, /* File/directory name option */ | ||
| 296 | @@ -69,7 +70,7 @@ static const cupsd_var_t cupsd_vars[] = | ||
| 297 | { | ||
| 298 | { "AutoPurgeJobs", &JobAutoPurge, CUPSD_VARTYPE_BOOLEAN }, | ||
| 299 | #ifdef HAVE_DNSSD | ||
| 300 | - { "BrowseDNSSDSubTypes", &DNSSDSubTypes, CUPSD_VARTYPE_STRING }, | ||
| 301 | + { "BrowseDNSSDSubTypes", &DNSSDSubTypes, CUPSD_VARTYPE_NULLSTRING }, | ||
| 302 | #endif /* HAVE_DNSSD */ | ||
| 303 | { "BrowseWebIF", &BrowseWebIF, CUPSD_VARTYPE_BOOLEAN }, | ||
| 304 | { "Browsing", &Browsing, CUPSD_VARTYPE_BOOLEAN }, | ||
| 305 | @@ -120,7 +121,7 @@ static const cupsd_var_t cupsd_vars[] = | ||
| 306 | { "MaxSubscriptionsPerPrinter",&MaxSubscriptionsPerPrinter, CUPSD_VARTYPE_INTEGER }, | ||
| 307 | { "MaxSubscriptionsPerUser", &MaxSubscriptionsPerUser, CUPSD_VARTYPE_INTEGER }, | ||
| 308 | { "MultipleOperationTimeout", &MultipleOperationTimeout, CUPSD_VARTYPE_TIME }, | ||
| 309 | - { "PageLogFormat", &PageLogFormat, CUPSD_VARTYPE_STRING }, | ||
| 310 | + { "PageLogFormat", &PageLogFormat, CUPSD_VARTYPE_NULLSTRING }, | ||
| 311 | { "PreserveJobFiles", &JobFiles, CUPSD_VARTYPE_TIME }, | ||
| 312 | { "PreserveJobHistory", &JobHistory, CUPSD_VARTYPE_TIME }, | ||
| 313 | { "ReloadTimeout", &ReloadTimeout, CUPSD_VARTYPE_TIME }, | ||
| 314 | @@ -777,6 +778,13 @@ cupsdReadConfiguration(void) | ||
| 315 | IdleExitTimeout = 60; | ||
| 316 | #endif /* HAVE_ONDEMAND */ | ||
| 317 | |||
| 318 | + if (!strcmp(CUPS_DEFAULT_PEER_CRED, "off")) | ||
| 319 | + PeerCred = CUPSD_PEERCRED_OFF; | ||
| 320 | + else if (!strcmp(CUPS_DEFAULT_PEER_CRED, "root-only")) | ||
| 321 | + PeerCred = CUPSD_PEERCRED_ROOTONLY; | ||
| 322 | + else | ||
| 323 | + PeerCred = CUPSD_PEERCRED_ON; | ||
| 324 | + | ||
| 325 | /* | ||
| 326 | * Setup environment variables... | ||
| 327 | */ | ||
| 328 | @@ -1826,7 +1834,7 @@ get_addr_and_mask(const char *value, /* I - String from config file */ | ||
| 329 | |||
| 330 | family = AF_INET6; | ||
| 331 | |||
| 332 | - for (i = 0, ptr = value + 1; *ptr && i < 8; i ++) | ||
| 333 | + for (i = 0, ptr = value + 1; *ptr && i >= 0 && i < 8; i ++) | ||
| 334 | { | ||
| 335 | if (*ptr == ']') | ||
| 336 | break; | ||
| 337 | @@ -1975,7 +1983,7 @@ get_addr_and_mask(const char *value, /* I - String from config file */ | ||
| 338 | #ifdef AF_INET6 | ||
| 339 | if (family == AF_INET6) | ||
| 340 | { | ||
| 341 | - if (i > 128) | ||
| 342 | + if (i < 0 || i > 128) | ||
| 343 | return (0); | ||
| 344 | |||
| 345 | i = 128 - i; | ||
| 346 | @@ -2009,7 +2017,7 @@ get_addr_and_mask(const char *value, /* I - String from config file */ | ||
| 347 | else | ||
| 348 | #endif /* AF_INET6 */ | ||
| 349 | { | ||
| 350 | - if (i > 32) | ||
| 351 | + if (i < 0 || i > 32) | ||
| 352 | return (0); | ||
| 353 | |||
| 354 | mask[0] = 0xffffffff; | ||
| 355 | @@ -2919,7 +2927,17 @@ parse_variable( | ||
| 356 | cupsdSetString((char **)var->ptr, temp); | ||
| 357 | break; | ||
| 358 | |||
| 359 | + case CUPSD_VARTYPE_NULLSTRING : | ||
| 360 | + cupsdSetString((char **)var->ptr, value); | ||
| 361 | + break; | ||
| 362 | + | ||
| 363 | case CUPSD_VARTYPE_STRING : | ||
| 364 | + if (!value) | ||
| 365 | + { | ||
| 366 | + cupsdLogMessage(CUPSD_LOG_ERROR, "Missing value for %s on line %d of %s.", line, linenum, filename); | ||
| 367 | + return (0); | ||
| 368 | + } | ||
| 369 | + | ||
| 370 | cupsdSetString((char **)var->ptr, value); | ||
| 371 | break; | ||
| 372 | } | ||
| 373 | @@ -3447,9 +3465,10 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */ | ||
| 374 | line, value ? " " : "", value ? value : "", linenum, | ||
| 375 | ConfigurationFile, CupsFilesFile); | ||
| 376 | } | ||
| 377 | - else | ||
| 378 | - parse_variable(ConfigurationFile, linenum, line, value, | ||
| 379 | - sizeof(cupsd_vars) / sizeof(cupsd_vars[0]), cupsd_vars); | ||
| 380 | + else if (!parse_variable(ConfigurationFile, linenum, line, value, | ||
| 381 | + sizeof(cupsd_vars) / sizeof(cupsd_vars[0]), cupsd_vars) && | ||
| 382 | + (FatalErrors & CUPSD_FATAL_CONFIG)) | ||
| 383 | + return (0); | ||
| 384 | } | ||
| 385 | |||
| 386 | return (1); | ||
| 387 | @@ -3609,6 +3628,31 @@ read_cups_files_conf(cups_file_t *fp) /* I - File to read from */ | ||
| 388 | break; | ||
| 389 | } | ||
| 390 | } | ||
| 391 | + else if (!_cups_strcasecmp(line, "PeerCred") && value) | ||
| 392 | + { | ||
| 393 | + /* | ||
| 394 | + * PeerCred {off,on,root-only} | ||
| 395 | + */ | ||
| 396 | + | ||
| 397 | + if (!_cups_strcasecmp(value, "off")) | ||
| 398 | + { | ||
| 399 | + PeerCred = CUPSD_PEERCRED_OFF; | ||
| 400 | + } | ||
| 401 | + else if (!_cups_strcasecmp(value, "on")) | ||
| 402 | + { | ||
| 403 | + PeerCred = CUPSD_PEERCRED_ON; | ||
| 404 | + } | ||
| 405 | + else if (!_cups_strcasecmp(value, "root-only")) | ||
| 406 | + { | ||
| 407 | + PeerCred = CUPSD_PEERCRED_ROOTONLY; | ||
| 408 | + } | ||
| 409 | + else | ||
| 410 | + { | ||
| 411 | + cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown PeerCred \"%s\" on line %d of %s.", value, linenum, CupsFilesFile); | ||
| 412 | + if (FatalErrors & CUPSD_FATAL_CONFIG) | ||
| 413 | + return (0); | ||
| 414 | + } | ||
| 415 | + } | ||
| 416 | else if (!_cups_strcasecmp(line, "PrintcapFormat") && value) | ||
| 417 | { | ||
| 418 | /* | ||
| 419 | diff --git a/test/run-stp-tests.sh b/test/run-stp-tests.sh | ||
| 420 | index 1c447edd7..8d677db71 100755 | ||
| 421 | --- a/test/run-stp-tests.sh | ||
| 422 | +++ b/test/run-stp-tests.sh | ||
| 423 | @@ -512,7 +512,7 @@ fi | ||
| 424 | |||
| 425 | cat >$BASE/cups-files.conf <<EOF | ||
| 426 | FileDevice yes | ||
| 427 | -Printcap | ||
| 428 | +Printcap $BASE/printcap | ||
| 429 | User $user | ||
| 430 | ServerRoot $BASE | ||
| 431 | StateDir $BASE | ||
| 432 | diff --git a/vcnet/config.h b/vcnet/config.h | ||
| 433 | index dbc6f05d5..317c956a6 100644 | ||
| 434 | --- a/vcnet/config.h | ||
| 435 | +++ b/vcnet/config.h | ||
| 436 | @@ -169,6 +169,13 @@ typedef unsigned long useconds_t; | ||
| 437 | #define CUPS_DEFAULT_ERROR_POLICY "stop-printer" | ||
| 438 | |||
| 439 | |||
| 440 | +/* | ||
| 441 | + * Default PeerCred value... | ||
| 442 | + */ | ||
| 443 | + | ||
| 444 | +#define CUPS_DEFAULT_PEER_CRED "on" | ||
| 445 | + | ||
| 446 | + | ||
| 447 | /* | ||
| 448 | * Default MaxCopies value... | ||
| 449 | */ | ||
| 450 | diff --git a/xcode/CUPS.xcodeproj/project.pbxproj b/xcode/CUPS.xcodeproj/project.pbxproj | ||
| 451 | index 597946440..54ac652a1 100644 | ||
| 452 | --- a/xcode/CUPS.xcodeproj/project.pbxproj | ||
| 453 | +++ b/xcode/CUPS.xcodeproj/project.pbxproj | ||
| 454 | @@ -3434,7 +3434,6 @@ | ||
| 455 | 72220FB313330BCE00FCA411 /* mime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mime.c; path = ../scheduler/mime.c; sourceTree = "<group>"; }; | ||
| 456 | 72220FB413330BCE00FCA411 /* mime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mime.h; path = ../scheduler/mime.h; sourceTree = "<group>"; }; | ||
| 457 | 72220FB513330BCE00FCA411 /* type.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = type.c; path = ../scheduler/type.c; sourceTree = "<group>"; }; | ||
| 458 | - 7226369B18AE6D19004ED309 /* org.cups.cups-lpd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "org.cups.cups-lpd.plist"; path = "../scheduler/org.cups.cups-lpd.plist"; sourceTree = SOURCE_ROOT; }; | ||
| 459 | 7226369C18AE6D19004ED309 /* org.cups.cupsd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = org.cups.cupsd.plist; path = ../scheduler/org.cups.cupsd.plist; sourceTree = SOURCE_ROOT; }; | ||
| 460 | 7226369D18AE73BB004ED309 /* config.h.in */ = {isa = PBXFileReference; lastKnownFileType = text; name = config.h.in; path = ../config.h.in; sourceTree = "<group>"; }; | ||
| 461 | 722A24EE2178D00C000CAB20 /* debug-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "debug-internal.h"; path = "../cups/debug-internal.h"; sourceTree = "<group>"; }; | ||
| 462 | @@ -5056,7 +5055,6 @@ | ||
| 463 | isa = PBXGroup; | ||
| 464 | children = ( | ||
| 465 | 72E65BDC18DC852700097E89 /* Makefile */, | ||
| 466 | - 7226369B18AE6D19004ED309 /* org.cups.cups-lpd.plist */, | ||
| 467 | 72E65BD518DC818400097E89 /* org.cups.cups-lpd.plist.in */, | ||
| 468 | 7226369C18AE6D19004ED309 /* org.cups.cupsd.plist */, | ||
| 469 | 72220F6913330B0C00FCA411 /* auth.c */, | ||
| 470 | diff --git a/xcode/config.h b/xcode/config.h | ||
| 471 | index e0ddd09dc..caec083ca 100644 | ||
| 472 | --- a/xcode/config.h | ||
| 473 | +++ b/xcode/config.h | ||
| 474 | @@ -88,6 +88,13 @@ | ||
| 475 | #define CUPS_DEFAULT_ERROR_POLICY "stop-printer" | ||
| 476 | |||
| 477 | |||
| 478 | +/* | ||
| 479 | + * Default PeerCred value... | ||
| 480 | + */ | ||
| 481 | + | ||
| 482 | +#define CUPS_DEFAULT_PEER_CRED "on" | ||
| 483 | + | ||
| 484 | + | ||
| 485 | /* | ||
| 486 | * Default MaxCopies value... | ||
| 487 | */ | ||
diff --git a/meta/recipes-extended/libarchive/libarchive/CVE-2025-60753.patch b/meta/recipes-extended/libarchive/libarchive/CVE-2025-60753-01.patch index 604e0421be..604e0421be 100644 --- a/meta/recipes-extended/libarchive/libarchive/CVE-2025-60753.patch +++ b/meta/recipes-extended/libarchive/libarchive/CVE-2025-60753-01.patch | |||
diff --git a/meta/recipes-extended/libarchive/libarchive/CVE-2025-60753-02.patch b/meta/recipes-extended/libarchive/libarchive/CVE-2025-60753-02.patch new file mode 100644 index 0000000000..525ee2462c --- /dev/null +++ b/meta/recipes-extended/libarchive/libarchive/CVE-2025-60753-02.patch | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | From cfb02de558d843dc5355c4aa2aeb4af49f88bdb9 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Martin Matuska <martin@matuska.de> | ||
| 3 | Date: Mon, 8 Dec 2025 21:40:46 +0100 | ||
| 4 | Subject: [PATCH] tar: fix off-bounds read resulting from #2787 (3150539ed) | ||
| 5 | |||
| 6 | CVE: CVE-2025-60753 | ||
| 7 | Upstream-Status: Backport [https://github.com/libarchive/libarchive/commit/cfb02de558d843dc5355c4aa2aeb4af49f88bdb9] | ||
| 8 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 9 | --- | ||
| 10 | tar/subst.c | 16 ++++++++-------- | ||
| 11 | 1 file changed, 8 insertions(+), 8 deletions(-) | ||
| 12 | |||
| 13 | diff --git a/tar/subst.c b/tar/subst.c | ||
| 14 | index a466f653..53497ad0 100644 | ||
| 15 | --- a/tar/subst.c | ||
| 16 | +++ b/tar/subst.c | ||
| 17 | @@ -239,7 +239,7 @@ apply_substitution(struct bsdtar *bsdtar, const char *name, char **result, | ||
| 18 | |||
| 19 | char isEnd = 0; | ||
| 20 | do { | ||
| 21 | - isEnd = *name == '\0'; | ||
| 22 | + isEnd = *name == '\0'; | ||
| 23 | if (regexec(&rule->re, name, 10, matches, 0)) | ||
| 24 | break; | ||
| 25 | |||
| 26 | @@ -294,13 +294,13 @@ apply_substitution(struct bsdtar *bsdtar, const char *name, char **result, | ||
| 27 | |||
| 28 | realloc_strcat(result, rule->result + j); | ||
| 29 | if (matches[0].rm_eo > 0) { | ||
| 30 | - name += matches[0].rm_eo; | ||
| 31 | - } else { | ||
| 32 | - // We skip a character because the match is 0-length | ||
| 33 | - // so we need to add it to the output | ||
| 34 | - realloc_strncat(result, name, 1); | ||
| 35 | - name += 1; | ||
| 36 | - } | ||
| 37 | + name += matches[0].rm_eo; | ||
| 38 | + } else if (!isEnd) { | ||
| 39 | + // We skip a character because the match is 0-length | ||
| 40 | + // so we need to add it to the output | ||
| 41 | + realloc_strncat(result, name, 1); | ||
| 42 | + name += 1; | ||
| 43 | + } | ||
| 44 | } while (rule->global && !isEnd); // Testing one step after because sed et al. run 0-length patterns a last time on the empty string at the end | ||
| 45 | } | ||
| 46 | |||
diff --git a/meta/recipes-extended/libarchive/libarchive_3.6.2.bb b/meta/recipes-extended/libarchive/libarchive_3.6.2.bb index 66f30ec89b..e74326b40f 100644 --- a/meta/recipes-extended/libarchive/libarchive_3.6.2.bb +++ b/meta/recipes-extended/libarchive/libarchive_3.6.2.bb | |||
| @@ -48,7 +48,8 @@ SRC_URI = "http://libarchive.org/downloads/libarchive-${PV}.tar.gz \ | |||
| 48 | file://0001-Merge-pull-request-2749-from-KlaraSystems-des-tempdi.patch \ | 48 | file://0001-Merge-pull-request-2749-from-KlaraSystems-des-tempdi.patch \ |
| 49 | file://0001-Merge-pull-request-2753-from-KlaraSystems-des-temp-f.patch \ | 49 | file://0001-Merge-pull-request-2753-from-KlaraSystems-des-temp-f.patch \ |
| 50 | file://0001-Merge-pull-request-2768-from-Commandoss-master.patch \ | 50 | file://0001-Merge-pull-request-2768-from-Commandoss-master.patch \ |
| 51 | file://CVE-2025-60753.patch \ | 51 | file://CVE-2025-60753-01.patch \ |
| 52 | file://CVE-2025-60753-02.patch \ | ||
| 52 | " | 53 | " |
| 53 | UPSTREAM_CHECK_URI = "http://libarchive.org/" | 54 | UPSTREAM_CHECK_URI = "http://libarchive.org/" |
| 54 | 55 | ||
diff --git a/meta/recipes-support/curl/curl/CVE-2025-14017.patch b/meta/recipes-support/curl/curl/CVE-2025-14017.patch new file mode 100644 index 0000000000..a18e1d74dd --- /dev/null +++ b/meta/recipes-support/curl/curl/CVE-2025-14017.patch | |||
| @@ -0,0 +1,115 @@ | |||
| 1 | From 39d1976b7f709a516e3243338ebc0443bdd8d56d Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Daniel Stenberg <daniel@haxx.se> | ||
| 3 | Date: Thu, 4 Dec 2025 00:14:20 +0100 | ||
| 4 | Subject: [PATCH] ldap: call ldap_init() before setting the options | ||
| 5 | |||
| 6 | Closes #19830 | ||
| 7 | |||
| 8 | CVE: CVE-2025-14017 | ||
| 9 | Upstream-Status: Backport [https://github.com/curl/curl/commit/39d1976b7f709a516e3243338ebc0443bdd8d56d] | ||
| 10 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 11 | --- | ||
| 12 | lib/ldap.c | 49 +++++++++++++++++++------------------------------ | ||
| 13 | 1 file changed, 19 insertions(+), 30 deletions(-) | ||
| 14 | |||
| 15 | diff --git a/lib/ldap.c b/lib/ldap.c | ||
| 16 | index 63b2cbc414..0911a9239a 100644 | ||
| 17 | --- a/lib/ldap.c | ||
| 18 | +++ b/lib/ldap.c | ||
| 19 | @@ -333,16 +333,29 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) | ||
| 20 | passwd = conn->passwd; | ||
| 21 | } | ||
| 22 | |||
| 23 | +#ifdef USE_WIN32_LDAP | ||
| 24 | + if(ldap_ssl) | ||
| 25 | + server = ldap_sslinit(host, (int)conn->port, 1); | ||
| 26 | + else | ||
| 27 | +#else | ||
| 28 | + server = ldap_init(host, (int)conn->port); | ||
| 29 | +#endif | ||
| 30 | + if(!server) { | ||
| 31 | + failf(data, "LDAP local: Cannot connect to %s:%ld", | ||
| 32 | + conn->host.dispname, conn->port); | ||
| 33 | + result = CURLE_COULDNT_CONNECT; | ||
| 34 | + goto quit; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | #ifdef LDAP_OPT_NETWORK_TIMEOUT | ||
| 38 | - ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &ldap_timeout); | ||
| 39 | + ldap_set_option(server, LDAP_OPT_NETWORK_TIMEOUT, &ldap_timeout); | ||
| 40 | #endif | ||
| 41 | - ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); | ||
| 42 | + ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); | ||
| 43 | |||
| 44 | if(ldap_ssl) { | ||
| 45 | #ifdef HAVE_LDAP_SSL | ||
| 46 | #ifdef USE_WIN32_LDAP | ||
| 47 | /* Win32 LDAP SDK doesn't support insecure mode without CA! */ | ||
| 48 | - server = ldap_sslinit(host, (int)conn->port, 1); | ||
| 49 | ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON); | ||
| 50 | #else | ||
| 51 | int ldap_option; | ||
| 52 | @@ -410,7 +423,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) | ||
| 53 | goto quit; | ||
| 54 | } | ||
| 55 | infof(data, "LDAP local: using PEM CA cert: %s", ldap_ca); | ||
| 56 | - rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ldap_ca); | ||
| 57 | + rc = ldap_set_option(server, LDAP_OPT_X_TLS_CACERTFILE, ldap_ca); | ||
| 58 | if(rc != LDAP_SUCCESS) { | ||
| 59 | failf(data, "LDAP local: ERROR setting PEM CA cert: %s", | ||
| 60 | ldap_err2string(rc)); | ||
| 61 | @@ -422,20 +435,13 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) | ||
| 62 | else | ||
| 63 | ldap_option = LDAP_OPT_X_TLS_NEVER; | ||
| 64 | |||
| 65 | - rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_option); | ||
| 66 | + rc = ldap_set_option(server, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_option); | ||
| 67 | if(rc != LDAP_SUCCESS) { | ||
| 68 | failf(data, "LDAP local: ERROR setting cert verify mode: %s", | ||
| 69 | ldap_err2string(rc)); | ||
| 70 | result = CURLE_SSL_CERTPROBLEM; | ||
| 71 | goto quit; | ||
| 72 | } | ||
| 73 | - server = ldap_init(host, (int)conn->port); | ||
| 74 | - if(!server) { | ||
| 75 | - failf(data, "LDAP local: Cannot connect to %s:%ld", | ||
| 76 | - conn->host.dispname, conn->port); | ||
| 77 | - result = CURLE_COULDNT_CONNECT; | ||
| 78 | - goto quit; | ||
| 79 | - } | ||
| 80 | ldap_option = LDAP_OPT_X_TLS_HARD; | ||
| 81 | rc = ldap_set_option(server, LDAP_OPT_X_TLS, &ldap_option); | ||
| 82 | if(rc != LDAP_SUCCESS) { | ||
| 83 | @@ -444,15 +450,6 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) | ||
| 84 | result = CURLE_SSL_CERTPROBLEM; | ||
| 85 | goto quit; | ||
| 86 | } | ||
| 87 | -/* | ||
| 88 | - rc = ldap_start_tls_s(server, NULL, NULL); | ||
| 89 | - if(rc != LDAP_SUCCESS) { | ||
| 90 | - failf(data, "LDAP local: ERROR starting SSL/TLS mode: %s", | ||
| 91 | - ldap_err2string(rc)); | ||
| 92 | - result = CURLE_SSL_CERTPROBLEM; | ||
| 93 | - goto quit; | ||
| 94 | - } | ||
| 95 | -*/ | ||
| 96 | #else | ||
| 97 | /* we should probably never come up to here since configure | ||
| 98 | should check in first place if we can support LDAP SSL/TLS */ | ||
| 99 | @@ -469,15 +466,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) | ||
| 100 | result = CURLE_NOT_BUILT_IN; | ||
| 101 | goto quit; | ||
| 102 | } | ||
| 103 | - else { | ||
| 104 | - server = ldap_init(host, (int)conn->port); | ||
| 105 | - if(!server) { | ||
| 106 | - failf(data, "LDAP local: Cannot connect to %s:%ld", | ||
| 107 | - conn->host.dispname, conn->port); | ||
| 108 | - result = CURLE_COULDNT_CONNECT; | ||
| 109 | - goto quit; | ||
| 110 | - } | ||
| 111 | - } | ||
| 112 | + | ||
| 113 | #ifdef USE_WIN32_LDAP | ||
| 114 | ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); | ||
| 115 | rc = ldap_win_bind(data, server, user, passwd); | ||
diff --git a/meta/recipes-support/curl/curl/CVE-2025-15079.patch b/meta/recipes-support/curl/curl/CVE-2025-15079.patch new file mode 100644 index 0000000000..47fa518309 --- /dev/null +++ b/meta/recipes-support/curl/curl/CVE-2025-15079.patch | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | From adca486c125d9a6d9565b9607a19dce803a8b479 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Daniel Stenberg <daniel@haxx.se> | ||
| 3 | Date: Wed, 24 Dec 2025 17:47:03 +0100 | ||
| 4 | Subject: [PATCH] libssh: set both knownhosts options to the same file | ||
| 5 | |||
| 6 | Reported-by: Harry Sintonen | ||
| 7 | |||
| 8 | Closes #20092 | ||
| 9 | |||
| 10 | CVE: CVE-2025-15079 | ||
| 11 | Upstream-Status: Backport [https://github.com/curl/curl/commit/adca486c125d9a6d9565b9607a19dce803a8b479] | ||
| 12 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 13 | --- | ||
| 14 | lib/vssh/libssh.c | 5 +++++ | ||
| 15 | 1 file changed, 5 insertions(+) | ||
| 16 | |||
| 17 | diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c | ||
| 18 | index 7d5905c83d..98c109ab59 100644 | ||
| 19 | --- a/lib/vssh/libssh.c | ||
| 20 | +++ b/lib/vssh/libssh.c | ||
| 21 | @@ -2224,6 +2224,11 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done) | ||
| 22 | infof(data, "Known hosts: %s", data->set.str[STRING_SSH_KNOWNHOSTS]); | ||
| 23 | rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_KNOWNHOSTS, | ||
| 24 | data->set.str[STRING_SSH_KNOWNHOSTS]); | ||
| 25 | + if(rc == SSH_OK) | ||
| 26 | + /* libssh has two separate options for this. Set both to the same file | ||
| 27 | + to avoid surprises */ | ||
| 28 | + rc = ssh_options_set(ssh->ssh_session, SSH_OPTIONS_GLOBAL_KNOWNHOSTS, | ||
| 29 | + data->set.str[STRING_SSH_KNOWNHOSTS]); | ||
| 30 | if(rc != SSH_OK) { | ||
| 31 | failf(data, "Could not set known hosts file path"); | ||
| 32 | return CURLE_FAILED_INIT; | ||
diff --git a/meta/recipes-support/curl/curl/CVE-2025-15224.patch b/meta/recipes-support/curl/curl/CVE-2025-15224.patch new file mode 100644 index 0000000000..36f5f1b93a --- /dev/null +++ b/meta/recipes-support/curl/curl/CVE-2025-15224.patch | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | From 16d5f2a5660c61cc27bd5f1c7f512391d1c927aa Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Harry Sintonen <sintonen@iki.fi> | ||
| 3 | Date: Mon, 29 Dec 2025 16:56:39 +0100 | ||
| 4 | Subject: [PATCH] libssh: require private key or user-agent for public key auth | ||
| 5 | |||
| 6 | Closes #20110 | ||
| 7 | |||
| 8 | CVE: CVE-2025-15224 | ||
| 9 | Upstream-Status: Backport [https://github.com/curl/curl/commit/16d5f2a5660c61cc27bd5f1c7f512391d1c927aa] | ||
| 10 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 11 | --- | ||
| 12 | lib/vssh/libssh.c | 6 +++++- | ||
| 13 | 1 file changed, 5 insertions(+), 1 deletion(-) | ||
| 14 | |||
| 15 | diff --git a/lib/vssh/libssh.c b/lib/vssh/libssh.c | ||
| 16 | index 5d5125b526..bde6355f73 100644 | ||
| 17 | --- a/lib/vssh/libssh.c | ||
| 18 | +++ b/lib/vssh/libssh.c | ||
| 19 | @@ -741,7 +741,11 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block) | ||
| 20 | } | ||
| 21 | |||
| 22 | sshc->auth_methods = ssh_userauth_list(sshc->ssh_session, NULL); | ||
| 23 | - if(sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) { | ||
| 24 | + /* For public key auth we need either the private key or | ||
| 25 | + CURLSSH_AUTH_AGENT. */ | ||
| 26 | + if((sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) && | ||
| 27 | + (data->set.str[STRING_SSH_PRIVATE_KEY] || | ||
| 28 | + (data->set.ssh_auth_types & CURLSSH_AUTH_AGENT))) { | ||
| 29 | state(data, SSH_AUTH_PKEY_INIT); | ||
| 30 | infof(data, "Authentication using SSH public key file"); | ||
| 31 | } | ||
diff --git a/meta/recipes-support/curl/curl_7.82.0.bb b/meta/recipes-support/curl/curl_7.82.0.bb index 2326392a4f..72bd1a2088 100644 --- a/meta/recipes-support/curl/curl_7.82.0.bb +++ b/meta/recipes-support/curl/curl_7.82.0.bb | |||
| @@ -67,6 +67,9 @@ SRC_URI = "https://curl.se/download/${BP}.tar.xz \ | |||
| 67 | file://CVE-2024-11053-0002.patch \ | 67 | file://CVE-2024-11053-0002.patch \ |
| 68 | file://CVE-2025-0167.patch \ | 68 | file://CVE-2025-0167.patch \ |
| 69 | file://CVE-2025-9086.patch \ | 69 | file://CVE-2025-9086.patch \ |
| 70 | file://CVE-2025-14017.patch \ | ||
| 71 | file://CVE-2025-15079.patch \ | ||
| 72 | file://CVE-2025-15224.patch \ | ||
| 70 | " | 73 | " |
| 71 | SRC_URI[sha256sum] = "0aaa12d7bd04b0966254f2703ce80dd5c38dbbd76af0297d3d690cdce58a583c" | 74 | SRC_URI[sha256sum] = "0aaa12d7bd04b0966254f2703ce80dd5c38dbbd76af0297d3d690cdce58a583c" |
| 72 | 75 | ||
diff --git a/meta/recipes-support/gnupg/gnupg/CVE-2025-68973.patch b/meta/recipes-support/gnupg/gnupg/CVE-2025-68973.patch new file mode 100644 index 0000000000..1d5225361b --- /dev/null +++ b/meta/recipes-support/gnupg/gnupg/CVE-2025-68973.patch | |||
| @@ -0,0 +1,108 @@ | |||
| 1 | From 4ecc5122f20e10c17172ed72f4fa46c784b5fb48 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Werner Koch <wk@gnupg.org> | ||
| 3 | Date: Thu, 23 Oct 2025 11:36:04 +0200 | ||
| 4 | Subject: [PATCH] gpg: Fix possible memory corruption in the armor parser. | ||
| 5 | |||
| 6 | * g10/armor.c (armor_filter): Fix faulty double increment. | ||
| 7 | |||
| 8 | * common/iobuf.c (underflow_target): Assert that the filter | ||
| 9 | implementations behave well. | ||
| 10 | -- | ||
| 11 | |||
| 12 | This fixes a bug in a code path which can only be reached with special | ||
| 13 | crafted input data and would then error out at an upper layer due to | ||
| 14 | corrupt input (every second byte in the buffer is unitialized | ||
| 15 | garbage). No fuzzing has yet hit this case and we don't have a test | ||
| 16 | case for this code path. However memory corruption can never be | ||
| 17 | tolerated as it always has the protential for remode code execution. | ||
| 18 | |||
| 19 | Reported-by: 8b79fe4dd0581c1cd000e1fbecba9f39e16a396a | ||
| 20 | Fixes-commit: c27c7416d5148865a513e007fb6f0a34993a6073 | ||
| 21 | which fixed | ||
| 22 | Fixes-commit: 7d0efec7cf5ae110c99511abc32587ff0c45b14f | ||
| 23 | Backported-from-master: 115d138ba599328005c5321c0ef9f00355838ca9 | ||
| 24 | |||
| 25 | The bug was introduced on 1999-01-07 by me: | ||
| 26 | * armor.c: Rewrote large parts. | ||
| 27 | which I fixed on 1999-03-02 but missed to fix the other case: | ||
| 28 | * armor.c (armor_filter): Fixed armor bypassing. | ||
| 29 | |||
| 30 | Below is base64+gzipped test data which can be used with valgrind to | ||
| 31 | show access to uninitalized memory in write(2) in the unpatched code. | ||
| 32 | |||
| 33 | --8<---------------cut here---------------start------------->8--- | ||
| 34 | H4sICIDd+WgCA3h4AO3QMQ6CQBCG0djOKbY3G05gscYFSRAJt/AExp6Di0cQG0ze | ||
| 35 | a//MV0zOq3Pt+jFN3ZTKfLvP9ZLafqifJUe8juOjeZbVtSkbRPmRgICAgICAgICA | ||
| 36 | gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA | ||
| 37 | gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA | ||
| 38 | gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA | ||
| 39 | gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA | ||
| 40 | gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA | ||
| 41 | gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA | ||
| 42 | gICAgICAgICAgICAgICAgICAgICAgICAgMCXF6dYDgAAAAAAAAAAAAAAAAAAAAAA | ||
| 43 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7E14AAAAA | ||
| 44 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 45 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 46 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 47 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwZ94aieId3+8EAA== | ||
| 48 | --8<---------------cut here---------------end--------------->8--- | ||
| 49 | |||
| 50 | CVE: CVE-2025-68973 | ||
| 51 | Upstream-Status: Backport [https://github.com/gpg/gnupg/commit/4ecc5122f20e10c17172ed72f4fa46c784b5fb48] | ||
| 52 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 53 | --- | ||
| 54 | common/iobuf.c | 8 +++++++- | ||
| 55 | g10/armor.c | 4 ++-- | ||
| 56 | 2 files changed, 9 insertions(+), 3 deletions(-) | ||
| 57 | |||
| 58 | diff --git a/common/iobuf.c b/common/iobuf.c | ||
| 59 | index 748e6935d..2497713c1 100644 | ||
| 60 | --- a/common/iobuf.c | ||
| 61 | +++ b/common/iobuf.c | ||
| 62 | @@ -2041,6 +2041,8 @@ underflow_target (iobuf_t a, int clear_pending_eof, size_t target) | ||
| 63 | rc = 0; | ||
| 64 | else | ||
| 65 | { | ||
| 66 | + size_t tmplen; | ||
| 67 | + | ||
| 68 | /* If no buffered data and drain buffer has been setup, and drain | ||
| 69 | * buffer is largish, read data directly to drain buffer. */ | ||
| 70 | if (a->d.len == 0 | ||
| 71 | @@ -2053,8 +2055,10 @@ underflow_target (iobuf_t a, int clear_pending_eof, size_t target) | ||
| 72 | log_debug ("iobuf-%d.%d: underflow: A->FILTER (%lu bytes, to external drain)\n", | ||
| 73 | a->no, a->subno, (ulong)len); | ||
| 74 | |||
| 75 | - rc = a->filter (a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain, | ||
| 76 | + tmplen = len; /* Used to check for bugs in the filter. */ | ||
| 77 | + rc = a->filter (a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain, | ||
| 78 | a->e_d.buf, &len); | ||
| 79 | + log_assert (len <= tmplen); | ||
| 80 | a->e_d.used = len; | ||
| 81 | len = 0; | ||
| 82 | } | ||
| 83 | @@ -2064,8 +2068,10 @@ underflow_target (iobuf_t a, int clear_pending_eof, size_t target) | ||
| 84 | log_debug ("iobuf-%d.%d: underflow: A->FILTER (%lu bytes)\n", | ||
| 85 | a->no, a->subno, (ulong)len); | ||
| 86 | |||
| 87 | + tmplen = len; /* Used to check for bugs in the filter. */ | ||
| 88 | rc = a->filter (a->filter_ov, IOBUFCTRL_UNDERFLOW, a->chain, | ||
| 89 | &a->d.buf[a->d.len], &len); | ||
| 90 | + log_assert (len <= tmplen); | ||
| 91 | } | ||
| 92 | } | ||
| 93 | a->d.len += len; | ||
| 94 | diff --git a/g10/armor.c b/g10/armor.c | ||
| 95 | index 81af15339..f8cfa86db 100644 | ||
| 96 | --- a/g10/armor.c | ||
| 97 | +++ b/g10/armor.c | ||
| 98 | @@ -1312,8 +1312,8 @@ armor_filter( void *opaque, int control, | ||
| 99 | n = 0; | ||
| 100 | if( afx->buffer_len ) { | ||
| 101 | /* Copy the data from AFX->BUFFER to BUF. */ | ||
| 102 | - for(; n < size && afx->buffer_pos < afx->buffer_len; n++ ) | ||
| 103 | - buf[n++] = afx->buffer[afx->buffer_pos++]; | ||
| 104 | + for(; n < size && afx->buffer_pos < afx->buffer_len;) | ||
| 105 | + buf[n++] = afx->buffer[afx->buffer_pos++]; | ||
| 106 | if( afx->buffer_pos >= afx->buffer_len ) | ||
| 107 | afx->buffer_len = 0; | ||
| 108 | } | ||
diff --git a/meta/recipes-support/gnupg/gnupg_2.3.7.bb b/meta/recipes-support/gnupg/gnupg_2.3.7.bb index 27b2d3682a..f52ae921d4 100644 --- a/meta/recipes-support/gnupg/gnupg_2.3.7.bb +++ b/meta/recipes-support/gnupg/gnupg_2.3.7.bb | |||
| @@ -23,6 +23,7 @@ SRC_URI = "${GNUPG_MIRROR}/${BPN}/${BPN}-${PV}.tar.bz2 \ | |||
| 23 | file://CVE-2025-30258-0003.patch \ | 23 | file://CVE-2025-30258-0003.patch \ |
| 24 | file://CVE-2025-30258-0004.patch \ | 24 | file://CVE-2025-30258-0004.patch \ |
| 25 | file://CVE-2025-30258-0005.patch \ | 25 | file://CVE-2025-30258-0005.patch \ |
| 26 | file://CVE-2025-68973.patch \ | ||
| 26 | " | 27 | " |
| 27 | SRC_URI:append:class-native = " file://0001-configure.ac-use-a-custom-value-for-the-location-of-.patch \ | 28 | SRC_URI:append:class-native = " file://0001-configure.ac-use-a-custom-value-for-the-location-of-.patch \ |
| 28 | file://relocate.patch" | 29 | file://relocate.patch" |
diff --git a/meta/recipes-support/libsoup/libsoup/CVE-2025-12105.patch b/meta/recipes-support/libsoup/libsoup/CVE-2025-12105.patch new file mode 100644 index 0000000000..9426ef3001 --- /dev/null +++ b/meta/recipes-support/libsoup/libsoup/CVE-2025-12105.patch | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | From 465410f833e4288ad053b4e18d5fa6c3be3148e1 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Eugene Mutavchi <Ievgen_Mutavchi@comcast.com> | ||
| 3 | Date: Fri, 10 Oct 2025 16:24:27 +0000 | ||
| 4 | Subject: [PATCH] fix 'heap-use-after-free' caused by 'finishing' queue item | ||
| 5 | twice | ||
| 6 | |||
| 7 | CVE: CVE-2025-12105 | ||
| 8 | Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libsoup/-/commit/9ba1243a24e442fa5ec44684617a4480027da960] | ||
| 9 | |||
| 10 | Signed-off-by: Changqing Li <changqing.li@windriver.com> | ||
| 11 | --- | ||
| 12 | libsoup/soup-session.c | 6 ++++-- | ||
| 13 | 1 file changed, 4 insertions(+), 2 deletions(-) | ||
| 14 | |||
| 15 | diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c | ||
| 16 | index 5f2929f..b9f3e42 100644 | ||
| 17 | --- a/libsoup/soup-session.c | ||
| 18 | +++ b/libsoup/soup-session.c | ||
| 19 | @@ -3093,8 +3093,10 @@ run_until_read_done (SoupMessage *msg, | ||
| 20 | if (soup_message_io_in_progress (msg)) | ||
| 21 | soup_message_io_finished (msg); | ||
| 22 | item->paused = FALSE; | ||
| 23 | - item->state = SOUP_MESSAGE_FINISHING; | ||
| 24 | - soup_session_process_queue_item (item->session, item, NULL, FALSE); | ||
| 25 | + if (item->state != SOUP_MESSAGE_FINISHED) { | ||
| 26 | + item->state = SOUP_MESSAGE_FINISHING; | ||
| 27 | + soup_session_process_queue_item (item->session, item, NULL, FALSE); | ||
| 28 | + } | ||
| 29 | } | ||
| 30 | async_send_request_return_result (item, NULL, error); | ||
| 31 | } | ||
| 32 | -- | ||
| 33 | 2.34.1 | ||
| 34 | |||
diff --git a/meta/recipes-support/libsoup/libsoup_3.0.7.bb b/meta/recipes-support/libsoup/libsoup_3.0.7.bb index af8554aa78..0f82736727 100644 --- a/meta/recipes-support/libsoup/libsoup_3.0.7.bb +++ b/meta/recipes-support/libsoup/libsoup_3.0.7.bb | |||
| @@ -45,6 +45,7 @@ SRC_URI = "${GNOME_MIRROR}/libsoup/${SHRT_VER}/libsoup-${PV}.tar.xz \ | |||
| 45 | file://CVE-2025-46421.patch \ | 45 | file://CVE-2025-46421.patch \ |
| 46 | file://CVE-2025-4948.patch \ | 46 | file://CVE-2025-4948.patch \ |
| 47 | file://CVE-2025-4945.patch \ | 47 | file://CVE-2025-4945.patch \ |
| 48 | file://CVE-2025-12105.patch \ | ||
| 48 | " | 49 | " |
| 49 | SRC_URI[sha256sum] = "ebdf90cf3599c11acbb6818a9d9e3fc9d2c68e56eb829b93962972683e1bf7c8" | 50 | SRC_URI[sha256sum] = "ebdf90cf3599c11acbb6818a9d9e3fc9d2c68e56eb829b93962972683e1bf7c8" |
| 50 | 51 | ||
diff --git a/meta/recipes-support/libxslt/libxslt/CVE-2025-11731.patch b/meta/recipes-support/libxslt/libxslt/CVE-2025-11731.patch new file mode 100644 index 0000000000..19702af6cb --- /dev/null +++ b/meta/recipes-support/libxslt/libxslt/CVE-2025-11731.patch | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | From fe508f201efb9ea37bfbe95413b8b28251497de3 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: =?UTF-8?q?Dominik=20R=C3=B6ttsches?= <drott@chromium.org> | ||
| 3 | Date: Wed, 27 Aug 2025 14:28:40 +0300 | ||
| 4 | Subject: [PATCH] End function node ancestor search at document | ||
| 5 | |||
| 6 | Avoids dereferencing a non-existent ->ns property on an | ||
| 7 | XML_DOCUMENT_NODE pointer. | ||
| 8 | |||
| 9 | Fixes #151. | ||
| 10 | |||
| 11 | CVE: CVE-2025-11731 | ||
| 12 | |||
| 13 | Upstream-Status: Backport [https://gitlab.gnome.org/GNOME/libxslt/-/commit/fe508f201efb9ea37bfbe95413b8b28251497de3] | ||
| 14 | |||
| 15 | Signed-off-by: Mingli Yu <mingli.yu@windriver.com> | ||
| 16 | --- | ||
| 17 | libexslt/functions.c | 9 +++++++-- | ||
| 18 | 1 file changed, 7 insertions(+), 2 deletions(-) | ||
| 19 | |||
| 20 | diff --git a/libexslt/functions.c b/libexslt/functions.c | ||
| 21 | index 8d35a7ae..a54ee70c 100644 | ||
| 22 | --- a/libexslt/functions.c | ||
| 23 | +++ b/libexslt/functions.c | ||
| 24 | @@ -617,8 +617,13 @@ exsltFuncResultComp (xsltStylesheetPtr style, xmlNodePtr inst, | ||
| 25 | * instanciation of a func:result element. | ||
| 26 | */ | ||
| 27 | for (test = inst->parent; test != NULL; test = test->parent) { | ||
| 28 | - if (IS_XSLT_ELEM(test) && | ||
| 29 | - IS_XSLT_NAME(test, "stylesheet")) { | ||
| 30 | + if (/* Traversal has reached the top-level document without | ||
| 31 | + * finding a func:function ancestor. */ | ||
| 32 | + (test != NULL && test->type == XML_DOCUMENT_NODE) || | ||
| 33 | + /* Traversal reached a stylesheet-namespace node, | ||
| 34 | + * and has left the function namespace. */ | ||
| 35 | + (IS_XSLT_ELEM(test) && | ||
| 36 | + IS_XSLT_NAME(test, "stylesheet"))) { | ||
| 37 | xsltGenericError(xsltGenericErrorContext, | ||
| 38 | "func:result element not a descendant " | ||
| 39 | "of a func:function\n"); | ||
| 40 | -- | ||
| 41 | 2.34.1 | ||
| 42 | |||
diff --git a/meta/recipes-support/libxslt/libxslt_1.1.35.bb b/meta/recipes-support/libxslt/libxslt_1.1.35.bb index fc1fafbf19..4f86069d77 100644 --- a/meta/recipes-support/libxslt/libxslt_1.1.35.bb +++ b/meta/recipes-support/libxslt/libxslt_1.1.35.bb | |||
| @@ -22,6 +22,7 @@ SRC_URI = "${GNOME_MIRROR}/libxslt/1.1/libxslt-${PV}.tar.xz \ | |||
| 22 | file://CVE-2023-40403-004.patch \ | 22 | file://CVE-2023-40403-004.patch \ |
| 23 | file://CVE-2023-40403-005.patch \ | 23 | file://CVE-2023-40403-005.patch \ |
| 24 | file://CVE-2025-7424.patch \ | 24 | file://CVE-2025-7424.patch \ |
| 25 | file://CVE-2025-11731.patch \ | ||
| 25 | " | 26 | " |
| 26 | 27 | ||
| 27 | SRC_URI[sha256sum] = "8247f33e9a872c6ac859aa45018bc4c4d00b97e2feac9eebc10c93ce1f34dd79" | 28 | SRC_URI[sha256sum] = "8247f33e9a872c6ac859aa45018bc4c4d00b97e2feac9eebc10c93ce1f34dd79" |
