Skip to content

Commit aa65857

Browse files
steadmongitster
authored andcommitted
commit-graph, fuzz: add fuzzer for commit-graph
Break load_commit_graph_one() into a new function, parse_commit_graph(). The latter function operates on arbitrary buffers, which makes it suitable as a fuzzing target. Since parse_commit_graph() is only called by load_commit_graph_one() (and the fuzzer described below), we omit error messages that would be duplicated by the caller. Adds fuzz-commit-graph.c, which provides a fuzzing entry point compatible with libFuzzer (and possibly other fuzzing engines). Signed-off-by: Josh Steadmon <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 7755635 commit aa65857

File tree

5 files changed

+57
-17
lines changed

5 files changed

+57
-17
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/fuzz-commit-graph
12
/fuzz_corpora
23
/fuzz-pack-headers
34
/fuzz-pack-idx

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,7 @@ SCRIPTS = $(SCRIPT_SH_INS) \
684684

685685
ETAGS_TARGET = TAGS
686686

687+
FUZZ_OBJS += fuzz-commit-graph.o
687688
FUZZ_OBJS += fuzz-pack-headers.o
688689
FUZZ_OBJS += fuzz-pack-idx.o
689690

commit-graph.c

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -84,16 +84,10 @@ static int commit_graph_compatible(struct repository *r)
8484
struct commit_graph *load_commit_graph_one(const char *graph_file)
8585
{
8686
void *graph_map;
87-
const unsigned char *data, *chunk_lookup;
8887
size_t graph_size;
8988
struct stat st;
90-
uint32_t i;
91-
struct commit_graph *graph;
89+
struct commit_graph *ret;
9290
int fd = git_open(graph_file);
93-
uint64_t last_chunk_offset;
94-
uint32_t last_chunk_id;
95-
uint32_t graph_signature;
96-
unsigned char graph_version, hash_version;
9791

9892
if (fd < 0)
9993
return NULL;
@@ -108,27 +102,55 @@ struct commit_graph *load_commit_graph_one(const char *graph_file)
108102
die(_("graph file %s is too small"), graph_file);
109103
}
110104
graph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);
105+
ret = parse_commit_graph(graph_map, fd, graph_size);
106+
107+
if (!ret) {
108+
munmap(graph_map, graph_size);
109+
close(fd);
110+
exit(1);
111+
}
112+
113+
return ret;
114+
}
115+
116+
struct commit_graph *parse_commit_graph(void *graph_map, int fd,
117+
size_t graph_size)
118+
{
119+
const unsigned char *data, *chunk_lookup;
120+
uint32_t i;
121+
struct commit_graph *graph;
122+
uint64_t last_chunk_offset;
123+
uint32_t last_chunk_id;
124+
uint32_t graph_signature;
125+
unsigned char graph_version, hash_version;
126+
127+
if (!graph_map)
128+
return NULL;
129+
130+
if (graph_size < GRAPH_MIN_SIZE)
131+
return NULL;
132+
111133
data = (const unsigned char *)graph_map;
112134

113135
graph_signature = get_be32(data);
114136
if (graph_signature != GRAPH_SIGNATURE) {
115137
error(_("graph signature %X does not match signature %X"),
116138
graph_signature, GRAPH_SIGNATURE);
117-
goto cleanup_fail;
139+
return NULL;
118140
}
119141

120142
graph_version = *(unsigned char*)(data + 4);
121143
if (graph_version != GRAPH_VERSION) {
122144
error(_("graph version %X does not match version %X"),
123145
graph_version, GRAPH_VERSION);
124-
goto cleanup_fail;
146+
return NULL;
125147
}
126148

127149
hash_version = *(unsigned char*)(data + 5);
128150
if (hash_version != GRAPH_OID_VERSION) {
129151
error(_("hash version %X does not match version %X"),
130152
hash_version, GRAPH_OID_VERSION);
131-
goto cleanup_fail;
153+
return NULL;
132154
}
133155

134156
graph = alloc_commit_graph();
@@ -152,7 +174,8 @@ struct commit_graph *load_commit_graph_one(const char *graph_file)
152174
if (chunk_offset > graph_size - GIT_MAX_RAWSZ) {
153175
error(_("improper chunk offset %08x%08x"), (uint32_t)(chunk_offset >> 32),
154176
(uint32_t)chunk_offset);
155-
goto cleanup_fail;
177+
free(graph);
178+
return NULL;
156179
}
157180

158181
switch (chunk_id) {
@@ -187,7 +210,8 @@ struct commit_graph *load_commit_graph_one(const char *graph_file)
187210

188211
if (chunk_repeated) {
189212
error(_("chunk id %08x appears multiple times"), chunk_id);
190-
goto cleanup_fail;
213+
free(graph);
214+
return NULL;
191215
}
192216

193217
if (last_chunk_id == GRAPH_CHUNKID_OIDLOOKUP)
@@ -201,11 +225,6 @@ struct commit_graph *load_commit_graph_one(const char *graph_file)
201225
}
202226

203227
return graph;
204-
205-
cleanup_fail:
206-
munmap(graph_map, graph_size);
207-
close(fd);
208-
exit(1);
209228
}
210229

211230
static void prepare_commit_graph_one(struct repository *r, const char *obj_dir)

commit-graph.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ struct commit_graph {
5454

5555
struct commit_graph *load_commit_graph_one(const char *graph_file);
5656

57+
struct commit_graph *parse_commit_graph(void *graph_map, int fd,
58+
size_t graph_size);
59+
5760
/*
5861
* Return 1 if and only if the repository has a commit-graph
5962
* file and generation numbers are computed in that file.

fuzz-commit-graph.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#include "commit-graph.h"
2+
3+
struct commit_graph *parse_commit_graph(void *graph_map, int fd,
4+
size_t graph_size);
5+
6+
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
7+
8+
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
9+
{
10+
struct commit_graph *g;
11+
12+
g = parse_commit_graph((void *)data, -1, size);
13+
free(g);
14+
15+
return 0;
16+
}

0 commit comments

Comments
 (0)