]> git.ipfire.org Git - thirdparty/git.git/commitdiff
midx: bounds-check large offset chunk
authorJeff King <peff@peff.net>
Mon, 9 Oct 2023 21:05:30 +0000 (17:05 -0400)
committerJunio C Hamano <gitster@pobox.com>
Mon, 9 Oct 2023 22:55:01 +0000 (15:55 -0700)
When we see a large offset bit in the regular midx offset table, we
use the entry as an index into a separate large offset table (just like
a pack idx does). But we don't bounds-check the access to that large
offset table (nor even record its size when we parse the chunk!).

The equivalent code for a regular pack idx is in check_pack_index_ptr().
But things are a bit simpler here because of the chunked format: we can
just check our array index directly.

As a bonus, we can get rid of the st_mult() here. If our array
bounds-check is successful, then we know that the result will fit in a
size_t (and the bounds check uses a division to avoid overflow
entirely).

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
midx.c
midx.h
t/t5319-multi-pack-index.sh

diff --git a/midx.c b/midx.c
index 7b1b45f381c88cbf9ec0411250145f7bf49837eb..3e768d0df079b79339b61e590d6cdd50f5bdb502 100644 (file)
--- a/midx.c
+++ b/midx.c
@@ -180,7 +180,8 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local
        if (read_chunk(cf, MIDX_CHUNKID_OBJECTOFFSETS, midx_read_object_offsets, m))
                die(_("multi-pack-index required object offsets chunk missing or corrupted"));
 
-       pair_chunk_unsafe(cf, MIDX_CHUNKID_LARGEOFFSETS, &m->chunk_large_offsets);
+       pair_chunk(cf, MIDX_CHUNKID_LARGEOFFSETS, &m->chunk_large_offsets,
+                  &m->chunk_large_offsets_len);
 
        if (git_env_bool("GIT_TEST_MIDX_READ_RIDX", 1))
                pair_chunk_unsafe(cf, MIDX_CHUNKID_REVINDEX, &m->chunk_revindex);
@@ -303,8 +304,9 @@ off_t nth_midxed_offset(struct multi_pack_index *m, uint32_t pos)
                        die(_("multi-pack-index stores a 64-bit offset, but off_t is too small"));
 
                offset32 ^= MIDX_LARGE_OFFSET_NEEDED;
-               return get_be64(m->chunk_large_offsets +
-                               st_mult(sizeof(uint64_t), offset32));
+               if (offset32 >= m->chunk_large_offsets_len / sizeof(uint64_t))
+                       die(_("multi-pack-index large offset out of bounds"));
+               return get_be64(m->chunk_large_offsets + sizeof(uint64_t) * offset32);
        }
 
        return offset32;
diff --git a/midx.h b/midx.h
index 5b2a7da0433c0046020bfb93fd7eb676a70a16cc..e8e8884d16b08be6dbb088dc01229a314db8fe39 100644 (file)
--- a/midx.h
+++ b/midx.h
@@ -37,6 +37,7 @@ struct multi_pack_index {
        const unsigned char *chunk_oid_lookup;
        const unsigned char *chunk_object_offsets;
        const unsigned char *chunk_large_offsets;
+       size_t chunk_large_offsets_len;
        const unsigned char *chunk_revindex;
 
        const char **pack_names;
index 30687d5452f25e74890cd9f6bfdb4c5bf1362417..16050f39d997de4694c54c334794b1a40f60cd9c 100755 (executable)
@@ -1118,4 +1118,24 @@ test_expect_success 'reader notices too-small object offset chunk' '
        test_cmp expect err
 '
 
+test_expect_success 'reader bounds-checks large offset table' '
+       # re-use the objects64 dir here to cheaply get access to a midx
+       # with large offsets.
+       git init repo &&
+       test_when_finished "rm -rf repo" &&
+       (
+               cd repo &&
+               (cd ../objects64 && pwd) >.git/objects/info/alternates &&
+               git multi-pack-index --object-dir=../objects64 write &&
+               midx=../objects64/pack/multi-pack-index &&
+               corrupt_chunk_file $midx LOFF clear &&
+               test_must_fail git cat-file \
+                       --batch-check --batch-all-objects 2>err &&
+               cat >expect <<-\EOF &&
+               fatal: multi-pack-index large offset out of bounds
+               EOF
+               test_cmp expect err
+       )
+'
+
 test_done