diff options
author | Nick Mathewson <nickm@torproject.org> | 2014-10-21 13:14:27 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2014-10-21 13:14:27 -0400 |
commit | 3826a88fc072f97673ee3b106f3dd1b93c875b27 (patch) | |
tree | 2681f478ed1fe8b56025109172f8b6da2c029d0f /src/common | |
parent | e3d166b7a63b4f0c248e20b759dba2ccb8d30092 (diff) | |
parent | a1c6a40c22736aa66ce59341689392ed80cdd2dc (diff) | |
download | tor-3826a88fc072f97673ee3b106f3dd1b93c875b27.tar.gz tor-3826a88fc072f97673ee3b106f3dd1b93c875b27.zip |
Merge remote-tracking branch 'teor/bug13476-improve-time-handling'
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/compat.c | 18 | ||||
-rw-r--r-- | src/common/util.c | 68 |
2 files changed, 64 insertions, 22 deletions
diff --git a/src/common/compat.c b/src/common/compat.c index 4dd04455a2..b6fdb1ad78 100644 --- a/src/common/compat.c +++ b/src/common/compat.c @@ -2770,14 +2770,24 @@ correct_tm(int islocal, const time_t *timep, struct tm *resultbuf, const char *outcome; if (PREDICT_LIKELY(r)) { - if (r->tm_year > 8099) { /* We can't strftime dates after 9999 CE. */ + /* We can't strftime dates after 9999 CE, and we want to avoid dates + * before 1 CE (avoiding the year 0 issue and negative years). */ + if (r->tm_year > 8099) { r->tm_year = 8099; r->tm_mon = 11; r->tm_mday = 31; - r->tm_yday = 365; + r->tm_yday = 364; r->tm_hour = 23; r->tm_min = 59; r->tm_sec = 59; + } else if (r->tm_year < (1-1900)) { + r->tm_year = (1-1900); + r->tm_mon = 0; + r->tm_mday = 1; + r->tm_yday = 0; + r->tm_hour = 0; + r->tm_min = 0; + r->tm_sec = 0; } return r; } @@ -2791,7 +2801,7 @@ correct_tm(int islocal, const time_t *timep, struct tm *resultbuf, r->tm_year = 70; /* 1970 CE */ r->tm_mon = 0; r->tm_mday = 1; - r->tm_yday = 1; + r->tm_yday = 0; r->tm_hour = 0; r->tm_min = 0 ; r->tm_sec = 0; @@ -2804,7 +2814,7 @@ correct_tm(int islocal, const time_t *timep, struct tm *resultbuf, r->tm_year = 137; /* 2037 CE */ r->tm_mon = 11; r->tm_mday = 31; - r->tm_yday = 365; + r->tm_yday = 364; r->tm_hour = 23; r->tm_min = 59; r->tm_sec = 59; diff --git a/src/common/util.c b/src/common/util.c index 1d9d99dea2..ece8aaad81 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -1376,7 +1376,8 @@ n_leapdays(int y1, int y2) --y2; return (y2/4 - y1/4) - (y2/100 - y1/100) + (y2/400 - y1/400); } -/** Number of days per month in non-leap year; used by tor_timegm. */ +/** Number of days per month in non-leap year; used by tor_timegm and + * parse_rfc1123_time. */ static const int days_per_month[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; @@ -1390,10 +1391,32 @@ tor_timegm(const struct tm *tm, time_t *time_out) * It's way more brute-force than fiddling with tzset(). */ time_t year, days, hours, minutes, seconds; - int i; - year = tm->tm_year + 1900; - if (year < 1970 || tm->tm_mon < 0 || tm->tm_mon > 11 || - tm->tm_year >= INT32_MAX-1900) { + int i, invalid_year, dpm; + /* avoid int overflow on addition */ + if (tm->tm_year < INT32_MAX-1900) { + year = tm->tm_year + 1900; + } else { + /* clamp year */ + year = INT32_MAX; + } + invalid_year = (year < 1970 || tm->tm_year >= INT32_MAX-1900); + + if (tm->tm_mon >= 0 && tm->tm_mon <= 11) { + dpm = days_per_month[tm->tm_mon]; + if (tm->tm_mon == 1 && !invalid_year && IS_LEAPYEAR(tm->tm_year)) { + dpm = 29; + } + } else { + /* invalid month - default to 0 days per month */ + dpm = 0; + } + + if (invalid_year || + tm->tm_mon < 0 || tm->tm_mon > 11 || + tm->tm_mday < 1 || tm->tm_mday > dpm || + tm->tm_hour < 0 || tm->tm_hour > 23 || + tm->tm_min < 0 || tm->tm_min > 59 || + tm->tm_sec < 0 || tm->tm_sec > 60) { log_warn(LD_BUG, "Out-of-range argument to tor_timegm"); return -1; } @@ -1457,8 +1480,9 @@ parse_rfc1123_time(const char *buf, time_t *t) struct tm tm; char month[4]; char weekday[4]; - int i, m; + int i, m, invalid_year; unsigned tm_mday, tm_year, tm_hour, tm_min, tm_sec; + unsigned dpm; if (strlen(buf) != RFC1123_TIME_LEN) return -1; @@ -1471,18 +1495,6 @@ parse_rfc1123_time(const char *buf, time_t *t) tor_free(esc); return -1; } - if (tm_mday < 1 || tm_mday > 31 || tm_hour > 23 || tm_min > 59 || - tm_sec > 60 || tm_year >= INT32_MAX || tm_year < 1970) { - char *esc = esc_for_log(buf); - log_warn(LD_GENERAL, "Got invalid RFC1123 time %s", esc); - tor_free(esc); - return -1; - } - tm.tm_mday = (int)tm_mday; - tm.tm_year = (int)tm_year; - tm.tm_hour = (int)tm_hour; - tm.tm_min = (int)tm_min; - tm.tm_sec = (int)tm_sec; m = -1; for (i = 0; i < 12; ++i) { @@ -1499,6 +1511,26 @@ parse_rfc1123_time(const char *buf, time_t *t) } tm.tm_mon = m; + invalid_year = (tm_year >= INT32_MAX || tm_year < 1970); + tor_assert(m >= 0 && m <= 11); + dpm = days_per_month[m]; + if (m == 1 && !invalid_year && IS_LEAPYEAR(tm_year)) { + dpm = 29; + } + + if (invalid_year || tm_mday < 1 || tm_mday > dpm || + tm_hour > 23 || tm_min > 59 || tm_sec > 60) { + char *esc = esc_for_log(buf); + log_warn(LD_GENERAL, "Got invalid RFC1123 time %s", esc); + tor_free(esc); + return -1; + } + tm.tm_mday = (int)tm_mday; + tm.tm_year = (int)tm_year; + tm.tm_hour = (int)tm_hour; + tm.tm_min = (int)tm_min; + tm.tm_sec = (int)tm_sec; + if (tm.tm_year < 1970) { char *esc = esc_for_log(buf); log_warn(LD_GENERAL, |