Skip to content

Commit 6cf61d0

Browse files
peffgitster
authored andcommitted
commit-graph: bounds-check base graphs chunk
When we are loading a commit-graph chain, we check that each slice of the chain points to the appropriate set of base graphs via its BASE chunk. But since we don't record the size of the chunk, we may access out-of-bounds memory if the file is corrupted. Since we know the number of entries we expect to find (based on the position within the commit-graph-chain file), we can just check the size up front. In theory this would also let us drop the st_mult() call a few lines later when we actually access the memory, since we know that the computed offset will fit in a size_t. But because the operands "g->hash_len" and "n" have types "unsigned char" and "int", we'd have to cast to size_t first. Leaving the st_mult() does that cast, and makes it more obvious that we don't have an overflow problem. Note that the test does not actually segfault before this patch, since it just reads garbage from the chunk after BASE (and indeed, it even rejects the file because that garbage does not have the expected hash value). You could construct a file with BASE at the end that did segfault, but corrupting the existing one is easy, and we can check stderr for the expected message. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 9622610 commit 6cf61d0

File tree

3 files changed

+22
-1
lines changed

3 files changed

+22
-1
lines changed

commit-graph.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,8 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,
435435
read_chunk(cf, GRAPH_CHUNKID_DATA, graph_read_commit_data, graph);
436436
pair_chunk(cf, GRAPH_CHUNKID_EXTRAEDGES, &graph->chunk_extra_edges,
437437
&graph->chunk_extra_edges_size);
438-
pair_chunk_unsafe(cf, GRAPH_CHUNKID_BASE, &graph->chunk_base_graphs);
438+
pair_chunk(cf, GRAPH_CHUNKID_BASE, &graph->chunk_base_graphs,
439+
&graph->chunk_base_graphs_size);
439440

440441
if (s->commit_graph_generation_version >= 2) {
441442
pair_chunk_unsafe(cf, GRAPH_CHUNKID_GENERATION_DATA,
@@ -546,6 +547,11 @@ static int add_graph_to_chain(struct commit_graph *g,
546547
return 0;
547548
}
548549

550+
if (g->chunk_base_graphs_size / g->hash_len < n) {
551+
warning(_("commit-graph base graphs chunk is too small"));
552+
return 0;
553+
}
554+
549555
while (n) {
550556
n--;
551557

commit-graph.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ struct commit_graph {
9797
const unsigned char *chunk_extra_edges;
9898
size_t chunk_extra_edges_size;
9999
const unsigned char *chunk_base_graphs;
100+
size_t chunk_base_graphs_size;
100101
const unsigned char *chunk_bloom_indexes;
101102
const unsigned char *chunk_bloom_data;
102103

t/t5324-split-commit-graph.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
test_description='split commit graph'
44
. ./test-lib.sh
5+
. "$TEST_DIRECTORY"/lib-chunk.sh
56

67
GIT_TEST_COMMIT_GRAPH=0
78
GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=0
@@ -398,6 +399,19 @@ test_expect_success 'verify across alternates' '
398399
)
399400
'
400401

402+
test_expect_success 'reader bounds-checks base-graph chunk' '
403+
git clone --no-hardlinks . corrupt-base-chunk &&
404+
(
405+
cd corrupt-base-chunk &&
406+
tip_file=$graphdir/graph-$(tail -n 1 $graphdir/commit-graph-chain).graph &&
407+
corrupt_chunk_file "$tip_file" BASE clear 01020304 &&
408+
git -c core.commitGraph=false log >expect.out &&
409+
git -c core.commitGraph=true log >out 2>err &&
410+
test_cmp expect.out out &&
411+
grep "commit-graph base graphs chunk is too small" err
412+
)
413+
'
414+
401415
test_expect_success 'add octopus merge' '
402416
git reset --hard commits/10 &&
403417
git merge commits/3 commits/4 &&

0 commit comments

Comments
 (0)