Skip to content

Commit

Permalink
Merge branch 'jk/commit-dates-parsing-fix' into maint
Browse files Browse the repository at this point in the history
Codepaths that parse timestamps in commit objects have been
tightened.

* jk/commit-dates-parsing-fix:
  show_ident_date: fix tz range check
  log: do not segfault on gmtime errors
  log: handle integer overflow in timestamps
  date: check date overflow against time_t
  fsck: report integer overflow in author timestamps
  t4212: test bogus timestamps with git-log
  • Loading branch information
Junio C Hamano committed Mar 18, 2014
2 parents a5aca6e + 3f419d4 commit 8aac6c9
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 11 deletions.
1 change: 1 addition & 0 deletions cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,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
Expand Down
23 changes: 21 additions & 2 deletions date.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,10 @@ const char *show_date(unsigned long time, int tz, enum date_mode mode)
tz = local_tzoffset(time);

tm = time_to_tm(time, tz);
if (!tm)
return NULL;
if (!tm) {
tm = time_to_tm(0, 0);
tz = 0;
}

strbuf_reset(&timebuf);
if (mode == DATE_SHORT)
Expand Down Expand Up @@ -1113,3 +1115,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);
}
12 changes: 6 additions & 6 deletions fsck.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func)

static int fsck_ident(char **ident, struct object *obj, fsck_error error_func)
{
char *end;

if (**ident == '<')
return error_func(obj, FSCK_ERROR, "invalid author/committer line - missing space before email");
*ident += strcspn(*ident, "<>\n");
Expand All @@ -264,10 +266,11 @@ 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");
*ident += strspn(*ident, "0123456789");
if (**ident != ' ')
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");
(*ident)++;
*ident = end + 1;
if ((**ident != '+' && **ident != '-') ||
!isdigit((*ident)[1]) ||
!isdigit((*ident)[2]) ||
Expand All @@ -287,9 +290,6 @@ static int fsck_commit(struct commit *commit, fsck_error error_func)
int parents = 0;
int err;

if (commit->date == ULONG_MAX)
return error_func(&commit->object, FSCK_ERROR, "invalid author/committer line");

if (memcmp(buffer, "tree ", 5))
return error_func(&commit->object, FSCK_ERROR, "invalid format - expected 'tree' line");
if (get_sha1_hex(buffer+5, tree_sha1) || buffer[45] != '\n')
Expand Down
12 changes: 9 additions & 3 deletions pretty.c
Original file line number Diff line number Diff line change
Expand Up @@ -397,12 +397,18 @@ static const char *show_ident_date(const struct ident_split *ident,
enum date_mode mode)
{
unsigned long date = 0;
int tz = 0;
long tz = 0;

if (ident->date_begin && ident->date_end)
date = strtoul(ident->date_begin, NULL, 10);
if (ident->tz_begin && ident->tz_end)
tz = strtol(ident->tz_begin, NULL, 10);
if (date_overflows(date))
date = 0;
else {
if (ident->tz_begin && ident->tz_end)
tz = strtol(ident->tz_begin, NULL, 10);
if (tz >= INT_MAX || tz <= INT_MIN)
tz = 0;
}
return show_date(date, tz, mode);
}

Expand Down
14 changes: 14 additions & 0 deletions t/t1450-fsck.sh
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,20 @@ test_expect_success '> in name is reported' '
grep "error in commit $new" out
'

# date is 2^64 + 1
test_expect_success 'integer overflow in timestamps is reported' '
git cat-file commit HEAD >basis &&
sed "s/^\\(author .*>\\) [0-9]*/\\1 18446744073709551617/" \
<basis >bad-timestamp &&
new=$(git hash-object -t commit -w --stdin <bad-timestamp) &&
test_when_finished "remove_object $new" &&
git update-ref refs/heads/bogus "$new" &&
test_when_finished "git update-ref -d refs/heads/bogus" &&
git fsck 2>out &&
cat out &&
grep "error in commit $new.*integer overflow" out
'

test_expect_success 'tag pointing to nonexistent' '
cat >invalid-tag <<-\EOF &&
object ffffffffffffffffffffffffffffffffffffffff
Expand Down
45 changes: 45 additions & 0 deletions t/t4212-log-corrupt.sh
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,49 @@ test_expect_success 'git log --format with broken author email' '
test_cmp expect.err actual.err
'

munge_author_date () {
git cat-file commit "$1" >commit.orig &&
sed "s/^\(author .*>\) [0-9]*/\1 $2/" <commit.orig >commit.munge &&
git hash-object -w -t commit commit.munge
}

test_expect_success 'unparsable dates produce sentinel value' '
commit=$(munge_author_date HEAD totally_bogus) &&
echo "Date: Thu Jan 1 00:00:00 1970 +0000" >expect &&
git log -1 $commit >actual.full &&
grep Date <actual.full >actual &&
test_cmp expect actual
'

test_expect_success 'unparsable dates produce sentinel value (%ad)' '
commit=$(munge_author_date HEAD totally_bogus) &&
echo >expect &&
git log -1 --format=%ad $commit >actual
test_cmp expect actual
'

# date is 2^64 + 1
test_expect_success 'date parser recognizes integer overflow' '
commit=$(munge_author_date HEAD 18446744073709551617) &&
echo "Thu Jan 1 00:00:00 1970 +0000" >expect &&
git log -1 --format=%ad $commit >actual &&
test_cmp expect actual
'

# date is 2^64 - 2
test_expect_success 'date parser recognizes time_t overflow' '
commit=$(munge_author_date HEAD 18446744073709551614) &&
echo "Thu Jan 1 00:00:00 1970 +0000" >expect &&
git log -1 --format=%ad $commit >actual &&
test_cmp expect actual
'

# date is within 2^63-1, but enough to choke glibc's gmtime
test_expect_success 'absurdly far-in-future dates produce sentinel' '
commit=$(munge_author_date HEAD 999999999999999999) &&
echo "Thu Jan 1 00:00:00 1970 +0000" >expect &&
git log -1 --format=%ad $commit >actual &&
test_cmp expect actual
'

test_done

0 comments on commit 8aac6c9

Please sign in to comment.