From 4a8092b28196c0db9a2e140c1124b90eb87d8845 Mon Sep 17 00:00:00 2001 From: Kanishk Bansal <103916909+Kanishk-Bansal@users.noreply.github.com> Date: Sat, 4 Oct 2025 01:05:38 +0530 Subject: [PATCH] Patch `python3` for CVE-2025-8194 [High] (#14691) Signed-off-by: Kanishk Bansal Co-authored-by: Kanishk Bansal (cherry picked from commit b174f1e614c0a4d7b93d30c430a9ebc9455c91b9) --- SPECS/python3/CVE-2025-8194.patch | 216 ++++++++++++++++++ SPECS/python3/python3.spec | 10 +- .../manifests/package/pkggen_core_aarch64.txt | 8 +- .../manifests/package/pkggen_core_x86_64.txt | 8 +- .../manifests/package/toolchain_aarch64.txt | 18 +- .../manifests/package/toolchain_x86_64.txt | 18 +- 6 files changed, 250 insertions(+), 28 deletions(-) create mode 100644 SPECS/python3/CVE-2025-8194.patch diff --git a/SPECS/python3/CVE-2025-8194.patch b/SPECS/python3/CVE-2025-8194.patch new file mode 100644 index 00000000000..60cc204f12e --- /dev/null +++ b/SPECS/python3/CVE-2025-8194.patch @@ -0,0 +1,216 @@ +From 72b6fd266e42bfa6196317bcf049666c5bad74a3 Mon Sep 17 00:00:00 2001 +From: Alexander Urieles +Date: Mon, 28 Jul 2025 17:37:26 +0200 +Subject: [PATCH] gh-130577: tarfile now validates archives to ensure member + offsets are non-negative (GH-137027) + +Co-authored-by: Gregory P. Smith +(cherry picked from commit 7040aa54f14676938970e10c5f74ea93cd56aa38) + +Upstream Patch Reference: https://github.com/python/cpython/pull/137645 +Signed-off-by: Kanishk Bansal + +--- + Lib/tarfile.py | 3 + + Lib/test/test_tarfile.py | 156 ++++++++++++++++++ + ...-07-23-00-35-29.gh-issue-130577.c7EITy.rst | 3 + + 3 files changed, 162 insertions(+) + create mode 100644 Misc/NEWS.d/next/Library/2025-07-23-00-35-29.gh-issue-130577.c7EITy.rst + +diff --git a/Lib/tarfile.py b/Lib/tarfile.py +index 7c9027dde849fd..209c206231dc97 100755 +--- a/Lib/tarfile.py ++++ b/Lib/tarfile.py +@@ -1602,6 +1602,9 @@ def _block(self, count): + """Round up a byte count by BLOCKSIZE and return it, + e.g. _block(834) => 1024. + """ ++ # Only non-negative offsets are allowed ++ if count < 0: ++ raise InvalidHeaderError("invalid offset") + blocks, remainder = divmod(count, BLOCKSIZE) + if remainder: + blocks += 1 +diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py +index 01d1e5e0ccf410..17d2239339ec1a 100644 +--- a/Lib/test/test_tarfile.py ++++ b/Lib/test/test_tarfile.py +@@ -48,6 +48,7 @@ def sha256sum(data): + xzname = os.path.join(TEMPDIR, "testtar.tar.xz") + tmpname = os.path.join(TEMPDIR, "tmp.tar") + dotlessname = os.path.join(TEMPDIR, "testtar") ++SPACE = b" " + + sha256_regtype = ( + "e09e4bc8b3c9d9177e77256353b36c159f5f040531bbd4b024a8f9b9196c71ce" +@@ -4234,6 +4235,161 @@ def valueerror_filter(tarinfo, path): + self.expect_exception(TypeError) # errorlevel is not int + + ++class OffsetValidationTests(unittest.TestCase): ++ tarname = tmpname ++ invalid_posix_header = ( ++ # name: 100 bytes ++ tarfile.NUL * tarfile.LENGTH_NAME ++ # mode, space, null terminator: 8 bytes ++ + b"000755" + SPACE + tarfile.NUL ++ # uid, space, null terminator: 8 bytes ++ + b"000001" + SPACE + tarfile.NUL ++ # gid, space, null terminator: 8 bytes ++ + b"000001" + SPACE + tarfile.NUL ++ # size, space: 12 bytes ++ + b"\xff" * 11 + SPACE ++ # mtime, space: 12 bytes ++ + tarfile.NUL * 11 + SPACE ++ # chksum: 8 bytes ++ + b"0011407" + tarfile.NUL ++ # type: 1 byte ++ + tarfile.REGTYPE ++ # linkname: 100 bytes ++ + tarfile.NUL * tarfile.LENGTH_LINK ++ # magic: 6 bytes, version: 2 bytes ++ + tarfile.POSIX_MAGIC ++ # uname: 32 bytes ++ + tarfile.NUL * 32 ++ # gname: 32 bytes ++ + tarfile.NUL * 32 ++ # devmajor, space, null terminator: 8 bytes ++ + tarfile.NUL * 6 + SPACE + tarfile.NUL ++ # devminor, space, null terminator: 8 bytes ++ + tarfile.NUL * 6 + SPACE + tarfile.NUL ++ # prefix: 155 bytes ++ + tarfile.NUL * tarfile.LENGTH_PREFIX ++ # padding: 12 bytes ++ + tarfile.NUL * 12 ++ ) ++ invalid_gnu_header = ( ++ # name: 100 bytes ++ tarfile.NUL * tarfile.LENGTH_NAME ++ # mode, null terminator: 8 bytes ++ + b"0000755" + tarfile.NUL ++ # uid, null terminator: 8 bytes ++ + b"0000001" + tarfile.NUL ++ # gid, space, null terminator: 8 bytes ++ + b"0000001" + tarfile.NUL ++ # size, space: 12 bytes ++ + b"\xff" * 11 + SPACE ++ # mtime, space: 12 bytes ++ + tarfile.NUL * 11 + SPACE ++ # chksum: 8 bytes ++ + b"0011327" + tarfile.NUL ++ # type: 1 byte ++ + tarfile.REGTYPE ++ # linkname: 100 bytes ++ + tarfile.NUL * tarfile.LENGTH_LINK ++ # magic: 8 bytes ++ + tarfile.GNU_MAGIC ++ # uname: 32 bytes ++ + tarfile.NUL * 32 ++ # gname: 32 bytes ++ + tarfile.NUL * 32 ++ # devmajor, null terminator: 8 bytes ++ + tarfile.NUL * 8 ++ # devminor, null terminator: 8 bytes ++ + tarfile.NUL * 8 ++ # padding: 167 bytes ++ + tarfile.NUL * 167 ++ ) ++ invalid_v7_header = ( ++ # name: 100 bytes ++ tarfile.NUL * tarfile.LENGTH_NAME ++ # mode, space, null terminator: 8 bytes ++ + b"000755" + SPACE + tarfile.NUL ++ # uid, space, null terminator: 8 bytes ++ + b"000001" + SPACE + tarfile.NUL ++ # gid, space, null terminator: 8 bytes ++ + b"000001" + SPACE + tarfile.NUL ++ # size, space: 12 bytes ++ + b"\xff" * 11 + SPACE ++ # mtime, space: 12 bytes ++ + tarfile.NUL * 11 + SPACE ++ # chksum: 8 bytes ++ + b"0010070" + tarfile.NUL ++ # type: 1 byte ++ + tarfile.REGTYPE ++ # linkname: 100 bytes ++ + tarfile.NUL * tarfile.LENGTH_LINK ++ # padding: 255 bytes ++ + tarfile.NUL * 255 ++ ) ++ valid_gnu_header = tarfile.TarInfo("filename").tobuf(tarfile.GNU_FORMAT) ++ data_block = b"\xff" * tarfile.BLOCKSIZE ++ ++ def _write_buffer(self, buffer): ++ with open(self.tarname, "wb") as f: ++ f.write(buffer) ++ ++ def _get_members(self, ignore_zeros=None): ++ with open(self.tarname, "rb") as f: ++ with tarfile.open( ++ mode="r", fileobj=f, ignore_zeros=ignore_zeros ++ ) as tar: ++ return tar.getmembers() ++ ++ def _assert_raises_read_error_exception(self): ++ with self.assertRaisesRegex( ++ tarfile.ReadError, "file could not be opened successfully" ++ ): ++ self._get_members() ++ ++ def test_invalid_offset_header_validations(self): ++ for tar_format, invalid_header in ( ++ ("posix", self.invalid_posix_header), ++ ("gnu", self.invalid_gnu_header), ++ ("v7", self.invalid_v7_header), ++ ): ++ with self.subTest(format=tar_format): ++ self._write_buffer(invalid_header) ++ self._assert_raises_read_error_exception() ++ ++ def test_early_stop_at_invalid_offset_header(self): ++ buffer = self.valid_gnu_header + self.invalid_gnu_header + self.valid_gnu_header ++ self._write_buffer(buffer) ++ members = self._get_members() ++ self.assertEqual(len(members), 1) ++ self.assertEqual(members[0].name, "filename") ++ self.assertEqual(members[0].offset, 0) ++ ++ def test_ignore_invalid_archive(self): ++ # 3 invalid headers with their respective data ++ buffer = (self.invalid_gnu_header + self.data_block) * 3 ++ self._write_buffer(buffer) ++ members = self._get_members(ignore_zeros=True) ++ self.assertEqual(len(members), 0) ++ ++ def test_ignore_invalid_offset_headers(self): ++ for first_block, second_block, expected_offset in ( ++ ( ++ (self.valid_gnu_header), ++ (self.invalid_gnu_header + self.data_block), ++ 0, ++ ), ++ ( ++ (self.invalid_gnu_header + self.data_block), ++ (self.valid_gnu_header), ++ 1024, ++ ), ++ ): ++ self._write_buffer(first_block + second_block) ++ members = self._get_members(ignore_zeros=True) ++ self.assertEqual(len(members), 1) ++ self.assertEqual(members[0].name, "filename") ++ self.assertEqual(members[0].offset, expected_offset) ++ ++ + def setUpModule(): + support.unlink(TEMPDIR) + os.makedirs(TEMPDIR) +diff --git a/Misc/NEWS.d/next/Library/2025-07-23-00-35-29.gh-issue-130577.c7EITy.rst b/Misc/NEWS.d/next/Library/2025-07-23-00-35-29.gh-issue-130577.c7EITy.rst +new file mode 100644 +index 00000000000000..342cabbc865dc4 +--- /dev/null ++++ b/Misc/NEWS.d/next/Library/2025-07-23-00-35-29.gh-issue-130577.c7EITy.rst +@@ -0,0 +1,3 @@ ++:mod:`tarfile` now validates archives to ensure member offsets are ++non-negative. (Contributed by Alexander Enrique Urieles Nieto in ++:gh:`130577`.) diff --git a/SPECS/python3/python3.spec b/SPECS/python3/python3.spec index fbdacc6178c..96451dc1356 100644 --- a/SPECS/python3/python3.spec +++ b/SPECS/python3/python3.spec @@ -12,7 +12,7 @@ Summary: A high-level scripting language Name: python3 Version: 3.9.19 -Release: 14%{?dist} +Release: 15%{?dist} License: PSF Vendor: Microsoft Corporation Distribution: Mariner @@ -36,6 +36,7 @@ Patch12: CVE-2025-1795.patch Patch13: CVE-2025-6069.patch Patch14: CVE-2025-4516.patch Patch15: CVE-2025-4138.patch +Patch16: CVE-2025-8194.patch # Patch for setuptools, resolved in 65.5.1 Patch1000: CVE-2022-40897.patch Patch1001: CVE-2024-6345.patch @@ -70,7 +71,8 @@ Provides: /bin/python3 Provides: %{name}-docs = %{version}-%{release} Provides: python%{majmin} = %{version}-%{release} Provides: python%{majmin_nodots} = %{version}-%{release} -%if %{with_check} + +%if 0%{?with_check} BuildRequires: iana-etc BuildRequires: tzdata %endif @@ -196,6 +198,7 @@ The test package contains all regression tests for Python as well as the modules %patch13 -p1 %patch14 -p1 %patch15 -p1 +%patch16 -p1 %build # Remove GCC specs and build environment linker scripts @@ -371,6 +374,9 @@ make test TESTOPTS="-x test_multiprocessing_spawn -x test_socket -x test_email" %{_libdir}/python%{majmin}/test/* %changelog +* Thu Sep 18 2025 Kanishk Bansal - 3.9.19-15 +- Patch CVE-2025-8194 + * Mon Jun 30 2025 Aninda Pradhan - 3.9.19-14 - Addresses CVE-2025-6069, CVE-2025-4516, CVE-2025-50181, CVE-2023-5752, CVE-2023-45803 - Patch for CVE-2025-4138: Addresses CVE-2024-12718, CVE-2025-4138, CVE-2025-4330, CVE-2025-4517, CVE-2025-4435 diff --git a/toolkit/resources/manifests/package/pkggen_core_aarch64.txt b/toolkit/resources/manifests/package/pkggen_core_aarch64.txt index a2e392dc861..22b17488fe6 100644 --- a/toolkit/resources/manifests/package/pkggen_core_aarch64.txt +++ b/toolkit/resources/manifests/package/pkggen_core_aarch64.txt @@ -237,10 +237,10 @@ ca-certificates-base-2.0.0-22.cm2.noarch.rpm ca-certificates-2.0.0-22.cm2.noarch.rpm dwz-0.14-2.cm2.aarch64.rpm unzip-6.0-22.cm2.aarch64.rpm -python3-3.9.19-14.cm2.aarch64.rpm -python3-devel-3.9.19-14.cm2.aarch64.rpm -python3-libs-3.9.19-14.cm2.aarch64.rpm -python3-setuptools-3.9.19-14.cm2.noarch.rpm +python3-3.9.19-15.cm2.aarch64.rpm +python3-devel-3.9.19-15.cm2.aarch64.rpm +python3-libs-3.9.19-15.cm2.aarch64.rpm +python3-setuptools-3.9.19-15.cm2.noarch.rpm python3-pygments-2.4.2-7.cm2.noarch.rpm which-2.21-8.cm2.aarch64.rpm libselinux-3.2-1.cm2.aarch64.rpm diff --git a/toolkit/resources/manifests/package/pkggen_core_x86_64.txt b/toolkit/resources/manifests/package/pkggen_core_x86_64.txt index 98d520e440f..5b3a2232b57 100644 --- a/toolkit/resources/manifests/package/pkggen_core_x86_64.txt +++ b/toolkit/resources/manifests/package/pkggen_core_x86_64.txt @@ -237,10 +237,10 @@ ca-certificates-base-2.0.0-22.cm2.noarch.rpm ca-certificates-2.0.0-22.cm2.noarch.rpm dwz-0.14-2.cm2.x86_64.rpm unzip-6.0-22.cm2.x86_64.rpm -python3-3.9.19-14.cm2.x86_64.rpm -python3-devel-3.9.19-14.cm2.x86_64.rpm -python3-libs-3.9.19-14.cm2.x86_64.rpm -python3-setuptools-3.9.19-14.cm2.noarch.rpm +python3-3.9.19-15.cm2.x86_64.rpm +python3-devel-3.9.19-15.cm2.x86_64.rpm +python3-libs-3.9.19-15.cm2.x86_64.rpm +python3-setuptools-3.9.19-15.cm2.noarch.rpm python3-pygments-2.4.2-7.cm2.noarch.rpm which-2.21-8.cm2.x86_64.rpm libselinux-3.2-1.cm2.x86_64.rpm diff --git a/toolkit/resources/manifests/package/toolchain_aarch64.txt b/toolkit/resources/manifests/package/toolchain_aarch64.txt index 1ca7d4cfa85..ef4867ecc36 100644 --- a/toolkit/resources/manifests/package/toolchain_aarch64.txt +++ b/toolkit/resources/manifests/package/toolchain_aarch64.txt @@ -510,28 +510,28 @@ procps-ng-devel-3.3.17-2.cm2.aarch64.rpm procps-ng-lang-3.3.17-2.cm2.aarch64.rpm pyproject-rpm-macros-1.0.0~rc1-4.cm2.noarch.rpm python-markupsafe-debuginfo-2.1.0-1.cm2.aarch64.rpm -python3-3.9.19-14.cm2.aarch64.rpm +python3-3.9.19-15.cm2.aarch64.rpm python3-audit-3.0.6-8.cm2.aarch64.rpm python3-cracklib-2.9.7-5.cm2.aarch64.rpm -python3-curses-3.9.19-14.cm2.aarch64.rpm +python3-curses-3.9.19-15.cm2.aarch64.rpm python3-Cython-0.29.33-2.cm2.aarch64.rpm -python3-debuginfo-3.9.19-14.cm2.aarch64.rpm -python3-devel-3.9.19-14.cm2.aarch64.rpm +python3-debuginfo-3.9.19-15.cm2.aarch64.rpm +python3-devel-3.9.19-15.cm2.aarch64.rpm python3-gpg-1.16.0-2.cm2.aarch64.rpm python3-jinja2-3.0.3-7.cm2.noarch.rpm python3-libcap-ng-0.8.2-2.cm2.aarch64.rpm -python3-libs-3.9.19-14.cm2.aarch64.rpm +python3-libs-3.9.19-15.cm2.aarch64.rpm python3-libxml2-2.10.4-8.cm2.aarch64.rpm python3-lxml-4.9.1-1.cm2.aarch64.rpm python3-magic-5.40-3.cm2.noarch.rpm python3-markupsafe-2.1.0-1.cm2.aarch64.rpm python3-newt-0.52.21-5.cm2.aarch64.rpm -python3-pip-3.9.19-14.cm2.noarch.rpm +python3-pip-3.9.19-15.cm2.noarch.rpm python3-pygments-2.4.2-7.cm2.noarch.rpm python3-rpm-4.18.0-4.cm2.aarch64.rpm -python3-setuptools-3.9.19-14.cm2.noarch.rpm -python3-test-3.9.19-14.cm2.aarch64.rpm -python3-tools-3.9.19-14.cm2.aarch64.rpm +python3-setuptools-3.9.19-15.cm2.noarch.rpm +python3-test-3.9.19-15.cm2.aarch64.rpm +python3-tools-3.9.19-15.cm2.aarch64.rpm readline-8.1-1.cm2.aarch64.rpm readline-debuginfo-8.1-1.cm2.aarch64.rpm readline-devel-8.1-1.cm2.aarch64.rpm diff --git a/toolkit/resources/manifests/package/toolchain_x86_64.txt b/toolkit/resources/manifests/package/toolchain_x86_64.txt index f88c2b33adf..acbd987f3e0 100644 --- a/toolkit/resources/manifests/package/toolchain_x86_64.txt +++ b/toolkit/resources/manifests/package/toolchain_x86_64.txt @@ -516,28 +516,28 @@ procps-ng-devel-3.3.17-2.cm2.x86_64.rpm procps-ng-lang-3.3.17-2.cm2.x86_64.rpm pyproject-rpm-macros-1.0.0~rc1-4.cm2.noarch.rpm python-markupsafe-debuginfo-2.1.0-1.cm2.x86_64.rpm -python3-3.9.19-14.cm2.x86_64.rpm +python3-3.9.19-15.cm2.x86_64.rpm python3-audit-3.0.6-8.cm2.x86_64.rpm python3-cracklib-2.9.7-5.cm2.x86_64.rpm -python3-curses-3.9.19-14.cm2.x86_64.rpm +python3-curses-3.9.19-15.cm2.x86_64.rpm python3-Cython-0.29.33-2.cm2.x86_64.rpm -python3-debuginfo-3.9.19-14.cm2.x86_64.rpm -python3-devel-3.9.19-14.cm2.x86_64.rpm +python3-debuginfo-3.9.19-15.cm2.x86_64.rpm +python3-devel-3.9.19-15.cm2.x86_64.rpm python3-gpg-1.16.0-2.cm2.x86_64.rpm python3-jinja2-3.0.3-7.cm2.noarch.rpm python3-libcap-ng-0.8.2-2.cm2.x86_64.rpm -python3-libs-3.9.19-14.cm2.x86_64.rpm +python3-libs-3.9.19-15.cm2.x86_64.rpm python3-libxml2-2.10.4-8.cm2.x86_64.rpm python3-lxml-4.9.1-1.cm2.x86_64.rpm python3-magic-5.40-3.cm2.noarch.rpm python3-markupsafe-2.1.0-1.cm2.x86_64.rpm python3-newt-0.52.21-5.cm2.x86_64.rpm -python3-pip-3.9.19-14.cm2.noarch.rpm +python3-pip-3.9.19-15.cm2.noarch.rpm python3-pygments-2.4.2-7.cm2.noarch.rpm python3-rpm-4.18.0-4.cm2.x86_64.rpm -python3-setuptools-3.9.19-14.cm2.noarch.rpm -python3-test-3.9.19-14.cm2.x86_64.rpm -python3-tools-3.9.19-14.cm2.x86_64.rpm +python3-setuptools-3.9.19-15.cm2.noarch.rpm +python3-test-3.9.19-15.cm2.x86_64.rpm +python3-tools-3.9.19-15.cm2.x86_64.rpm readline-8.1-1.cm2.x86_64.rpm readline-debuginfo-8.1-1.cm2.x86_64.rpm readline-devel-8.1-1.cm2.x86_64.rpm