Skip to content

Commit ec6c7b4

Browse files
peffgitster
authored andcommitted
pack-bitmap: bounds-check size of cache extension
A .bitmap file may have a "name hash cache" extension, which puts a sequence of uint32_t values (one per object) at the end of the file. When we see a flag indicating this extension, we blindly subtract the appropriate number of bytes from our available length. However, if the .bitmap file is too short, we'll underflow our length variable and wrap around, thinking we have a very large length. This can lead to reading out-of-bounds bytes while loading individual ewah bitmaps. We can fix this by checking the number of available bytes when we parse the header. The existing "truncated bitmap" test is now split into two tests: one where we don't have this extension at all (and hence actually do try to read a truncated ewah bitmap) and one where we realize up-front that we can't even fit in the cache structure. We'll check stderr in each case to make sure we hit the error we're expecting. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Taylor Blau <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent ca51090 commit ec6c7b4

File tree

2 files changed

+21
-4
lines changed

2 files changed

+21
-4
lines changed

pack-bitmap.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,14 +153,18 @@ static int load_bitmap_header(struct bitmap_index *index)
153153
/* Parse known bitmap format options */
154154
{
155155
uint32_t flags = ntohs(header->options);
156+
size_t cache_size = st_mult(index->pack->num_objects, sizeof(uint32_t));
157+
unsigned char *index_end = index->map + index->map_size - the_hash_algo->rawsz;
156158

157159
if ((flags & BITMAP_OPT_FULL_DAG) == 0)
158160
return error("Unsupported options for bitmap index file "
159161
"(Git requires BITMAP_OPT_FULL_DAG)");
160162

161163
if (flags & BITMAP_OPT_HASH_CACHE) {
162-
unsigned char *end = index->map + index->map_size - the_hash_algo->rawsz;
163-
index->hashes = ((uint32_t *)end) - index->pack->num_objects;
164+
if (cache_size > index_end - index->map - header_size)
165+
return error("corrupted bitmap index file (too short to fit hash cache)");
166+
index->hashes = (void *)(index_end - cache_size);
167+
index_end -= cache_size;
164168
}
165169
}
166170

t/t5310-pack-bitmaps.sh

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,8 @@ test_expect_success 'pack reuse respects --incremental' '
343343
test_must_be_empty actual
344344
'
345345

346-
test_expect_success 'truncated bitmap fails gracefully' '
346+
test_expect_success 'truncated bitmap fails gracefully (ewah)' '
347+
test_config pack.writebitmaphashcache false &&
347348
git repack -ad &&
348349
git rev-list --use-bitmap-index --count --all >expect &&
349350
bitmap=$(ls .git/objects/pack/*.bitmap) &&
@@ -352,7 +353,19 @@ test_expect_success 'truncated bitmap fails gracefully' '
352353
mv -f $bitmap.tmp $bitmap &&
353354
git rev-list --use-bitmap-index --count --all >actual 2>stderr &&
354355
test_cmp expect actual &&
355-
test_i18ngrep corrupt stderr
356+
test_i18ngrep corrupt.ewah.bitmap stderr
357+
'
358+
359+
test_expect_success 'truncated bitmap fails gracefully (cache)' '
360+
git repack -ad &&
361+
git rev-list --use-bitmap-index --count --all >expect &&
362+
bitmap=$(ls .git/objects/pack/*.bitmap) &&
363+
test_when_finished "rm -f $bitmap" &&
364+
test_copy_bytes 512 <$bitmap >$bitmap.tmp &&
365+
mv -f $bitmap.tmp $bitmap &&
366+
git rev-list --use-bitmap-index --count --all >actual 2>stderr &&
367+
test_cmp expect actual &&
368+
test_i18ngrep corrupted.bitmap.index stderr
356369
'
357370

358371
# have_delta <obj> <expected_base>

0 commit comments

Comments
 (0)