From be2125409679c5ce4e1c7a98333f29e1b1f4df12 Mon Sep 17 00:00:00 2001 From: fatihhcelik Date: Sun, 28 Dec 2025 15:20:27 +0300 Subject: [PATCH 01/10] gh-143241: Fix infinite loop DoS in zoneinfo._common.load_data --- Lib/test/test_zoneinfo/test_zoneinfo.py | 2 ++ Lib/zoneinfo/_common.py | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_zoneinfo/test_zoneinfo.py b/Lib/test/test_zoneinfo/test_zoneinfo.py index 8f3ca59c9ef5ed..236622195445a4 100644 --- a/Lib/test/test_zoneinfo/test_zoneinfo.py +++ b/Lib/test/test_zoneinfo/test_zoneinfo.py @@ -252,6 +252,8 @@ def test_bad_zones(self): bad_zones = [ b"", # Empty file b"AAAA3" + b" " * 15, # Bad magic + # Truncated V2 file (infinite loop DoS) + b"TZif2" + (b"\x00" * 39) + b"TZif2" + (b"\x00" * 39) + b"\n" + b"Part", ] for bad_zone in bad_zones: diff --git a/Lib/zoneinfo/_common.py b/Lib/zoneinfo/_common.py index 03cc42149f9b74..e0f2351af817a5 100644 --- a/Lib/zoneinfo/_common.py +++ b/Lib/zoneinfo/_common.py @@ -119,8 +119,10 @@ def get_abbr(idx): assert c == b"\n", c tz_bytes = b"" - while (c := fobj.read(1)) != b"\n": - tz_bytes += c + line = fobj.readline() + if not line.endswith(b"\n"): + raise ValueError("Invalid TZif file: unexpected end of file") + tz_bytes = line.rstrip(b"\n") tz_str = tz_bytes else: From a240d3a88a872cbff07651dcf6e7e17087c75bc8 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sun, 28 Dec 2025 12:38:54 +0000 Subject: [PATCH 02/10] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2025-12-28-12-38-53.gh-issue-143241.yW250u.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2025-12-28-12-38-53.gh-issue-143241.yW250u.rst diff --git a/Misc/NEWS.d/next/Library/2025-12-28-12-38-53.gh-issue-143241.yW250u.rst b/Misc/NEWS.d/next/Library/2025-12-28-12-38-53.gh-issue-143241.yW250u.rst new file mode 100644 index 00000000000000..6cf1d550236efe --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-28-12-38-53.gh-issue-143241.yW250u.rst @@ -0,0 +1 @@ +Fix infinite loop in zoneinfo._common.load_data caused by a malformed TZif file. From 4b7f2411f6c6553ae79bd5bf9f222093c4366add Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fatih=20=C3=87elik?= Date: Sun, 28 Dec 2025 16:38:39 +0300 Subject: [PATCH 03/10] Update Lib/test/test_zoneinfo/test_zoneinfo.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/test/test_zoneinfo/test_zoneinfo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_zoneinfo/test_zoneinfo.py b/Lib/test/test_zoneinfo/test_zoneinfo.py index 236622195445a4..8a5ed1bd680b87 100644 --- a/Lib/test/test_zoneinfo/test_zoneinfo.py +++ b/Lib/test/test_zoneinfo/test_zoneinfo.py @@ -252,7 +252,7 @@ def test_bad_zones(self): bad_zones = [ b"", # Empty file b"AAAA3" + b" " * 15, # Bad magic - # Truncated V2 file (infinite loop DoS) + # Truncated V2 file (should loop indefinitely) b"TZif2" + (b"\x00" * 39) + b"TZif2" + (b"\x00" * 39) + b"\n" + b"Part", ] From 3691e9ad26ec61699bff3851f0869940126e26cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fatih=20=C3=87elik?= Date: Sun, 28 Dec 2025 16:42:54 +0300 Subject: [PATCH 04/10] Update Lib/test/test_zoneinfo/test_zoneinfo.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/test/test_zoneinfo/test_zoneinfo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_zoneinfo/test_zoneinfo.py b/Lib/test/test_zoneinfo/test_zoneinfo.py index 8a5ed1bd680b87..581072d0701d65 100644 --- a/Lib/test/test_zoneinfo/test_zoneinfo.py +++ b/Lib/test/test_zoneinfo/test_zoneinfo.py @@ -252,7 +252,7 @@ def test_bad_zones(self): bad_zones = [ b"", # Empty file b"AAAA3" + b" " * 15, # Bad magic - # Truncated V2 file (should loop indefinitely) + # Truncated V2 file (should not loop indefinitely) b"TZif2" + (b"\x00" * 39) + b"TZif2" + (b"\x00" * 39) + b"\n" + b"Part", ] From d6f950f980bc0c1b9367b11c0626b3624d3b0b27 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sun, 28 Dec 2025 13:49:07 +0000 Subject: [PATCH 05/10] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2025-12-28-13-49-06.gh-issue-143241.5H4b8d.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2025-12-28-13-49-06.gh-issue-143241.5H4b8d.rst diff --git a/Misc/NEWS.d/next/Library/2025-12-28-13-49-06.gh-issue-143241.5H4b8d.rst b/Misc/NEWS.d/next/Library/2025-12-28-13-49-06.gh-issue-143241.5H4b8d.rst new file mode 100644 index 00000000000000..377bcfcb51025a --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-28-13-49-06.gh-issue-143241.5H4b8d.rst @@ -0,0 +1 @@ +Fix infinite loop in zoneinfo.ZoneInfo.from_file when parsing a malformed TZif file. From 7f46a5b87ebba6792349ef03699eeb4ed524db71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fatih=20=C3=87elik?= Date: Sun, 28 Dec 2025 16:55:13 +0300 Subject: [PATCH 06/10] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unnecessary tz_bytes variable. Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/zoneinfo/_common.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Lib/zoneinfo/_common.py b/Lib/zoneinfo/_common.py index e0f2351af817a5..59f3f0ce853f74 100644 --- a/Lib/zoneinfo/_common.py +++ b/Lib/zoneinfo/_common.py @@ -118,13 +118,10 @@ def get_abbr(idx): c = fobj.read(1) # Should be \n assert c == b"\n", c - tz_bytes = b"" line = fobj.readline() if not line.endswith(b"\n"): raise ValueError("Invalid TZif file: unexpected end of file") - tz_bytes = line.rstrip(b"\n") - - tz_str = tz_bytes + tz_str = line.rstrip(b"\n") else: tz_str = None From ddd029b9aa015886cdbdbea3fb4f3a5580f9c691 Mon Sep 17 00:00:00 2001 From: fatihhcelik Date: Sun, 28 Dec 2025 17:03:43 +0300 Subject: [PATCH 07/10] gh-143241: Document ValueError for invalid files in ZoneInfo.from_file --- Doc/library/zoneinfo.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/library/zoneinfo.rst b/Doc/library/zoneinfo.rst index 8147e58d322667..759ec4277b8b7d 100644 --- a/Doc/library/zoneinfo.rst +++ b/Doc/library/zoneinfo.rst @@ -206,6 +206,9 @@ The ``ZoneInfo`` class has two alternate constructors: Objects created via this constructor cannot be pickled (see `pickling`_). + :exc:`ValueError` is raised if the data read from *file_obj* is not a valid + TZif file. + .. classmethod:: ZoneInfo.no_cache(key) An alternate constructor that bypasses the constructor's cache. It is From 79042d2d7e89b6c52a2b68f6bfcf15ed7be1fafb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fatih=20=C3=87elik?= Date: Sun, 28 Dec 2025 17:08:17 +0300 Subject: [PATCH 08/10] Delete Misc/NEWS.d/next/Library/2025-12-28-12-38-53.gh-issue-143241.yW250u.rst --- .../next/Library/2025-12-28-12-38-53.gh-issue-143241.yW250u.rst | 1 - 1 file changed, 1 deletion(-) delete mode 100644 Misc/NEWS.d/next/Library/2025-12-28-12-38-53.gh-issue-143241.yW250u.rst diff --git a/Misc/NEWS.d/next/Library/2025-12-28-12-38-53.gh-issue-143241.yW250u.rst b/Misc/NEWS.d/next/Library/2025-12-28-12-38-53.gh-issue-143241.yW250u.rst deleted file mode 100644 index 6cf1d550236efe..00000000000000 --- a/Misc/NEWS.d/next/Library/2025-12-28-12-38-53.gh-issue-143241.yW250u.rst +++ /dev/null @@ -1 +0,0 @@ -Fix infinite loop in zoneinfo._common.load_data caused by a malformed TZif file. From c2b00dc28a5d4db03c49fa068843706c1f0cb9f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fatih=20=C3=87elik?= Date: Sun, 28 Dec 2025 17:14:26 +0300 Subject: [PATCH 09/10] Update Misc/NEWS.d/next/Library/2025-12-28-13-49-06.gh-issue-143241.5H4b8d.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- .../Library/2025-12-28-13-49-06.gh-issue-143241.5H4b8d.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-12-28-13-49-06.gh-issue-143241.5H4b8d.rst b/Misc/NEWS.d/next/Library/2025-12-28-13-49-06.gh-issue-143241.5H4b8d.rst index 377bcfcb51025a..922e1a2dcd3073 100644 --- a/Misc/NEWS.d/next/Library/2025-12-28-13-49-06.gh-issue-143241.5H4b8d.rst +++ b/Misc/NEWS.d/next/Library/2025-12-28-13-49-06.gh-issue-143241.5H4b8d.rst @@ -1 +1,2 @@ -Fix infinite loop in zoneinfo.ZoneInfo.from_file when parsing a malformed TZif file. +:mod:`zoneinfo`: fix infinite loop in :meth:`ZoneInfo.from_file +` when parsing a malformed TZif file. From af906939b5d1a4e2d72d68693a5767bd6e0a0fe5 Mon Sep 17 00:00:00 2001 From: fatihhcelik Date: Sun, 28 Dec 2025 17:16:39 +0300 Subject: [PATCH 10/10] gh-143241: Add Patch by credit to NEWS --- .../next/Library/2025-12-28-13-49-06.gh-issue-143241.5H4b8d.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-12-28-13-49-06.gh-issue-143241.5H4b8d.rst b/Misc/NEWS.d/next/Library/2025-12-28-13-49-06.gh-issue-143241.5H4b8d.rst index 922e1a2dcd3073..7170a06015ee7c 100644 --- a/Misc/NEWS.d/next/Library/2025-12-28-13-49-06.gh-issue-143241.5H4b8d.rst +++ b/Misc/NEWS.d/next/Library/2025-12-28-13-49-06.gh-issue-143241.5H4b8d.rst @@ -1,2 +1,2 @@ :mod:`zoneinfo`: fix infinite loop in :meth:`ZoneInfo.from_file -` when parsing a malformed TZif file. +` when parsing a malformed TZif file. Patch by Fatih Celik.