summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPraveen Kumar <praveen.kumar@windriver.com>2025-08-06 11:08:44 +0530
committerSteve Sakoman <steve@sakoman.com>2025-08-13 08:42:58 -0700
commit170d5d05230f992a6b003bd15eb02cec4aef2cd9 (patch)
tree781905d4d0cc07edd3b89ce158c793c118f569d8
parent50b9a965514c6026f26ea048ed5f2f8b174f738e (diff)
downloadpoky-170d5d05230f992a6b003bd15eb02cec4aef2cd9.tar.gz
python3: fix CVE-2025-8194
There is a defect in the CPython “tarfile” module affecting the “TarFile” extraction and entry enumeration APIs. The tar implementation would process tar archives with negative offsets without error, resulting in an infinite loop and deadlock during the parsing of maliciously crafted tar archives. This vulnerability can be mitigated by including the following patch after importing the “tarfile” module: https://gist.github.com/sethmlarson/1716ac5b82b73dbcbf23ad2eff8b33e1 Reference: https://nvd.nist.gov/vuln/detail/CVE-2025-8194 Upstream-patch: https://github.com/python/cpython/commit/cdae923ffe187d6ef916c0f665a31249619193fe (From OE-Core rev: c0f1143ca3f189fc6346a445a381829aed78aae8) Signed-off-by: Praveen Kumar <praveen.kumar@windriver.com> Signed-off-by: Steve Sakoman <steve@sakoman.com>
-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 = " \