diff --git a/CVE-2025-8194-tarfile-no-neg-offsets.patch b/CVE-2025-8194-tarfile-no-neg-offsets.patch deleted file mode 100644 index 96d08b0..0000000 --- a/CVE-2025-8194-tarfile-no-neg-offsets.patch +++ /dev/null @@ -1,212 +0,0 @@ -From fd29bcd380150035ef825b762d8cd085bdab6e53 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) (cherry picked from commit - 7040aa54f14676938970e10c5f74ea93cd56aa38) - -Co-authored-by: Alexander Urieles -Co-authored-by: Gregory P. Smith ---- - Lib/tarfile.py | 3 - Lib/test/test_tarfile.py | 156 ++++++++++ - Misc/NEWS.d/next/Library/2025-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 - -Index: Python-3.13.5/Lib/tarfile.py -=================================================================== ---- Python-3.13.5.orig/Lib/tarfile.py 2025-08-01 22:13:44.185826095 +0200 -+++ Python-3.13.5/Lib/tarfile.py 2025-08-01 22:13:45.524140183 +0200 -@@ -1636,6 +1636,9 @@ - """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 -Index: Python-3.13.5/Lib/test/test_tarfile.py -=================================================================== ---- Python-3.13.5.orig/Lib/test/test_tarfile.py 2025-06-11 17:36:57.000000000 +0200 -+++ Python-3.13.5/Lib/test/test_tarfile.py 2025-08-01 22:13:45.524778259 +0200 -@@ -50,6 +50,7 @@ - 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" -@@ -4578,6 +4579,161 @@ - ar.extractall(self.testdir, filter='fully_trusted') - - -+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(): - os_helper.unlink(TEMPDIR) - os.makedirs(TEMPDIR) -Index: Python-3.13.5/Misc/NEWS.d/next/Library/2025-07-23-00-35-29.gh-issue-130577.c7EITy.rst -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ Python-3.13.5/Misc/NEWS.d/next/Library/2025-07-23-00-35-29.gh-issue-130577.c7EITy.rst 2025-08-01 22:13:45.525174751 +0200 -@@ -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/Python-3.13.5.tar.xz b/Python-3.13.5.tar.xz deleted file mode 100644 index 16b1f7d..0000000 --- a/Python-3.13.5.tar.xz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:93e583f243454e6e9e4588ca2c2662206ad961659863277afcdb96801647d640 -size 22856016 diff --git a/Python-3.13.5.tar.xz.sigstore b/Python-3.13.5.tar.xz.sigstore deleted file mode 100644 index 225651c..0000000 --- a/Python-3.13.5.tar.xz.sigstore +++ /dev/null @@ -1 +0,0 @@ -{"mediaType": "application/vnd.dev.sigstore.bundle.v0.3+json", "verificationMaterial": {"certificate": {"rawBytes": "MIICyjCCAlCgAwIBAgIUdRfsw3XxSwqBsRu/Ryhu0kfD1TEwCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjUwNjExMTc0NjIzWhcNMjUwNjExMTc1NjIzWjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE616iCJ8T+boBEGZNSBgbHZ2TS6Bl7yRCs1F78fvUBWcO/fJl9vTWXF+oPaOhLWVl35iAkn1W04PDVWrqNpFntKOCAW8wggFrMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUlLnv2c6W2ETiqJdQsF9NjtUCVqEwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4YZD8wHwYDVR0RAQH/BBUwE4ERdGhvbWFzQHB5dGhvbi5vcmcwKQYKKwYBBAGDvzABAQQbaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tMCsGCisGAQQBg78wAQgEHQwbaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tMIGKBgorBgEEAdZ5AgQCBHwEegB4AHYA3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4AAAGXYBmnGAAABAMARzBFAiBDOyOIs3CL2AVMb7j6sHu3PYA8pOzJQNmm7J+zPIYzlgIhAK5GqY5j781IK5E7NTaGuPzwcj08xstDLULewS3KRwLBMAoGCCqGSM49BAMDA2gAMGUCMQDn2SkdZvHZZ6RKG8bIgPJdW+qMM9DNUmRm0/F+ePCPjMNwNUY/VQHqgsD4+m7FoX0CMAoIIxK3JZiKBFcP0oUNpnoZcZzZg/SeCkY6fePDlrRMMh5guyKUvMjXOIFREzNaRA=="}, "tlogEntries": [{"logIndex": "235130253", "logId": {"keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="}, "kindVersion": {"kind": "hashedrekord", "version": "0.0.1"}, "integratedTime": "1749663983", "inclusionPromise": {"signedEntryTimestamp": "MEUCIEXmlLAwKmFPqJl0qZIn6l9LeN1eFpo/O29cweVvcLM6AiEAkPbiV9MFAugYnKigfY2M6d4/IlgLMlamVTNMjYG1Ujc="}, "inclusionProof": {"logIndex": "113225991", "rootHash": "+L93VCZOPa9BkLmARBWDo1xEWF+fT68+yQcazjpxAAU=", "treeSize": "113225992", "hashes": ["Rdu+myw6n6JxBUvJ8Q+8oqhqACFhkt/3w7I+DEesttk=", "RxFdYWKOAXBMCLz1xkC2n0/oY0PPGjB9g/1mK9X9Lpk=", "nRMGDo+FIXFJXJGmLI3xYofkA1BacK+jsaHI6Dah6SQ=", "P4PZCTzvD59p99NgLr2g5UaCSGBHniridbmhL+bTkOA=", "Ho1rvGrV8vApgV6ObQmLHUFtPdLht0dxaKIMr2L227A=", "bUrfsqt1y90MYAQSa4N7IMFLQ58Gr3kyGuZsXADQmyk=", "zQYNyoYKqtevNhM4z5didetaiTZZe4Ydpenxywyp2HM=", "yB2hiozejE1yTbQwbDQpScNo2G9QaqtVTvrtSzcAWLk=", "ni+UOcPDIr1WWONf2Z1uda+A31LRXKpMYBvhb3MyUvI=", "jak2gEavHKki8uP+13+VibRhrrjlEQ57Cu6sFEmzL98=", "x/DbUcJZd7Krichz/nbTRqNRynFXkcgDj6/SVp3Xpa8=", "KL733V6m2mKaszPoebRYld3g+XcUSNldm6GnXG4M7kM=", "f42cOIPnrB9x+HYKZ+7UAkXKjk7k9ttvx1Mm5/glCwo=", "G4CdPz/xjoqWI4G874tZWPeP98DJpseyihrtz0ivBtU=", "mta5fH/gFwxJ/0fT8yGpn3sFCY0G1RY555Iflm0LInM=", "7v8qPHNDLerpduaMx06eb/MwgoQwczTn/cYGKX/9wZ4="], "checkpoint": {"envelope": "rekor.sigstore.dev - 1193050959916656506\n113225992\n+L93VCZOPa9BkLmARBWDo1xEWF+fT68+yQcazjpxAAU=\n\n\u2014 rekor.sigstore.dev wNI9ajBEAiBKR6/aQGwMRmyBmdgiaLd8393XQqJh41H6LIYA8Y6SYgIgDMucmAXZHwIDjA6YXg9k2vhoOuscGewoHiSomHsf+kg=\n"}}, "canonicalizedBody": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI5M2U1ODNmMjQzNDU0ZTZlOWU0NTg4Y2EyYzI2NjIyMDZhZDk2MTY1OTg2MzI3N2FmY2RiOTY4MDE2NDdkNjQwIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJRWVnU0xnMVBzNmNEMkpNbTJzK1o4dzBzbGlMazY0SCtHeHQ2VFpRb1NIaUFpRUE1b2FmTTJhNlJqQSszUFpVdmNjUWNhQ0QzRVFsQ1hSdmI3d2x3SU9JQ1IwPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVTjVha05EUVd4RFowRjNTVUpCWjBsVlpGSm1jM2N6V0hoVGQzRkNjMUoxTDFKNWFIVXdhMlpFTVZSRmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFZkMDVxUlhoTlZHTXdUbXBKZWxkb1kwNU5hbFYzVG1wRmVFMVVZekZPYWtsNlYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVUyTVRacFEwbzRWQ3RpYjBKRlIxcE9VMEpuWWtoYU1sUlROa0pzTjNsU1EzTXhSamNLT0daMlZVSlhZMDh2Wmtwc09YWlVWMWhHSzI5UVlVOW9URmRXYkRNMWFVRnJiakZYTURSUVJGWlhjbkZPY0VadWRFdFBRMEZYT0hkblowWnlUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXUkNaMDVXU0ZFMFJVWm5VVlZzVEc1MkNqSmpObGN5UlZScGNVcGtVWE5HT1U1cWRGVkRWbkZGZDBoM1dVUldVakJxUWtKbmQwWnZRVlV6T1ZCd2VqRlphMFZhWWpWeFRtcHdTMFpYYVhocE5Ga0tXa1E0ZDBoM1dVUldVakJTUVZGSUwwSkNWWGRGTkVWU1pFZG9kbUpYUm5wUlNFSTFaRWRvZG1KcE5YWmpiV04zUzFGWlMwdDNXVUpDUVVkRWRucEJRZ3BCVVZGaVlVaFNNR05JVFRaTWVUbG9XVEpPZG1SWE5UQmplVFZ1WWpJNWJtSkhWWFZaTWpsMFRVTnpSME5wYzBkQlVWRkNaemM0ZDBGUlowVklVWGRpQ21GSVVqQmpTRTAyVEhrNWFGa3lUblprVnpVd1kzazFibUl5T1c1aVIxVjFXVEk1ZEUxSlIwdENaMjl5UW1kRlJVRmtXalZCWjFGRFFraDNSV1ZuUWpRS1FVaFpRVE5VTUhkaGMySklSVlJLYWtkU05HTnRWMk16UVhGS1MxaHlhbVZRU3pNdmFEUndlV2RET0hBM2J6UkJRVUZIV0ZsQ2JXNUhRVUZCUWtGTlFRcFNla0pHUVdsQ1JFOTVUMGx6TTBOTU1rRldUV0kzYWpaelNIVXpVRmxCT0hCUGVrcFJUbTF0TjBvcmVsQkpXWHBzWjBsb1FVczFSM0ZaTldvM09ERkpDa3MxUlRkT1ZHRkhkVkI2ZDJOcU1EaDRjM1JFVEZWTVpYZFRNMHRTZDB4Q1RVRnZSME5EY1VkVFRUUTVRa0ZOUkVFeVowRk5SMVZEVFZGRWJqSlRhMlFLV25aSVdsbzJVa3RIT0dKSloxQktaRmNyY1UxTk9VUk9WVzFTYlRBdlJpdGxVRU5RYWsxT2QwNVZXUzlXVVVoeFozTkVOQ3R0TjBadldEQkRUVUZ2U1FwSmVFc3pTbHBwUzBKR1kxQXdiMVZPY0c1dldtTmFlbHBuTDFObFEydFpObVpsVUVSc2NsSk5UV2cxWjNWNVMxVjJUV3BZVDBsR1VrVjZUbUZTUVQwOUNpMHRMUzB0UlU1RUlFTkZVbFJKUmtsRFFWUkZMUzB0TFMwSyJ9fX19"}], "timestampVerificationData": {}}, "messageSignature": {"messageDigest": {"algorithm": "SHA2_256", "digest": "k+WD8kNFTm6eRYjKLCZiIGrZYWWYYyd6/NuWgBZH1kA="}, "signature": "MEUCIEegSLg1Ps6cD2JMm2s+Z8w0sliLk64H+Gxt6TZQoSHiAiEA5oafM2a6RjA+3PZUvccQcaCD3EQlCXRvb7wlwIOICR0="}}