Compare commits

...

No commits in common. 'c9' and 'c9-beta' have entirely different histories.
c9 ... c9-beta

2
.gitignore vendored

@ -1 +1 @@
SOURCES/Python-3.9.18.tar.xz
SOURCES/Python-3.9.19.tar.xz

@ -1 +1 @@
abe4a20dcc11798495b17611ef9f8f33d6975722 SOURCES/Python-3.9.18.tar.xz
57d08ec0b329a78923b486abae906d4fa12fadb7 SOURCES/Python-3.9.19.tar.xz

@ -1,77 +1,63 @@
From c9364e8727ea2426519a74593ab03ebcb0da72b8 Mon Sep 17 00:00:00 2001
From 60d40d7095983e0bc23a103b2050adc519dc7fe3 Mon Sep 17 00:00:00 2001
From: Lumir Balhar <lbalhar@redhat.com>
Date: Fri, 3 May 2024 14:17:48 +0200
Subject: [PATCH] Expect failures in tests not working properly with expat with
a fixed CVE in RHEL
---
Lib/test/test_xml_etree.py | 53 ++++++++++++++++++++++----------------
1 file changed, 31 insertions(+), 22 deletions(-)
Lib/test/test_pyexpat.py | 1 +
Lib/test/test_sax.py | 1 +
Lib/test/test_xml_etree.py | 3 +++
3 files changed, 5 insertions(+)
diff --git a/Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py
index 43cbd27..27b1502 100644
--- a/Lib/test/test_pyexpat.py
+++ b/Lib/test/test_pyexpat.py
@@ -793,6 +793,7 @@ class ReparseDeferralTest(unittest.TestCase):
self.assertEqual(started, ['doc'])
+ @unittest.expectedFailure
def test_reparse_deferral_disabled(self):
started = []
diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py
index 9b3014a..646c92d 100644
--- a/Lib/test/test_sax.py
+++ b/Lib/test/test_sax.py
@@ -1240,6 +1240,7 @@ class ExpatReaderTest(XmlTestBase):
self.assertEqual(result.getvalue(), start + b"<doc></doc>")
+ @unittest.expectedFailure
def test_flush_reparse_deferral_disabled(self):
result = BytesIO()
xmlgen = XMLGenerator(result)
diff --git a/Lib/test/test_xml_etree.py b/Lib/test/test_xml_etree.py
index 7c346f2..24e0bb8 100644
index 9c382d1..62f2871 100644
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -1391,28 +1391,37 @@ class XMLPullParserTest(unittest.TestCase):
self.assertEqual([(action, elem.tag) for action, elem in events],
expected)
@@ -1424,9 +1424,11 @@ class XMLPullParserTest(unittest.TestCase):
self.assert_event_tags(parser, [('end', 'root')])
self.assertIsNone(parser.close())
+ @unittest.expectedFailure
def test_simple_xml_chunk_1(self):
self.test_simple_xml(chunk_size=1, flush=True)
- def test_simple_xml(self):
- for chunk_size in (None, 1, 5):
- with self.subTest(chunk_size=chunk_size):
- parser = ET.XMLPullParser()
- self.assert_event_tags(parser, [])
- self._feed(parser, "<!-- comment -->\n", chunk_size)
- self.assert_event_tags(parser, [])
- self._feed(parser,
- "<root>\n <element key='value'>text</element",
- chunk_size)
- self.assert_event_tags(parser, [])
- self._feed(parser, ">\n", chunk_size)
- self.assert_event_tags(parser, [('end', 'element')])
- self._feed(parser, "<element>text</element>tail\n", chunk_size)
- self._feed(parser, "<empty-element/>\n", chunk_size)
- self.assert_event_tags(parser, [
- ('end', 'element'),
- ('end', 'empty-element'),
- ])
- self._feed(parser, "</root>\n", chunk_size)
- self.assert_event_tags(parser, [('end', 'root')])
- self.assertIsNone(parser.close())
+ def test_simple_xml(self, chunk_size=None):
+ parser = ET.XMLPullParser()
+ self.assert_event_tags(parser, [])
+ self._feed(parser, "<!-- comment -->\n", chunk_size)
+ self.assert_event_tags(parser, [])
+ self._feed(parser,
+ "<root>\n <element key='value'>text</element",
+ chunk_size)
+ self.assert_event_tags(parser, [])
+ self._feed(parser, ">\n", chunk_size)
+ self.assert_event_tags(parser, [('end', 'element')])
+ self._feed(parser, "<element>text</element>tail\n", chunk_size)
+ self._feed(parser, "<empty-element/>\n", chunk_size)
+ self.assert_event_tags(parser, [
+ ('end', 'element'),
+ ('end', 'empty-element'),
+ ])
+ self._feed(parser, "</root>\n", chunk_size)
+ self.assert_event_tags(parser, [('end', 'root')])
+ self.assertIsNone(parser.close())
+
+ @unittest.expectedFailure
+ def test_simple_xml_chunk_1(self):
+ self.test_simple_xml(chunk_size=1)
+
def test_simple_xml_chunk_5(self):
self.test_simple_xml(chunk_size=5, flush=True)
@@ -1651,6 +1653,7 @@ class XMLPullParserTest(unittest.TestCase):
self.assert_event_tags(parser, [('end', 'doc')])
+ @unittest.expectedFailure
+ def test_simple_xml_chunk_5(self):
+ self.test_simple_xml(chunk_size=5)
+
+ def test_simple_xml_chunk_22(self):
+ self.test_simple_xml(chunk_size=22)
def test_flush_reparse_deferral_disabled(self):
parser = ET.XMLPullParser(events=('start', 'end'))
def test_feed_while_iterating(self):
parser = ET.XMLPullParser()
--
2.45.0
2.44.0

