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 <steadmon@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Josh Steadmon committed
Jan 15, 2019 at 14:25 UTC
aa658574bfcbe03f5703458ac10be1ef3f5f5472
5 files changed
+57
-17
.gitignore
+1
@@ -1,3 +1,4 @@
1
+/fuzz-commit-graph
2
/fuzz_corpora
3
/fuzz-pack-headers
4
/fuzz-pack-idx
Makefile
+1
@@ -684,6 +684,7 @@ SCRIPTS = $(SCRIPT_SH_INS) \
684
685
ETAGS_TARGET = TAGS
686
687
+FUZZ_OBJS += fuzz-commit-graph.o
688
FUZZ_OBJS += fuzz-pack-headers.o
689
FUZZ_OBJS += fuzz-pack-idx.o
690
commit-graph.c
+36
-17
@@ -84,16 +84,10 @@ static int commit_graph_compatible(struct repository *r)
84
struct commit_graph *load_commit_graph_one(const char *graph_file)
85
{
86
void *graph_map;
87
- const unsigned char *data, *chunk_lookup;
87
size_t graph_size;
88
struct stat st;
90
- uint32_t i;
91
- struct commit_graph *graph;
89
+ struct commit_graph *ret;
90
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;
91
92
if (fd < 0)
93
return NULL;
@@ -108,27 +102,55 @@ struct commit_graph *load_commit_graph_one(const char *graph_file)
102
die(_("graph file %s is too small"), graph_file);
103
}
104
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
+
133
data = (const unsigned char *)graph_map;
134
135
graph_signature = get_be32(data);
136
if (graph_signature != GRAPH_SIGNATURE) {
137
error(_("graph signature %X does not match signature %X"),
138
graph_signature, GRAPH_SIGNATURE);
117
- goto cleanup_fail;
139
+ return NULL;
140
}
141
142
graph_version = *(unsigned char*)(data + 4);
143
if (graph_version != GRAPH_VERSION) {
144
error(_("graph version %X does not match version %X"),
145
graph_version, GRAPH_VERSION);
124
- goto cleanup_fail;
146
+ return NULL;
147
}
148
149
hash_version = *(unsigned char*)(data + 5);
150
if (hash_version != GRAPH_OID_VERSION) {
151
error(_("hash version %X does not match version %X"),
152
hash_version, GRAPH_OID_VERSION);
131
- goto cleanup_fail;
153
+ return NULL;
154
}
155
156
graph = alloc_commit_graph();
@@ -152,7 +174,8 @@ struct commit_graph *load_commit_graph_one(const char *graph_file)
174
if (chunk_offset > graph_size - GIT_MAX_RAWSZ) {
175
error(_("improper chunk offset %08x%08x"), (uint32_t)(chunk_offset >> 32),
176
(uint32_t)chunk_offset);
155
- goto cleanup_fail;
177
+ free(graph);
178
+ return NULL;
179
}
180
181
switch (chunk_id) {
@@ -187,7 +210,8 @@ struct commit_graph *load_commit_graph_one(const char *graph_file)
210
211
if (chunk_repeated) {
212
error(_("chunk id %08x appears multiple times"), chunk_id);
190
- goto cleanup_fail;
213
+ free(graph);
214
+ return NULL;
215
}
216
217
if (last_chunk_id == GRAPH_CHUNKID_OIDLOOKUP)
@@ -201,11 +225,6 @@ struct commit_graph *load_commit_graph_one(const char *graph_file)
225
}
226
227
return graph;
204
-
205
-cleanup_fail:
206
- munmap(graph_map, graph_size);
207
- close(fd);
208
- exit(1);
228
}
229
230
static void prepare_commit_graph_one(struct repository *r, const char *obj_dir)
commit-graph.h
+3
@@ -54,6 +54,9 @@ struct commit_graph {
54
55
struct commit_graph *load_commit_graph_one(const char *graph_file);
56
57
+struct commit_graph *parse_commit_graph(void *graph_map, int fd,
58
+ size_t graph_size);
59
+
60
/*
61
* Return 1 if and only if the repository has a commit-graph
62
* file and generation numbers are computed in that file.
fuzz-commit-graph.c
new
+16
@@ -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
+}