summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta/recipes-devtools/python/python3/CVE-2025-8194.patch224
-rw-r--r--meta/recipes-devtools/python/python3_3.13.4.bb1
2 files changed, 225 insertions, 0 deletions
diff --git a/meta/recipes-devtools/python/python3/CVE-2025-8194.patch b/meta/recipes-devtools/python/python3/CVE-2025-8194.patch
new file mode 100644
index 0000000000..28653e1843
--- /dev/null
+++ b/meta/recipes-devtools/python/python3/CVE-2025-8194.patch
@@ -0,0 +1,224 @@
1From cdae923ffe187d6ef916c0f665a31249619193fe Mon Sep 17 00:00:00 2001
2From: "Miss Islington (bot)"
3 <31488909+miss-islington@users.noreply.github.com>
4Date: Mon, 28 Jul 2025 17:59:33 +0200
5Subject: [PATCH] gh-130577: tarfile now validates archives to ensure member
6 offsets are non-negative (GH-137027) (#137170)
7
8gh-130577: tarfile now validates archives to ensure member offsets are non-negative (GH-137027)
9(cherry picked from commit 7040aa54f14676938970e10c5f74ea93cd56aa38)
10
11Co-authored-by: Alexander Urieles <aeurielesn@users.noreply.github.com>
12Co-authored-by: Gregory P. Smith <greg@krypto.org>
13
14CVE: CVE-2025-8194
15
16Upstream-Status: Backport [https://github.com/python/cpython/commit/cdae923ffe187d6ef916c0f665a31249619193fe]
17
18Signed-off-by: Praveen Kumar <praveen.kumar@windriver.com>
19---
20 Lib/tarfile.py | 3 +
21 Lib/test/test_tarfile.py | 156 ++++++++++++++++++
22 ...-07-23-00-35-29.gh-issue-130577.c7EITy.rst | 3 +
23 3 files changed, 162 insertions(+)
24 create mode 100644 Misc/NEWS.d/next/Library/2025-07-23-00-35-29.gh-issue-130577.c7EITy.rst
25
26diff --git a/Lib/tarfile.py b/Lib/tarfile.py
27index 0980f6a..9ff9df6 100755
28--- a/Lib/tarfile.py
29+++ b/Lib/tarfile.py
30@@ -1636,6 +1636,9 @@ class TarInfo(object):
31 """Round up a byte count by BLOCKSIZE and return it,
32 e.g. _block(834) => 1024.
33 """
34+ # Only non-negative offsets are allowed
35+ if count < 0:
36+ raise InvalidHeaderError("invalid offset")
37 blocks, remainder = divmod(count, BLOCKSIZE)
38 if remainder:
39 blocks += 1
40diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py
41index ac31be0..7024be4 100644
42--- a/Lib/test/test_tarfile.py
43+++ b/Lib/test/test_tarfile.py
44@@ -50,6 +50,7 @@ bz2name = os.path.join(TEMPDIR, "testtar.tar.bz2")
45 xzname = os.path.join(TEMPDIR, "testtar.tar.xz")
46 tmpname = os.path.join(TEMPDIR, "tmp.tar")
47 dotlessname = os.path.join(TEMPDIR, "testtar")
48+SPACE = b" "
49
50 sha256_regtype = (
51 "e09e4bc8b3c9d9177e77256353b36c159f5f040531bbd4b024a8f9b9196c71ce"
52@@ -4578,6 +4579,161 @@ class OverwriteTests(archiver_tests.OverwriteTests, unittest.TestCase):
53 ar.extractall(self.testdir, filter='fully_trusted')
54
55
56+class OffsetValidationTests(unittest.TestCase):
57+ tarname = tmpname
58+ invalid_posix_header = (
59+ # name: 100 bytes
60+ tarfile.NUL * tarfile.LENGTH_NAME
61+ # mode, space, null terminator: 8 bytes
62+ + b"000755" + SPACE + tarfile.NUL
63+ # uid, space, null terminator: 8 bytes
64+ + b"000001" + SPACE + tarfile.NUL
65+ # gid, space, null terminator: 8 bytes
66+ + b"000001" + SPACE + tarfile.NUL
67+ # size, space: 12 bytes
68+ + b"\xff" * 11 + SPACE
69+ # mtime, space: 12 bytes
70+ + tarfile.NUL * 11 + SPACE
71+ # chksum: 8 bytes
72+ + b"0011407" + tarfile.NUL
73+ # type: 1 byte
74+ + tarfile.REGTYPE
75+ # linkname: 100 bytes
76+ + tarfile.NUL * tarfile.LENGTH_LINK
77+ # magic: 6 bytes, version: 2 bytes
78+ + tarfile.POSIX_MAGIC
79+ # uname: 32 bytes
80+ + tarfile.NUL * 32
81+ # gname: 32 bytes
82+ + tarfile.NUL * 32
83+ # devmajor, space, null terminator: 8 bytes
84+ + tarfile.NUL * 6 + SPACE + tarfile.NUL
85+ # devminor, space, null terminator: 8 bytes
86+ + tarfile.NUL * 6 + SPACE + tarfile.NUL
87+ # prefix: 155 bytes
88+ + tarfile.NUL * tarfile.LENGTH_PREFIX
89+ # padding: 12 bytes
90+ + tarfile.NUL * 12
91+ )
92+ invalid_gnu_header = (
93+ # name: 100 bytes
94+ tarfile.NUL * tarfile.LENGTH_NAME
95+ # mode, null terminator: 8 bytes
96+ + b"0000755" + tarfile.NUL
97+ # uid, null terminator: 8 bytes
98+ + b"0000001" + tarfile.NUL
99+ # gid, space, null terminator: 8 bytes
100+ + b"0000001" + tarfile.NUL
101+ # size, space: 12 bytes
102+ + b"\xff" * 11 + SPACE
103+ # mtime, space: 12 bytes
104+ + tarfile.NUL * 11 + SPACE
105+ # chksum: 8 bytes
106+ + b"0011327" + tarfile.NUL
107+ # type: 1 byte
108+ + tarfile.REGTYPE
109+ # linkname: 100 bytes
110+ + tarfile.NUL * tarfile.LENGTH_LINK
111+ # magic: 8 bytes
112+ + tarfile.GNU_MAGIC
113+ # uname: 32 bytes
114+ + tarfile.NUL * 32
115+ # gname: 32 bytes
116+ + tarfile.NUL * 32
117+ # devmajor, null terminator: 8 bytes
118+ + tarfile.NUL * 8
119+ # devminor, null terminator: 8 bytes
120+ + tarfile.NUL * 8
121+ # padding: 167 bytes
122+ + tarfile.NUL * 167
123+ )
124+ invalid_v7_header = (
125+ # name: 100 bytes
126+ tarfile.NUL * tarfile.LENGTH_NAME
127+ # mode, space, null terminator: 8 bytes
128+ + b"000755" + SPACE + tarfile.NUL
129+ # uid, space, null terminator: 8 bytes
130+ + b"000001" + SPACE + tarfile.NUL
131+ # gid, space, null terminator: 8 bytes
132+ + b"000001" + SPACE + tarfile.NUL
133+ # size, space: 12 bytes
134+ + b"\xff" * 11 + SPACE
135+ # mtime, space: 12 bytes
136+ + tarfile.NUL * 11 + SPACE
137+ # chksum: 8 bytes
138+ + b"0010070" + tarfile.NUL
139+ # type: 1 byte
140+ + tarfile.REGTYPE
141+ # linkname: 100 bytes
142+ + tarfile.NUL * tarfile.LENGTH_LINK
143+ # padding: 255 bytes
144+ + tarfile.NUL * 255
145+ )
146+ valid_gnu_header = tarfile.TarInfo("filename").tobuf(tarfile.GNU_FORMAT)
147+ data_block = b"\xff" * tarfile.BLOCKSIZE
148+
149+ def _write_buffer(self, buffer):
150+ with open(self.tarname, "wb") as f:
151+ f.write(buffer)
152+
153+ def _get_members(self, ignore_zeros=None):
154+ with open(self.tarname, "rb") as f:
155+ with tarfile.open(
156+ mode="r", fileobj=f, ignore_zeros=ignore_zeros
157+ ) as tar:
158+ return tar.getmembers()
159+
160+ def _assert_raises_read_error_exception(self):
161+ with self.assertRaisesRegex(
162+ tarfile.ReadError, "file could not be opened successfully"
163+ ):
164+ self._get_members()
165+
166+ def test_invalid_offset_header_validations(self):
167+ for tar_format, invalid_header in (
168+ ("posix", self.invalid_posix_header),
169+ ("gnu", self.invalid_gnu_header),
170+ ("v7", self.invalid_v7_header),
171+ ):
172+ with self.subTest(format=tar_format):
173+ self._write_buffer(invalid_header)
174+ self._assert_raises_read_error_exception()
175+
176+ def test_early_stop_at_invalid_offset_header(self):
177+ buffer = self.valid_gnu_header + self.invalid_gnu_header + self.valid_gnu_header
178+ self._write_buffer(buffer)
179+ members = self._get_members()
180+ self.assertEqual(len(members), 1)
181+ self.assertEqual(members[0].name, "filename")
182+ self.assertEqual(members[0].offset, 0)
183+
184+ def test_ignore_invalid_archive(self):
185+ # 3 invalid headers with their respective data
186+ buffer = (self.invalid_gnu_header + self.data_block) * 3
187+ self._write_buffer(buffer)
188+ members = self._get_members(ignore_zeros=True)
189+ self.assertEqual(len(members), 0)
190+
191+ def test_ignore_invalid_offset_headers(self):
192+ for first_block, second_block, expected_offset in (
193+ (
194+ (self.valid_gnu_header),
195+ (self.invalid_gnu_header + self.data_block),
196+ 0,
197+ ),
198+ (
199+ (self.invalid_gnu_header + self.data_block),
200+ (self.valid_gnu_header),
201+ 1024,
202+ ),
203+ ):
204+ self._write_buffer(first_block + second_block)
205+ members = self._get_members(ignore_zeros=True)
206+ self.assertEqual(len(members), 1)
207+ self.assertEqual(members[0].name, "filename")
208+ self.assertEqual(members[0].offset, expected_offset)
209+
210+
211 def setUpModule():
212 os_helper.unlink(TEMPDIR)
213 os.makedirs(TEMPDIR)
214diff --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
215new file mode 100644
216index 0000000..342cabb
217--- /dev/null
218+++ b/Misc/NEWS.d/next/Library/2025-07-23-00-35-29.gh-issue-130577.c7EITy.rst
219@@ -0,0 +1,3 @@
220+:mod:`tarfile` now validates archives to ensure member offsets are
221+non-negative. (Contributed by Alexander Enrique Urieles Nieto in
222+:gh:`130577`.)
223--
2242.40.0
diff --git a/meta/recipes-devtools/python/python3_3.13.4.bb b/meta/recipes-devtools/python/python3_3.13.4.bb
index 0a2c41cdce..6823a21cc3 100644
--- a/meta/recipes-devtools/python/python3_3.13.4.bb
+++ b/meta/recipes-devtools/python/python3_3.13.4.bb
@@ -30,6 +30,7 @@ SRC_URI = "http://www.python.org/ftp/python/${PV}/Python-${PV}.tar.xz \
30 file://0001-test_active_children-skip-problematic-test.patch \ 30 file://0001-test_active_children-skip-problematic-test.patch \
31 file://0001-test_readline-skip-limited-history-test.patch \ 31 file://0001-test_readline-skip-limited-history-test.patch \
32 file://0001-Generate-data-for-OpenSSL-3.4-and-add-it-to-multissl.patch \ 32 file://0001-Generate-data-for-OpenSSL-3.4-and-add-it-to-multissl.patch \
33 file://CVE-2025-8194.patch \
33 " 34 "
34 35
35SRC_URI:append:class-native = " \ 36SRC_URI:append:class-native = " \