@ -1,211 +0,0 @@
From d54e22a669ae6e987199bb5d2c69bb5a46b0083b Mon Sep 17 00:00:00 2001
From: Serhiy Storchaka <storchaka@gmail.com>
Date: Wed, 17 Jan 2024 15:47:47 +0200
Subject: [PATCH] [3.9] gh-91133: tempfile.TemporaryDirectory: fix symlink bug
in cleanup (GH-99930) (GH-112842)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
(cherry picked from commit 81c16cd94ec38d61aa478b9a452436dc3b1b524d)
Co-authored-by: Søren Løvborg <sorenl@unity3d.com>
---
Lib/tempfile.py | 27 ++--
Lib/test/test_tempfile.py | 117 +++++++++++++++++-
...2-12-01-16-57-44.gh-issue-91133.LKMVCV.rst | 2 +
3 files changed, 136 insertions(+), 10 deletions(-)
create mode 100644 Misc/NEWS.d/next/Library/2022-12-01-16-57-44.gh-issue-91133.LKMVCV.rst
diff --git a/Lib/tempfile.py b/Lib/tempfile.py
index eafce6f25b6fb2..59a628a1744685 100644
--- a/Lib/tempfile.py
+++ b/Lib/tempfile.py
@@ -268,6 +268,22 @@ def _mkstemp_inner(dir, pre, suf, flags, output_type):
raise FileExistsError(_errno.EEXIST,
"No usable temporary file name found")
+def _dont_follow_symlinks(func, path, *args):
+ # Pass follow_symlinks=False, unless not supported on this platform.
+ if func in _os.supports_follow_symlinks:
+ func(path, *args, follow_symlinks=False)
+ elif _os.name == 'nt' or not _os.path.islink(path):
+ func(path, *args)
+
+def _resetperms(path):
+ try:
+ chflags = _os.chflags
+ except AttributeError:
+ pass
+ else:
+ _dont_follow_symlinks(chflags, path, 0)
+ _dont_follow_symlinks(_os.chmod, path, 0o700)
+
# User visible interfaces.
@@ -789,17 +805,10 @@ def __init__(self, suffix=None, prefix=None, dir=None):
def _rmtree(cls, name):
def onerror(func, path, exc_info):
if issubclass(exc_info[0], PermissionError):
- def resetperms(path):
- try:
- _os.chflags(path, 0)
- except AttributeError:
- pass
- _os.chmod(path, 0o700)
-
try:
if path != name:
- resetperms(_os.path.dirname(path))
- resetperms(path)
+ _resetperms(_os.path.dirname(path))
+ _resetperms(path)
try:
_os.unlink(path)
diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py
index 8ad1bb98e8e899..571263d9c957d7 100644
--- a/Lib/test/test_tempfile.py
+++ b/Lib/test/test_tempfile.py
@@ -1394,6 +1394,103 @@ def test_cleanup_with_symlink_to_a_directory(self):
"were deleted")
d2.cleanup()
+ @support.skip_unless_symlink
+ def test_cleanup_with_symlink_modes(self):
+ # cleanup() should not follow symlinks when fixing mode bits (#91133)
+ with self.do_create(recurse=0) as d2:
+ file1 = os.path.join(d2, 'file1')
+ open(file1, 'wb').close()
+ dir1 = os.path.join(d2, 'dir1')
+ os.mkdir(dir1)
+ for mode in range(8):
+ mode <<= 6
+ with self.subTest(mode=format(mode, '03o')):
+ def test(target, target_is_directory):
+ d1 = self.do_create(recurse=0)
+ symlink = os.path.join(d1.name, 'symlink')
+ os.symlink(target, symlink,
+ target_is_directory=target_is_directory)
+ try:
+ os.chmod(symlink, mode, follow_symlinks=False)
+ except NotImplementedError:
+ pass
+ try:
+ os.chmod(symlink, mode)
+ except FileNotFoundError:
+ pass
+ os.chmod(d1.name, mode)
+ d1.cleanup()
+ self.assertFalse(os.path.exists(d1.name))
+
+ with self.subTest('nonexisting file'):
+ test('nonexisting', target_is_directory=False)
+ with self.subTest('nonexisting dir'):
+ test('nonexisting', target_is_directory=True)
+
+ with self.subTest('existing file'):
+ os.chmod(file1, mode)
+ old_mode = os.stat(file1).st_mode
+ test(file1, target_is_directory=False)
+ new_mode = os.stat(file1).st_mode
+ self.assertEqual(new_mode, old_mode,
+ '%03o != %03o' % (new_mode, old_mode))
+
+ with self.subTest('existing dir'):
+ os.chmod(dir1, mode)
+ old_mode = os.stat(dir1).st_mode
+ test(dir1, target_is_directory=True)
+ new_mode = os.stat(dir1).st_mode
+ self.assertEqual(new_mode, old_mode,
+ '%03o != %03o' % (new_mode, old_mode))
+
+ @unittest.skipUnless(hasattr(os, 'chflags'), 'requires os.chflags')
+ @support.skip_unless_symlink
+ def test_cleanup_with_symlink_flags(self):
+ # cleanup() should not follow symlinks when fixing flags (#91133)
+ flags = stat.UF_IMMUTABLE | stat.UF_NOUNLINK
+ self.check_flags(flags)
+
+ with self.do_create(recurse=0) as d2:
+ file1 = os.path.join(d2, 'file1')
+ open(file1, 'wb').close()
+ dir1 = os.path.join(d2, 'dir1')
+ os.mkdir(dir1)
+ def test(target, target_is_directory):
+ d1 = self.do_create(recurse=0)
+ symlink = os.path.join(d1.name, 'symlink')
+ os.symlink(target, symlink,
+ target_is_directory=target_is_directory)
+ try:
+ os.chflags(symlink, flags, follow_symlinks=False)
+ except NotImplementedError:
+ pass
+ try:
+ os.chflags(symlink, flags)
+ except FileNotFoundError:
+ pass
+ os.chflags(d1.name, flags)
+ d1.cleanup()
+ self.assertFalse(os.path.exists(d1.name))
+
+ with self.subTest('nonexisting file'):
+ test('nonexisting', target_is_directory=False)
+ with self.subTest('nonexisting dir'):
+ test('nonexisting', target_is_directory=True)
+
+ with self.subTest('existing file'):
+ os.chflags(file1, flags)
+ old_flags = os.stat(file1).st_flags
+ test(file1, target_is_directory=False)
+ new_flags = os.stat(file1).st_flags
+ self.assertEqual(new_flags, old_flags)
+
+ with self.subTest('existing dir'):
+ os.chflags(dir1, flags)
+ old_flags = os.stat(dir1).st_flags
+ test(dir1, target_is_directory=True)
+ new_flags = os.stat(dir1).st_flags
+ self.assertEqual(new_flags, old_flags)
+
@support.cpython_only
def test_del_on_collection(self):
# A TemporaryDirectory is deleted when garbage collected
@@ -1506,9 +1603,27 @@ def test_modes(self):
d.cleanup()
self.assertFalse(os.path.exists(d.name))
- @unittest.skipUnless(hasattr(os, 'chflags'), 'requires os.lchflags')
+ def check_flags(self, flags):
+ # skip the test if these flags are not supported (ex: FreeBSD 13)
+ filename = support.TESTFN
+ try:
+ open(filename, "w").close()
+ try:
+ os.chflags(filename, flags)
+ except OSError as exc:
+ # "OSError: [Errno 45] Operation not supported"
+ self.skipTest(f"chflags() doesn't support flags "
+ f"{flags:#b}: {exc}")
+ else:
+ os.chflags(filename, 0)
+ finally:
+ support.unlink(filename)
+
+ @unittest.skipUnless(hasattr(os, 'chflags'), 'requires os.chflags')
def test_flags(self):
flags = stat.UF_IMMUTABLE | stat.UF_NOUNLINK
+ self.check_flags(flags)
+
d = self.do_create(recurse=3, dirs=2, files=2)
with d:
# Change files and directories flags recursively.
diff --git a/Misc/NEWS.d/next/Library/2022-12-01-16-57-44.gh-issue-91133.LKMVCV.rst b/Misc/NEWS.d/next/Library/2022-12-01-16-57-44.gh-issue-91133.LKMVCV.rst
new file mode 100644
index 00000000000000..7991048fc48e03
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-12-01-16-57-44.gh-issue-91133.LKMVCV.rst
@@ -0,0 +1,2 @@
+Fix a bug in :class:`tempfile.TemporaryDirectory` cleanup, which now no longer
+dereferences symlinks when working around file system permission errors.

