diff --git a/cache.h b/cache.h index bb71bf8a7f9..9a2c377b73f 100644 --- a/cache.h +++ b/cache.h @@ -909,6 +909,7 @@ void datestamp(char *buf, int bufsize); unsigned long approxidate_careful(const char *, int *); unsigned long approxidate_relative(const char *date, const struct timeval *now); enum date_mode parse_date_format(const char *format); +int date_overflows(unsigned long date); #define IDENT_STRICT 1 #define IDENT_NO_DATE 2 diff --git a/date.c b/date.c index 57331ed406e..2dae471dd12 100644 --- a/date.c +++ b/date.c @@ -1085,3 +1085,20 @@ unsigned long approxidate_careful(const char *date, int *error_ret) gettimeofday(&tv, NULL); return approxidate_str(date, &tv, error_ret); } + +int date_overflows(unsigned long t) +{ + time_t sys; + + /* If we overflowed our unsigned long, that's bad... */ + if (t == ULONG_MAX) + return 1; + + /* + * ...but we also are going to feed the result to system + * functions that expect time_t, which is often "signed long". + * Make sure that we fit into time_t, as well. + */ + sys = t; + return t != sys || (t < 1) != (sys < 1); +} diff --git a/fsck.c b/fsck.c index 760e072ccef..64bf279fd7e 100644 --- a/fsck.c +++ b/fsck.c @@ -266,7 +266,7 @@ static int fsck_ident(char **ident, struct object *obj, fsck_error error_func) (*ident)++; if (**ident == '0' && (*ident)[1] != ' ') return error_func(obj, FSCK_ERROR, "invalid author/committer line - zero-padded date"); - if (strtoul(*ident, &end, 10) == ULONG_MAX) + if (date_overflows(strtoul(*ident, &end, 10))) return error_func(obj, FSCK_ERROR, "invalid author/committer line - date causes integer overflow"); if (end == *ident || *end != ' ') return error_func(obj, FSCK_ERROR, "invalid author/committer line - bad date");