]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
warc: fix UB signed overflow in time conversion 3344/head
authordatauwu <datauwu@users.noreply.github.com>
Sat, 1 Aug 2026 18:57:11 +0000 (02:57 +0800)
committerdatauwu <datauwu@users.noreply.github.com>
Sat, 1 Aug 2026 19:04:20 +0000 (03:04 +0800)
Use checked 64-bit math when timegm() is not available.
Reject values outside time_t instead of overflowing signed integers.

libarchive/archive_read_support_format_warc.c

index d70c718320e1e3b9544d878069ec6624dc3f0cd4..87238c7e18a463a325d5ad7d91952218fb88be8c 100644 (file)
@@ -552,19 +552,29 @@ time_from_tm(struct tm *t)
         /* Use platform timegm() if available. */
         return (timegm(t));
 #else
+        int64_t days, result;
+
         /* Otherwise, calculate directly using POSIX assumptions. */
         /* First, fix up tm_yday based on the year, month, and day. */
         if (mktime(t) == (time_t)-1)
                 return ((time_t)-1);
         /* Then compute timegm() from first principles. */
-        return (t->tm_sec
-            + t->tm_min * 60
-            + t->tm_hour * 3600
-            + t->tm_yday * 86400
-            + (t->tm_year - 70) * 31536000
-            + ((t->tm_year - 69) / 4) * 86400
-            - ((t->tm_year - 1) / 100) * 86400
-            + ((t->tm_year + 299) / 400) * 86400);
+        days = (int64_t)t->tm_yday
+            + ((int64_t)t->tm_year - 70) * 365
+            + ((int64_t)t->tm_year - 69) / 4
+            - ((int64_t)t->tm_year - 1) / 100
+            + ((int64_t)t->tm_year + 299) / 400;
+        if (archive_ckd_mul_i64(&result, days, 86400) ||
+            archive_ckd_add_i64(&result, result,
+                (int64_t)t->tm_hour * 3600 + t->tm_min * 60
+                + t->tm_sec))
+                return ((time_t)-1);
+        if (result < 0) {
+                if (TIME_MIN == 0 || result < (int64_t)TIME_MIN)
+                        return ((time_t)-1);
+        } else if ((uint64_t)result > (uint64_t)TIME_MAX)
+                return ((time_t)-1);
+        return ((time_t)result);
 #endif
 }