From 597868f0a2379a7c65f8c8967418b01535792cd4 Mon Sep 17 00:00:00 2001 From: Azure Linux Security Servicing Account Date: Mon, 29 Sep 2025 06:28:57 +0000 Subject: [PATCH] Patch python-pip for CVE-2025-8869 --- SPECS/python-pip/CVE-2025-8869.patch | 629 ++++++++++++++++++ SPECS/python-pip/python-pip.spec | 6 +- .../manifests/package/toolchain_aarch64.txt | 2 +- .../manifests/package/toolchain_x86_64.txt | 2 +- 4 files changed, 636 insertions(+), 3 deletions(-) create mode 100644 SPECS/python-pip/CVE-2025-8869.patch diff --git a/SPECS/python-pip/CVE-2025-8869.patch b/SPECS/python-pip/CVE-2025-8869.patch new file mode 100644 index 00000000000..9248a0a0e79 --- /dev/null +++ b/SPECS/python-pip/CVE-2025-8869.patch @@ -0,0 +1,629 @@ +From 9084a9b8d57d9dd8df279e4f69e37aefa6098b73 Mon Sep 17 00:00:00 2001 +From: user +Date: Wed, 20 Aug 2025 13:05:34 +0800 +Subject: [PATCH 01/10] Check symlink target in tar extraction fallback for + Pythons without data_filter + +--- + src/pip/_internal/utils/unpacking.py | 19 +++++ + tests/unit/test_utils_unpacking.py | 100 +++++++++++++++++++++++++++ + 2 files changed, 119 insertions(+) + +diff --git a/src/pip/_internal/utils/unpacking.py b/src/pip/_internal/utils/unpacking.py +index 875e30e..f9906f7 100644 +--- a/src/pip/_internal/utils/unpacking.py ++++ b/src/pip/_internal/utils/unpacking.py +@@ -255,6 +255,17 @@ def _untar_without_filter( + leading: bool, + ) -> None: + """Fallback for Python without tarfile.data_filter""" ++ ++ def _check_link_target(tar: tarfile.TarFile, tarinfo: tarfile.TarInfo) -> None: ++ linkname = "/".join( ++ filter(None, (os.path.dirname(tarinfo.name), tarinfo.linkname)) ++ ) ++ ++ try: ++ tar.getmember(linkname) ++ except KeyError: ++ raise KeyError(linkname) ++ + for member in tar.getmembers(): + fn = member.name + if leading: +@@ -269,6 +280,14 @@ def _untar_without_filter( + if member.isdir(): + ensure_dir(path) + elif member.issym(): ++ try: ++ _check_link_target(tar, member) ++ except KeyError as exc: ++ message = ( ++ "The tar file ({}) has a file ({}) trying to install " ++ "outside target directory ({})" ++ ) ++ raise InstallationError(message.format(filename, member.name, exc)) + try: + tar._extract_member(member, path) + except Exception as exc: +diff --git a/tests/unit/test_utils_unpacking.py b/tests/unit/test_utils_unpacking.py +index efccbdc..6313e45 100644 +--- a/tests/unit/test_utils_unpacking.py ++++ b/tests/unit/test_utils_unpacking.py +@@ -11,6 +11,7 @@ from pathlib import Path + from typing import List, Tuple + + import pytest ++from _pytest.monkeypatch import MonkeyPatch + + from pip._internal.exceptions import InstallationError + from pip._internal.utils.unpacking import is_within_directory, untar_file, unzip_file +@@ -238,6 +239,105 @@ class TestUnpackArchives: + with open(os.path.join(unpack_dir, "symlink.txt"), "rb") as f: + assert f.read() == content + ++ def test_unpack_normal_tar_links_no_data_filter( ++ self, monkeypatch: MonkeyPatch ++ ) -> None: ++ """ ++ Test unpacking a normal tar with file containing soft links, but no data_filter ++ """ ++ if hasattr(tarfile, "data_filter"): ++ monkeypatch.delattr("tarfile.data_filter") ++ ++ tar_filename = "test_tar_links_no_data_filter.tar" ++ tar_filepath = os.path.join(self.tempdir, tar_filename) ++ ++ extract_path = os.path.join(self.tempdir, "extract_path") ++ ++ with tarfile.open(tar_filepath, "w") as tar: ++ file_data = io.BytesIO(b"normal\n") ++ normal_file_tarinfo = tarfile.TarInfo(name="normal_file") ++ normal_file_tarinfo.size = len(file_data.getbuffer()) ++ tar.addfile(normal_file_tarinfo, fileobj=file_data) ++ ++ info = tarfile.TarInfo("normal_symlink") ++ info.type = tarfile.SYMTYPE ++ info.linkpath = "normal_file" ++ tar.addfile(info) ++ ++ untar_file(tar_filepath, extract_path) ++ ++ assert os.path.islink(os.path.join(extract_path, "normal_symlink")) ++ ++ link_path = os.readlink(os.path.join(extract_path, "normal_symlink")) ++ assert link_path == "normal_file" ++ ++ with open(os.path.join(extract_path, "normal_symlink"), "rb") as f: ++ assert f.read() == b"normal\n" ++ ++ def test_unpack_evil_tar_link1_no_data_filter( ++ self, monkeypatch: MonkeyPatch ++ ) -> None: ++ """ ++ Test unpacking a evil tar with file containing soft links, but no data_filter ++ """ ++ if hasattr(tarfile, "data_filter"): ++ monkeypatch.delattr("tarfile.data_filter") ++ ++ tar_filename = "test_tar_links_no_data_filter.tar" ++ tar_filepath = os.path.join(self.tempdir, tar_filename) ++ ++ import_filename = "import_file" ++ import_filepath = os.path.join(self.tempdir, import_filename) ++ open(import_filepath, "w").close() ++ ++ extract_path = os.path.join(self.tempdir, "extract_path") ++ ++ with tarfile.open(tar_filepath, "w") as tar: ++ info = tarfile.TarInfo("evil_symlink") ++ info.type = tarfile.SYMTYPE ++ info.linkpath = import_filepath ++ tar.addfile(info) ++ ++ with pytest.raises(InstallationError) as e: ++ untar_file(tar_filepath, extract_path) ++ ++ assert "trying to install outside target directory" in str(e.value) ++ assert "import_file" in str(e.value) ++ ++ assert not os.path.exists(os.path.join(extract_path, "evil_symlink")) ++ ++ def test_unpack_evil_tar_link2_no_data_filter( ++ self, monkeypatch: MonkeyPatch ++ ) -> None: ++ """ ++ Test unpacking a evil tar with file containing soft links, but no data_filter ++ """ ++ if hasattr(tarfile, "data_filter"): ++ monkeypatch.delattr("tarfile.data_filter") ++ ++ tar_filename = "test_tar_links_no_data_filter.tar" ++ tar_filepath = os.path.join(self.tempdir, tar_filename) ++ ++ import_filename = "import_file" ++ import_filepath = os.path.join(self.tempdir, import_filename) ++ open(import_filepath, "w").close() ++ ++ extract_path = os.path.join(self.tempdir, "extract_path") ++ ++ with tarfile.open(tar_filepath, "w") as tar: ++ info = tarfile.TarInfo("evil_symlink") ++ info.type = tarfile.SYMTYPE ++ info.linkpath = ".." + os.sep + import_filename ++ tar.addfile(info) ++ ++ with pytest.raises(InstallationError) as e: ++ untar_file(tar_filepath, extract_path) ++ ++ assert "trying to install outside target directory" in str(e.value) ++ assert ".." + os.sep + import_filename in str(e.value) ++ ++ assert not os.path.exists(os.path.join(extract_path, "evil_symlink")) ++ + + def test_unpack_tar_unicode(tmpdir: Path) -> None: + test_tar = tmpdir / "test.tar" +-- +2.45.4 + + +From e0499276f96ed4697ddcbf195a9333c56f152956 Mon Sep 17 00:00:00 2001 +From: user +Date: Wed, 20 Aug 2025 13:35:51 +0800 +Subject: [PATCH 02/10] Add NEWS entry + +--- + news/13550.bugfix.rst | 2 ++ + 1 file changed, 2 insertions(+) + create mode 100644 news/13550.bugfix.rst + +diff --git a/news/13550.bugfix.rst b/news/13550.bugfix.rst +new file mode 100644 +index 0000000..64fea7f +--- /dev/null ++++ b/news/13550.bugfix.rst +@@ -0,0 +1,2 @@ ++Add the _check_link_targetfunction to validate the file pointed to by a symlink. If path traversal ++is detected, it should raise an InstallationErrorexception, similar to is_within_directory. +\ No newline at end of file +-- +2.45.4 + + +From f461cca46f45c9b435456a9141caf8836f0990c1 Mon Sep 17 00:00:00 2001 +From: user +Date: Wed, 20 Aug 2025 13:46:25 +0800 +Subject: [PATCH 03/10] Fix the Windows path issue in test cases. + +--- + tests/unit/test_utils_unpacking.py | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tests/unit/test_utils_unpacking.py b/tests/unit/test_utils_unpacking.py +index 6313e45..1c83eec 100644 +--- a/tests/unit/test_utils_unpacking.py ++++ b/tests/unit/test_utils_unpacking.py +@@ -334,7 +334,8 @@ class TestUnpackArchives: + untar_file(tar_filepath, extract_path) + + assert "trying to install outside target directory" in str(e.value) +- assert ".." + os.sep + import_filename in str(e.value) ++ assert ".." in str(e.value) ++ assert import_filename in str(e.value) + + assert not os.path.exists(os.path.join(extract_path, "evil_symlink")) + +-- +2.45.4 + + +From 330047761c9fef468fbb97596e6939047306e396 Mon Sep 17 00:00:00 2001 +From: user +Date: Wed, 20 Aug 2025 16:28:53 +0800 +Subject: [PATCH 04/10] normpath linkname + +--- + news/13550.bugfix.rst | 4 +-- + src/pip/_internal/utils/unpacking.py | 2 ++ + tests/unit/test_utils_unpacking.py | 37 +++++++++++++++++++++++++++- + 3 files changed, 40 insertions(+), 3 deletions(-) + +diff --git a/news/13550.bugfix.rst b/news/13550.bugfix.rst +index 64fea7f..cfc6b96 100644 +--- a/news/13550.bugfix.rst ++++ b/news/13550.bugfix.rst +@@ -1,2 +1,2 @@ +-Add the _check_link_targetfunction to validate the file pointed to by a symlink. If path traversal +-is detected, it should raise an InstallationErrorexception, similar to is_within_directory. +\ No newline at end of file ++Add the _check_link_targetfunction to validate the file pointed to by a symlink. If path traversal ++is detected, it should raise an InstallationErrorexception, similar to is_within_directory. +diff --git a/src/pip/_internal/utils/unpacking.py b/src/pip/_internal/utils/unpacking.py +index f9906f7..338ba78 100644 +--- a/src/pip/_internal/utils/unpacking.py ++++ b/src/pip/_internal/utils/unpacking.py +@@ -261,6 +261,8 @@ def _untar_without_filter( + filter(None, (os.path.dirname(tarinfo.name), tarinfo.linkname)) + ) + ++ linkname = os.path.normpath(linkname) ++ + try: + tar.getmember(linkname) + except KeyError: +diff --git a/tests/unit/test_utils_unpacking.py b/tests/unit/test_utils_unpacking.py +index 1c83eec..f4984e9 100644 +--- a/tests/unit/test_utils_unpacking.py ++++ b/tests/unit/test_utils_unpacking.py +@@ -239,7 +239,7 @@ class TestUnpackArchives: + with open(os.path.join(unpack_dir, "symlink.txt"), "rb") as f: + assert f.read() == content + +- def test_unpack_normal_tar_links_no_data_filter( ++ def test_unpack_normal_tar_link1_no_data_filter( + self, monkeypatch: MonkeyPatch + ) -> None: + """ +@@ -274,6 +274,41 @@ class TestUnpackArchives: + with open(os.path.join(extract_path, "normal_symlink"), "rb") as f: + assert f.read() == b"normal\n" + ++ def test_unpack_normal_tar_link2_no_data_filter( ++ self, monkeypatch: MonkeyPatch ++ ) -> None: ++ """ ++ Test unpacking a normal tar with file containing soft links, but no data_filter ++ """ ++ if hasattr(tarfile, "data_filter"): ++ monkeypatch.delattr("tarfile.data_filter") ++ ++ tar_filename = "test_tar_links_no_data_filter.tar" ++ tar_filepath = os.path.join(self.tempdir, tar_filename) ++ ++ extract_path = os.path.join(self.tempdir, "extract_path") ++ ++ with tarfile.open(tar_filepath, "w") as tar: ++ file_data = io.BytesIO(b"normal\n") ++ normal_file_tarinfo = tarfile.TarInfo(name="normal_file") ++ normal_file_tarinfo.size = len(file_data.getbuffer()) ++ tar.addfile(normal_file_tarinfo, fileobj=file_data) ++ ++ info = tarfile.TarInfo("sub/normal_symlink") ++ info.type = tarfile.SYMTYPE ++ info.linkpath = ".." + os.path.sep + "normal_file" ++ tar.addfile(info) ++ ++ untar_file(tar_filepath, extract_path) ++ ++ assert os.path.islink(os.path.join(extract_path, "sub", "normal_symlink")) ++ ++ link_path = os.readlink(os.path.join(extract_path, "sub", "normal_symlink")) ++ assert link_path == ".." + os.path.sep + "normal_file" ++ ++ with open(os.path.join(extract_path, "sub", "normal_symlink"), "rb") as f: ++ assert f.read() == b"normal\n" ++ + def test_unpack_evil_tar_link1_no_data_filter( + self, monkeypatch: MonkeyPatch + ) -> None: +-- +2.45.4 + + +From c1f1eaeee43563376535f270285e774fcff8f59e Mon Sep 17 00:00:00 2001 +From: user +Date: Wed, 20 Aug 2025 17:54:38 +0800 +Subject: [PATCH 05/10] Handle cases where the name of a member in a tar + archive may use different separators. + +--- + src/pip/_internal/utils/unpacking.py | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/src/pip/_internal/utils/unpacking.py b/src/pip/_internal/utils/unpacking.py +index 338ba78..3dce496 100644 +--- a/src/pip/_internal/utils/unpacking.py ++++ b/src/pip/_internal/utils/unpacking.py +@@ -266,6 +266,15 @@ def _untar_without_filter( + try: + tar.getmember(linkname) + except KeyError: ++ if "\\" in linkname or "/" in linkname: ++ if "\\" in linkname: ++ linkname = linkname.replace("\\", "/") ++ else: ++ linkname = linkname.replace("/", "\\") ++ try: ++ tar.getmember(linkname) ++ except KeyError: ++ raise KeyError(linkname) + raise KeyError(linkname) + + for member in tar.getmembers(): +-- +2.45.4 + + +From 4f696e9666464d33edcb0b784422467cd7bdf11d Mon Sep 17 00:00:00 2001 +From: user +Date: Wed, 20 Aug 2025 18:22:18 +0800 +Subject: [PATCH 06/10] Fix the bug in the process logic. + +--- + src/pip/_internal/utils/unpacking.py | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/pip/_internal/utils/unpacking.py b/src/pip/_internal/utils/unpacking.py +index 3dce496..4f18199 100644 +--- a/src/pip/_internal/utils/unpacking.py ++++ b/src/pip/_internal/utils/unpacking.py +@@ -275,7 +275,8 @@ def _untar_without_filter( + tar.getmember(linkname) + except KeyError: + raise KeyError(linkname) +- raise KeyError(linkname) ++ else: ++ raise KeyError(linkname) + + for member in tar.getmembers(): + fn = member.name +-- +2.45.4 + + +From b8192ae99c1446a0e91e45c565a55665c1f7c7ba Mon Sep 17 00:00:00 2001 +From: dkjsone <221672629+dkjsone@users.noreply.github.com> +Date: Wed, 27 Aug 2025 22:06:51 +0800 +Subject: [PATCH 07/10] =?UTF-8?q?Replace=20=5Fcheck=5Flink=5Ftarget=20with?= + =?UTF-8?q?=20is=5Fsymlink=5Ftarget=5Fin=5Ftar=E2=80=8B=E2=80=8B;=20?= + =?UTF-8?q?=E2=80=8B=E2=80=8BAdd=20deprecation=20note=20for=20=5Funtar=5Fw?= + =?UTF-8?q?ithout=5Ffilter=20for=20future=20removal=E2=80=8B?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--- + news/13550.bugfix.rst | 4 +-- + src/pip/_internal/utils/unpacking.py | 49 +++++++++++++--------------- + 2 files changed, 24 insertions(+), 29 deletions(-) + +diff --git a/news/13550.bugfix.rst b/news/13550.bugfix.rst +index cfc6b96..667d4bd 100644 +--- a/news/13550.bugfix.rst ++++ b/news/13550.bugfix.rst +@@ -1,2 +1,2 @@ +-Add the _check_link_targetfunction to validate the file pointed to by a symlink. If path traversal +-is detected, it should raise an InstallationErrorexception, similar to is_within_directory. ++Pip will now raise an installation error for a source distribution when it includes a symlink that ++points outside the source distribution archive. +diff --git a/src/pip/_internal/utils/unpacking.py b/src/pip/_internal/utils/unpacking.py +index 4f18199..6ff1801 100644 +--- a/src/pip/_internal/utils/unpacking.py ++++ b/src/pip/_internal/utils/unpacking.py +@@ -248,6 +248,21 @@ def untar_file(filename: str, location: str) -> None: + tar.close() + + ++def is_symlink_target_in_tar(tar: tarfile.TarFile, tarinfo: tarfile.TarInfo) -> bool: ++ """Check if the file pointed to by the symbolic link is in the tar archive""" ++ linkname = os.path.join(os.path.dirname(tarinfo.name), tarinfo.linkname) ++ ++ linkname = os.path.normpath(linkname) ++ if "\\" in linkname: ++ linkname = linkname.replace("\\", "/") ++ ++ try: ++ tar.getmember(linkname) ++ return True ++ except KeyError: ++ return False ++ ++ + def _untar_without_filter( + filename: str, + location: str, +@@ -255,29 +270,9 @@ def _untar_without_filter( + leading: bool, + ) -> None: + """Fallback for Python without tarfile.data_filter""" +- +- def _check_link_target(tar: tarfile.TarFile, tarinfo: tarfile.TarInfo) -> None: +- linkname = "/".join( +- filter(None, (os.path.dirname(tarinfo.name), tarinfo.linkname)) +- ) +- +- linkname = os.path.normpath(linkname) +- +- try: +- tar.getmember(linkname) +- except KeyError: +- if "\\" in linkname or "/" in linkname: +- if "\\" in linkname: +- linkname = linkname.replace("\\", "/") +- else: +- linkname = linkname.replace("/", "\\") +- try: +- tar.getmember(linkname) +- except KeyError: +- raise KeyError(linkname) +- else: +- raise KeyError(linkname) +- ++ # NOTE: This function can be removed once pip requires CPython ≥ 3.12.​ ++ # PEP 706 added tarfile.data_filter, made tarfile extraction operations more secure. ++ # This feature is fully supported from CPython 3.12 onward. + for member in tar.getmembers(): + fn = member.name + if leading: +@@ -292,14 +287,14 @@ def _untar_without_filter( + if member.isdir(): + ensure_dir(path) + elif member.issym(): +- try: +- _check_link_target(tar, member) +- except KeyError as exc: ++ if not is_symlink_target_in_tar(tar, member): + message = ( + "The tar file ({}) has a file ({}) trying to install " + "outside target directory ({})" + ) +- raise InstallationError(message.format(filename, member.name, exc)) ++ raise InstallationError( ++ message.format(filename, member.name, member.linkname) ++ ) + try: + tar._extract_member(member, path) + except Exception as exc: +-- +2.45.4 + + +From e9f867e200dd9ce8056ae8dd403a4a1d74a12fff Mon Sep 17 00:00:00 2001 +From: dkjsone <221672629+dkjsone@users.noreply.github.com> +Date: Wed, 3 Sep 2025 23:24:51 +0800 +Subject: [PATCH 08/10] Update test cases with clearer exception assertions; + Update news entry + +--- + news/13550.bugfix.rst | 4 ++-- + tests/unit/test_utils_unpacking.py | 13 +++++++------ + 2 files changed, 9 insertions(+), 8 deletions(-) + +diff --git a/news/13550.bugfix.rst b/news/13550.bugfix.rst +index 667d4bd..6804656 100644 +--- a/news/13550.bugfix.rst ++++ b/news/13550.bugfix.rst +@@ -1,2 +1,2 @@ +-Pip will now raise an installation error for a source distribution when it includes a symlink that +-points outside the source distribution archive. ++For Python versions that do not support PEP 706, pip will now raise an installation error for a ++source distribution when it includes a symlink that points outside the source distribution archive. +\ No newline at end of file +diff --git a/tests/unit/test_utils_unpacking.py b/tests/unit/test_utils_unpacking.py +index f4984e9..4f379f9 100644 +--- a/tests/unit/test_utils_unpacking.py ++++ b/tests/unit/test_utils_unpacking.py +@@ -336,8 +336,8 @@ class TestUnpackArchives: + with pytest.raises(InstallationError) as e: + untar_file(tar_filepath, extract_path) + +- assert "trying to install outside target directory" in str(e.value) +- assert "import_file" in str(e.value) ++ msg = "The tar file ({}) has a file ({}) trying to install outside target directory ({})" ++ assert msg.format(tar_filepath, "evil_symlink", import_filepath) in str(e.value) + + assert not os.path.exists(os.path.join(extract_path, "evil_symlink")) + +@@ -359,18 +359,19 @@ class TestUnpackArchives: + + extract_path = os.path.join(self.tempdir, "extract_path") + ++ link_path = ".." + os.sep + import_filename ++ + with tarfile.open(tar_filepath, "w") as tar: + info = tarfile.TarInfo("evil_symlink") + info.type = tarfile.SYMTYPE +- info.linkpath = ".." + os.sep + import_filename ++ info.linkpath = link_path + tar.addfile(info) + + with pytest.raises(InstallationError) as e: + untar_file(tar_filepath, extract_path) + +- assert "trying to install outside target directory" in str(e.value) +- assert ".." in str(e.value) +- assert import_filename in str(e.value) ++ msg = "The tar file ({}) has a file ({}) trying to install outside target directory ({})" ++ assert msg.format(tar_filepath, "evil_symlink", link_path) in str(e.value) + + assert not os.path.exists(os.path.join(extract_path, "evil_symlink")) + +-- +2.45.4 + + +From 28aa631c2e97cbefe100dba9c77e69bda199efe8 Mon Sep 17 00:00:00 2001 +From: user +Date: Thu, 4 Sep 2025 11:16:23 +0800 +Subject: [PATCH 09/10] Format adjustment, no content changes + +--- + news/13550.bugfix.rst | 4 ++-- + tests/unit/test_utils_unpacking.py | 10 ++++++++-- + 2 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/news/13550.bugfix.rst b/news/13550.bugfix.rst +index 6804656..e7de219 100644 +--- a/news/13550.bugfix.rst ++++ b/news/13550.bugfix.rst +@@ -1,2 +1,2 @@ +-For Python versions that do not support PEP 706, pip will now raise an installation error for a +-source distribution when it includes a symlink that points outside the source distribution archive. +\ No newline at end of file ++For Python versions that do not support PEP 706, pip will now raise an installation error for a ++source distribution when it includes a symlink that points outside the source distribution archive. +diff --git a/tests/unit/test_utils_unpacking.py b/tests/unit/test_utils_unpacking.py +index 4f379f9..d681fcb 100644 +--- a/tests/unit/test_utils_unpacking.py ++++ b/tests/unit/test_utils_unpacking.py +@@ -336,7 +336,10 @@ class TestUnpackArchives: + with pytest.raises(InstallationError) as e: + untar_file(tar_filepath, extract_path) + +- msg = "The tar file ({}) has a file ({}) trying to install outside target directory ({})" ++ msg = ( ++ "The tar file ({}) has a file ({}) trying to install outside " ++ "target directory ({})" ++ ) + assert msg.format(tar_filepath, "evil_symlink", import_filepath) in str(e.value) + + assert not os.path.exists(os.path.join(extract_path, "evil_symlink")) +@@ -370,7 +373,10 @@ class TestUnpackArchives: + with pytest.raises(InstallationError) as e: + untar_file(tar_filepath, extract_path) + +- msg = "The tar file ({}) has a file ({}) trying to install outside target directory ({})" ++ msg = ( ++ "The tar file ({}) has a file ({}) trying to install outside " ++ "target directory ({})" ++ ) + assert msg.format(tar_filepath, "evil_symlink", link_path) in str(e.value) + + assert not os.path.exists(os.path.join(extract_path, "evil_symlink")) +-- +2.45.4 + + +From 1da79ca807cdf4d9948cff1210eceba3b329cbb5 Mon Sep 17 00:00:00 2001 +From: user +Date: Fri, 5 Sep 2025 10:22:10 +0800 +Subject: [PATCH 10/10] =?UTF-8?q?Remove=20redundant=20check=20before=20bac?= + =?UTF-8?q?kslash=20replacement=E2=80=8B?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: https://patch-diff.githubusercontent.com/raw/pypa/pip/pull/13550.patch +--- + src/pip/_internal/utils/unpacking.py | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/src/pip/_internal/utils/unpacking.py b/src/pip/_internal/utils/unpacking.py +index 6ff1801..03467e8 100644 +--- a/src/pip/_internal/utils/unpacking.py ++++ b/src/pip/_internal/utils/unpacking.py +@@ -253,8 +253,7 @@ def is_symlink_target_in_tar(tar: tarfile.TarFile, tarinfo: tarfile.TarInfo) -> + linkname = os.path.join(os.path.dirname(tarinfo.name), tarinfo.linkname) + + linkname = os.path.normpath(linkname) +- if "\\" in linkname: +- linkname = linkname.replace("\\", "/") ++ linkname = linkname.replace("\\", "/") + + try: + tar.getmember(linkname) +-- +2.45.4 + diff --git a/SPECS/python-pip/python-pip.spec b/SPECS/python-pip/python-pip.spec index 10bfa241b3f..61892c221b7 100644 --- a/SPECS/python-pip/python-pip.spec +++ b/SPECS/python-pip/python-pip.spec @@ -5,7 +5,7 @@ A tool for installing and managing Python packages} Summary: A tool for installing and managing Python packages Name: python-pip Version: 24.2 -Release: 3%{?dist} +Release: 4%{?dist} License: MIT AND Python-2.0.1 AND Apache-2.0 AND BSD-2-Clause AND BSD-3-Clause AND ISC AND LGPL-2.1-only AND MPL-2.0 AND (Apache-2.0 OR BSD-2-Clause) Vendor: Microsoft Corporation Distribution: Azure Linux @@ -13,6 +13,7 @@ Group: Development/Tools URL: https://pip.pypa.io/ Source0: https://github.com/pypa/pip/archive/%{version}/%{srcname}-%{version}.tar.gz Patch0: CVE-2024-37891.patch +Patch1: CVE-2025-8869.patch BuildArch: noarch @@ -52,6 +53,9 @@ BuildRequires: python3-wheel %{python3_sitelib}/pip* %changelog +* Mon Sep 29 2025 Azure Linux Security Servicing Account - 24.2-4 +- Patch for CVE-2025-8869 + * Mon Jul 07 2025 Kavya Sree Kaitepalli - 24.2-3 - Bump release to build with asciidoc diff --git a/toolkit/resources/manifests/package/toolchain_aarch64.txt b/toolkit/resources/manifests/package/toolchain_aarch64.txt index 7991d4309ba..0e5960b108f 100644 --- a/toolkit/resources/manifests/package/toolchain_aarch64.txt +++ b/toolkit/resources/manifests/package/toolchain_aarch64.txt @@ -549,7 +549,7 @@ python3-magic-5.45-1.azl3.noarch.rpm python3-markupsafe-2.1.3-1.azl3.aarch64.rpm python3-newt-0.52.23-1.azl3.aarch64.rpm python3-packaging-23.2-3.azl3.noarch.rpm -python3-pip-24.2-3.azl3.noarch.rpm +python3-pip-24.2-4.azl3.noarch.rpm python3-pygments-2.7.4-2.azl3.noarch.rpm python3-rpm-4.18.2-1.azl3.aarch64.rpm python3-rpm-generators-14-11.azl3.noarch.rpm diff --git a/toolkit/resources/manifests/package/toolchain_x86_64.txt b/toolkit/resources/manifests/package/toolchain_x86_64.txt index 7db74d5b3d7..79ce035cc76 100644 --- a/toolkit/resources/manifests/package/toolchain_x86_64.txt +++ b/toolkit/resources/manifests/package/toolchain_x86_64.txt @@ -557,7 +557,7 @@ python3-magic-5.45-1.azl3.noarch.rpm python3-markupsafe-2.1.3-1.azl3.x86_64.rpm python3-newt-0.52.23-1.azl3.x86_64.rpm python3-packaging-23.2-3.azl3.noarch.rpm -python3-pip-24.2-3.azl3.noarch.rpm +python3-pip-24.2-4.azl3.noarch.rpm python3-pygments-2.7.4-2.azl3.noarch.rpm python3-rpm-4.18.2-1.azl3.x86_64.rpm python3-rpm-generators-14-11.azl3.noarch.rpm