package/python3: add patch for CVE-2026-11940

This fixes the following vulnerability:
- CVE-2026-11940:
    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.   The extraction
    fallback validated the symlink at it's archived location  but
    recreated it at the hardlink's shallower path, letting a relative
    target the filter judged contained escape the destination directory. 
    This allowed a malicious tar archive to create a symlink pointing
    outside the destination, enabling out-of-destination file reads or
    writes. This was an incomplete fix of CVE-2025-4330.
    https://www.cve.org/CVERecord?id=CVE-2026-11940

Signed-off-by: Titouan Christophe <titouan.christophe@mind.be>
(cherry picked from commit 1a0164ac81)
Signed-off-by: Thomas Perale <thomas.perale@mind.be>
This commit is contained in:
Titouan Christophe
2026-06-29 11:48:35 +02:00
committed by Thomas Perale
parent 18b68d8442
commit 30b10fd08f
2 changed files with 79 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
From d0ba16dce6df2f68e8968699d5c247eddeef9960 Mon Sep 17 00:00:00 2001
From: Stan Ulbrych <stan@python.org>
Date: Tue, 23 Jun 2026 14:31:38 +0100
Subject: [PATCH] gh-151558: Fix symlink escape via `tarfile`
hardlink-extraction fallback (GH-151559) (cherry picked from commit
27dd970bf6b17ebca7c8ed486a40ab043ed7af8f)
Co-authored-by: Stan Ulbrych <stan@python.org>
Upstream: https://github.com/python/cpython/pull/152000
CVE: CVE-2026-11940
Signed-off-by: Titouan Christophe <titouan.christophe@mind.be>
---
Lib/tarfile.py | 3 +++
Lib/test/test_tarfile.py | 24 +++++++++++++++++++
...-06-10-13-08-19.gh-issue-151558.mL74i2.rst | 3 +++
3 files changed, 30 insertions(+)
create mode 100644 Misc/NEWS.d/next/Security/2026-06-10-13-08-19.gh-issue-151558.mL74i2.rst
diff --git a/Lib/tarfile.py b/Lib/tarfile.py
index 461ec16dcd8592..73e9ece4153170 100755
--- a/Lib/tarfile.py
+++ b/Lib/tarfile.py
@@ -2677,6 +2677,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 9a4c5a301b30d0..902538d2262ceb 100644
--- a/Lib/test/test_tarfile.py
+++ b/Lib/test/test_tarfile.py
@@ -4182,6 +4182,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)
diff --git a/Misc/NEWS.d/next/Security/2026-06-10-13-08-19.gh-issue-151558.mL74i2.rst b/Misc/NEWS.d/next/Security/2026-06-10-13-08-19.gh-issue-151558.mL74i2.rst
new file mode 100644
index 00000000000000..74459d5680e21a
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2026-06-10-13-08-19.gh-issue-151558.mL74i2.rst
@@ -0,0 +1,3 @@
+Fixed an vulnerability in the :mod:`tarfile` ``data`` and ``tar`` extraction
+filters where crafted archives could create a symlink pointing outside the
+destination directory. This was a bypass of :cve:`2025-4330`.

View File

@@ -21,6 +21,8 @@ PYTHON3_IGNORE_CVES += CVE-2026-7774
PYTHON3_IGNORE_CVES += CVE-2026-8328
# 0016-prevent-bz2-decompressor-reuse-after-errors.patch
PYTHON3_IGNORE_CVES += CVE-2026-9669
# 0017-Fix-symlink-escape-via-tarfile-hardlink-extraction-fallback.patch
PYTHON3_IGNORE_CVES += CVE-2026-11940
# This host Python is installed in $(HOST_DIR), as it is needed when
# cross-compiling third-party Python modules.