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 **   drh@hwaci.com
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 #endif
65 
66 /* The type of fuzzing to do */
67 static int eFuzzType = FUZZ_WIKI;
68 
69 /* The fuzzer invokes this routine once for each fuzzer input
70 */
LLVMFuzzerTestOneInput(const uint8_t * aData,size_t nByte)71 int LLVMFuzzerTestOneInput(const uint8_t *aData, size_t nByte){
72   Blob in, out;
73   blob_init(&in, 0, 0);
74   blob_append(&in, (char*)aData, (int)nByte);
75   blob_zero(&out);
76   switch( eFuzzType ){
77     case FUZZ_WIKI: {
78       Blob title = BLOB_INITIALIZER;
79       wiki_convert(&in, &out, 0);
80       blob_reset(&out);
81       markdown_to_html(&in, &title, &out);
82       blob_reset(&title);
83       break;
84     }
85   }
86   blob_reset(&in);
87   blob_reset(&out);
88   return 0;
89 }
90 
91 /*
92 ** Check fuzzer command-line options.
93 */
fuzzer_options(void)94 static void fuzzer_options(void){
95   const char *zType;
96   db_find_and_open_repository(OPEN_OK_NOT_FOUND|OPEN_SUBSTITUTE,0);
97   db_multi_exec("PRAGMA query_only=1;");
98   zType = find_option("fuzztype",0,1);
99   if( zType==0 || fossil_strcmp(zType,"wiki")==0 ){
100     eFuzzType = FUZZ_WIKI;
101   }else if( fossil_strcmp(zType,"markdown")==0 ){
102     eFuzzType = FUZZ_MARKDOWN;
103   }else{
104     fossil_fatal("unknown fuzz type: \"%s\"", zType);
105   }
106 }
107 
108 /* Libfuzzer invokes this routine once prior to start-up to
109 ** process command-line options.
110 */
LLVMFuzzerInitialize(int * pArgc,char *** pArgv)111 int LLVMFuzzerInitialize(int *pArgc, char ***pArgv){
112   expand_args_option(*pArgc, *pArgv);
113   fuzzer_options();
114   *pArgc = g.argc;
115   *pArgv = g.argv;
116   return 0;
117 }
118 
119 /*
120 ** COMMAND: test-fuzz
121 **
122 ** Usage: %fossil test-fuzz [-type TYPE] INPUTFILE...
123 **
124 ** Run a fuzz test using INPUTFILE as the test data.  TYPE can be one of:
125 **
126 **     wiki                  Fuzz the Fossil-wiki translator
127 **     markdown              Fuzz the markdown translator
128 **     artifact              Fuzz the artifact parser
129 */
fuzz_command(void)130 void fuzz_command(void){
131   Blob in;
132   int i;
133   fuzzer_options();
134   verify_all_options();
135   for(i=2; i<g.argc; i++){
136     blob_read_from_file(&in, g.argv[i], ExtFILE);
137     LLVMFuzzerTestOneInput((const uint8_t*)in.aData, (size_t)in.nUsed);
138     fossil_print("%s\n", g.argv[i]);
139     blob_reset(&in);
140   }
141 }
142