@ -1,143 +0,0 @@
From a2c59992e9e8d35baba9695eb186ad6c6ff85c51 Mon Sep 17 00:00:00 2001
From: "Miss Islington (bot)"
<31488909+miss-islington@users.noreply.github.com>
Date: Wed, 17 Jan 2024 14:48:06 +0100
Subject: [PATCH] [3.9] gh-109858: Protect zipfile from "quoted-overlap"
zipbomb (GH-110016) (GH-113915)
Raise BadZipFile when try to read an entry that overlaps with other entry or
central directory.
(cherry picked from commit 66363b9a7b9fe7c99eba3a185b74c5fdbf842eba)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
---
Lib/test/test_zipfile.py | 60 +++++++++++++++++++
Lib/zipfile.py | 12 ++++
...-09-28-13-15-51.gh-issue-109858.43e2dg.rst | 3 +
3 files changed, 75 insertions(+)
create mode 100644 Misc/NEWS.d/next/Library/2023-09-28-13-15-51.gh-issue-109858.43e2dg.rst
diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py
index bd383d3f68552b..17e95eb86239a5 100644
--- a/Lib/test/test_zipfile.py
+++ b/Lib/test/test_zipfile.py
@@ -2045,6 +2045,66 @@ def test_decompress_without_3rd_party_library(self):
with zipfile.ZipFile(zip_file) as zf:
self.assertRaises(RuntimeError, zf.extract, 'a.txt')
+ @requires_zlib()
+ def test_full_overlap(self):
+ data = (
+ b'PK\x03\x04\x14\x00\x00\x00\x08\x00\xa0lH\x05\xe2\x1e'
+ b'8\xbb\x10\x00\x00\x00\t\x04\x00\x00\x01\x00\x00\x00a\xed'
+ b'\xc0\x81\x08\x00\x00\x00\xc00\xd6\xfbK\\d\x0b`P'
+ b'K\x01\x02\x14\x00\x14\x00\x00\x00\x08\x00\xa0lH\x05\xe2'
+ b'\x1e8\xbb\x10\x00\x00\x00\t\x04\x00\x00\x01\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00aPK'
+ b'\x01\x02\x14\x00\x14\x00\x00\x00\x08\x00\xa0lH\x05\xe2\x1e'
+ b'8\xbb\x10\x00\x00\x00\t\x04\x00\x00\x01\x00\x00\x00\x00\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00bPK\x05'
+ b'\x06\x00\x00\x00\x00\x02\x00\x02\x00^\x00\x00\x00/\x00\x00'
+ b'\x00\x00\x00'
+ )
+ with zipfile.ZipFile(io.BytesIO(data), 'r') as zipf:
+ self.assertEqual(zipf.namelist(), ['a', 'b'])
+ zi = zipf.getinfo('a')
+ self.assertEqual(zi.header_offset, 0)
+ self.assertEqual(zi.compress_size, 16)
+ self.assertEqual(zi.file_size, 1033)
+ zi = zipf.getinfo('b')
+ self.assertEqual(zi.header_offset, 0)
+ self.assertEqual(zi.compress_size, 16)
+ self.assertEqual(zi.file_size, 1033)
+ self.assertEqual(len(zipf.read('a')), 1033)
+ with self.assertRaisesRegex(zipfile.BadZipFile, 'File name.*differ'):
+ zipf.read('b')
+
+ @requires_zlib()
+ def test_quoted_overlap(self):
+ data = (
+ b'PK\x03\x04\x14\x00\x00\x00\x08\x00\xa0lH\x05Y\xfc'
+ b'8\x044\x00\x00\x00(\x04\x00\x00\x01\x00\x00\x00a\x00'
+ b'\x1f\x00\xe0\xffPK\x03\x04\x14\x00\x00\x00\x08\x00\xa0l'
+ b'H\x05\xe2\x1e8\xbb\x10\x00\x00\x00\t\x04\x00\x00\x01\x00'
+ b'\x00\x00b\xed\xc0\x81\x08\x00\x00\x00\xc00\xd6\xfbK\\'
+ b'd\x0b`PK\x01\x02\x14\x00\x14\x00\x00\x00\x08\x00\xa0'
+ b'lH\x05Y\xfc8\x044\x00\x00\x00(\x04\x00\x00\x01'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+ b'\x00aPK\x01\x02\x14\x00\x14\x00\x00\x00\x08\x00\xa0l'
+ b'H\x05\xe2\x1e8\xbb\x10\x00\x00\x00\t\x04\x00\x00\x01\x00'
+ b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$\x00\x00\x00'
+ b'bPK\x05\x06\x00\x00\x00\x00\x02\x00\x02\x00^\x00\x00'
+ b'\x00S\x00\x00\x00\x00\x00'
+ )
+ with zipfile.ZipFile(io.BytesIO(data), 'r') as zipf:
+ self.assertEqual(zipf.namelist(), ['a', 'b'])
+ zi = zipf.getinfo('a')
+ self.assertEqual(zi.header_offset, 0)
+ self.assertEqual(zi.compress_size, 52)
+ self.assertEqual(zi.file_size, 1064)
+ zi = zipf.getinfo('b')
+ self.assertEqual(zi.header_offset, 36)
+ self.assertEqual(zi.compress_size, 16)
+ self.assertEqual(zi.file_size, 1033)
+ with self.assertRaisesRegex(zipfile.BadZipFile, 'Overlapped entries'):
+ zipf.read('a')
+ self.assertEqual(len(zipf.read('b')), 1033)
+
def tearDown(self):
unlink(TESTFN)
unlink(TESTFN2)
diff --git a/Lib/zipfile.py b/Lib/zipfile.py
index 1e942a503e8ee1..95f95ee112667a 100644
--- a/Lib/zipfile.py
+++ b/Lib/zipfile.py
@@ -338,6 +338,7 @@ class ZipInfo (object):
'compress_size',
'file_size',
'_raw_time',
+ '_end_offset',
)
def __init__(self, filename="NoName", date_time=(1980,1,1,0,0,0)):
@@ -379,6 +380,7 @@ def __init__(self, filename="NoName", date_time=(1980,1,1,0,0,0)):
self.external_attr = 0 # External file attributes
self.compress_size = 0 # Size of the compressed file
self.file_size = 0 # Size of the uncompressed file
+ self._end_offset = None # Start of the next local header or central directory
# Other attributes are set by class ZipFile:
# header_offset Byte offset to the file header
# CRC CRC-32 of the uncompressed file
@@ -1399,6 +1401,12 @@ def _RealGetContents(self):
if self.debug > 2:
print("total", total)
+ end_offset = self.start_dir
+ for zinfo in sorted(self.filelist,
+ key=lambda zinfo: zinfo.header_offset,
+ reverse=True):
+ zinfo._end_offset = end_offset
+ end_offset = zinfo.header_offset
def namelist(self):
"""Return a list of file names in the archive."""
@@ -1554,6 +1562,10 @@ def open(self, name, mode="r", pwd=None, *, force_zip64=False):
'File name in directory %r and header %r differ.'
% (zinfo.orig_filename, fname))
+ if (zinfo._end_offset is not None and
+ zef_file.tell() + zinfo.compress_size > zinfo._end_offset):
+ raise BadZipFile(f"Overlapped entries: {zinfo.orig_filename!r} (possible zip bomb)")
+
# check for encrypted flag & handle password
is_encrypted = zinfo.flag_bits & 0x1
if is_encrypted:
diff --git a/Misc/NEWS.d/next/Library/2023-09-28-13-15-51.gh-issue-109858.43e2dg.rst b/Misc/NEWS.d/next/Library/2023-09-28-13-15-51.gh-issue-109858.43e2dg.rst
new file mode 100644
index 00000000000000..be279caffc46ee
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-09-28-13-15-51.gh-issue-109858.43e2dg.rst
@@ -0,0 +1,3 @@
+Protect :mod:`zipfile` from "quoted-overlap" zipbomb. It now raises
+BadZipFile when try to read an entry that overlaps with other entry or
+central directory.

