Thanks for the bug report and patch. I installed the attached, which as
far as the code is concerned is slightly simpler than the patch you
sent. Please give it a try.
From 37a4d178474e3b85faede06e44abda4d0b2a4da0 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email protected]>
Date: Wed, 1 Apr 2026 00:35:13 -0700
Subject: [PROPOSED] Fix zic overflow bug with too-large offsets
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Without this fix, ‘Zone Ouch 2147483648:00:00 - LMT’ causes zic
to convert 2147483648 to int, which can cause a trap.
Other adversarial inputs can even cause buffer overflow.
Problem reported by Naveed Khan in:
https://lists.iana.org/hyperkitty/list/[email protected]/thread/POOFMB4SHW2U6BNNNQVGH6ZK7TLBLK7P/
* NEWS: Mention this.
* zic.c (stringoffset): Check for too-large hour offset before
assigning it to an int.
---
NEWS | 7 +++++--
zic.c | 4 ++--
2 files changed, 7 insertions(+), 4 deletions(-)
diff --git a/NEWS b/NEWS
index a297861d..1a97cbfe 100644
--- a/NEWS
+++ b/NEWS
@@ -21,8 +21,11 @@ Unreleased, experimental changes
zic no longer overflows a buffer when generating a TZ string like
"PST-167:59:58PDT-167:59:59,M11.5.6/-167:59:59,M12.5.6/-167:59:59",
- which can occur with adversarial input. (Thanks to GitHub
- user rootvector2.)
+ which can occur with adversarial input. (Thanks to Naveed Khan.)
+
+ zic no longer overflows an int when processing input like ‘Zone
+ Ouch 2147483648:00:00 - LMT’. The int overflow can lead to buffer
+ overflow in adversarial cases. (Thanks to Naveed Khan.)
zic now checks for signals more often.
diff --git a/zic.c b/zic.c
index c0891001..6e859d09 100644
--- a/zic.c
+++ b/zic.c
@@ -3182,11 +3182,11 @@ stringoffset(char *result, zic_t offset)
offset /= SECSPERMIN;
minutes = offset % MINSPERHOUR;
offset /= MINSPERHOUR;
- hours = offset;
- if (hours >= HOURSPERDAY * DAYSPERWEEK) {
+ if (offset >= HOURSPERDAY * DAYSPERWEEK) {
result[0] = '\0';
return 0;
}
+ hours = offset;
len += sprintf(result + len, "%d", hours);
if (minutes != 0 || seconds != 0) {
len += sprintf(result + len, ":%02d", minutes);
--
2.51.0