AryaWu/sqlite
0
1/*2** This module interfaces SQLite to the Google OSS-Fuzz, fuzzer as a service.3** (https://github.com/google/oss-fuzz)4*/5#include <stddef.h>6#if !defined(_MSC_VER)7# include <stdint.h>8#endif9#include <stdio.h>10#include <string.h>11#include "sqlite3.h"12 13#if defined(_MSC_VER)14typedef unsigned char uint8_t;15#endif16 17/* Global debugging settings. OSS-Fuzz will have all debugging turned18** off. But if LLVMFuzzerTestOneInput() is called interactively from19** the ossshell utility program, then these flags might be set.20*/21static unsigned mDebug = 0;22#define FUZZ_SQL_TRACE 0x0001 /* Set an sqlite3_trace() callback */23#define FUZZ_SHOW_MAX_DELAY 0x0002 /* Show maximum progress callback delay */24#define FUZZ_SHOW_ERRORS 0x0004 /* Print error messages from SQLite */25 26/* The ossshell utility program invokes this interface to see the27** debugging flags. Unused by OSS-Fuzz.28*/29void ossfuzz_set_debug_flags(unsigned x){30 mDebug = x;31}32 33/* Return the current real-world time in milliseconds since the34** Julian epoch (-4714-11-24).35*/36static sqlite3_int64 timeOfDay(void){37 static sqlite3_vfs *clockVfs = 0;38 sqlite3_int64 t;39 if( clockVfs==0 ){40 clockVfs = sqlite3_vfs_find(0);41 if( clockVfs==0 ) return 0;42 }43 if( clockVfs->iVersion>=2 && clockVfs->xCurrentTimeInt64!=0 ){44 clockVfs->xCurrentTimeInt64(clockVfs, &t);45 }else{46 double r;47 clockVfs->xCurrentTime(clockVfs, &r);48 t = (sqlite3_int64)(r*86400000.0);49 }50 return t;51}52 53/* An instance of the following object is passed by pointer as the54** client data to various callbacks.55*/56typedef struct FuzzCtx {57 sqlite3 *db; /* The database connection */58 sqlite3_int64 iCutoffTime; /* Stop processing at this time. */59 sqlite3_int64 iLastCb; /* Time recorded for previous progress callback */60 sqlite3_int64 mxInterval; /* Longest interval between two progress calls */61 unsigned nCb; /* Number of progress callbacks */62 unsigned execCnt; /* Number of calls to the sqlite3_exec callback */63} FuzzCtx;64 65/*66** Progress handler callback.67**68** The argument is the cutoff-time after which all processing should69** stop. So return non-zero if the cut-off time is exceeded.70*/71static int progress_handler(void *pClientData) {72 FuzzCtx *p = (FuzzCtx*)pClientData;73 sqlite3_int64 iNow = timeOfDay();74 int rc = iNow>=p->iCutoffTime;75 sqlite3_int64 iDiff = iNow - p->iLastCb;76 if( iDiff > p->mxInterval ) p->mxInterval = iDiff;77 p->nCb++;78 return rc;79}80 81/*82** Disallow debugging pragmas such as "PRAGMA vdbe_debug" and83** "PRAGMA parser_trace" since they can dramatically increase the84** amount of output without actually testing anything useful.85*/86static int block_debug_pragmas(87 void *Notused,88 int eCode,89 const char *zArg1,90 const char *zArg2,91 const char *zArg3,92 const char *zArg493){94 if( eCode==SQLITE_PRAGMA95 && (sqlite3_strnicmp("vdbe_", zArg1, 5)==096 || sqlite3_stricmp("parser_trace", zArg1)==0)97 ){98 return SQLITE_DENY;99 }100 return SQLITE_OK;101}102 103/*104** Callback for sqlite3_exec().105*/106static int exec_handler(void *pClientData, int argc, char **argv, char **namev){107 FuzzCtx *p = (FuzzCtx*)pClientData;108 int i;109 if( argv ){110 for(i=0; i<argc; i++) sqlite3_free(sqlite3_mprintf("%s", argv[i]));111 }112 return (p->execCnt--)<=0 || progress_handler(pClientData);113}114 115/*116** Main entry point. The fuzzer invokes this function with each117** fuzzed input.118*/119int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {120 char *zErrMsg = 0; /* Error message returned by sqlite_exec() */121 uint8_t uSelector; /* First byte of input data[] */122 int rc; /* Return code from various interfaces */123 char *zSql; /* Zero-terminated copy of data[] */124 FuzzCtx cx; /* Fuzzing context */125 126 memset(&cx, 0, sizeof(cx));127 if( size<3 ) return 0; /* Early out if unsufficient data */128 129 /* Extract the selector byte from the beginning of the input. But only130 ** do this if the second byte is a \n. If the second byte is not \n,131 ** then use a default selector */132 if( data[1]=='\n' ){133 uSelector = data[0]; data += 2; size -= 2;134 }else{135 uSelector = 0xfd;136 }137 138 /* Open the database connection. Only use an in-memory database. */139 if( sqlite3_initialize() ) return 0;140 rc = sqlite3_open_v2("fuzz.db", &cx.db,141 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MEMORY, 0);142 if( rc ) return 0;143 144 /* Invoke the progress handler frequently to check to see if we145 ** are taking too long. The progress handler will return true146 ** (which will block further processing) if more than 10 seconds have147 ** elapsed since the start of the test.148 */149 cx.iLastCb = timeOfDay();150 cx.iCutoffTime = cx.iLastCb + 10000; /* Now + 10 seconds */151#ifndef SQLITE_OMIT_PROGRESS_CALLBACK152 sqlite3_progress_handler(cx.db, 10, progress_handler, (void*)&cx);153#endif154 155 /* Set a limit on the maximum size of a prepared statement */156 sqlite3_limit(cx.db, SQLITE_LIMIT_VDBE_OP, 25000);157 158 /* Set a limit on the maximum LIKE or GLOB pattern length due to159 ** https://issues.oss-fuzz.com/issues/453240497. The default is 50K160 ** which is causing timeouts in OSS-Fuzz */161 sqlite3_limit(cx.db, SQLITE_LIMIT_LIKE_PATTERN_LENGTH, 250);162 163 /* Limit total memory available to SQLite to 20MB */164 sqlite3_hard_heap_limit64(20000000);165 166 /* Set a limit on the maximum length of a string or BLOB. Without this167 ** limit, fuzzers will invoke randomblob(N) for a large N, and the process168 ** will timeout trying to generate the huge blob */169 sqlite3_limit(cx.db, SQLITE_LIMIT_LENGTH, 50000);170 171 /* Bit 1 of the selector enables foreign key constraints */172 sqlite3_db_config(cx.db, SQLITE_DBCONFIG_ENABLE_FKEY, uSelector&1, &rc);173 uSelector >>= 1;174 175 /* Do not allow debugging pragma statements that might cause excess output */176 sqlite3_set_authorizer(cx.db, block_debug_pragmas, 0);177 178 /* Remaining bits of the selector determine a limit on the number of179 ** output rows */180 cx.execCnt = uSelector + 1;181 182 /* Run the SQL. The sqlite_exec() interface expects a zero-terminated183 ** string, so make a copy. */184 zSql = sqlite3_mprintf("%.*s", (int)size, data);185#ifndef SQLITE_OMIT_COMPLETE186 sqlite3_complete(zSql);187#endif188 sqlite3_exec(cx.db, zSql, exec_handler, (void*)&cx, &zErrMsg);189 190 /* Show any errors */191 if( (mDebug & FUZZ_SHOW_ERRORS)!=0 && zErrMsg ){192 printf("Error: %s\n", zErrMsg);193 }194 195 /* Cleanup and return */196 sqlite3_free(zErrMsg);197 sqlite3_free(zSql);198 sqlite3_exec(cx.db, "PRAGMA temp_store_directory=''", 0, 0, 0);199 sqlite3_close(cx.db);200 201 if( mDebug & FUZZ_SHOW_MAX_DELAY ){202 printf("Progress callback count....... %d\n", cx.nCb);203 printf("Max time between callbacks.... %d ms\n", (int)cx.mxInterval);204 }205 return 0;206}207 