|
1
|
/* |
|
2
|
** Copyright (c) 2019 D. Richard Hipp |
|
3
|
** |
|
4
|
** This program is free software; you can redistribute it and/or |
|
5
|
** modify it under the terms of the Simplified BSD License (also |
|
6
|
** known as the "2-Clause License" or "FreeBSD License".) |
|
7
|
* |
|
8
|
** This program is distributed in the hope that it will be useful, |
|
9
|
** but without any warranty; without even the implied warranty of |
|
10
|
** merchantability or fitness for a particular purpose. |
|
11
|
** |
|
12
|
** Author contact information: |
|
13
|
** [email protected] |
|
14
|
** http://www.hwaci.com/drh/ |
|
15
|
** |
|
16
|
******************************************************************************* |
|
17
|
** |
|
18
|
** This file contains code to connect Fossil to libFuzzer. Do a web search |
|
19
|
** for "libfuzzer" for details about that fuzzing platform. |
|
20
|
** |
|
21
|
** To build on linux (the only platform for which this works at |
|
22
|
** present) first do |
|
23
|
** |
|
24
|
** ./configure |
|
25
|
** |
|
26
|
** Then edit the Makefile as follows: |
|
27
|
** |
|
28
|
** (1) Change CC to be "clang-6.0" or some other compiler that |
|
29
|
** supports libFuzzer |
|
30
|
** |
|
31
|
** (2) Change APPNAME to "fossil-fuzz" |
|
32
|
** |
|
33
|
** (3) Add "-fsanitize=fuzzer" and "-DFOSSIL_FUZZ" to TCCFLAGS. Perhaps |
|
34
|
** make the first change "-fsanitize=fuzzer,undefined,address" for |
|
35
|
** extra, but slower, testing. |
|
36
|
** |
|
37
|
** Then build the fuzzer using: |
|
38
|
** |
|
39
|
** make clean fossil-fuzz |
|
40
|
** |
|
41
|
** To run the fuzzer, create a working directory ("cases"): |
|
42
|
** |
|
43
|
** mkdir cases |
|
44
|
** |
|
45
|
** Then seed the working directory with example input files. For example, |
|
46
|
** if fuzzing the wiki formatter, perhaps copy *.wiki into cases. Then |
|
47
|
** run the fuzzer thusly: |
|
48
|
** |
|
49
|
** fossil-fuzz cases |
|
50
|
** |
|
51
|
** The default is to fuzz the Fossil-wiki translator. Use the --fuzztype TYPE |
|
52
|
** option to fuzz different aspects of the system. |
|
53
|
*/ |
|
54
|
#include "config.h" |
|
55
|
#include "fuzz.h" |
|
56
|
|
|
57
|
#if LOCAL_INTERFACE |
|
58
|
/* |
|
59
|
** Type of fuzzing: |
|
60
|
*/ |
|
61
|
#define FUZZ_WIKI 0 /* The Fossil-Wiki formatter */ |
|
62
|
#define FUZZ_MARKDOWN 1 /* The Markdown formatter */ |
|
63
|
#define FUZZ_ARTIFACT 2 /* Fuzz the artifact parser */ |
|
64
|
#define FUZZ_WIKI2 3 /* FOSSIL_WIKI and FOSSIL_MARKDOWN */ |
|
65
|
#define FUZZ_COMFORMAT 4 /* comment_print() */ |
|
66
|
#endif |
|
67
|
|
|
68
|
/* The type of fuzzing to do */ |
|
69
|
static int eFuzzType = FUZZ_WIKI; |
|
70
|
|
|
71
|
/* The fuzzer invokes this routine once for each fuzzer input |
|
72
|
*/ |
|
73
|
int LLVMFuzzerTestOneInput(const uint8_t *aData, size_t nByte){ |
|
74
|
Blob in, out; |
|
75
|
blob_init(&in, 0, 0); |
|
76
|
blob_append(&in, (char*)aData, (int)nByte); |
|
77
|
blob_zero(&out); |
|
78
|
switch( eFuzzType ){ |
|
79
|
case FUZZ_WIKI: { |
|
80
|
wiki_convert(&in, &out, 0); |
|
81
|
blob_reset(&out); |
|
82
|
break; |
|
83
|
} |
|
84
|
case FUZZ_MARKDOWN: { |
|
85
|
Blob title = BLOB_INITIALIZER; |
|
86
|
blob_reset(&out); |
|
87
|
markdown_to_html(&in, &title, &out); |
|
88
|
blob_reset(&title); |
|
89
|
break; |
|
90
|
} |
|
91
|
case FUZZ_WIKI2: { |
|
92
|
Blob title = BLOB_INITIALIZER; |
|
93
|
wiki_convert(&in, &out, 0); |
|
94
|
blob_reset(&out); |
|
95
|
markdown_to_html(&in, &title, &out); |
|
96
|
blob_reset(&title); |
|
97
|
break; |
|
98
|
} |
|
99
|
case FUZZ_ARTIFACT: { |
|
100
|
fossil_fatal("FUZZ_ARTIFACT is not implemented."); |
|
101
|
break; |
|
102
|
} |
|
103
|
case FUZZ_COMFORMAT: { |
|
104
|
if( nByte>=3 && aData[1]!=0 && memchr(&aData[1], 0, nByte-1)!=0 ){ |
|
105
|
int flags = (int)aData[0]; |
|
106
|
comment_print((const char*)&aData[1],0,15,80,flags); |
|
107
|
} |
|
108
|
} |
|
109
|
} |
|
110
|
blob_reset(&in); |
|
111
|
blob_reset(&out); |
|
112
|
return 0; |
|
113
|
} |
|
114
|
|
|
115
|
/* |
|
116
|
** Check fuzzer command-line options. |
|
117
|
*/ |
|
118
|
static void fuzzer_options(void){ |
|
119
|
const char *zType; |
|
120
|
db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0); |
|
121
|
db_multi_exec("PRAGMA query_only=1;"); |
|
122
|
zType = find_option("fuzztype",0,1); |
|
123
|
if( zType==0 || fossil_strcmp(zType,"wiki")==0 ){ |
|
124
|
eFuzzType = FUZZ_WIKI; |
|
125
|
}else if( fossil_strcmp(zType,"markdown")==0 ){ |
|
126
|
eFuzzType = FUZZ_MARKDOWN; |
|
127
|
}else if( fossil_strcmp(zType,"wiki2")==0 ){ |
|
128
|
eFuzzType = FUZZ_WIKI2; |
|
129
|
}else if( fossil_strcmp(zType,"comformat")==0 ){ |
|
130
|
eFuzzType = FUZZ_COMFORMAT; |
|
131
|
}else{ |
|
132
|
fossil_fatal("unknown fuzz type: \"%s\"", zType); |
|
133
|
} |
|
134
|
} |
|
135
|
|
|
136
|
/* Libfuzzer invokes this routine once prior to start-up to |
|
137
|
** process command-line options. |
|
138
|
*/ |
|
139
|
int LLVMFuzzerInitialize(int *pArgc, char ***pArgv){ |
|
140
|
expand_args_option(*pArgc, *pArgv); |
|
141
|
fuzzer_options(); |
|
142
|
*pArgc = g.argc; |
|
143
|
*pArgv = g.argv; |
|
144
|
return 0; |
|
145
|
} |
|
146
|
|
|
147
|
/* |
|
148
|
** COMMAND: test-fuzz |
|
149
|
** |
|
150
|
** Usage: %fossil test-fuzz [-fuzztype TYPE] INPUTFILE... |
|
151
|
** |
|
152
|
** Run a fuzz test using INPUTFILE as the test data. TYPE can be one of: |
|
153
|
** |
|
154
|
** comformat Fuzz the comment_print() routine |
|
155
|
** wiki Fuzz the Fossil-wiki translator |
|
156
|
** markdown Fuzz the markdown translator |
|
157
|
** artifact Fuzz the artifact parser |
|
158
|
** wiki2 Fuzz the Fossil-wiki and markdown translator |
|
159
|
*/ |
|
160
|
void fuzz_command(void){ |
|
161
|
Blob in; |
|
162
|
int i; |
|
163
|
fuzzer_options(); |
|
164
|
verify_all_options(); |
|
165
|
for(i=2; i<g.argc; i++){ |
|
166
|
blob_read_from_file(&in, g.argv[i], ExtFILE); |
|
167
|
LLVMFuzzerTestOneInput((const uint8_t*)in.aData, (size_t)in.nUsed); |
|
168
|
fossil_print("%s\n", g.argv[i]); |
|
169
|
blob_reset(&in); |
|
170
|
} |
|
171
|
} |
|
172
|
|