* [OE-core][scarthgap 2/8] gnutls: patch CVE-2025-9820
2025-12-02 22:19 [OE-core][scarthgap 0/8] Patch review Steve Sakoman
@ 2025-12-02 22:19 ` Steve Sakoman
2025-12-02 22:19 ` [OE-core][scarthgap 3/8] python3: fix CVE-2025-6075 Steve Sakoman
` (6 subsequent siblings)
7 siblings, 0 replies; 19+ messages in thread
From: Steve Sakoman @ 2025-12-02 22:19 UTC (permalink / raw)
To: openembedded-core
From: Peter Marko <peter.marko@siemens.com>
This CVE is announced under [1].
Pick commit which mentions this CVE per [2].
[1] https://www.gnutls.org/security-new.html#GNUTLS-SA-2025-11-18
[2] https://security-tracker.debian.org/tracker/CVE-2025-9820
Signed-off-by: Peter Marko <peter.marko@siemens.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
---
.../gnutls/gnutls/CVE-2025-9820.patch | 250 ++++++++++++++++++
meta/recipes-support/gnutls/gnutls_3.8.4.bb | 1 +
2 files changed, 251 insertions(+)
create mode 100644 meta/recipes-support/gnutls/gnutls/CVE-2025-9820.patch
diff --git a/meta/recipes-support/gnutls/gnutls/CVE-2025-9820.patch b/meta/recipes-support/gnutls/gnutls/CVE-2025-9820.patch
new file mode 100644
index 0000000000..99a6c11ee4
--- /dev/null
+++ b/meta/recipes-support/gnutls/gnutls/CVE-2025-9820.patch
@@ -0,0 +1,250 @@
+From 1d56f96f6ab5034d677136b9d50b5a75dff0faf5 Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <ueno@gnu.org>
+Date: Tue, 18 Nov 2025 13:17:55 +0900
+Subject: [PATCH] pkcs11: avoid stack overwrite when initializing a token
+
+If gnutls_pkcs11_token_init is called with label longer than 32
+characters, the internal storage used to blank-fill it would
+overflow. This adds a guard to prevent that.
+
+Signed-off-by: Daiki Ueno <ueno@gnu.org>
+
+CVE: CVE-2025-9820
+Upstream-Status: Backport [https://gitlab.com/gnutls/gnutls/-/commit/1d56f96f6ab5034d677136b9d50b5a75dff0faf5]
+Signed-off-by: Peter Marko <peter.marko@siemens.com>
+---
+ NEWS | 4 +
+ lib/pkcs11_write.c | 5 +-
+ tests/Makefile.am | 2 +-
+ tests/pkcs11/long-label.c | 164 ++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 172 insertions(+), 3 deletions(-)
+ create mode 100644 tests/pkcs11/long-label.c
+
+diff --git a/NEWS b/NEWS
+index 0ae3c9991..d6df70ee6 100644
+--- a/NEWS
++++ b/NEWS
+@@ -5,6 +5,10 @@ Copyright (C) 2000-2016 Free Software Foundation, Inc.
+ Copyright (C) 2013-2019 Nikos Mavrogiannopoulos
+ See the end for copying conditions.
+
++** libgnutls: Fix stack overwrite in gnutls_pkcs11_token_init
++ Reported by Luigino Camastra from Aisle Research. [GNUTLS-SA-2025-11-18,
++ CVSS: low] [CVE-2025-9820]
++
+ ** libgnutls: Fix NULL pointer dereference when 2nd Client Hello omits PSK
+ Reported by Stefan Bühler. [GNUTLS-SA-2025-07-07-4, CVSS: medium]
+ [CVE-2025-6395]
+diff --git a/lib/pkcs11_write.c b/lib/pkcs11_write.c
+index f5e9058e0..64b85a2df 100644
+--- a/lib/pkcs11_write.c
++++ b/lib/pkcs11_write.c
+@@ -28,6 +28,7 @@
+ #include "pkcs11x.h"
+ #include "x509/common.h"
+ #include "pk.h"
++#include "minmax.h"
+
+ static const ck_bool_t tval = 1;
+ static const ck_bool_t fval = 0;
+@@ -1173,7 +1174,7 @@ int gnutls_pkcs11_delete_url(const char *object_url, unsigned int flags)
+ * gnutls_pkcs11_token_init:
+ * @token_url: A PKCS #11 URL specifying a token
+ * @so_pin: Security Officer's PIN
+- * @label: A name to be used for the token
++ * @label: A name to be used for the token, at most 32 characters
+ *
+ * This function will initialize (format) a token. If the token is
+ * at a factory defaults state the security officer's PIN given will be
+@@ -1211,7 +1212,7 @@ int gnutls_pkcs11_token_init(const char *token_url, const char *so_pin,
+ /* so it seems memset has other uses than zeroing! */
+ memset(flabel, ' ', sizeof(flabel));
+ if (label != NULL)
+- memcpy(flabel, label, strlen(label));
++ memcpy(flabel, label, MIN(sizeof(flabel), strlen(label)));
+
+ rv = pkcs11_init_token(module, slot, (uint8_t *)so_pin, strlen(so_pin),
+ (uint8_t *)flabel);
+diff --git a/tests/Makefile.am b/tests/Makefile.am
+index be4966f4b..8327c90ca 100644
+--- a/tests/Makefile.am
++++ b/tests/Makefile.am
+@@ -496,7 +496,7 @@ pathbuf_CPPFLAGS = $(AM_CPPFLAGS) \
+ if ENABLE_PKCS11
+ if !WINDOWS
+ ctests += tls13/post-handshake-with-cert-pkcs11 pkcs11/tls-neg-pkcs11-no-key \
+- global-init-override pkcs11/distrust-after
++ global-init-override pkcs11/distrust-after pkcs11/long-label
+ tls13_post_handshake_with_cert_pkcs11_DEPENDENCIES = libpkcs11mock2.la libutils.la
+ tls13_post_handshake_with_cert_pkcs11_LDADD = $(LDADD) $(LIBDL)
+ pkcs11_tls_neg_pkcs11_no_key_DEPENDENCIES = libpkcs11mock2.la libutils.la
+diff --git a/tests/pkcs11/long-label.c b/tests/pkcs11/long-label.c
+new file mode 100644
+index 000000000..a70bc9728
+--- /dev/null
++++ b/tests/pkcs11/long-label.c
+@@ -0,0 +1,164 @@
++/*
++ * Copyright (C) 2025 Red Hat, Inc.
++ *
++ * Author: Daiki Ueno
++ *
++ * This file is part of GnuTLS.
++ *
++ * GnuTLS is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * GnuTLS is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public License
++ * along with this program. If not, see <https://www.gnu.org/licenses/>
++ */
++
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
++#include <stdbool.h>
++#include <stdio.h>
++#include <stdlib.h>
++
++#if defined(_WIN32)
++
++int main(void)
++{
++ exit(77);
++}
++
++#else
++
++#include <string.h>
++#include <unistd.h>
++#include <gnutls/gnutls.h>
++
++#include "cert-common.h"
++#include "pkcs11/softhsm.h"
++#include "utils.h"
++
++/* This program tests that a token can be initialized with
++ * a label longer than 32 characters.
++ */
++
++static void tls_log_func(int level, const char *str)
++{
++ fprintf(stderr, "server|<%d>| %s", level, str);
++}
++
++#define PIN "1234"
++
++#define CONFIG_NAME "softhsm-long-label"
++#define CONFIG CONFIG_NAME ".config"
++
++static int pin_func(void *userdata, int attempt, const char *url,
++ const char *label, unsigned flags, char *pin,
++ size_t pin_max)
++{
++ if (attempt == 0) {
++ strcpy(pin, PIN);
++ return 0;
++ }
++ return -1;
++}
++
++static void test(const char *provider)
++{
++ int ret;
++ size_t i;
++
++ gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL);
++
++ success("test with %s\n", provider);
++
++ if (debug) {
++ gnutls_global_set_log_function(tls_log_func);
++ gnutls_global_set_log_level(4711);
++ }
++
++ /* point to SoftHSM token that libpkcs11mock4.so internally uses */
++ setenv(SOFTHSM_ENV, CONFIG, 1);
++
++ gnutls_pkcs11_set_pin_function(pin_func, NULL);
++
++ ret = gnutls_pkcs11_add_provider(provider, "trusted");
++ if (ret != 0) {
++ fail("gnutls_pkcs11_add_provider: %s\n", gnutls_strerror(ret));
++ }
++
++ /* initialize softhsm token */
++ ret = gnutls_pkcs11_token_init(
++ SOFTHSM_URL, PIN,
++ "this is a very long label whose length exceeds 32");
++ if (ret < 0) {
++ fail("gnutls_pkcs11_token_init: %s\n", gnutls_strerror(ret));
++ }
++
++ for (i = 0;; i++) {
++ char *url = NULL;
++
++ ret = gnutls_pkcs11_token_get_url(i, 0, &url);
++ if (ret < 0)
++ break;
++ if (strstr(url,
++ "token=this%20is%20a%20very%20long%20label%20whose"))
++ break;
++ }
++ if (ret < 0)
++ fail("gnutls_pkcs11_token_get_url: %s\n", gnutls_strerror(ret));
++
++ gnutls_pkcs11_deinit();
++}
++
++void doit(void)
++{
++ const char *bin;
++ const char *lib;
++ char buf[128];
++
++ if (gnutls_fips140_mode_enabled())
++ exit(77);
++
++ /* this must be called once in the program */
++ global_init();
++
++ /* we call gnutls_pkcs11_init manually */
++ gnutls_pkcs11_deinit();
++
++ /* check if softhsm module is loadable */
++ lib = softhsm_lib();
++
++ /* initialize SoftHSM token that libpkcs11mock4.so internally uses */
++ bin = softhsm_bin();
++
++ set_softhsm_conf(CONFIG);
++ snprintf(buf, sizeof(buf),
++ "%s --init-token --slot 0 --label test --so-pin " PIN
++ " --pin " PIN,
++ bin);
++ system(buf);
++
++ test(lib);
++
++ lib = getenv("P11MOCKLIB4");
++ if (lib == NULL) {
++ fail("P11MOCKLIB4 is not set\n");
++ }
++
++ set_softhsm_conf(CONFIG);
++ snprintf(buf, sizeof(buf),
++ "%s --init-token --slot 0 --label test --so-pin " PIN
++ " --pin " PIN,
++ bin);
++ system(buf);
++
++ test(lib);
++}
++#endif /* _WIN32 */
diff --git a/meta/recipes-support/gnutls/gnutls_3.8.4.bb b/meta/recipes-support/gnutls/gnutls_3.8.4.bb
index dde3bc3014..026ae650f6 100644
--- a/meta/recipes-support/gnutls/gnutls_3.8.4.bb
+++ b/meta/recipes-support/gnutls/gnutls_3.8.4.bb
@@ -33,6 +33,7 @@ SRC_URI = "https://www.gnupg.org/ftp/gcrypt/gnutls/v${SHRT_VER}/gnutls-${PV}.tar
file://CVE-2025-32988.patch \
file://CVE-2025-32990.patch \
file://CVE-2025-6395.patch \
+ file://CVE-2025-9820.patch \
"
SRC_URI[sha256sum] = "2bea4e154794f3f00180fa2a5c51fe8b005ac7a31cd58bd44cdfa7f36ebc3a9b"
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [OE-core][scarthgap 3/8] python3: fix CVE-2025-6075
2025-12-02 22:19 [OE-core][scarthgap 0/8] Patch review Steve Sakoman
2025-12-02 22:19 ` [OE-core][scarthgap 2/8] gnutls: patch CVE-2025-9820 Steve Sakoman
@ 2025-12-02 22:19 ` Steve Sakoman
2025-12-02 22:19 ` [OE-core][scarthgap 4/8] libpng: patch CVE-2025-64505 Steve Sakoman
` (5 subsequent siblings)
7 siblings, 0 replies; 19+ messages in thread
From: Steve Sakoman @ 2025-12-02 22:19 UTC (permalink / raw)
To: openembedded-core
From: Praveen Kumar <praveen.kumar@windriver.com>
If the value passed to os.path.expandvars() is user-controlled a
performance degradation is possible when expanding environment variables.
Reference:
https://nvd.nist.gov/vuln/detail/CVE-2025-6075
Upstream-patch:
https://github.com/python/cpython/commit/9ab89c026aa9611c4b0b67c288b8303a480fe742
Signed-off-by: Praveen Kumar <praveen.kumar@windriver.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
---
.../python/python3/CVE-2025-6075.patch | 355 ++++++++++++++++++
.../python/python3_3.12.12.bb | 1 +
2 files changed, 356 insertions(+)
create mode 100644 meta/recipes-devtools/python/python3/CVE-2025-6075.patch
diff --git a/meta/recipes-devtools/python/python3/CVE-2025-6075.patch b/meta/recipes-devtools/python/python3/CVE-2025-6075.patch
new file mode 100644
index 0000000000..346af4df94
--- /dev/null
+++ b/meta/recipes-devtools/python/python3/CVE-2025-6075.patch
@@ -0,0 +1,355 @@
+From 9ab89c026aa9611c4b0b67c288b8303a480fe742 Mon Sep 17 00:00:00 2001
+From: Łukasz Langa <lukasz@langa.pl>
+Date: Fri, 31 Oct 2025 17:58:09 +0100
+Subject: [PATCH] gh-136065: Fix quadratic complexity in os.path.expandvars()
+ (GH-134952) (GH-140845)
+
+(cherry picked from commit f029e8db626ddc6e3a3beea4eff511a71aaceb5c)
+
+Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
+Co-authored-by: Łukasz Langa <lukasz@langa.pl>
+
+CVE: CVE-2025-6075
+
+Upstream-Status: Backport [https://github.com/python/cpython/commit/9ab89c026aa9611c4b0b67c288b8303a480fe742]
+
+Signed-off-by: Praveen Kumar <praveen.kumar@windriver.com>
+---
+ Lib/ntpath.py | 126 ++++++------------
+ Lib/posixpath.py | 43 +++---
+ Lib/test/test_genericpath.py | 14 ++
+ Lib/test/test_ntpath.py | 18 ++-
+ ...-05-30-22-33-27.gh-issue-136065.bu337o.rst | 1 +
+ 5 files changed, 92 insertions(+), 110 deletions(-)
+ create mode 100644 Misc/NEWS.d/next/Security/2025-05-30-22-33-27.gh-issue-136065.bu337o.rst
+
+diff --git a/Lib/ntpath.py b/Lib/ntpath.py
+index 1bef630..393d358 100644
+--- a/Lib/ntpath.py
++++ b/Lib/ntpath.py
+@@ -409,17 +409,23 @@ def expanduser(path):
+ # XXX With COMMAND.COM you can use any characters in a variable name,
+ # XXX except '^|<>='.
+
++_varpattern = r"'[^']*'?|%(%|[^%]*%?)|\$(\$|[-\w]+|\{[^}]*\}?)"
++_varsub = None
++_varsubb = None
++
+ def expandvars(path):
+ """Expand shell variables of the forms $var, ${var} and %var%.
+
+ Unknown variables are left unchanged."""
+ path = os.fspath(path)
++ global _varsub, _varsubb
+ if isinstance(path, bytes):
+ if b'$' not in path and b'%' not in path:
+ return path
+- import string
+- varchars = bytes(string.ascii_letters + string.digits + '_-', 'ascii')
+- quote = b'\''
++ if not _varsubb:
++ import re
++ _varsubb = re.compile(_varpattern.encode(), re.ASCII).sub
++ sub = _varsubb
+ percent = b'%'
+ brace = b'{'
+ rbrace = b'}'
+@@ -428,94 +434,44 @@ def expandvars(path):
+ else:
+ if '$' not in path and '%' not in path:
+ return path
+- import string
+- varchars = string.ascii_letters + string.digits + '_-'
+- quote = '\''
++ if not _varsub:
++ import re
++ _varsub = re.compile(_varpattern, re.ASCII).sub
++ sub = _varsub
+ percent = '%'
+ brace = '{'
+ rbrace = '}'
+ dollar = '$'
+ environ = os.environ
+- res = path[:0]
+- index = 0
+- pathlen = len(path)
+- while index < pathlen:
+- c = path[index:index+1]
+- if c == quote: # no expansion within single quotes
+- path = path[index + 1:]
+- pathlen = len(path)
+- try:
+- index = path.index(c)
+- res += c + path[:index + 1]
+- except ValueError:
+- res += c + path
+- index = pathlen - 1
+- elif c == percent: # variable or '%'
+- if path[index + 1:index + 2] == percent:
+- res += c
+- index += 1
+- else:
+- path = path[index+1:]
+- pathlen = len(path)
+- try:
+- index = path.index(percent)
+- except ValueError:
+- res += percent + path
+- index = pathlen - 1
+- else:
+- var = path[:index]
+- try:
+- if environ is None:
+- value = os.fsencode(os.environ[os.fsdecode(var)])
+- else:
+- value = environ[var]
+- except KeyError:
+- value = percent + var + percent
+- res += value
+- elif c == dollar: # variable or '$$'
+- if path[index + 1:index + 2] == dollar:
+- res += c
+- index += 1
+- elif path[index + 1:index + 2] == brace:
+- path = path[index+2:]
+- pathlen = len(path)
+- try:
+- index = path.index(rbrace)
+- except ValueError:
+- res += dollar + brace + path
+- index = pathlen - 1
+- else:
+- var = path[:index]
+- try:
+- if environ is None:
+- value = os.fsencode(os.environ[os.fsdecode(var)])
+- else:
+- value = environ[var]
+- except KeyError:
+- value = dollar + brace + var + rbrace
+- res += value
+- else:
+- var = path[:0]
+- index += 1
+- c = path[index:index + 1]
+- while c and c in varchars:
+- var += c
+- index += 1
+- c = path[index:index + 1]
+- try:
+- if environ is None:
+- value = os.fsencode(os.environ[os.fsdecode(var)])
+- else:
+- value = environ[var]
+- except KeyError:
+- value = dollar + var
+- res += value
+- if c:
+- index -= 1
++
++ def repl(m):
++ lastindex = m.lastindex
++ if lastindex is None:
++ return m[0]
++ name = m[lastindex]
++ if lastindex == 1:
++ if name == percent:
++ return name
++ if not name.endswith(percent):
++ return m[0]
++ name = name[:-1]
+ else:
+- res += c
+- index += 1
+- return res
++ if name == dollar:
++ return name
++ if name.startswith(brace):
++ if not name.endswith(rbrace):
++ return m[0]
++ name = name[1:-1]
++
++ try:
++ if environ is None:
++ return os.fsencode(os.environ[os.fsdecode(name)])
++ else:
++ return environ[name]
++ except KeyError:
++ return m[0]
++
++ return sub(repl, path)
+
+
+ # Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B.
+diff --git a/Lib/posixpath.py b/Lib/posixpath.py
+index 90a6f54..6306f14 100644
+--- a/Lib/posixpath.py
++++ b/Lib/posixpath.py
+@@ -314,42 +314,41 @@ def expanduser(path):
+ # This expands the forms $variable and ${variable} only.
+ # Non-existent variables are left unchanged.
+
+-_varprog = None
+-_varprogb = None
++_varpattern = r'\$(\w+|\{[^}]*\}?)'
++_varsub = None
++_varsubb = None
+
+ def expandvars(path):
+ """Expand shell variables of form $var and ${var}. Unknown variables
+ are left unchanged."""
+ path = os.fspath(path)
+- global _varprog, _varprogb
++ global _varsub, _varsubb
+ if isinstance(path, bytes):
+ if b'$' not in path:
+ return path
+- if not _varprogb:
++ if not _varsubb:
+ import re
+- _varprogb = re.compile(br'\$(\w+|\{[^}]*\})', re.ASCII)
+- search = _varprogb.search
++ _varsubb = re.compile(_varpattern.encode(), re.ASCII).sub
++ sub = _varsubb
+ start = b'{'
+ end = b'}'
+ environ = getattr(os, 'environb', None)
+ else:
+ if '$' not in path:
+ return path
+- if not _varprog:
++ if not _varsub:
+ import re
+- _varprog = re.compile(r'\$(\w+|\{[^}]*\})', re.ASCII)
+- search = _varprog.search
++ _varsub = re.compile(_varpattern, re.ASCII).sub
++ sub = _varsub
+ start = '{'
+ end = '}'
+ environ = os.environ
+- i = 0
+- while True:
+- m = search(path, i)
+- if not m:
+- break
+- i, j = m.span(0)
+- name = m.group(1)
+- if name.startswith(start) and name.endswith(end):
++
++ def repl(m):
++ name = m[1]
++ if name.startswith(start):
++ if not name.endswith(end):
++ return m[0]
+ name = name[1:-1]
+ try:
+ if environ is None:
+@@ -357,13 +356,11 @@ def expandvars(path):
+ else:
+ value = environ[name]
+ except KeyError:
+- i = j
++ return m[0]
+ else:
+- tail = path[j:]
+- path = path[:i] + value
+- i = len(path)
+- path += tail
+- return path
++ return value
++
++ return sub(repl, path)
+
+
+ # Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
+diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py
+index 3eefb72..1cec587 100644
+--- a/Lib/test/test_genericpath.py
++++ b/Lib/test/test_genericpath.py
+@@ -7,6 +7,7 @@ import os
+ import sys
+ import unittest
+ import warnings
++from test import support
+ from test.support import is_emscripten
+ from test.support import os_helper
+ from test.support import warnings_helper
+@@ -443,6 +444,19 @@ class CommonTest(GenericTest):
+ os.fsencode('$bar%s bar' % nonascii))
+ check(b'$spam}bar', os.fsencode('%s}bar' % nonascii))
+
++ @support.requires_resource('cpu')
++ def test_expandvars_large(self):
++ expandvars = self.pathmodule.expandvars
++ with os_helper.EnvironmentVarGuard() as env:
++ env.clear()
++ env["A"] = "B"
++ n = 100_000
++ self.assertEqual(expandvars('$A'*n), 'B'*n)
++ self.assertEqual(expandvars('${A}'*n), 'B'*n)
++ self.assertEqual(expandvars('$A!'*n), 'B!'*n)
++ self.assertEqual(expandvars('${A}A'*n), 'BA'*n)
++ self.assertEqual(expandvars('${'*10*n), '${'*10*n)
++
+ def test_abspath(self):
+ self.assertIn("foo", self.pathmodule.abspath("foo"))
+ with warnings.catch_warnings():
+diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py
+index ced9dc4..f4d5063 100644
+--- a/Lib/test/test_ntpath.py
++++ b/Lib/test/test_ntpath.py
+@@ -7,6 +7,7 @@ import sys
+ import unittest
+ import warnings
+ from ntpath import ALLOW_MISSING
++from test import support
+ from test.support import cpython_only, os_helper
+ from test.support import TestFailed, is_emscripten
+ from test.support.os_helper import FakePath
+@@ -58,7 +59,7 @@ def tester(fn, wantResult):
+ fn = fn.replace("\\", "\\\\")
+ gotResult = eval(fn)
+ if wantResult != gotResult and _norm(wantResult) != _norm(gotResult):
+- raise TestFailed("%s should return: %s but returned: %s" \
++ raise support.TestFailed("%s should return: %s but returned: %s" \
+ %(str(fn), str(wantResult), str(gotResult)))
+
+ # then with bytes
+@@ -74,7 +75,7 @@ def tester(fn, wantResult):
+ warnings.simplefilter("ignore", DeprecationWarning)
+ gotResult = eval(fn)
+ if _norm(wantResult) != _norm(gotResult):
+- raise TestFailed("%s should return: %s but returned: %s" \
++ raise support.TestFailed("%s should return: %s but returned: %s" \
+ %(str(fn), str(wantResult), repr(gotResult)))
+
+
+@@ -882,6 +883,19 @@ class TestNtpath(NtpathTestCase):
+ check('%spam%bar', '%sbar' % nonascii)
+ check('%{}%bar'.format(nonascii), 'ham%sbar' % nonascii)
+
++ @support.requires_resource('cpu')
++ def test_expandvars_large(self):
++ expandvars = ntpath.expandvars
++ with os_helper.EnvironmentVarGuard() as env:
++ env.clear()
++ env["A"] = "B"
++ n = 100_000
++ self.assertEqual(expandvars('%A%'*n), 'B'*n)
++ self.assertEqual(expandvars('%A%A'*n), 'BA'*n)
++ self.assertEqual(expandvars("''"*n + '%%'), "''"*n + '%')
++ self.assertEqual(expandvars("%%"*n), "%"*n)
++ self.assertEqual(expandvars("$$"*n), "$"*n)
++
+ def test_expanduser(self):
+ tester('ntpath.expanduser("test")', 'test')
+
+diff --git a/Misc/NEWS.d/next/Security/2025-05-30-22-33-27.gh-issue-136065.bu337o.rst b/Misc/NEWS.d/next/Security/2025-05-30-22-33-27.gh-issue-136065.bu337o.rst
+new file mode 100644
+index 0000000..1d152bb
+--- /dev/null
++++ b/Misc/NEWS.d/next/Security/2025-05-30-22-33-27.gh-issue-136065.bu337o.rst
+@@ -0,0 +1 @@
++Fix quadratic complexity in :func:`os.path.expandvars`.
+--
+2.40.0
diff --git a/meta/recipes-devtools/python/python3_3.12.12.bb b/meta/recipes-devtools/python/python3_3.12.12.bb
index 9a957c59bc..b70f434ca9 100644
--- a/meta/recipes-devtools/python/python3_3.12.12.bb
+++ b/meta/recipes-devtools/python/python3_3.12.12.bb
@@ -34,6 +34,7 @@ SRC_URI = "http://www.python.org/ftp/python/${PV}/Python-${PV}.tar.xz \
file://0001-test_deadlock-skip-problematic-test.patch \
file://0001-test_active_children-skip-problematic-test.patch \
file://0001-test_readline-skip-limited-history-test.patch \
+ file://CVE-2025-6075.patch \
"
SRC_URI:append:class-native = " \
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [OE-core][scarthgap 4/8] libpng: patch CVE-2025-64505
2025-12-02 22:19 [OE-core][scarthgap 0/8] Patch review Steve Sakoman
2025-12-02 22:19 ` [OE-core][scarthgap 2/8] gnutls: patch CVE-2025-9820 Steve Sakoman
2025-12-02 22:19 ` [OE-core][scarthgap 3/8] python3: fix CVE-2025-6075 Steve Sakoman
@ 2025-12-02 22:19 ` Steve Sakoman
2025-12-02 22:19 ` [OE-core][scarthgap 5/8] libpng: patch CVE-2025-64506 Steve Sakoman
` (4 subsequent siblings)
7 siblings, 0 replies; 19+ messages in thread
From: Steve Sakoman @ 2025-12-02 22:19 UTC (permalink / raw)
To: openembedded-core
From: Peter Marko <peter.marko@siemens.com>
Pick commit per NVD report.
Add two patches to apply it cleanly.
Signed-off-by: Peter Marko <peter.marko@siemens.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
---
.../libpng/files/CVE-2025-64505-01.patch | 111 ++++++++++++
.../libpng/files/CVE-2025-64505-02.patch | 163 ++++++++++++++++++
.../libpng/files/CVE-2025-64505-03.patch | 52 ++++++
.../libpng/libpng_1.6.42.bb | 3 +
4 files changed, 329 insertions(+)
create mode 100644 meta/recipes-multimedia/libpng/files/CVE-2025-64505-01.patch
create mode 100644 meta/recipes-multimedia/libpng/files/CVE-2025-64505-02.patch
create mode 100644 meta/recipes-multimedia/libpng/files/CVE-2025-64505-03.patch
diff --git a/meta/recipes-multimedia/libpng/files/CVE-2025-64505-01.patch b/meta/recipes-multimedia/libpng/files/CVE-2025-64505-01.patch
new file mode 100644
index 0000000000..1e7d122803
--- /dev/null
+++ b/meta/recipes-multimedia/libpng/files/CVE-2025-64505-01.patch
@@ -0,0 +1,111 @@
+From 0fa3c0f698c2ca618a0fa44e10a822678df85373 Mon Sep 17 00:00:00 2001
+From: Cosmin Truta <ctruta@gmail.com>
+Date: Thu, 15 Feb 2024 21:53:24 +0200
+Subject: [PATCH] chore: Clean up the spurious uses of `sizeof(png_byte)`; fix
+ the manual
+
+By definition, `sizeof(png_byte)` is 1.
+
+Remove all the occurences of `sizeof(png_byte)` from the code, and fix
+a related typo in the libpng manual.
+
+Also update the main .editorconfig file to reflect the fixing expected
+by a FIXME note.
+
+CVE: CVE-2025-64505
+Upstream-Status: Backport [https://github.com/pnggroup/libpng/commit/0fa3c0f698c2ca618a0fa44e10a822678df85373]
+Signed-off-by: Peter Marko <peter.marko@siemens.com>
+---
+ libpng-manual.txt | 4 ++--
+ libpng.3 | 4 ++--
+ pngrtran.c | 17 +++++++----------
+ 3 files changed, 11 insertions(+), 14 deletions(-)
+
+diff --git a/libpng-manual.txt b/libpng-manual.txt
+index eb24ef483..d2918ce31 100644
+--- a/libpng-manual.txt
++++ b/libpng-manual.txt
+@@ -1178,11 +1178,11 @@ where row_pointers is an array of pointers to the pixel data for each row:
+ If you know your image size and pixel size ahead of time, you can allocate
+ row_pointers prior to calling png_read_png() with
+
+- if (height > PNG_UINT_32_MAX/(sizeof (png_byte)))
++ if (height > PNG_UINT_32_MAX / (sizeof (png_bytep)))
+ png_error(png_ptr,
+ "Image is too tall to process in memory");
+
+- if (width > PNG_UINT_32_MAX/pixel_size)
++ if (width > PNG_UINT_32_MAX / pixel_size)
+ png_error(png_ptr,
+ "Image is too wide to process in memory");
+
+diff --git a/libpng.3 b/libpng.3
+index 57d06f2db..8875b219a 100644
+--- a/libpng.3
++++ b/libpng.3
+@@ -1697,11 +1697,11 @@ where row_pointers is an array of pointers to the pixel data for each row:
+ If you know your image size and pixel size ahead of time, you can allocate
+ row_pointers prior to calling png_read_png() with
+
+- if (height > PNG_UINT_32_MAX/(sizeof (png_byte)))
++ if (height > PNG_UINT_32_MAX / (sizeof (png_bytep)))
+ png_error(png_ptr,
+ "Image is too tall to process in memory");
+
+- if (width > PNG_UINT_32_MAX/pixel_size)
++ if (width > PNG_UINT_32_MAX / pixel_size)
+ png_error(png_ptr,
+ "Image is too wide to process in memory");
+
+diff --git a/pngrtran.c b/pngrtran.c
+index 74cca476b..041f9306c 100644
+--- a/pngrtran.c
++++ b/pngrtran.c
+@@ -441,7 +441,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
+ int i;
+
+ png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr,
+- (png_alloc_size_t)((png_uint_32)num_palette * (sizeof (png_byte))));
++ (png_alloc_size_t)num_palette);
+ for (i = 0; i < num_palette; i++)
+ png_ptr->quantize_index[i] = (png_byte)i;
+ }
+@@ -458,7 +458,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
+
+ /* Initialize an array to sort colors */
+ png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr,
+- (png_alloc_size_t)((png_uint_32)num_palette * (sizeof (png_byte))));
++ (png_alloc_size_t)num_palette);
+
+ /* Initialize the quantize_sort array */
+ for (i = 0; i < num_palette; i++)
+@@ -592,11 +592,9 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
+
+ /* Initialize palette index arrays */
+ png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr,
+- (png_alloc_size_t)((png_uint_32)num_palette *
+- (sizeof (png_byte))));
++ (png_alloc_size_t)num_palette);
+ png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr,
+- (png_alloc_size_t)((png_uint_32)num_palette *
+- (sizeof (png_byte))));
++ (png_alloc_size_t)num_palette);
+
+ /* Initialize the sort array */
+ for (i = 0; i < num_palette; i++)
+@@ -761,12 +759,11 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
+ size_t num_entries = ((size_t)1 << total_bits);
+
+ png_ptr->palette_lookup = (png_bytep)png_calloc(png_ptr,
+- (png_alloc_size_t)(num_entries * (sizeof (png_byte))));
++ (png_alloc_size_t)(num_entries));
+
+- distance = (png_bytep)png_malloc(png_ptr, (png_alloc_size_t)(num_entries *
+- (sizeof (png_byte))));
++ distance = (png_bytep)png_malloc(png_ptr, (png_alloc_size_t)num_entries);
+
+- memset(distance, 0xff, num_entries * (sizeof (png_byte)));
++ memset(distance, 0xff, num_entries);
+
+ for (i = 0; i < num_palette; i++)
+ {
diff --git a/meta/recipes-multimedia/libpng/files/CVE-2025-64505-02.patch b/meta/recipes-multimedia/libpng/files/CVE-2025-64505-02.patch
new file mode 100644
index 0000000000..5a3e50b642
--- /dev/null
+++ b/meta/recipes-multimedia/libpng/files/CVE-2025-64505-02.patch
@@ -0,0 +1,163 @@
+From ea094764f3436e3c6524622724c2d342a3eff235 Mon Sep 17 00:00:00 2001
+From: Cosmin Truta <ctruta@gmail.com>
+Date: Sat, 8 Nov 2025 17:16:59 +0200
+Subject: [PATCH] Fix a memory leak in function `png_set_quantize`; refactor
+
+Release the previously-allocated array `quantize_index` before
+reallocating it. This avoids leaking memory when the function
+`png_set_quantize` is called multiple times on the same `png_struct`.
+
+This function assumed single-call usage, but fuzzing revealed that
+repeated calls would overwrite the pointers without freeing the
+original allocations, leaking 256 bytes per call for `quantize_index`
+and additional memory for `quantize_sort` when histogram-based
+quantization is used.
+
+Also remove the array `quantize_sort` from the list of `png_struct`
+members and make it a local variable. This array is initialized,
+used and released exclusively inside the function `png_set_quantize`.
+
+Reported-by: Samsung-PENTEST <Samsung-PENTEST@users.noreply.github.com>
+Analyzed-by: degrigis <degrigis@users.noreply.github.com>
+Reviewed-by: John Bowler <jbowler@acm.org>
+
+CVE: CVE-2025-64505
+Upstream-Status: Backport [https://github.com/pnggroup/libpng/commit/ea094764f3436e3c6524622724c2d342a3eff235]
+Signed-off-by: Peter Marko <peter.marko@siemens.com>
+---
+ pngrtran.c | 43 +++++++++++++++++++++++--------------------
+ pngstruct.h | 1 -
+ 2 files changed, 23 insertions(+), 21 deletions(-)
+
+diff --git a/pngrtran.c b/pngrtran.c
+index 1809db704..4632dd521 100644
+--- a/pngrtran.c
++++ b/pngrtran.c
+@@ -440,6 +440,12 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
+ {
+ int i;
+
++ /* Initialize the array to index colors.
++ *
++ * Be careful to avoid leaking memory. Applications are allowed to call
++ * this function more than once per png_struct.
++ */
++ png_free(png_ptr, png_ptr->quantize_index);
+ png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr,
+ (png_alloc_size_t)num_palette);
+ for (i = 0; i < num_palette; i++)
+@@ -454,15 +460,14 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
+ * Perhaps not the best solution, but good enough.
+ */
+
+- int i;
++ png_bytep quantize_sort;
++ int i, j;
+
+- /* Initialize an array to sort colors */
+- png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr,
++ /* Initialize the local array to sort colors. */
++ quantize_sort = (png_bytep)png_malloc(png_ptr,
+ (png_alloc_size_t)num_palette);
+-
+- /* Initialize the quantize_sort array */
+ for (i = 0; i < num_palette; i++)
+- png_ptr->quantize_sort[i] = (png_byte)i;
++ quantize_sort[i] = (png_byte)i;
+
+ /* Find the least used palette entries by starting a
+ * bubble sort, and running it until we have sorted
+@@ -474,19 +479,18 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
+ for (i = num_palette - 1; i >= maximum_colors; i--)
+ {
+ int done; /* To stop early if the list is pre-sorted */
+- int j;
+
+ done = 1;
+ for (j = 0; j < i; j++)
+ {
+- if (histogram[png_ptr->quantize_sort[j]]
+- < histogram[png_ptr->quantize_sort[j + 1]])
++ if (histogram[quantize_sort[j]]
++ < histogram[quantize_sort[j + 1]])
+ {
+ png_byte t;
+
+- t = png_ptr->quantize_sort[j];
+- png_ptr->quantize_sort[j] = png_ptr->quantize_sort[j + 1];
+- png_ptr->quantize_sort[j + 1] = t;
++ t = quantize_sort[j];
++ quantize_sort[j] = quantize_sort[j + 1];
++ quantize_sort[j + 1] = t;
+ done = 0;
+ }
+ }
+@@ -498,18 +502,18 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
+ /* Swap the palette around, and set up a table, if necessary */
+ if (full_quantize != 0)
+ {
+- int j = num_palette;
++ j = num_palette;
+
+ /* Put all the useful colors within the max, but don't
+ * move the others.
+ */
+ for (i = 0; i < maximum_colors; i++)
+ {
+- if ((int)png_ptr->quantize_sort[i] >= maximum_colors)
++ if ((int)quantize_sort[i] >= maximum_colors)
+ {
+ do
+ j--;
+- while ((int)png_ptr->quantize_sort[j] >= maximum_colors);
++ while ((int)quantize_sort[j] >= maximum_colors);
+
+ palette[i] = palette[j];
+ }
+@@ -517,7 +521,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
+ }
+ else
+ {
+- int j = num_palette;
++ j = num_palette;
+
+ /* Move all the used colors inside the max limit, and
+ * develop a translation table.
+@@ -525,13 +529,13 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
+ for (i = 0; i < maximum_colors; i++)
+ {
+ /* Only move the colors we need to */
+- if ((int)png_ptr->quantize_sort[i] >= maximum_colors)
++ if ((int)quantize_sort[i] >= maximum_colors)
+ {
+ png_color tmp_color;
+
+ do
+ j--;
+- while ((int)png_ptr->quantize_sort[j] >= maximum_colors);
++ while ((int)quantize_sort[j] >= maximum_colors);
+
+ tmp_color = palette[j];
+ palette[j] = palette[i];
+@@ -569,8 +573,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
+ }
+ }
+ }
+- png_free(png_ptr, png_ptr->quantize_sort);
+- png_ptr->quantize_sort = NULL;
++ png_free(png_ptr, quantize_sort);
+ }
+ else
+ {
+diff --git a/pngstruct.h b/pngstruct.h
+index 084422bc1..fe5fa0415 100644
+--- a/pngstruct.h
++++ b/pngstruct.h
+@@ -413,7 +413,6 @@ struct png_struct_def
+
+ #ifdef PNG_READ_QUANTIZE_SUPPORTED
+ /* The following three members were added at version 1.0.14 and 1.2.4 */
+- png_bytep quantize_sort; /* working sort array */
+ png_bytep index_to_palette; /* where the original index currently is
+ in the palette */
+ png_bytep palette_to_index; /* which original index points to this
diff --git a/meta/recipes-multimedia/libpng/files/CVE-2025-64505-03.patch b/meta/recipes-multimedia/libpng/files/CVE-2025-64505-03.patch
new file mode 100644
index 0000000000..ddda8678ce
--- /dev/null
+++ b/meta/recipes-multimedia/libpng/files/CVE-2025-64505-03.patch
@@ -0,0 +1,52 @@
+From 6a528eb5fd0dd7f6de1c39d30de0e41473431c37 Mon Sep 17 00:00:00 2001
+From: Cosmin Truta <ctruta@gmail.com>
+Date: Sat, 8 Nov 2025 23:58:26 +0200
+Subject: [PATCH] Fix a buffer overflow in `png_do_quantize`
+
+Allocate the quantize_index array to PNG_MAX_PALETTE_LENGTH (256 bytes)
+instead of num_palette bytes. This approach matches the allocation
+pattern for `palette[]`, `trans_alpha[]` and `riffled_palette[]` which
+were similarly oversized in libpng 1.2.1 to prevent buffer overflows
+from malformed PNG files with out-of-range palette indices.
+
+Out-of-range palette indices `index >= num_palette` will now read
+identity-mapped values from the `quantize_index` array (where index N
+maps to palette entry N). This prevents undefined behavior while
+avoiding runtime bounds checking overhead in the performance-critical
+pixel processing loop.
+
+Reported-by: Samsung-PENTEST <Samsung-PENTEST@users.noreply.github.com>
+Analyzed-by: degrigis <degrigis@users.noreply.github.com>
+
+CVE: CVE-2025-64505
+Upstream-Status: Backport [https://github.com/pnggroup/libpng/commit/6a528eb5fd0dd7f6de1c39d30de0e41473431c37]
+Signed-off-by: Peter Marko <peter.marko@siemens.com>
+---
+ pngrtran.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/pngrtran.c b/pngrtran.c
+index 4632dd521..9c2475fde 100644
+--- a/pngrtran.c
++++ b/pngrtran.c
+@@ -441,14 +441,18 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
+ int i;
+
+ /* Initialize the array to index colors.
++ *
++ * Ensure quantize_index can fit 256 elements (PNG_MAX_PALETTE_LENGTH)
++ * rather than num_palette elements. This is to prevent buffer overflows
++ * caused by malformed PNG files with out-of-range palette indices.
+ *
+ * Be careful to avoid leaking memory. Applications are allowed to call
+ * this function more than once per png_struct.
+ */
+ png_free(png_ptr, png_ptr->quantize_index);
+ png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr,
+- (png_alloc_size_t)num_palette);
+- for (i = 0; i < num_palette; i++)
++ PNG_MAX_PALETTE_LENGTH);
++ for (i = 0; i < PNG_MAX_PALETTE_LENGTH; i++)
+ png_ptr->quantize_index[i] = (png_byte)i;
+ }
+
diff --git a/meta/recipes-multimedia/libpng/libpng_1.6.42.bb b/meta/recipes-multimedia/libpng/libpng_1.6.42.bb
index 4c21e8d597..dec78e568c 100644
--- a/meta/recipes-multimedia/libpng/libpng_1.6.42.bb
+++ b/meta/recipes-multimedia/libpng/libpng_1.6.42.bb
@@ -12,6 +12,9 @@ LIBV = "16"
SRC_URI = "${SOURCEFORGE_MIRROR}/project/${BPN}/${BPN}${LIBV}/${PV}/${BP}.tar.xz \
file://run-ptest \
+ file://CVE-2025-64505-01.patch \
+ file://CVE-2025-64505-02.patch \
+ file://CVE-2025-64505-03.patch \
"
SRC_URI[sha256sum] = "c919dbc11f4c03b05aba3f8884d8eb7adfe3572ad228af972bb60057bdb48450"
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [OE-core][scarthgap 5/8] libpng: patch CVE-2025-64506
2025-12-02 22:19 [OE-core][scarthgap 0/8] Patch review Steve Sakoman
` (2 preceding siblings ...)
2025-12-02 22:19 ` [OE-core][scarthgap 4/8] libpng: patch CVE-2025-64505 Steve Sakoman
@ 2025-12-02 22:19 ` Steve Sakoman
2025-12-02 22:19 ` [OE-core][scarthgap 6/8] libpng: patch CVE-2025-64720 Steve Sakoman
` (3 subsequent siblings)
7 siblings, 0 replies; 19+ messages in thread
From: Steve Sakoman @ 2025-12-02 22:19 UTC (permalink / raw)
To: openembedded-core
From: Peter Marko <peter.marko@siemens.com>
Pick commit per NVD report.
Signed-off-by: Peter Marko <peter.marko@siemens.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
---
.../libpng/files/CVE-2025-64506.patch | 57 +++++++++++++++++++
.../libpng/libpng_1.6.42.bb | 1 +
2 files changed, 58 insertions(+)
create mode 100644 meta/recipes-multimedia/libpng/files/CVE-2025-64506.patch
diff --git a/meta/recipes-multimedia/libpng/files/CVE-2025-64506.patch b/meta/recipes-multimedia/libpng/files/CVE-2025-64506.patch
new file mode 100644
index 0000000000..dc7fe00601
--- /dev/null
+++ b/meta/recipes-multimedia/libpng/files/CVE-2025-64506.patch
@@ -0,0 +1,57 @@
+From 2bd84c019c300b78e811743fbcddb67c9d9bf821 Mon Sep 17 00:00:00 2001
+From: Cosmin Truta <ctruta@gmail.com>
+Date: Fri, 7 Nov 2025 22:40:05 +0200
+Subject: [PATCH] Fix a heap buffer overflow in `png_write_image_8bit`
+
+The condition guarding the pre-transform path incorrectly allowed 8-bit
+input data to enter `png_write_image_8bit` which expects 16-bit input.
+This caused out-of-bounds reads when processing 8-bit grayscale+alpha
+images (GitHub #688), or 8-bit RGB or RGB+alpha images (GitHub #746),
+with the `convert_to_8bit` flag set (an invalid combination that should
+bypass the pre-transform path).
+
+The second part of the condition, i.e.
+
+ colormap == 0 && convert_to_8bit != 0
+
+failed to verify that input was 16-bit, i.e.
+
+ linear != 0
+
+contradicting the comment "This only applies when the input is 16-bit".
+
+The fix consists in restructuring the condition to ensure both the
+`alpha` path and the `convert_to_8bit` path require linear (16-bit)
+input. The corrected condition, i.e.
+
+ linear != 0 && (alpha != 0 || display->convert_to_8bit != 0)
+
+matches the expectation of the `png_write_image_8bit` function and
+prevents treating 8-bit buffers as 16-bit data.
+
+Reported-by: Samsung-PENTEST <Samsung-PENTEST@users.noreply.github.com>
+Reported-by: weijinjinnihao <weijinjinnihao@users.noreply.github.com>
+Analyzed-by: degrigis <degrigis@users.noreply.github.com>
+Reviewed-by: John Bowler <jbowler@acm.org>
+
+CVE: CVE-2025-64506
+Upstream-Status: Backport [https://github.com/pnggroup/libpng/commit/2bd84c019c300b78e811743fbcddb67c9d9bf821]
+Signed-off-by: Peter Marko <peter.marko@siemens.com>
+---
+ pngwrite.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/pngwrite.c b/pngwrite.c
+index 35a5d17b6..83148960e 100644
+--- a/pngwrite.c
++++ b/pngwrite.c
+@@ -2142,8 +2142,7 @@ png_image_write_main(png_voidp argument)
+ * before it is written. This only applies when the input is 16-bit and
+ * either there is an alpha channel or it is converted to 8-bit.
+ */
+- if ((linear != 0 && alpha != 0 ) ||
+- (colormap == 0 && display->convert_to_8bit != 0))
++ if (linear != 0 && (alpha != 0 || display->convert_to_8bit != 0))
+ {
+ png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr,
+ png_get_rowbytes(png_ptr, info_ptr)));
diff --git a/meta/recipes-multimedia/libpng/libpng_1.6.42.bb b/meta/recipes-multimedia/libpng/libpng_1.6.42.bb
index dec78e568c..ab043e3338 100644
--- a/meta/recipes-multimedia/libpng/libpng_1.6.42.bb
+++ b/meta/recipes-multimedia/libpng/libpng_1.6.42.bb
@@ -15,6 +15,7 @@ SRC_URI = "${SOURCEFORGE_MIRROR}/project/${BPN}/${BPN}${LIBV}/${PV}/${BP}.tar.xz
file://CVE-2025-64505-01.patch \
file://CVE-2025-64505-02.patch \
file://CVE-2025-64505-03.patch \
+ file://CVE-2025-64506.patch \
"
SRC_URI[sha256sum] = "c919dbc11f4c03b05aba3f8884d8eb7adfe3572ad228af972bb60057bdb48450"
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [OE-core][scarthgap 6/8] libpng: patch CVE-2025-64720
2025-12-02 22:19 [OE-core][scarthgap 0/8] Patch review Steve Sakoman
` (3 preceding siblings ...)
2025-12-02 22:19 ` [OE-core][scarthgap 5/8] libpng: patch CVE-2025-64506 Steve Sakoman
@ 2025-12-02 22:19 ` Steve Sakoman
2025-12-02 22:19 ` [OE-core][scarthgap 7/8] libpng: patch CVE-2025-65018 Steve Sakoman
` (2 subsequent siblings)
7 siblings, 0 replies; 19+ messages in thread
From: Steve Sakoman @ 2025-12-02 22:19 UTC (permalink / raw)
To: openembedded-core
From: Peter Marko <peter.marko@siemens.com>
Pick commit per NVD report.
Signed-off-by: Peter Marko <peter.marko@siemens.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
---
.../libpng/files/CVE-2025-64720.patch | 103 ++++++++++++++++++
.../libpng/libpng_1.6.42.bb | 1 +
2 files changed, 104 insertions(+)
create mode 100644 meta/recipes-multimedia/libpng/files/CVE-2025-64720.patch
diff --git a/meta/recipes-multimedia/libpng/files/CVE-2025-64720.patch b/meta/recipes-multimedia/libpng/files/CVE-2025-64720.patch
new file mode 100644
index 0000000000..08df7c3210
--- /dev/null
+++ b/meta/recipes-multimedia/libpng/files/CVE-2025-64720.patch
@@ -0,0 +1,103 @@
+From 08da33b4c88cfcd36e5a706558a8d7e0e4773643 Mon Sep 17 00:00:00 2001
+From: Cosmin Truta <ctruta@gmail.com>
+Date: Wed, 12 Nov 2025 13:46:23 +0200
+Subject: [PATCH] Fix a buffer overflow in `png_init_read_transformations`
+
+The palette compositing code in `png_init_read_transformations` was
+incorrectly applying background compositing when PNG_FLAG_OPTIMIZE_ALPHA
+was set. This violated the premultiplied alpha invariant
+`component <= alpha` expected by `png_image_read_composite`, causing
+values that exceeded the valid range for the PNG_sRGB_FROM_LINEAR lookup
+tables.
+
+When PNG_ALPHA_OPTIMIZED is active, palette entries should contain pure
+premultiplied RGB values without background compositing. The background
+compositing must happen later in `png_image_read_composite` where the
+actual background color from the PNG file is available.
+
+The fix consists in introducing conditional behavior based on
+PNG_FLAG_OPTIMIZE_ALPHA: when set, the code performs only
+premultiplication using the formula `component * alpha + 127) / 255`
+with proper gamma correction. When not set, the original background
+compositing calculation based on the `png_composite` macro is preserved.
+
+This prevents buffer overflows in `png_image_read_composite` where
+out-of-range premultiplied values would cause out-of-bounds array access
+in `png_sRGB_base[]` and `png_sRGB_delta[]`.
+
+Reported-by: Samsung-PENTEST <Samsung-PENTEST@users.noreply.github.com>
+Analyzed-by: John Bowler <jbowler@acm.org>
+
+CVE: CVE-2025-64720
+Upstream-Status: Backport [https://github.com/pnggroup/libpng/commit/08da33b4c88cfcd36e5a706558a8d7e0e4773643]
+Signed-off-by: Peter Marko <peter.marko@siemens.com>
+---
+ pngrtran.c | 52 ++++++++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 42 insertions(+), 10 deletions(-)
+
+diff --git a/pngrtran.c b/pngrtran.c
+index 548780030..2f5202255 100644
+--- a/pngrtran.c
++++ b/pngrtran.c
+@@ -1698,19 +1698,51 @@ png_init_read_transformations(png_structrp png_ptr)
+ }
+ else /* if (png_ptr->trans_alpha[i] != 0xff) */
+ {
+- png_byte v, w;
++ if ((png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0)
++ {
++ /* Premultiply only:
++ * component = round((component * alpha) / 255)
++ */
++ png_uint_32 component;
+
+- v = png_ptr->gamma_to_1[palette[i].red];
+- png_composite(w, v, png_ptr->trans_alpha[i], back_1.red);
+- palette[i].red = png_ptr->gamma_from_1[w];
++ component = png_ptr->gamma_to_1[palette[i].red];
++ component =
++ (component * png_ptr->trans_alpha[i] + 128) / 255;
++ palette[i].red = png_ptr->gamma_from_1[component];
+
+- v = png_ptr->gamma_to_1[palette[i].green];
+- png_composite(w, v, png_ptr->trans_alpha[i], back_1.green);
+- palette[i].green = png_ptr->gamma_from_1[w];
++ component = png_ptr->gamma_to_1[palette[i].green];
++ component =
++ (component * png_ptr->trans_alpha[i] + 128) / 255;
++ palette[i].green = png_ptr->gamma_from_1[component];
+
+- v = png_ptr->gamma_to_1[palette[i].blue];
+- png_composite(w, v, png_ptr->trans_alpha[i], back_1.blue);
+- palette[i].blue = png_ptr->gamma_from_1[w];
++ component = png_ptr->gamma_to_1[palette[i].blue];
++ component =
++ (component * png_ptr->trans_alpha[i] + 128) / 255;
++ palette[i].blue = png_ptr->gamma_from_1[component];
++ }
++ else
++ {
++ /* Composite with background color:
++ * component =
++ * alpha * component + (1 - alpha) * background
++ */
++ png_byte v, w;
++
++ v = png_ptr->gamma_to_1[palette[i].red];
++ png_composite(w, v,
++ png_ptr->trans_alpha[i], back_1.red);
++ palette[i].red = png_ptr->gamma_from_1[w];
++
++ v = png_ptr->gamma_to_1[palette[i].green];
++ png_composite(w, v,
++ png_ptr->trans_alpha[i], back_1.green);
++ palette[i].green = png_ptr->gamma_from_1[w];
++
++ v = png_ptr->gamma_to_1[palette[i].blue];
++ png_composite(w, v,
++ png_ptr->trans_alpha[i], back_1.blue);
++ palette[i].blue = png_ptr->gamma_from_1[w];
++ }
+ }
+ }
+ else
diff --git a/meta/recipes-multimedia/libpng/libpng_1.6.42.bb b/meta/recipes-multimedia/libpng/libpng_1.6.42.bb
index ab043e3338..6f5b69b754 100644
--- a/meta/recipes-multimedia/libpng/libpng_1.6.42.bb
+++ b/meta/recipes-multimedia/libpng/libpng_1.6.42.bb
@@ -16,6 +16,7 @@ SRC_URI = "${SOURCEFORGE_MIRROR}/project/${BPN}/${BPN}${LIBV}/${PV}/${BP}.tar.xz
file://CVE-2025-64505-02.patch \
file://CVE-2025-64505-03.patch \
file://CVE-2025-64506.patch \
+ file://CVE-2025-64720.patch \
"
SRC_URI[sha256sum] = "c919dbc11f4c03b05aba3f8884d8eb7adfe3572ad228af972bb60057bdb48450"
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [OE-core][scarthgap 7/8] libpng: patch CVE-2025-65018
2025-12-02 22:19 [OE-core][scarthgap 0/8] Patch review Steve Sakoman
` (4 preceding siblings ...)
2025-12-02 22:19 ` [OE-core][scarthgap 6/8] libpng: patch CVE-2025-64720 Steve Sakoman
@ 2025-12-02 22:19 ` Steve Sakoman
2025-12-02 22:19 ` [OE-core][scarthgap 8/8] curl: Ensure 'CURL_CA_BUNDLE' from host env is indeed respected Steve Sakoman
[not found] ` <ce604b9bf682e404baa15800fcdbc01abd6a66e1.1764713862.git.steve@sakoman.com>
7 siblings, 0 replies; 19+ messages in thread
From: Steve Sakoman @ 2025-12-02 22:19 UTC (permalink / raw)
To: openembedded-core
From: Peter Marko <peter.marko@siemens.com>
Pick commit per NVD report.
Add two patches to apply it cleanly.
Signed-off-by: Peter Marko <peter.marko@siemens.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
---
.../libpng/files/CVE-2025-65018-01.patch | 60 +++++++
.../libpng/files/CVE-2025-65018-02.patch | 163 ++++++++++++++++++
.../libpng/libpng_1.6.42.bb | 2 +
3 files changed, 225 insertions(+)
create mode 100644 meta/recipes-multimedia/libpng/files/CVE-2025-65018-01.patch
create mode 100644 meta/recipes-multimedia/libpng/files/CVE-2025-65018-02.patch
diff --git a/meta/recipes-multimedia/libpng/files/CVE-2025-65018-01.patch b/meta/recipes-multimedia/libpng/files/CVE-2025-65018-01.patch
new file mode 100644
index 0000000000..cdee6c76c0
--- /dev/null
+++ b/meta/recipes-multimedia/libpng/files/CVE-2025-65018-01.patch
@@ -0,0 +1,60 @@
+From 16b5e3823918840aae65c0a6da57c78a5a496a4d Mon Sep 17 00:00:00 2001
+From: Cosmin Truta <ctruta@gmail.com>
+Date: Mon, 17 Nov 2025 20:38:47 +0200
+Subject: [PATCH] Fix a buffer overflow in `png_image_finish_read`
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Reject bit-depth mismatches between IHDR and the requested output
+format. When a 16-bit PNG is processed with an 8-bit output format
+request, `png_combine_row` writes using the IHDR depth before
+transformation, causing writes beyond the buffer allocated via
+`PNG_IMAGE_SIZE(image)`.
+
+The validation establishes a safe API contract where
+`PNG_IMAGE_SIZE(image)` is guaranteed to be sufficient across the
+transformation pipeline.
+
+Example overflow (32×32 pixels, 16-bit RGB to 8-bit RGBA):
+- Input format: 16 bits/channel × 3 channels = 6144 bytes
+- Output buffer: 8 bits/channel × 4 channels = 4096 bytes
+- Overflow: 6144 bytes - 4096 bytes = 2048 bytes
+
+Larger images produce proportionally larger overflows. For example,
+for 256×256 pixels, the overflow is 131072 bytes.
+
+Reported-by: yosiimich <yosiimich@users.noreply.github.com>
+
+CVE: CVE-2025-65018
+Upstream-Status: Backport [https://github.com/pnggroup/libpng/commit/16b5e3823918840aae65c0a6da57c78a5a496a4d]
+Signed-off-by: Peter Marko <peter.marko@siemens.com>
+---
+ pngread.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/pngread.c b/pngread.c
+index 212afb7d2..92571ec33 100644
+--- a/pngread.c
++++ b/pngread.c
+@@ -4166,6 +4166,20 @@ png_image_finish_read(png_imagep image, png_const_colorp background,
+ int result;
+ png_image_read_control display;
+
++ /* Reject bit depth mismatches to avoid buffer overflows. */
++ png_uint_32 ihdr_bit_depth =
++ image->opaque->png_ptr->bit_depth;
++ int requested_linear =
++ (image->format & PNG_FORMAT_FLAG_LINEAR) != 0;
++ if (ihdr_bit_depth == 16 && !requested_linear)
++ return png_image_error(image,
++ "png_image_finish_read: "
++ "16-bit PNG must use 16-bit output format");
++ if (ihdr_bit_depth < 16 && requested_linear)
++ return png_image_error(image,
++ "png_image_finish_read: "
++ "8-bit PNG must not use 16-bit output format");
++
+ memset(&display, 0, (sizeof display));
+ display.image = image;
+ display.buffer = buffer;
diff --git a/meta/recipes-multimedia/libpng/files/CVE-2025-65018-02.patch b/meta/recipes-multimedia/libpng/files/CVE-2025-65018-02.patch
new file mode 100644
index 0000000000..891cd20c3f
--- /dev/null
+++ b/meta/recipes-multimedia/libpng/files/CVE-2025-65018-02.patch
@@ -0,0 +1,163 @@
+From 218612ddd6b17944e21eda56caf8b4bf7779d1ea Mon Sep 17 00:00:00 2001
+From: Cosmin Truta <ctruta@gmail.com>
+Date: Wed, 19 Nov 2025 21:45:13 +0200
+Subject: [PATCH] Rearchitect the fix to the buffer overflow in
+ `png_image_finish_read`
+
+Undo the fix from commit 16b5e3823918840aae65c0a6da57c78a5a496a4d.
+That fix turned out to be unnecessarily limiting. It rejected all
+16-to-8 bit transformations, although the vulnerability only affects
+interlaced PNGs where `png_combine_row` writes using IHDR bit-depth
+before the transformation completes.
+
+The proper solution is to add an intermediate `local_row` buffer,
+specifically for the slow but necessary step of 16-to-8 bit conversion
+of interlaced images. (The processing of non-interlaced images remains
+intact, using the fast path.) We added the flag `do_local_scale` and
+the function `png_image_read_direct_scaled`, following the pattern that
+involves `do_local_compose`.
+
+In conclusion:
+- The 16-to-8 bit transformations of interlaced images are now safe,
+ as they use an intermediate buffer.
+- The 16-to-8 bit transformations of non-interlaced images remain safe,
+ as the fast path remains unchanged.
+- All our regression tests are now passing.
+
+CVE: CVE-2025-65018
+Upstream-Status: Backport [https://github.com/pnggroup/libpng/commit/218612ddd6b17944e21eda56caf8b4bf7779d1ea]
+Signed-off-by: Peter Marko <peter.marko@siemens.com>
+---
+ pngread.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++---------
+ 1 file changed, 75 insertions(+), 14 deletions(-)
+
+diff --git a/pngread.c b/pngread.c
+index 92571ec33..79917daaa 100644
+--- a/pngread.c
++++ b/pngread.c
+@@ -3262,6 +3262,54 @@ png_image_read_colormapped(png_voidp argument)
+ }
+ }
+
++/* Row reading for interlaced 16-to-8 bit depth conversion with local buffer. */
++static int
++png_image_read_direct_scaled(png_voidp argument)
++{
++ png_image_read_control *display = png_voidcast(png_image_read_control*,
++ argument);
++ png_imagep image = display->image;
++ png_structrp png_ptr = image->opaque->png_ptr;
++ png_bytep local_row = png_voidcast(png_bytep, display->local_row);
++ png_bytep first_row = png_voidcast(png_bytep, display->first_row);
++ ptrdiff_t row_bytes = display->row_bytes;
++ int passes;
++
++ /* Handle interlacing. */
++ switch (png_ptr->interlaced)
++ {
++ case PNG_INTERLACE_NONE:
++ passes = 1;
++ break;
++
++ case PNG_INTERLACE_ADAM7:
++ passes = PNG_INTERLACE_ADAM7_PASSES;
++ break;
++
++ default:
++ png_error(png_ptr, "unknown interlace type");
++ }
++
++ /* Read each pass using local_row as intermediate buffer. */
++ while (--passes >= 0)
++ {
++ png_uint_32 y = image->height;
++ png_bytep output_row = first_row;
++
++ for (; y > 0; --y)
++ {
++ /* Read into local_row (gets transformed 8-bit data). */
++ png_read_row(png_ptr, local_row, NULL);
++
++ /* Copy from local_row to user buffer. */
++ memcpy(output_row, local_row, (size_t)row_bytes);
++ output_row += row_bytes;
++ }
++ }
++
++ return 1;
++}
++
+ /* Just the row reading part of png_image_read. */
+ static int
+ png_image_read_composite(png_voidp argument)
+@@ -3680,6 +3728,7 @@ png_image_read_direct(png_voidp argument)
+ int linear = (format & PNG_FORMAT_FLAG_LINEAR) != 0;
+ int do_local_compose = 0;
+ int do_local_background = 0; /* to avoid double gamma correction bug */
++ int do_local_scale = 0; /* for interlaced 16-to-8 bit conversion */
+ int passes = 0;
+
+ /* Add transforms to ensure the correct output format is produced then check
+@@ -3806,8 +3855,16 @@ png_image_read_direct(png_voidp argument)
+ png_set_expand_16(png_ptr);
+
+ else /* 8-bit output */
++ {
+ png_set_scale_16(png_ptr);
+
++ /* For interlaced images, use local_row buffer to avoid overflow
++ * in png_combine_row() which writes using IHDR bit-depth.
++ */
++ if (png_ptr->interlaced != 0)
++ do_local_scale = 1;
++ }
++
+ change &= ~PNG_FORMAT_FLAG_LINEAR;
+ }
+
+@@ -4083,6 +4140,24 @@ png_image_read_direct(png_voidp argument)
+ return result;
+ }
+
++ else if (do_local_scale != 0)
++ {
++ /* For interlaced 16-to-8 conversion, use an intermediate row buffer
++ * to avoid buffer overflows in png_combine_row. The local_row is sized
++ * for the transformed (8-bit) output, preventing the overflow that would
++ * occur if png_combine_row wrote 16-bit data directly to the user buffer.
++ */
++ int result;
++ png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));
++
++ display->local_row = row;
++ result = png_safe_execute(image, png_image_read_direct_scaled, display);
++ display->local_row = NULL;
++ png_free(png_ptr, row);
++
++ return result;
++ }
++
+ else
+ {
+ png_alloc_size_t row_bytes = (png_alloc_size_t)display->row_bytes;
+@@ -4166,20 +4241,6 @@ png_image_finish_read(png_imagep image, png_const_colorp background,
+ int result;
+ png_image_read_control display;
+
+- /* Reject bit depth mismatches to avoid buffer overflows. */
+- png_uint_32 ihdr_bit_depth =
+- image->opaque->png_ptr->bit_depth;
+- int requested_linear =
+- (image->format & PNG_FORMAT_FLAG_LINEAR) != 0;
+- if (ihdr_bit_depth == 16 && !requested_linear)
+- return png_image_error(image,
+- "png_image_finish_read: "
+- "16-bit PNG must use 16-bit output format");
+- if (ihdr_bit_depth < 16 && requested_linear)
+- return png_image_error(image,
+- "png_image_finish_read: "
+- "8-bit PNG must not use 16-bit output format");
+-
+ memset(&display, 0, (sizeof display));
+ display.image = image;
+ display.buffer = buffer;
diff --git a/meta/recipes-multimedia/libpng/libpng_1.6.42.bb b/meta/recipes-multimedia/libpng/libpng_1.6.42.bb
index 6f5b69b754..2d5216cb65 100644
--- a/meta/recipes-multimedia/libpng/libpng_1.6.42.bb
+++ b/meta/recipes-multimedia/libpng/libpng_1.6.42.bb
@@ -17,6 +17,8 @@ SRC_URI = "${SOURCEFORGE_MIRROR}/project/${BPN}/${BPN}${LIBV}/${PV}/${BP}.tar.xz
file://CVE-2025-64505-03.patch \
file://CVE-2025-64506.patch \
file://CVE-2025-64720.patch \
+ file://CVE-2025-65018-01.patch \
+ file://CVE-2025-65018-02.patch \
"
SRC_URI[sha256sum] = "c919dbc11f4c03b05aba3f8884d8eb7adfe3572ad228af972bb60057bdb48450"
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread* [OE-core][scarthgap 8/8] curl: Ensure 'CURL_CA_BUNDLE' from host env is indeed respected
2025-12-02 22:19 [OE-core][scarthgap 0/8] Patch review Steve Sakoman
` (5 preceding siblings ...)
2025-12-02 22:19 ` [OE-core][scarthgap 7/8] libpng: patch CVE-2025-65018 Steve Sakoman
@ 2025-12-02 22:19 ` Steve Sakoman
[not found] ` <ce604b9bf682e404baa15800fcdbc01abd6a66e1.1764713862.git.steve@sakoman.com>
7 siblings, 0 replies; 19+ messages in thread
From: Steve Sakoman @ 2025-12-02 22:19 UTC (permalink / raw)
To: openembedded-core
From: Moritz Haase <Moritz.Haase@bmw.de>
Due to what looks like a copy'n'paste mistake, the environment setup script
might override 'CURL_CA_BUNDLE' from the host env instead of leaving it
untouched. Fix that.
(cherry picked from commit 545e43a7a45be02fda8fc3af69faa20e889f58c4)
CC: changqing.li@windriver.com
CC: raj.khem@gmail.com
CC: Peter.Marko@siemens.com
Signed-off-by: Moritz Haase <Moritz.Haase@bmw.de>
Signed-off-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
---
meta/recipes-support/curl/curl/environment.d-curl.sh | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/meta/recipes-support/curl/curl/environment.d-curl.sh b/meta/recipes-support/curl/curl/environment.d-curl.sh
index 581108ef35..b948db2cf6 100644
--- a/meta/recipes-support/curl/curl/environment.d-curl.sh
+++ b/meta/recipes-support/curl/curl/environment.d-curl.sh
@@ -1,6 +1,6 @@
# Respect host env CURL_CA_BUNDLE/CURL_CA_PATH first, then auto-detected host cert, then cert in buildtools
-# CAFILE/CAPATH is auto-deteced when source buildtools
-if [ -z "${CURL_CA_PATH:-}" ]; then
+# CAFILE/CAPATH is auto-detected when source buildtools
+if [ -z "${CURL_CA_BUNDLE:-}" ]; then
if [ -n "${CAFILE:-}" ];then
export CURL_CA_BUNDLE="$CAFILE"
elif [ -e "${OECORE_NATIVE_SYSROOT}/etc/ssl/certs/ca-certificates.crt" ];then
--
2.43.0
^ permalink raw reply related [flat|nested] 19+ messages in thread[parent not found: <ce604b9bf682e404baa15800fcdbc01abd6a66e1.1764713862.git.steve@sakoman.com>]