* [PATCH 1/2] python3: fix CVE-2026-11940
2026-07-06 10:45 [PATCH 0/2] python3: fix CVE-2026-11940 and CVE-2026-11972 Benjamin Robin (Schneider Electric)
@ 2026-07-06 10:45 ` Benjamin Robin (Schneider Electric)
2026-07-06 10:45 ` [PATCH 2/2] python3: fix CVE-2026-11972 Benjamin Robin (Schneider Electric)
1 sibling, 0 replies; 3+ messages in thread
From: Benjamin Robin (Schneider Electric) @ 2026-07-06 10:45 UTC (permalink / raw)
To: openembedded-core
Cc: olivier.benjamin, mathieu.dubois-briand, pascal.eberhard,
wahid.essid, Benjamin Robin (Schneider Electric)
tarfile.extractall() with the 'data' or 'tar' filter could be bypassed
by a crafted archive where a hardlink references a symlink stored at a
deeper name than the hardlink itself.
Signed-off-by: Benjamin Robin (Schneider Electric) <benjamin.robin@bootlin.com>
---
.../python/python3/CVE-2026-11940.patch | 67 ++++++++++++++++++++++
meta/recipes-devtools/python/python3_3.14.6.bb | 1 +
2 files changed, 68 insertions(+)
diff --git a/meta/recipes-devtools/python/python3/CVE-2026-11940.patch b/meta/recipes-devtools/python/python3/CVE-2026-11940.patch
new file mode 100644
index 000000000000..05a5802c3965
--- /dev/null
+++ b/meta/recipes-devtools/python/python3/CVE-2026-11940.patch
@@ -0,0 +1,67 @@
+From e24b4e95524fbe8cd0f46aa3292e8040f0e07c83 Mon Sep 17 00:00:00 2001
+From: "Miss Islington (bot)"
+ <31488909+miss-islington@users.noreply.github.com>
+Date: Tue, 23 Jun 2026 15:58:47 +0200
+Subject: [PATCH 1/2] gh-151558: Fix symlink escape via `tarfile`
+ hardlink-extraction fallback (GH-151559)
+
+CVE: CVE-2026-11940
+Upstream-Status: Backport [https://github.com/python/cpython/commit/27dd970bf6b17ebca7c8ed486a40ab043ed7af8f]
+
+Signed-off-by: Benjamin Robin <benjamin.robin@bootlin.com>
+---
+ Lib/tarfile.py | 3 +++
+ Lib/test/test_tarfile.py | 24 ++++++++++++++++++++++++
+ 2 files changed, 27 insertions(+)
+
+diff --git a/Lib/tarfile.py b/Lib/tarfile.py
+index e6734db24f64..63f23490e8a1 100644
+--- a/Lib/tarfile.py
++++ b/Lib/tarfile.py
+@@ -2782,6 +2782,9 @@ def makelink_with_filter(self, tarinfo, targetpath,
+ "makelink_with_filter: if filter_function is not None, "
+ + "extraction_root must also not be None")
+ try:
++ filter_function(
++ unfiltered.replace(name=tarinfo.name, deep=False),
++ extraction_root)
+ filtered = filter_function(unfiltered, extraction_root)
+ except _FILTER_ERRORS as cause:
+ raise LinkFallbackError(tarinfo, unfiltered.name) from cause
+diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py
+index d974c7d46ec1..0fc7413be8db 100644
+--- a/Lib/test/test_tarfile.py
++++ b/Lib/test/test_tarfile.py
+@@ -4344,6 +4344,30 @@ def test_sneaky_hardlink_fallback(self):
+ self.expect_file("boom", symlink_to='../../link_here')
+ self.expect_file("c", symlink_to='b')
+
++ @symlink_test
++ def test_sneaky_hardlink_fallback_deep(self):
++ # (CVE-2026-11940)
++ with ArchiveMaker() as arc:
++ arc.add("a/b/s", symlink_to=os.path.join("..", "escape"))
++ arc.add("s", hardlink_to=os.path.join("a", "b", "s"))
++
++ with self.check_context(arc.open(), 'data'):
++ e = self.expect_exception(
++ tarfile.LinkFallbackError,
++ "link 's' would be extracted as a copy of "
++ + "'a/b/s', which was rejected")
++ self.assertIsInstance(e.__cause__,
++ tarfile.LinkOutsideDestinationError)
++
++ for filter in 'tar', 'fully_trusted':
++ with self.subTest(filter), self.check_context(arc.open(), filter):
++ if not os_helper.can_symlink():
++ self.expect_file("a/")
++ self.expect_file("a/b/")
++ else:
++ self.expect_file("a/b/s", symlink_to=os.path.join('..', 'escape'))
++ self.expect_file("s", symlink_to=os.path.join('..', 'escape'))
++
+ @symlink_test
+ def test_exfiltration_via_symlink(self):
+ # (CVE-2025-4138)
+--
+2.54.0
diff --git a/meta/recipes-devtools/python/python3_3.14.6.bb b/meta/recipes-devtools/python/python3_3.14.6.bb
index 6dfd22fc0fb6..23fc152950ea 100644
--- a/meta/recipes-devtools/python/python3_3.14.6.bb
+++ b/meta/recipes-devtools/python/python3_3.14.6.bb
@@ -22,6 +22,7 @@ SRC_URI = "http://www.python.org/ftp/python/${PV}/Python-${PV}.tar.xz \
file://0001-Avoid-shebang-overflow-on-python-config.py.patch \
file://0001-Update-test_sysconfig-for-posix_user-purelib.patch \
file://0001-prefer-valid-entrypoints.patch \
+ file://CVE-2026-11940.patch \
"
SRC_URI:append:class-native = " \
file://0001-Lib-sysconfig.py-use-prefix-value-from-build-configu.patch \
--
2.54.0
^ permalink raw reply related [flat|nested] 3+ messages in thread* [PATCH 2/2] python3: fix CVE-2026-11972
2026-07-06 10:45 [PATCH 0/2] python3: fix CVE-2026-11940 and CVE-2026-11972 Benjamin Robin (Schneider Electric)
2026-07-06 10:45 ` [PATCH 1/2] python3: fix CVE-2026-11940 Benjamin Robin (Schneider Electric)
@ 2026-07-06 10:45 ` Benjamin Robin (Schneider Electric)
1 sibling, 0 replies; 3+ messages in thread
From: Benjamin Robin (Schneider Electric) @ 2026-07-06 10:45 UTC (permalink / raw)
To: openembedded-core
Cc: olivier.benjamin, mathieu.dubois-briand, pascal.eberhard,
wahid.essid, Benjamin Robin (Schneider Electric)
When using the "tarfile" module with a file opened in "streaming mode"
(mode="r|") the tarfile module did not properly handle EOF, making archive
parsing take exponentially longer.
Signed-off-by: Benjamin Robin (Schneider Electric) <benjamin.robin@bootlin.com>
---
.../python/python3/CVE-2026-11972.patch | 59 ++++++++++++++++++++++
meta/recipes-devtools/python/python3_3.14.6.bb | 1 +
2 files changed, 60 insertions(+)
diff --git a/meta/recipes-devtools/python/python3/CVE-2026-11972.patch b/meta/recipes-devtools/python/python3/CVE-2026-11972.patch
new file mode 100644
index 000000000000..7dc9c6697112
--- /dev/null
+++ b/meta/recipes-devtools/python/python3/CVE-2026-11972.patch
@@ -0,0 +1,59 @@
+From 2d256d4bfd654bdcaf2d96733799be73b8ff8f69 Mon Sep 17 00:00:00 2001
+From: Petr Viktorin <encukou@gmail.com>
+Date: Tue, 23 Jun 2026 15:13:30 +0200
+Subject: [PATCH 2/2] gh-151981: Make tarfile._Stream.seek break at EOF
+ (GH-151982)
+
+CVE: CVE-2026-11972
+Upstream-Status: Backport [https://github.com/python/cpython/commit/f50bf13566189c8d0ce5a814f33eff3d89951896]
+
+Signed-off-by: Benjamin Robin <benjamin.robin@bootlin.com>
+---
+ Lib/tarfile.py | 4 +++-
+ Lib/test/test_tarfile.py | 16 ++++++++++++++++
+ 2 files changed, 19 insertions(+), 1 deletion(-)
+
+diff --git a/Lib/tarfile.py b/Lib/tarfile.py
+index 63f23490e8a1..399f906efdff 100644
+--- a/Lib/tarfile.py
++++ b/Lib/tarfile.py
+@@ -524,7 +524,9 @@ def seek(self, pos=0):
+ if pos - self.pos >= 0:
+ blocks, remainder = divmod(pos - self.pos, self.bufsize)
+ for i in range(blocks):
+- self.read(self.bufsize)
++ data = self.read(self.bufsize)
++ if not data:
++ break
+ self.read(remainder)
+ else:
+ raise StreamError("seeking backwards is not allowed")
+diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py
+index 0fc7413be8db..045377d620cc 100644
+--- a/Lib/test/test_tarfile.py
++++ b/Lib/test/test_tarfile.py
+@@ -4786,6 +4786,22 @@ def valueerror_filter(tarinfo, path):
+ with self.check_context(arc.open(errorlevel='boo!'), filtererror_filter):
+ self.expect_exception(TypeError) # errorlevel is not int
+
++ @support.subTests('format', [tarfile.GNU_FORMAT, tarfile.PAX_FORMAT])
++ def test_getmembers_big_size(self, format):
++ # gh-151981: A loop in seek() for streaming files tried to read the
++ # declared number of blocks even at EOF
++ tinfo = tarfile.TarInfo("huge-file")
++ tinfo.size = 1 << 64
++ bio = io.BytesIO()
++ # Write header without data
++ bio.write(tinfo.tobuf(format))
++
++ # Reset & try to get contents
++ bio.seek(0)
++ with tarfile.open(fileobj=bio, mode="r|") as tar:
++ with self.assertRaises(tarfile.ReadError):
++ tar.getmembers()
++
+
+ class OverwriteTests(archiver_tests.OverwriteTests, unittest.TestCase):
+ testdir = os.path.join(TEMPDIR, "testoverwrite")
+--
+2.54.0
diff --git a/meta/recipes-devtools/python/python3_3.14.6.bb b/meta/recipes-devtools/python/python3_3.14.6.bb
index 23fc152950ea..a45a4561339f 100644
--- a/meta/recipes-devtools/python/python3_3.14.6.bb
+++ b/meta/recipes-devtools/python/python3_3.14.6.bb
@@ -23,6 +23,7 @@ SRC_URI = "http://www.python.org/ftp/python/${PV}/Python-${PV}.tar.xz \
file://0001-Update-test_sysconfig-for-posix_user-purelib.patch \
file://0001-prefer-valid-entrypoints.patch \
file://CVE-2026-11940.patch \
+ file://CVE-2026-11972.patch \
"
SRC_URI:append:class-native = " \
file://0001-Lib-sysconfig.py-use-prefix-value-from-build-configu.patch \
--
2.54.0
^ permalink raw reply related [flat|nested] 3+ messages in thread