@ -1,8 +1,8 @@
From 22adf29da8d99933ffed8647d3e0726edd16f7f8 Mon Sep 17 00:00:00 2001
From f647bd8884bc89767914a5e0dea9ae099a8b50b5 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <encukou@gmail.com>
Date: Tue, 7 May 2024 11:57:58 +0200
Subject: [PATCH] [3.9] gh-113171: gh-65056: Fix "private" (non-global) IP
address ranges (GH-113179) (GH-113186) (GH-118177) (GH-118472)
Subject: [PATCH] gh-113171: gh-65056: Fix "private" (non-global) IP address
ranges (GH-113179) (GH-113186) (GH-118177) (GH-118472)
The _private_networks variables, used by various is_private
implementations, were missing some ranges and at the same time had
@ -42,7 +42,7 @@ Co-authored-by: Jakub Stasiak <jakub@stasiak.at>
create mode 100644 Misc/NEWS.d/next/Library/2024-03-14-01-38-44.gh-issue-113171.VFnObz.rst
diff --git a/Doc/library/ipaddress.rst b/Doc/library/ipaddress.rst
index 9c2dff55703273..f9c1ebf3f3df26 100644
index 9c2dff5..f9c1ebf 100644
--- a/Doc/library/ipaddress.rst
+++ b/Doc/library/ipaddress.rst
@@ -188,18 +188,53 @@ write code that handles both IP versions correctly. Address objects are
@ -104,7 +104,7 @@ index 9c2dff55703273..f9c1ebf3f3df26 100644
``True`` if the address is unspecified. See :RFC:`5735` (for IPv4)
diff --git a/Doc/tools/susp-ignored.csv b/Doc/tools/susp-ignored.csv
index 3eb3d7954f8fb2..de91a50bad063d 100644
index 3eb3d79..de91a50 100644
--- a/Doc/tools/susp-ignored.csv
+++ b/Doc/tools/susp-ignored.csv
@@ -169,6 +169,14 @@ library/ipaddress,,:db00,2001:db00::0/24
@ -123,7 +123,7 @@ index 3eb3d7954f8fb2..de91a50bad063d 100644
library/itertools,,:stop,elements from seq[start:stop:step]
library/itertools,,::,kernel = tuple(kernel)[::-1]
diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst
index 0064e074a3adfb..1756a3733863c8 100644
index 0064e07..1756a37 100644
--- a/Doc/whatsnew/3.9.rst
+++ b/Doc/whatsnew/3.9.rst
@@ -1616,3 +1616,12 @@ tarfile
@ -140,10 +140,10 @@ index 0064e074a3adfb..1756a3733863c8 100644
+* Fixed ``is_global`` and ``is_private`` behavior in ``IPv4Address``,
+ ``IPv6Address``, ``IPv4Network`` and ``IPv6Network``.
diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py
index 25f373a06a2b66..9b35340d9ac171 100644
index 25f373a..9b35340 100644
--- a/Lib/ipaddress.py
+++ b/Lib/ipaddress.py
@@ -1322,18 +1322,41 @@ def is_reserved(self):
@@ -1322,18 +1322,41 @@ class IPv4Address(_BaseV4, _BaseAddress):
@property
@functools.lru_cache()
def is_private(self):
@ -219,7 +219,7 @@ index 25f373a06a2b66..9b35340d9ac171 100644
_reserved_network = IPv4Network('240.0.0.0/4')
_unspecified_address = IPv4Address('0.0.0.0')
@@ -1995,23 +2025,42 @@ def is_site_local(self):
@@ -1995,23 +2025,42 @@ class IPv6Address(_BaseV6, _BaseAddress):
@property
@functools.lru_cache()
def is_private(self):
@ -306,10 +306,10 @@ index 25f373a06a2b66..9b35340d9ac171 100644
IPv6Network('::/8'), IPv6Network('100::/8'),
IPv6Network('200::/7'), IPv6Network('400::/6'),
diff --git a/Lib/test/test_ipaddress.py b/Lib/test/test_ipaddress.py
index 90897f6bedb868..bd14f04f6c6af1 100644
index 90897f6..bd14f04 100644
--- a/Lib/test/test_ipaddress.py
+++ b/Lib/test/test_ipaddress.py
@@ -2263,6 +2263,10 @@ def testReservedIpv4(self):
@@ -2263,6 +2263,10 @@ class IpaddrUnitTest(unittest.TestCase):
self.assertEqual(True, ipaddress.ip_address(
'172.31.255.255').is_private)
self.assertEqual(False, ipaddress.ip_address('172.32.0.0').is_private)
@ -320,7 +320,7 @@ index 90897f6bedb868..bd14f04f6c6af1 100644
self.assertEqual(True,
ipaddress.ip_address('169.254.100.200').is_link_local)
@@ -2278,6 +2282,40 @@ def testReservedIpv4(self):
@@ -2278,6 +2282,40 @@ class IpaddrUnitTest(unittest.TestCase):
self.assertEqual(False, ipaddress.ip_address('128.0.0.0').is_loopback)
self.assertEqual(True, ipaddress.ip_network('0.0.0.0').is_unspecified)
@ -361,7 +361,7 @@ index 90897f6bedb868..bd14f04f6c6af1 100644
def testReservedIpv6(self):
self.assertEqual(True, ipaddress.ip_network('ffff::').is_multicast)
@@ -2351,6 +2389,20 @@ def testReservedIpv6(self):
@@ -2351,6 +2389,20 @@ class IpaddrUnitTest(unittest.TestCase):
self.assertEqual(True, ipaddress.ip_address('0::0').is_unspecified)
self.assertEqual(False, ipaddress.ip_address('::1').is_unspecified)
@ -384,7 +384,7 @@ index 90897f6bedb868..bd14f04f6c6af1 100644
self.assertEqual(True, ipaddress.ip_network('4000::1/128').is_reserved)
diff --git a/Misc/NEWS.d/next/Library/2024-03-14-01-38-44.gh-issue-113171.VFnObz.rst b/Misc/NEWS.d/next/Library/2024-03-14-01-38-44.gh-issue-113171.VFnObz.rst
new file mode 100644
index 00000000000000..f9a72473be4e2c
index 0000000..f9a7247
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-03-14-01-38-44.gh-issue-113171.VFnObz.rst
@@ -0,0 +1,9 @@
@ -397,3 +397,6 @@ index 00000000000000..f9a72473be4e2c
+
+Also in the corresponding :class:`ipaddress.IPv4Network` and :class:`ipaddress.IPv6Network`
+attributes.
--
2.45.2

