Skip to content

Commit ee6a792

Browse files
peffgitster
authored andcommitted
commit-graph: bounds-check generation overflow chunk
If the generation entry in a commit-graph doesn't fit, we instead insert an offset into a generation overflow chunk. But since we don't record the size of the chunk, we may read outside the chunk if the offset we find on disk is malicious or corrupted. We can't check the size of the chunk up-front; it will vary based on how many entries need overflow. So instead, we'll do a bounds-check before accessing the chunk memory. Unfortunately there is no error-return from this function, so we'll just have to die(), which is what it does for other forms of corruption. As with other cases, we can drop the st_mult() call, since we know our bounds-checked value will fit within a size_t. Before this patch, the test here actually "works" because we read garbage data from the next chunk. And since that garbage data happens not to provide a generation number which changes the output, it appears to work. We could construct a case that actually segfaults or produces wrong output, but it would be a bit tricky. For our purposes its sufficient to check that we've detected the bounds error. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 4a3c346 commit ee6a792

File tree

3 files changed

+18
-3
lines changed

3 files changed

+18
-3
lines changed

commit-graph.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -451,8 +451,9 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,
451451
if (s->commit_graph_generation_version >= 2) {
452452
read_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA,
453453
graph_read_generation_data, graph);
454-
pair_chunk_unsafe(cf, GRAPH_CHUNKID_GENERATION_DATA_OVERFLOW,
455-
&graph->chunk_generation_data_overflow);
454+
pair_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA_OVERFLOW,
455+
&graph->chunk_generation_data_overflow,
456+
&graph->chunk_generation_data_overflow_size);
456457

457458
if (graph->chunk_generation_data)
458459
graph->read_generation_data = 1;
@@ -896,7 +897,10 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,
896897
die(_("commit-graph requires overflow generation data but has none"));
897898

898899
offset_pos = offset ^ CORRECTED_COMMIT_DATE_OFFSET_OVERFLOW;
899-
graph_data->generation = item->date + get_be64(g->chunk_generation_data_overflow + st_mult(8, offset_pos));
900+
if (g->chunk_generation_data_overflow_size / sizeof(uint64_t) <= offset_pos)
901+
die(_("commit-graph overflow generation data is too small"));
902+
graph_data->generation = item->date +
903+
get_be64(g->chunk_generation_data_overflow + sizeof(uint64_t) * offset_pos);
900904
} else
901905
graph_data->generation = item->date + offset;
902906
} else

commit-graph.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ struct commit_graph {
9494
const unsigned char *chunk_commit_data;
9595
const unsigned char *chunk_generation_data;
9696
const unsigned char *chunk_generation_data_overflow;
97+
size_t chunk_generation_data_overflow_size;
9798
const unsigned char *chunk_extra_edges;
9899
size_t chunk_extra_edges_size;
99100
const unsigned char *chunk_base_graphs;

t/t5328-commit-graph-64bit-time.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ then
1010
fi
1111

1212
. "$TEST_DIRECTORY"/lib-commit-graph.sh
13+
. "$TEST_DIRECTORY/lib-chunk.sh"
1314

1415
UNIX_EPOCH_ZERO="@0 +0000"
1516
FUTURE_DATE="@4147483646 +0000"
@@ -72,4 +73,13 @@ test_expect_success 'single commit with generation data exceeding UINT32_MAX' '
7273
git -C repo-uint32-max commit-graph verify
7374
'
7475

76+
test_expect_success 'reader notices out-of-bounds generation overflow' '
77+
graph=.git/objects/info/commit-graph &&
78+
test_when_finished "rm -rf $graph" &&
79+
git commit-graph write --reachable &&
80+
corrupt_chunk_file $graph GDO2 clear &&
81+
test_must_fail git log 2>err &&
82+
grep "commit-graph overflow generation data is too small" err
83+
'
84+
7585
test_done

0 commit comments

Comments
 (0)