Skip to content

Commit 47fe3f6

Browse files
peffgitster
authored andcommitted
nth_packed_object_offset: bounds-check extended offset
If a pack .idx file has a corrupted offset for an object, we may try to access an offset in the .idx or .pack file that is larger than the file's size. For the .pack case, we have use_pack() to protect us, which realizes the access is out of bounds. But if the corrupted value asks us to look in the .idx file's secondary 64-bit offset table, we blindly add it to the mmap'd index data and access arbitrary memory. We can fix this with a simple bounds-check compared to the size we found when we opened the .idx file. Note that there's similar code in index-pack that is triggered only during "index-pack --verify". To support both, we pull the bounds-check into a separate function, which dies when it sees a corrupted file. It would be nice if we could return an error, so that the pack code could try to find a good copy of the object elsewhere. Currently nth_packed_object_offset doesn't have any way to return an error, but it could probably use "0" as a sentinel value (since no object can start there). This is the minimal fix, and we can improve the resilience later on top. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent a128386 commit 47fe3f6

File tree

4 files changed

+27
-1
lines changed

4 files changed

+27
-1
lines changed

builtin/index-pack.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1445,6 +1445,7 @@ static void read_v2_anomalous_offsets(struct packed_git *p,
14451445
if (!(off & 0x80000000))
14461446
continue;
14471447
off = off & 0x7fffffff;
1448+
check_pack_index_ptr(p, &idx2[off * 2]);
14481449
if (idx2[off * 2])
14491450
continue;
14501451
/*

cache.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,6 +1236,16 @@ extern void free_pack_by_name(const char *);
12361236
extern void clear_delta_base_cache(void);
12371237
extern struct packed_git *add_packed_git(const char *, int, int);
12381238

1239+
/*
1240+
* Make sure that a pointer access into an mmap'd index file is within bounds,
1241+
* and can provide at least 8 bytes of data.
1242+
*
1243+
* Note that this is only necessary for variable-length segments of the file
1244+
* (like the 64-bit extended offset table), as we compare the size to the
1245+
* fixed-length parts when we open the file.
1246+
*/
1247+
extern void check_pack_index_ptr(const struct packed_git *p, const void *ptr);
1248+
12391249
/*
12401250
* Return the SHA-1 of the nth object within the specified packfile.
12411251
* Open the index if it is not already open. The return value points

sha1_file.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2359,6 +2359,20 @@ const unsigned char *nth_packed_object_sha1(struct packed_git *p,
23592359
}
23602360
}
23612361

2362+
void check_pack_index_ptr(const struct packed_git *p, const void *vptr)
2363+
{
2364+
const unsigned char *ptr = vptr;
2365+
const unsigned char *start = p->index_data;
2366+
const unsigned char *end = start + p->index_size;
2367+
if (ptr < start)
2368+
die("offset before start of pack index for %s (corrupt index?)",
2369+
p->pack_name);
2370+
/* No need to check for underflow; .idx files must be at least 8 bytes */
2371+
if (ptr >= end - 8)
2372+
die("offset beyond end of pack index for %s (truncated index?)",
2373+
p->pack_name);
2374+
}
2375+
23622376
off_t nth_packed_object_offset(const struct packed_git *p, uint32_t n)
23632377
{
23642378
const unsigned char *index = p->index_data;
@@ -2372,6 +2386,7 @@ off_t nth_packed_object_offset(const struct packed_git *p, uint32_t n)
23722386
if (!(off & 0x80000000))
23732387
return off;
23742388
index += p->num_objects * 4 + (off & 0x7fffffff) * 8;
2389+
check_pack_index_ptr(p, index);
23752390
return (((uint64_t)ntohl(*((uint32_t *)(index + 0)))) << 32) |
23762391
ntohl(*((uint32_t *)(index + 4)));
23772392
}

t/t5313-pack-bounds-checks.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ test_expect_success 'bogus object offset (v2, no msb)' '
128128
test_must_fail git index-pack --verify $pack
129129
'
130130

131-
test_expect_failure 'bogus offset into v2 extended table' '
131+
test_expect_success 'bogus offset into v2 extended table' '
132132
do_pack $object --index-version=2 &&
133133
munge $idx $(ofs_table 1) "\377\0\0\0" &&
134134
clear_base &&

0 commit comments

Comments
 (0)