@ -1,245 +0,0 @@
From b4225ca91547aa97ed3aca391614afbb255bc877 Mon Sep 17 00:00:00 2001
From: Seth Michael Larson <seth@python.org>
Date: Wed, 4 Sep 2024 10:46:01 -0500
Subject: [PATCH] [3.9] gh-121285: Remove backtracking when parsing tarfile
headers (GH-121286) (#123641)
* Remove backtracking when parsing tarfile headers
* Rewrite PAX header parsing to be stricter
* Optimize parsing of GNU extended sparse headers v0.0
(cherry picked from commit 34ddb64d088dd7ccc321f6103d23153256caa5d4)
Co-authored-by: Seth Michael Larson <seth@python.org>
Co-authored-by: Kirill Podoprigora <kirill.bast9@mail.ru>
Co-authored-by: Gregory P. Smith <greg@krypto.org>
---
Lib/tarfile.py | 105 +++++++++++-------
Lib/test/test_tarfile.py | 42 +++++++
...-07-02-13-39-20.gh-issue-121285.hrl-yI.rst | 2 +
3 files changed, 111 insertions(+), 38 deletions(-)
create mode 100644 Misc/NEWS.d/next/Security/2024-07-02-13-39-20.gh-issue-121285.hrl-yI.rst
diff --git a/Lib/tarfile.py b/Lib/tarfile.py
index 7a6158c2eb9893..d75ba50b6670c7 100755
--- a/Lib/tarfile.py
+++ b/Lib/tarfile.py
@@ -840,6 +840,9 @@ def data_filter(member, dest_path):
# Sentinel for replace() defaults, meaning "don't change the attribute"
_KEEP = object()
+# Header length is digits followed by a space.
+_header_length_prefix_re = re.compile(br"([0-9]{1,20}) ")
+
class TarInfo(object):
"""Informational class which holds the details about an
archive member given by a tar header block.
@@ -1399,41 +1402,59 @@ def _proc_pax(self, tarfile):
else:
pax_headers = tarfile.pax_headers.copy()
- # Check if the pax header contains a hdrcharset field. This tells us
- # the encoding of the path, linkpath, uname and gname fields. Normally,
- # these fields are UTF-8 encoded but since POSIX.1-2008 tar
- # implementations are allowed to store them as raw binary strings if
- # the translation to UTF-8 fails.
- match = re.search(br"\d+ hdrcharset=([^\n]+)\n", buf)
- if match is not None:
- pax_headers["hdrcharset"] = match.group(1).decode("utf-8")
-
- # For the time being, we don't care about anything other than "BINARY".
- # The only other value that is currently allowed by the standard is
- # "ISO-IR 10646 2000 UTF-8" in other words UTF-8.
- hdrcharset = pax_headers.get("hdrcharset")
- if hdrcharset == "BINARY":
- encoding = tarfile.encoding
- else:
- encoding = "utf-8"
-
# Parse pax header information. A record looks like that:
# "%d %s=%s\n" % (length, keyword, value). length is the size
# of the complete record including the length field itself and
- # the newline. keyword and value are both UTF-8 encoded strings.
- regex = re.compile(br"(\d+) ([^=]+)=")
+ # the newline.
pos = 0
- while True:
- match = regex.match(buf, pos)
- if not match:
- break
+ encoding = None
+ raw_headers = []
+ while len(buf) > pos and buf[pos] != 0x00:
+ if not (match := _header_length_prefix_re.match(buf, pos)):
+ raise InvalidHeaderError("invalid header")
+ try:
+ length = int(match.group(1))
+ except ValueError:
+ raise InvalidHeaderError("invalid header")
+ # Headers must be at least 5 bytes, shortest being '5 x=\n'.
+ # Value is allowed to be empty.
+ if length < 5:
+ raise InvalidHeaderError("invalid header")
+ if pos + length > len(buf):
+ raise InvalidHeaderError("invalid header")
- length, keyword = match.groups()
- length = int(length)
- if length == 0:
+ header_value_end_offset = match.start(1) + length - 1 # Last byte of the header
+ keyword_and_value = buf[match.end(1) + 1:header_value_end_offset]
+ raw_keyword, equals, raw_value = keyword_and_value.partition(b"=")
+
+ # Check the framing of the header. The last character must be '\n' (0x0A)
+ if not raw_keyword or equals != b"=" or buf[header_value_end_offset] != 0x0A:
raise InvalidHeaderError("invalid header")
- value = buf[match.end(2) + 1:match.start(1) + length - 1]
+ raw_headers.append((length, raw_keyword, raw_value))
+
+ # Check if the pax header contains a hdrcharset field. This tells us
+ # the encoding of the path, linkpath, uname and gname fields. Normally,
+ # these fields are UTF-8 encoded but since POSIX.1-2008 tar
+ # implementations are allowed to store them as raw binary strings if
+ # the translation to UTF-8 fails. For the time being, we don't care about
+ # anything other than "BINARY". The only other value that is currently
+ # allowed by the standard is "ISO-IR 10646 2000 UTF-8" in other words UTF-8.
+ # Note that we only follow the initial 'hdrcharset' setting to preserve
+ # the initial behavior of the 'tarfile' module.
+ if raw_keyword == b"hdrcharset" and encoding is None:
+ if raw_value == b"BINARY":
+ encoding = tarfile.encoding
+ else: # This branch ensures only the first 'hdrcharset' header is used.
+ encoding = "utf-8"
+
+ pos += length
+ # If no explicit hdrcharset is set, we use UTF-8 as a default.
+ if encoding is None:
+ encoding = "utf-8"
+
+ # After parsing the raw headers we can decode them to text.
+ for length, raw_keyword, raw_value in raw_headers:
# Normally, we could just use "utf-8" as the encoding and "strict"
# as the error handler, but we better not take the risk. For
# example, GNU tar <= 1.23 is known to store filenames it cannot
@@ -1441,17 +1462,16 @@ def _proc_pax(self, tarfile):
# hdrcharset=BINARY header).
# We first try the strict standard encoding, and if that fails we
# fall back on the user's encoding and error handler.
- keyword = self._decode_pax_field(keyword, "utf-8", "utf-8",
+ keyword = self._decode_pax_field(raw_keyword, "utf-8", "utf-8",
tarfile.errors)
if keyword in PAX_NAME_FIELDS:
- value = self._decode_pax_field(value, encoding, tarfile.encoding,
+ value = self._decode_pax_field(raw_value, encoding, tarfile.encoding,
tarfile.errors)
else:
- value = self._decode_pax_field(value, "utf-8", "utf-8",
+ value = self._decode_pax_field(raw_value, "utf-8", "utf-8",
tarfile.errors)
pax_headers[keyword] = value
- pos += length
# Fetch the next header.
try:
@@ -1466,7 +1486,7 @@ def _proc_pax(self, tarfile):
elif "GNU.sparse.size" in pax_headers:
# GNU extended sparse format version 0.0.
- self._proc_gnusparse_00(next, pax_headers, buf)
+ self._proc_gnusparse_00(next, raw_headers)
elif pax_headers.get("GNU.sparse.major") == "1" and pax_headers.get("GNU.sparse.minor") == "0":
# GNU extended sparse format version 1.0.
@@ -1488,15 +1508,24 @@ def _proc_pax(self, tarfile):
return next
- def _proc_gnusparse_00(self, next, pax_headers, buf):
+ def _proc_gnusparse_00(self, next, raw_headers):
"""Process a GNU tar extended sparse header, version 0.0.
"""
offsets = []
- for match in re.finditer(br"\d+ GNU.sparse.offset=(\d+)\n", buf):
- offsets.append(int(match.group(1)))
numbytes = []
- for match in re.finditer(br"\d+ GNU.sparse.numbytes=(\d+)\n", buf):
- numbytes.append(int(match.group(1)))
+ for _, keyword, value in raw_headers:
+ if keyword == b"GNU.sparse.offset":
+ try:
+ offsets.append(int(value.decode()))
+ except ValueError:
+ raise InvalidHeaderError("invalid header")
+
+ elif keyword == b"GNU.sparse.numbytes":
+ try:
+ numbytes.append(int(value.decode()))
+ except ValueError:
+ raise InvalidHeaderError("invalid header")
+
next.sparse = list(zip(offsets, numbytes))
def _proc_gnusparse_01(self, next, pax_headers):
diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py
index 3df64c78032275..2218401e3867be 100644
--- a/Lib/test/test_tarfile.py
+++ b/Lib/test/test_tarfile.py
@@ -1113,6 +1113,48 @@ def test_pax_number_fields(self):
finally:
tar.close()
+ def test_pax_header_bad_formats(self):
+ # The fields from the pax header have priority over the
+ # TarInfo.
+ pax_header_replacements = (
+ b" foo=bar\n",
+ b"0 \n",
+ b"1 \n",
+ b"2 \n",
+ b"3 =\n",
+ b"4 =a\n",
+ b"1000000 foo=bar\n",
+ b"0 foo=bar\n",
+ b"-12 foo=bar\n",
+ b"000000000000000000000000036 foo=bar\n",
+ )
+ pax_headers = {"foo": "bar"}
+
+ for replacement in pax_header_replacements:
+ with self.subTest(header=replacement):
+ tar = tarfile.open(tmpname, "w", format=tarfile.PAX_FORMAT,
+ encoding="iso8859-1")
+ try:
+ t = tarfile.TarInfo()
+ t.name = "pax" # non-ASCII
+ t.uid = 1
+ t.pax_headers = pax_headers
+ tar.addfile(t)
+ finally:
+ tar.close()
+
+ with open(tmpname, "rb") as f:
+ data = f.read()
+ self.assertIn(b"11 foo=bar\n", data)
+ data = data.replace(b"11 foo=bar\n", replacement)
+
+ with open(tmpname, "wb") as f:
+ f.truncate()
+ f.write(data)
+
+ with self.assertRaisesRegex(tarfile.ReadError, r"file could not be opened successfully"):
+ tarfile.open(tmpname, encoding="iso8859-1")
+
class WriteTestBase(TarTest):
# Put all write tests in here that are supposed to be tested
diff --git a/Misc/NEWS.d/next/Security/2024-07-02-13-39-20.gh-issue-121285.hrl-yI.rst b/Misc/NEWS.d/next/Security/2024-07-02-13-39-20.gh-issue-121285.hrl-yI.rst
new file mode 100644
index 00000000000000..81f918bfe2b255
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2024-07-02-13-39-20.gh-issue-121285.hrl-yI.rst
@@ -0,0 +1,2 @@
+Remove backtracking from tarfile header parsing for ``hdrcharset``, PAX, and
+GNU sparse headers.

@ -1,16 +0,0 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEE4/8oOcBIslwITevpsmmV4xAlBWgFAmTnntEACgkQsmmV4xAl
BWgmQw/9EFWMXtSfWBV93AQF37r0nbUnOBvrOcubkO7ygt+GfHKzN8EPuNeO2It7
yNZDuCmwepnNGaIkO7UkgbwYyNw3YaoHQqxG8izAfJAVqK6BSk8UAET/YKWFXbLv
cZBfgxSa0tTEkwq3BAY4vDewRXnLkUq7k6JRRCKFGLNSi/ygC56SijxyAV2g4Vio
Qcwr9VhsTvz6ujoWuPrfVpUY4I81LBJxKK7n9zBreYzh5uUXRu5k4lN2W8HrE4q0
7tTdsccB9j1CJAiUacYLxTFsvwd/hBs9+g9Eu5kqGeChqEU56Gd8wR96TEu8cVIZ
Bv5UEo9MgT1KsJwk0FMfV8qVScqZrGG3QaoMtNAeAm/tUrhhZO9ANYsC9dey03ut
tU6s5GAeh6i17bqW5WfvzCdhY9ayCInndzkq7SPi9F7fYx79PgdsofqPdyCSBXUo
Ozfn1VQkYQJTmYtrwqLfdAivubaEPIf1+fLqMOXbrI85Ujuy5xzlgVrrqO2K9rbE
DYyPgGZjPtss/yZGRCUdJX6rbW8Tq0HKt/8HpbW5fCt9o0wCSawR71GhzPA1fpNs
0mkAGvvoNGdiSizTLLPvNCaecw4kSzeBNViyP6oRCv69ifNqHPErItsMZ0YIMU14
w4/d9yI9kUa2bvE3cmx6G+9OS8PYip9MsJbQgP7kJsZ8wgt9rQU=
=aw+P
-----END PGP SIGNATURE-----

@ -0,0 +1,16 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEE4/8oOcBIslwITevpsmmV4xAlBWgFAmX5uMIACgkQsmmV4xAl
BWj1tQ//T2qX0m08xWGV7az0D1sH3qjoY+4fEYrknw5uAHqZFiQecRsF27jxv6iH
gP/6GAUw+lbH+9UofhCc0NbPOklliS7gFLNqJdKYFB6JXRNxiRYKh3uVx5o2n0ES
kR3kRl77S47rtCbSMrKTh6ZoWowyIUZGFsIonk5KsLv+oELXY1AK/Im9i3/iTJ1Z
jd/e2oHWuseIxbGZAO8AEP8zOsMMIHfsL3ry8H9xhhPyQM6t5DldqLH3UVE6kq95
fs+olGO4FEKif3VDuLaHVlgtGZOUr6aDIYUmWxctPicboSb6RJAq37CCYgWykOyB
WQec0ONbU7lxt5jhemLSDRy0mEio7+nXIKsO9rDN0Wk1QMpHUl77/C5qVlzfHal7
NhPt8Yl0hBnOjzTq+di+xhAKJcdKp+zZH7/ugAbthuqhNfnkqiF68PANHrCm3gbY
myN0eSaQ9yIa/MbHW8Am9NL/nuFbxdJUL/OIKQ9kFHgD7Qid86TZF0G2vbiBH/eF
IVYoMxRZLd7eu5dIcwXSef+Ai97pODbx9y7bOCFyBO9FuFrlhPObgc7KXCeAzP+y
k5eWvZtWTvvQ+2si2iT22EPBO0D0pnhYWZKpGK5EuKuw8nasNS1yLbhDTVpARynd
8buQh3t2wPfILlQr0+JzDY8GSdQ/nIHGgx2IERdSX/v+9Yo2AvU=
=gYAl
-----END PGP SIGNATURE-----

@ -13,11 +13,11 @@ URL: https://www.python.org/
# WARNING When rebasing to a new Python version,
# remember to update the python3-docs package as well
%global general_version %{pybasever}.18
%global general_version %{pybasever}.19
#global prerel ...
%global upstream_version %{general_version}%{?prerel}
Version: %{general_version}%{?prerel:~%{prerel}}
Release: 3%{?dist}.6
Release: 8%{?dist}
License: Python
@ -195,6 +195,13 @@ License: Python
%global py_INSTSONAME_optimized libpython%{LDVERSION_optimized}.so.%{py_SOVERSION}
%global py_INSTSONAME_debug libpython%{LDVERSION_debug}.so.%{py_SOVERSION}
# The -O flag for the compiler, optimized builds
# https://fedoraproject.org/wiki/Changes/Python_built_with_gcc_O3
%global optflags_optimized -O3
# The -O flag for the compiler, debug builds
# -Wno-cpp avoids some warnings with -O0
%global optflags_debug -O0 -Wno-cpp
# Disable automatic bytecompilation. The python3 binary is not yet be
# available in /usr/bin when Python is built. Also, the bytecompilation fails
# on files that test invalid syntax.
@ -436,23 +443,10 @@ Patch415: 00415-cve-2023-27043-gh-102988-reject-malformed-addresses-in-email-par
# CVE-2023-52425. Future versions of Expat may be more reactive.
Patch422: 00422-fix-tests-for-xmlpullparser-with-expat-2-6-0.patch
# 00426 #
# CVE-2023-6597: Path traversal on tempfile.TemporaryDirectory
# Fixed upstream:
# https://github.com/python/cpython/commit/d54e22a669ae6e987199bb5d2c69bb5a46b0083b
# Tracking bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2276518
Patch426: 00426-CVE-2023-6597.patch
# 00427 #
# CVE-2024-0450: The zipfile module is vulnerable to zip-bombs leading to denial of service
# Fixed upstream:
# https://github.com/python/cpython/commit/a2c59992e9e8d35baba9695eb186ad6c6ff85c51
# Tracking bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2276525
Patch427: 00427-CVE-2024-0450.patch
# 00431 #
# CVE-2024-4032: incorrect IPv4 and IPv6 private ranges
# Upstream issue: https://github.com/python/cpython/issues/113171
# Security fix for CVE-2024-4032: incorrect IPv4 and IPv6 private ranges
# Resolved upstream: https://github.com/python/cpython/issues/113171
# Tracking bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2292921
Patch431: 00431-CVE-2024-4032.patch
# 00435 # f2924d30f4dd44804219c10410a57dd96764d297
@ -478,15 +472,6 @@ Patch435: 00435-gh-121650-encode-newlines-in-headers-and-verify-headers-are-soun
# [CVE-2024-8088] gh-122905: Sanitize names in zipfile.Path.
Patch436: 00436-cve-2024-8088-gh-122905-sanitize-names-in-zipfile-path.patch
# 00437 #
# CVE-2024-6232
#
# Security fix for CVE-2024-6232
# ResolveS: RHEL- 57421
#
#
Patch437: 00437-CVE-2024-6232.patch
# (New patches go here ^^^)
#
# When adding new patches to "python" and "python3" in Fedora, EL, etc.,
@ -952,6 +937,7 @@ BuildPython() {
ConfName=$1
ExtraConfigArgs=$2
MoreCFlags=$3
MoreCFlagsNodist=$4
# Each build is done in its own directory
ConfDir=build/$ConfName
@ -986,7 +972,7 @@ BuildPython() {
$ExtraConfigArgs \
%{nil}
%global flags_override EXTRA_CFLAGS="$MoreCFlags" CFLAGS_NODIST="$CFLAGS_NODIST $MoreCFlags"
%global flags_override EXTRA_CFLAGS="$MoreCFlags" CFLAGS_NODIST="$CFLAGS_NODIST $MoreCFlags $MoreCFlagsNodist"
%if %{without bootstrap}
# Regenerate generated files (needs python3)
@ -1009,12 +995,14 @@ BuildPython() {
# See also: https://bugzilla.redhat.com/show_bug.cgi?id=1818857
BuildPython debug \
"--without-ensurepip --with-pydebug" \
"-O0 -Wno-cpp"
"%{optflags_debug}" \
""
%endif # with debug_build
BuildPython optimized \
"--without-ensurepip %{optimizations_flag}" \
""
"" \
"%{optflags_optimized}"
# ======================================================
# Installing the built code:
@ -1113,7 +1101,7 @@ EOF
%if %{with debug_build}
InstallPython debug \
%{py_INSTSONAME_debug} \
-O0 \
"%{optflags_debug}" \
%{LDVERSION_debug}
%endif # with debug_build
@ -1888,30 +1876,37 @@ CheckPython optimized
# ======================================================
%changelog
* Fri Oct 04 2024 Satish Mane <satmane@redhat.com> - 3.9.18-3.6
- Fix: CVE-2024-6232
- Resolves: RHEL-57421
* Fri Aug 23 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.9.18-3.5
* Fri Aug 23 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.9.19-8
- Security fix for CVE-2024-8088
Resolves: RHEL-55968
Resolves: RHEL-55967
* Tue Aug 13 2024 Lumír Balhar <lbalhar@redhat.com> - 3.9.18-3.4
* Tue Aug 13 2024 Lumír Balhar <lbalhar@redhat.com> - 3.9.19-7
- Security fix for CVE-2024-6923
Resolves: RHEL-53044
Resolves: RHEL-53045
* Thu Aug 01 2024 Miro Hrončok <mhroncok@redhat.com> - 3.9.19-6
- Ensure 3rd party extension modules for the debug build use the -O0 flag
* Thu Jul 25 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.9.19-5
- Properly propagate the optimization flags to C extensions
* Thu Jul 18 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.9.19-4
- Build Python with -O3
- https://fedoraproject.org/wiki/Changes/Python_built_with_gcc_O3
* Wed Jul 03 2024 Lumír Balhar <lbalhar@redhat.com> - 3.9.18-3.3
* Thu Jul 18 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.9.19-3
- Security fix for CVE-2024-4032
Resolves: RHEL-44106
Resolves: RHEL-44107
* Tue Jun 11 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.9.18-3.2
* Tue Jun 11 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.9.19-2
- Enable importing of hash-based .pyc files under FIPS mode
Resolves: RHEL-40767
Resolves: RHEL-40750
* Thu May 16 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.9.18-3.1
* Mon Apr 22 2024 Charalampos Stratakis <cstratak@redhat.com> - 3.9.19-1
- Update to 3.9.19
- Security fixes for CVE-2023-6597 and CVE-2024-0450
- Fix tests for XMLPullParser with Expat with fixed CVE
Resolves: RHEL-33887, RHEL-34287
Resolves: RHEL-33679, RHEL-33691
* Wed Jan 24 2024 Lumír Balhar <lbalhar@redhat.com> - 3.9.18-3
- Fix tests on s390x with hw acceleration

Loading…
Cancel
Save