Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork34k
Description
Bug report
Bug description:
Summary
An Infinite Loop bug was identified in the pure-Python implementation of zoneinfo._common.load_data (used by _zoneinfo.c). The bug is triggered when parsing a ZoneInfo file (version >= 2) that ends unexpectedly while reading the timezone string. The loop condition while (c := fobj.read(1)) != b"\n" fails to handle the End-Of-File (EOF) condition, causing it to loop indefinitely if b"\n" is never found.
Component
Lib/zoneinfo/_common.py
Affected Functions
load_data
Root Cause Analysis
The code attempts to read the timezone string byte-by-byte until a newline character is found:
# Lib/zoneinfo/_common.py:122while (c:=fobj.read(1))!=b"\n":tz_bytes+=c
If the file pointer reaches EOF,fobj.read(1) returnsb"" (empty bytes).
The comparisonb"" != b"\n" evaluates toTrue.
The loop continues indefinitely, appending empty bytes totz_bytes (or doing nothing iftz_bytes is efficiently handled, but consuming CPU).
Reproduction
- Input: A constructed ZoneInfo file with Version 2 header but truncated before the trailing newline of the timezone string.
- Command:
python3 reproduce_issue_4.py
Script:
importioimportzoneinfoimportstructimporttimedefreproduce():# First Header (V1 part of V2 file)# Magic(4) + Version(1) + Reserved(15) + Counts(24)header=b"TZif"+b"2"+ (b"\x00"*15)+ (b"\x00"*24)# Data is empty (counts are 0)# Second Header (V2 itself)# Magic(4) + Version(1) + Reserved(15) + Counts(24)header2=b"TZif"+b"2"+ (b"\x00"*15)+ (b"\x00"*24)# Newline checkdata=header+header2+b"\n"print("This script will HANG INDEFINITELY if the vulnerability is present.")print("Press Ctrl+C to stop.")try:bio=io.BytesIO(data)print("Starting ZoneInfo.from_file...")try:zoneinfo.ZoneInfo.from_file(bio)exceptValueErrorase:if"unexpected end of file"instr(e):print("SUCCESS: Code raised ValueError as expected (Fix verified)")returnelse:raiseeprint("Finished without expected ValueError?")exceptKeyboardInterrupt:print("\nInterrupted by user.")exceptExceptionase:print(f"Caught exception:{e}")if__name__=="__main__":reproduce()
Patch
I think this will solve the problem. I'll send a PR.
line = fobj.readline() if not line.endswith(b"\n"): raise ValueError("Invalid TZif file: unexpected end of file") tz_bytes = line.rstrip(b"\n")CPython versions tested on:
3.15
Operating systems tested on:
Linux