diff options
author | teor (Tim Wilson-Brown) <teor2345@gmail.com> | 2016-02-25 11:02:39 +0800 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2016-03-24 10:17:48 -0400 |
commit | e71e8e005a533ad519d6b226541ede115e0a5b79 (patch) | |
tree | 803860ef330d1d83fdfe9b57c110d949773df69b /src | |
parent | e019e11e61c2c57c84505aaf2559966bddd4a10d (diff) | |
download | tor-e71e8e005a533ad519d6b226541ede115e0a5b79.tar.gz tor-e71e8e005a533ad519d6b226541ede115e0a5b79.zip |
Avoid overflow in tor_timegm on 32 bit platforms due to year 2038
Diffstat (limited to 'src')
-rw-r--r-- | src/common/util.c | 23 |
1 files changed, 20 insertions, 3 deletions
diff --git a/src/common/util.c b/src/common/util.c index fda5993edf..6e90f25c8a 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -1475,9 +1475,19 @@ tor_timegm(const struct tm *tm, time_t *time_out) { /* This is a pretty ironclad timegm implementation, snarfed from Python2.2. * It's way more brute-force than fiddling with tzset(). - */ - time_t year, days, hours, minutes, seconds; + * + * We use int64_t rather than time_t to avoid overflow on multiplication on + * platforms with 32-bit time_t. Since year is clipped to INT32_MAX, and + * since 365 * 24 * 60 * 60 is approximately 31 million, it's not possible + * for INT32_MAX years to overflow int64_t when converted to seconds. */ + int64_t year, days, hours, minutes, seconds; int i, invalid_year, dpm; + + /* Initialize time_out to 0 for now, to avoid bad usage in case this function + fails and the caller ignores the return value. */ + tor_assert(time_out); + *time_out = 0; + /* avoid int overflow on addition */ if (tm->tm_year < INT32_MAX-1900) { year = tm->tm_year + 1900; @@ -1516,7 +1526,14 @@ tor_timegm(const struct tm *tm, time_t *time_out) minutes = hours*60 + tm->tm_min; seconds = minutes*60 + tm->tm_sec; - *time_out = seconds; + /* Check that "seconds" will fit in a time_t. On platforms where time_t is + * 32-bit, this check will fail for dates in and after 2038. + * "seconds" can't be negative, because "year" >= 1970. */ + if (seconds < TIME_MIN || seconds > TIME_MAX) { + log_warn(LD_BUG, "Result does not fit in tor_timegm"); + return -1; + } + *time_out = (time_t)seconds; return 0; } |