blob: a44a72250557e23c34bbbe26c9908fd454252bf4 [file] [log] [blame]
drh268e72f2015-04-17 14:30:49 +00001/*
2** 2015-04-17
3**
4** The author disclaims copyright to this source code. In place of
5** a legal notice, here is a blessing:
6**
7** May you do good and not evil.
8** May you find forgiveness for yourself and forgive others.
9** May you share freely, never taking more than you give.
10**
11*************************************************************************
12**
13** This is a utility program designed to aid running the SQLite library
14** against an external fuzzer, such as American Fuzzy Lop (AFL)
15** (http://lcamtuf.coredump.cx/afl/). Basically, this program reads
16** SQL text from standard input and passes it through to SQLite for evaluation,
17** just like the "sqlite3" command-line shell. Differences from the
18** command-line shell:
19**
20** (1) The complex "dot-command" extensions are omitted. This
21** prevents the fuzzer from discovering that it can run things
22** like ".shell rm -rf ~"
23**
24** (2) The database is opened with the SQLITE_OPEN_MEMORY flag so that
25** no disk I/O from the database is permitted. The ATTACH command
26** with a filename still uses an in-memory database.
27**
28** (3) The main in-memory database can be initialized from a template
29** disk database so that the fuzzer starts with a database containing
30** content.
31**
32** (4) The eval() SQL function is added, allowing the fuzzer to do
33** interesting recursive operations.
34*/
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <stdarg.h>
39#include "sqlite3.h"
40
41/*
42** All global variables are gathered into the "g" singleton.
43*/
44struct GlobalVars {
45 const char *zArgv0; /* Name of program */
46} g;
47
48
49
50/*
51** Print an error message and abort in such a way to indicate to the
52** fuzzer that this counts as a crash.
53*/
54static void abendError(const char *zFormat, ...){
55 va_list ap;
56 fprintf(stderr, "%s: ", g.zArgv0);
57 va_start(ap, zFormat);
58 vfprintf(stderr, zFormat, ap);
59 va_end(ap);
60 fprintf(stderr, "\n");
61 abort();
62}
63/*
64** Print an error message and quit, but not in a way that would look
65** like a crash.
66*/
67static void fatalError(const char *zFormat, ...){
68 va_list ap;
69 fprintf(stderr, "%s: ", g.zArgv0);
70 va_start(ap, zFormat);
71 vfprintf(stderr, zFormat, ap);
72 va_end(ap);
73 fprintf(stderr, "\n");
74 exit(1);
75}
76
77/*
78** This callback is invoked by sqlite3_log().
79*/
80static void shellLog(void *pNotUsed, int iErrCode, const char *zMsg){
81 printf("LOG: (%d) %s\n", iErrCode, zMsg);
82}
83
84/*
85** This callback is invoked by sqlite3_exec() to return query results.
86*/
87static int execCallback(void *NotUsed, int argc, char **argv, char **colv){
88 int i;
89 static unsigned cnt = 0;
90 printf("ROW #%u:\n", ++cnt);
91 for(i=0; i<argc; i++){
92 printf(" %s=", colv[i]);
93 if( argv[i] ){
94 printf("[%s]\n", argv[i]);
95 }else{
96 printf("NULL\n");
97 }
98 }
99 return 0;
100}
101
102/*
103** This callback is invoked by sqlite3_trace() as each SQL statement
104** starts.
105*/
106static void traceCallback(void *NotUsed, const char *zMsg){
107 printf("TRACE: %s\n", zMsg);
108}
109
110/***************************************************************************
111** eval() implementation copied from ../ext/misc/eval.c
112*/
113/*
114** Structure used to accumulate the output
115*/
116struct EvalResult {
117 char *z; /* Accumulated output */
118 const char *zSep; /* Separator */
119 int szSep; /* Size of the separator string */
120 sqlite3_int64 nAlloc; /* Number of bytes allocated for z[] */
121 sqlite3_int64 nUsed; /* Number of bytes of z[] actually used */
122};
123
124/*
125** Callback from sqlite_exec() for the eval() function.
126*/
127static int callback(void *pCtx, int argc, char **argv, char **colnames){
128 struct EvalResult *p = (struct EvalResult*)pCtx;
129 int i;
130 for(i=0; i<argc; i++){
131 const char *z = argv[i] ? argv[i] : "";
132 size_t sz = strlen(z);
133 if( (sqlite3_int64)sz+p->nUsed+p->szSep+1 > p->nAlloc ){
134 char *zNew;
135 p->nAlloc = p->nAlloc*2 + sz + p->szSep + 1;
136 /* Using sqlite3_realloc64() would be better, but it is a recent
137 ** addition and will cause a segfault if loaded by an older version
138 ** of SQLite. */
139 zNew = p->nAlloc<=0x7fffffff ? sqlite3_realloc(p->z, (int)p->nAlloc) : 0;
140 if( zNew==0 ){
141 sqlite3_free(p->z);
142 memset(p, 0, sizeof(*p));
143 return 1;
144 }
145 p->z = zNew;
146 }
147 if( p->nUsed>0 ){
148 memcpy(&p->z[p->nUsed], p->zSep, p->szSep);
149 p->nUsed += p->szSep;
150 }
151 memcpy(&p->z[p->nUsed], z, sz);
152 p->nUsed += sz;
153 }
154 return 0;
155}
156
157/*
158** Implementation of the eval(X) and eval(X,Y) SQL functions.
159**
160** Evaluate the SQL text in X. Return the results, using string
161** Y as the separator. If Y is omitted, use a single space character.
162*/
163static void sqlEvalFunc(
164 sqlite3_context *context,
165 int argc,
166 sqlite3_value **argv
167){
168 const char *zSql;
169 sqlite3 *db;
170 char *zErr = 0;
171 int rc;
172 struct EvalResult x;
173
174 memset(&x, 0, sizeof(x));
175 x.zSep = " ";
176 zSql = (const char*)sqlite3_value_text(argv[0]);
177 if( zSql==0 ) return;
178 if( argc>1 ){
179 x.zSep = (const char*)sqlite3_value_text(argv[1]);
180 if( x.zSep==0 ) return;
181 }
182 x.szSep = (int)strlen(x.zSep);
183 db = sqlite3_context_db_handle(context);
184 rc = sqlite3_exec(db, zSql, callback, &x, &zErr);
185 if( rc!=SQLITE_OK ){
186 sqlite3_result_error(context, zErr, -1);
187 sqlite3_free(zErr);
188 }else if( x.zSep==0 ){
189 sqlite3_result_error_nomem(context);
190 sqlite3_free(x.z);
191 }else{
192 sqlite3_result_text(context, x.z, (int)x.nUsed, sqlite3_free);
193 }
194}
195/* End of the eval() implementation
196******************************************************************************/
197
198/*
199** Print sketchy documentation for this utility program
200*/
201static void showHelp(void){
202 printf("Usage: %s [options]\n", g.zArgv0);
203 printf(
204"Read SQL text from standard input and evaluate it.\n"
205"Options:\n"
206" -f FILE Read SQL text from FILE instead of standard input\n"
207" --help Show this help text\n"
208" --initdb DBFILE Initialize the in-memory database using template DBFILE\n"
209 );
210}
211
212
213int main(int argc, char **argv){
214 char *zIn = 0; /* Input text */
215 int nAlloc = 0; /* Number of bytes allocated for zIn[] */
216 int nIn = 0; /* Number of bytes of zIn[] used */
217 size_t got; /* Bytes read from input */
218 FILE *in = stdin; /* Where to read SQL text from */
219 int rc = SQLITE_OK; /* Result codes from API functions */
220 int i; /* Loop counter */
221 sqlite3 *db; /* Open database */
222 sqlite3 *dbInit; /* On-disk database used to initialize the in-memory db */
223 const char *zInitDb = 0;/* Name of the initialization database file */
224 char *zErrMsg = 0; /* Error message returned from sqlite3_exec() */
225
226 g.zArgv0 = argv[0];
227 for(i=1; i<argc; i++){
228 const char *z = argv[i];
229 if( z[0]=='-' ){
230 z++;
231 if( z[0]=='-' ) z++;
232 if( strcmp(z,"help")==0 ){
233 showHelp();
234 return 0;
235 }else
236 if( strcmp(z, "f")==0 && i+1<argc ){
237 if( in!=stdin ) abendError("only one -f allowed");
238 in = fopen(argv[++i],"rb");
239 if( in==0 ) abendError("cannot open input file \"%s\"", argv[i]);
240 }else
241 if( strcmp(z, "initdb")==0 && i+1<argc ){
242 if( zInitDb!=0 ) abendError("only one --initdb allowed");
243 zInitDb = argv[++i];
244 }else
245 {
246 abendError("unknown option: %s", argv[i]);
247 }
248 }else{
249 abendError("unknown argument: %s", argv[i]);
250 }
251 }
252 sqlite3_config(SQLITE_CONFIG_LOG, shellLog, 0);
253 rc = sqlite3_open_v2(
254 "main.db", &db,
255 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MEMORY,
256 0);
257 if( rc!=SQLITE_OK ){
258 abendError("Unable to open the in-memory database");
259 }
260 if( zInitDb ){
261 sqlite3_backup *pBackup;
262 rc = sqlite3_open_v2(zInitDb, &dbInit, SQLITE_OPEN_READONLY, 0);
263 if( rc!=SQLITE_OK ){
264 abendError("unable to open initialization database \"%s\"", zInitDb);
265 }
266 pBackup = sqlite3_backup_init(db, "main", dbInit, "main");
267 rc = sqlite3_backup_step(pBackup, -1);
268 if( rc!=SQLITE_DONE ){
269 abendError("attempt to initialize the in-memory database failed (rc=%d)",rc);
270 }
271 sqlite3_backup_finish(pBackup);
272 sqlite3_close(dbInit);
273 }
274 sqlite3_trace(db, traceCallback, 0);
275 sqlite3_create_function(db, "eval", 1, SQLITE_UTF8, 0, sqlEvalFunc, 0, 0);
276 sqlite3_create_function(db, "eval", 2, SQLITE_UTF8, 0, sqlEvalFunc, 0, 0);
277 while( !feof(in) ){
278 nAlloc += 1000;
279 zIn = sqlite3_realloc(zIn, nAlloc);
280 if( zIn==0 ) fatalError("out of memory");
281 got = fread(zIn+nIn, 1, nAlloc-nIn-1, in);
282 nIn += (int)got;
283 zIn[nIn] = 0;
284 if( got==0 ) break;
285 }
286 printf("INPUT (%d bytes): [%s]\n", nIn, zIn);
287 rc = sqlite3_exec(db, zIn, execCallback, 0, &zErrMsg);
288 printf("RESULT-CODE: %d\n", rc);
289 if( zErrMsg ){
290 printf("ERROR-MSG: [%s]\n", zErrMsg);
291 sqlite3_free(zErrMsg);
292 }
293 return rc!=SQLITE_OK;
294}