- Timestamp:
- Jun 15, 2018 8:36:17 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/iprt/fuzz.h
r72465 r72571 150 150 151 151 /** 152 * Adds a new seed to the input corpus of the given fuzzing context from the given VFS file. 153 * 154 * @returns IPRT status code. 155 * @param hFuzzCtx The fuzzing context handle. 156 * @param hVfsFile The VFS file handle to load the seed from. 157 */ 158 RTDECL(int) RTFuzzCtxCorpusInputAddFromVfsFile(RTFUZZCTX hFuzzCtx, RTVFSFILE hVfsFile); 159 160 /** 152 161 * Adds new seeds to the input corpus of the given fuzzing context from the given directory. 153 162 * … … 368 377 * @param hFuzzObs The fuzzing observer handle. 369 378 * @param cProcs Number of processes to run simulteanously, 370 * 0 will create as man ny processes as there are CPUs available.379 * 0 will create as many processes as there are CPUs available. 371 380 */ 372 381 RTDECL(int) RTFuzzObsExecStart(RTFUZZOBS hFuzzObs, uint32_t cProcs); -
trunk/include/iprt/mangling.h
r72465 r72571 1018 1018 # define RTFuzzCtxCorpusInputAddFromDirPath RT_MANGLER(RTFuzzCtxCorpusInputAddFromDirPath) 1019 1019 # define RTFuzzCtxCorpusInputAddFromFile RT_MANGLER(RTFuzzCtxCorpusInputAddFromFile) 1020 # define RTFuzzCtxCorpusInputAddFromVfsFile RT_MANGLER(RTFuzzCtxCorpusInputAddFromVfsFile) 1020 1021 # define RTFuzzCtxCreate RT_MANGLER(RTFuzzCtxCreate) 1021 1022 # define RTFuzzCtxCreateFromState RT_MANGLER(RTFuzzCtxCreateFromState) -
trunk/src/VBox/Runtime/common/fuzz/fuzz-observer.cpp
r72465 r72571 880 880 881 881 if (RT_SUCCESS(rc)) 882 { 882 883 pThis->paObsThreads = paObsThreads; 884 pThis->cThreads = cThreads; 885 } 883 886 else 884 887 RTMemFree(paObsThreads); … … 957 960 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 958 961 959 /* Wait for the master thread to terminate. */ 960 if (pThis->hThreadGlobal != NIL_RTTHREAD) 961 { 962 ASMAtomicXchgBool(&pThis->fShutdown, true); 963 RTThreadWait(pThis->hThreadGlobal, RT_INDEFINITE_WAIT, NULL); 964 } 965 966 /* Clean up the workers. */ 967 if (pThis->paObsThreads) 968 { 969 for (unsigned i = 0; i < pThis->cThreads; i++) 970 { 971 PRTFUZZOBSTHRD pThrd = &pThis->paObsThreads[i]; 972 ASMAtomicXchgBool(&pThrd->fShutdown, true); 973 RTThreadWait(pThrd->hThread, RT_INDEFINITE_WAIT, NULL); 974 if (pThrd->hFuzzInput) 975 RTFuzzInputRelease(pThrd->hFuzzInput); 976 } 977 RTMemFree(pThis->paObsThreads); 978 pThis->paObsThreads = NULL; 979 } 962 RTFuzzObsExecStop(hFuzzObs); 980 963 981 964 /* Clean up all acquired resources. */ … … 1145 1128 RTDECL(int) RTFuzzObsExecStop(RTFUZZOBS hFuzzObs) 1146 1129 { 1147 RT_NOREF(hFuzzObs); 1148 return VERR_NOT_IMPLEMENTED; 1149 } 1150 1130 PRTFUZZOBSINT pThis = hFuzzObs; 1131 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 1132 1133 /* Wait for the master thread to terminate. */ 1134 if (pThis->hThreadGlobal != NIL_RTTHREAD) 1135 { 1136 ASMAtomicXchgBool(&pThis->fShutdown, true); 1137 RTSemEventSignal(pThis->hEvtGlobal); 1138 RTThreadWait(pThis->hThreadGlobal, RT_INDEFINITE_WAIT, NULL); 1139 pThis->hThreadGlobal = NIL_RTTHREAD; 1140 } 1141 1142 /* Destroy the workers. */ 1143 if (pThis->paObsThreads) 1144 { 1145 for (unsigned i = 0; i < pThis->cThreads; i++) 1146 { 1147 PRTFUZZOBSTHRD pThrd = &pThis->paObsThreads[i]; 1148 ASMAtomicXchgBool(&pThrd->fShutdown, true); 1149 RTThreadUserSignal(pThrd->hThread); 1150 RTThreadWait(pThrd->hThread, RT_INDEFINITE_WAIT, NULL); 1151 if (pThrd->hFuzzInput) 1152 RTFuzzInputRelease(pThrd->hFuzzInput); 1153 } 1154 1155 RTMemFree(pThis->paObsThreads); 1156 pThis->paObsThreads = NULL; 1157 pThis->cThreads = 0; 1158 } 1159 1160 RTSemEventDestroy(pThis->hEvtGlobal); 1161 pThis->hEvtGlobal = NIL_RTSEMEVENT; 1162 return VINF_SUCCESS; 1163 } 1164 -
trunk/src/VBox/Runtime/common/fuzz/fuzz.cpp
r72454 r72571 45 45 #include <iprt/string.h> 46 46 #include <iprt/time.h> 47 #include <iprt/vfs.h> 47 48 48 49 … … 642 643 643 644 645 RTDECL(int) RTFuzzCtxCorpusInputAddFromVfsFile(RTFUZZCTX hFuzzCtx, RTVFSFILE hVfsFile) 646 { 647 PRTFUZZCTXINT pThis = hFuzzCtx; 648 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 649 AssertReturn(hVfsFile != NIL_RTVFSFILE, VERR_INVALID_HANDLE); 650 651 uint64_t cbFile = 0; 652 int rc = RTVfsFileGetSize(hVfsFile, &cbFile); 653 if (RT_SUCCESS(rc)) 654 { 655 PRTFUZZINPUTINT pInput = (PRTFUZZINPUTINT)RTMemAllocZ(RT_OFFSETOF(RTFUZZINPUTINT, abInput[cbFile])); 656 if (RT_LIKELY(pInput)) 657 { 658 pInput->cRefs = 1; 659 pInput->pFuzzer = pThis; 660 pInput->cbInput = cbFile; 661 662 rc = RTVfsFileRead(hVfsFile, &pInput->abInput[0], cbFile, NULL); 663 if (RT_SUCCESS(rc)) 664 { 665 /* Generate MD5 checksum and try to locate input. */ 666 uint8_t abDigest[RTMD5_HASH_SIZE]; 667 RTMd5(&pInput->abInput[0], cbFile, &abDigest[0]); 668 669 if (!rtFuzzCtxInputLocate(pThis, &abDigest[0], true /*fExact*/, NULL /*ppIntermediate*/)) 670 { 671 memcpy(&pInput->abMd5Hash[0], &abDigest[0], sizeof(abDigest)); 672 rc = rtFuzzCtxInputAdd(pThis, pInput); 673 } 674 else 675 rc = VERR_ALREADY_EXISTS; 676 } 677 678 if (RT_FAILURE(rc)) 679 RTMemFree(pInput); 680 } 681 else 682 rc = VERR_NO_MEMORY; 683 } 684 685 return rc; 686 } 687 688 644 689 RTDECL(int) RTFuzzCtxCorpusInputAddFromDirPath(RTFUZZCTX hFuzzCtx, const char *pszDirPath) 645 690 { … … 698 743 PRTFUZZCTXINT pThis = hFuzzCtx; 699 744 AssertPtrReturn(pThis, VERR_INVALID_POINTER); 700 AssertReturn(cbMax, VERR_INVALID_PARAMETER);701 745 702 746 pThis->cbInputMax = cbMax; -
trunk/src/VBox/Runtime/common/fuzz/fuzzmastercmd.cpp
r72465 r72571 34 34 #include <iprt/asm.h> 35 35 #include <iprt/assert.h> 36 #include <iprt/base64.h> 36 37 #include <iprt/buildconfig.h> 37 38 #include <iprt/ctype.h> 38 39 #include <iprt/err.h> 40 #include <iprt/file.h> 39 41 #include <iprt/getopt.h> 42 #include <iprt/json.h> 43 #include <iprt/list.h> 40 44 #include <iprt/mem.h> 41 45 #include <iprt/message.h> 46 #include <iprt/path.h> 47 #include <iprt/process.h> 42 48 #include <iprt/stream.h> 49 #include <iprt/string.h> 50 #include <iprt/tcp.h> 43 51 #include <iprt/thread.h> 44 52 #include <iprt/vfs.h> 53 #include <iprt/zip.h> 54 55 56 /** 57 * A running fuzzer state. 58 */ 59 typedef struct RTFUZZRUN 60 { 61 /** List node. */ 62 RTLISTNODE NdFuzzed; 63 /** Identifier. */ 64 char *pszId; 65 /** Number of processes. */ 66 uint32_t cProcs; 67 /** Maximum input size to generate. */ 68 size_t cbInputMax; 69 /** The fuzzing observer state handle. */ 70 RTFUZZOBS hFuzzObs; 71 } RTFUZZRUN; 72 /** Pointer to a running fuzzer state. */ 73 typedef RTFUZZRUN *PRTFUZZRUN; 74 75 76 /** 77 * Fuzzing master command state. 78 */ 79 typedef struct RTFUZZCMDMASTER 80 { 81 /** List of running fuzzers. */ 82 RTLISTANCHOR LstFuzzed; 83 /** The port to listen on. */ 84 uint16_t uPort; 85 /** The TCP server for requests. */ 86 PRTTCPSERVER hTcpSrv; 87 /** The root temp directory. */ 88 const char *pszTmpDir; 89 /** The root results directory. */ 90 const char *pszResultsDir; 91 /** Flag whether to shutdown. */ 92 bool fShutdown; 93 } RTFUZZCMDMASTER; 94 /** Pointer to a fuzzing master command state. */ 95 typedef RTFUZZCMDMASTER *PRTFUZZCMDMASTER; 45 96 46 97 … … 68 119 69 120 /** 70 * Executes the 71 */ 72 static RTEXITCODE rtFuzzCmdMasterDoIt(const char *pszBinary, uint32_t cProcs, const char *pszInpSeedDir, 73 const char *pszResultsDir, size_t cbInputMax, const char * const *papszClientArgs, 74 unsigned cClientArgs, bool fInputFile, const char *pszTmpDir) 75 { 76 RTFUZZOBS hFuzzObs; 77 78 int rc = RTFuzzObsCreate(&hFuzzObs); 79 if (RT_SUCCESS(rc)) 80 { 81 RTFUZZCTX hFuzzCtx; 82 83 rc = RTFuzzObsQueryCtx(hFuzzObs, &hFuzzCtx); 84 if (RT_SUCCESS(rc)) 85 { 86 uint32_t fFlags = 0; 87 88 if (fInputFile) 89 { 90 fFlags |= RTFUZZ_OBS_BINARY_F_INPUT_FILE; 91 rc = RTFuzzObsSetTmpDirectory(hFuzzObs, pszTmpDir); 92 } 93 94 if (RT_SUCCESS(rc)) 95 rc = RTFuzzObsSetResultDirectory(hFuzzObs, pszResultsDir); 121 * Returns a running fuzzer state by the given ID. 122 * 123 * @returns Pointer to the running fuzzer state or NULL if not found. 124 * @param pThis The fuzzing master command state. 125 * @param pszId The ID to look for. 126 */ 127 static PRTFUZZRUN rtFuzzCmdMasterGetFuzzerById(PRTFUZZCMDMASTER pThis, const char *pszId) 128 { 129 PRTFUZZRUN pIt = NULL; 130 RTListForEach(&pThis->LstFuzzed, pIt, RTFUZZRUN, NdFuzzed) 131 { 132 if (!RTStrCmp(pIt->pszId, pszId)) 133 return pIt; 134 } 135 136 return NULL; 137 } 138 139 140 #if 0 /* unused */ 141 /** 142 * Processes and returns the value of the given config item in the JSON request. 143 * 144 * @returns IPRT status code. 145 * @param ppszStr Where to store the pointer to the string on success. 146 * @param pszCfgItem The config item to resolve. 147 * @param hJsonCfg The JSON object containing the item. 148 * @param pErrInfo Where to store the error information on failure, optional. 149 */ 150 static int rtFuzzCmdMasterFuzzRunProcessCfgString(char **ppszStr, const char *pszCfgItem, RTJSONVAL hJsonCfg, PRTERRINFO pErrInfo) 151 { 152 int rc = RTJsonValueQueryStringByName(hJsonCfg, pszCfgItem, ppszStr); 153 if (RT_FAILURE(rc)) 154 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query string value of \"%s\"", pszCfgItem); 155 156 return rc; 157 } 158 159 160 /** 161 * Processes and returns the value of the given config item in the JSON request. 162 * 163 * @returns IPRT status code. 164 * @param pfVal Where to store the config value on success. 165 * @param pszCfgItem The config item to resolve. 166 * @param hJsonCfg The JSON object containing the item. 167 * @param pErrInfo Where to store the error information on failure, optional. 168 */ 169 static int rtFuzzCmdMasterFuzzRunProcessCfgBool(bool *pfVal, const char *pszCfgItem, RTJSONVAL hJsonCfg, PRTERRINFO pErrInfo) 170 { 171 int rc = RTJsonValueQueryBooleanByName(hJsonCfg, pszCfgItem, pfVal); 172 if (RT_FAILURE(rc)) 173 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query boolean value of \"%s\"", pszCfgItem); 174 175 return rc; 176 } 177 #endif 178 179 180 /** 181 * Processes and returns the value of the given config item in the JSON request. 182 * 183 * @returns IPRT status code. 184 * @param pfVal Where to store the config value on success. 185 * @param pszCfgItem The config item to resolve. 186 * @param hJsonCfg The JSON object containing the item. 187 * @param fDef Default value if the item wasn't found. 188 * @param pErrInfo Where to store the error information on failure, optional. 189 */ 190 static int rtFuzzCmdMasterFuzzRunProcessCfgBoolDef(bool *pfVal, const char *pszCfgItem, RTJSONVAL hJsonCfg, bool fDef, PRTERRINFO pErrInfo) 191 { 192 int rc = RTJsonValueQueryBooleanByName(hJsonCfg, pszCfgItem, pfVal); 193 if (rc == VERR_NOT_FOUND) 194 { 195 *pfVal = fDef; 196 rc = VINF_SUCCESS; 197 } 198 else if (RT_FAILURE(rc)) 199 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query boolean value of \"%s\"", pszCfgItem); 200 201 return rc; 202 } 203 204 205 /** 206 * Processes and returns the value of the given config item in the JSON request. 207 * 208 * @returns IPRT status code. 209 * @param pcbVal Where to store the config value on success. 210 * @param pszCfgItem The config item to resolve. 211 * @param hJsonCfg The JSON object containing the item. 212 * @param cbDef Default value if the item wasn't found. 213 * @param pErrInfo Where to store the error information on failure, optional. 214 */ 215 static int rtFuzzCmdMasterFuzzRunProcessCfgSizeDef(size_t *pcbVal, const char *pszCfgItem, RTJSONVAL hJsonCfg, size_t cbDef, PRTERRINFO pErrInfo) 216 { 217 int64_t i64Val = 0; 218 int rc = RTJsonValueQueryIntegerByName(hJsonCfg, pszCfgItem, &i64Val); 219 if (rc == VERR_NOT_FOUND) 220 { 221 *pcbVal = cbDef; 222 rc = VINF_SUCCESS; 223 } 224 else if (RT_FAILURE(rc)) 225 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query size_t value of \"%s\"", pszCfgItem); 226 else if (i64Val < 0 || (size_t)i64Val != (uint64_t)i64Val) 227 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_OUT_OF_RANGE, "JSON request malformed: Integer \"%s\" is out of range", pszCfgItem); 228 else 229 *pcbVal = (size_t)i64Val; 230 231 return rc; 232 } 233 234 235 /** 236 * Processes and returns the value of the given config item in the JSON request. 237 * 238 * @returns IPRT status code. 239 * @param pcbVal Where to store the config value on success. 240 * @param pszCfgItem The config item to resolve. 241 * @param hJsonCfg The JSON object containing the item. 242 * @param cbDef Default value if the item wasn't found. 243 * @param pErrInfo Where to store the error information on failure, optional. 244 */ 245 static int rtFuzzCmdMasterFuzzRunProcessCfgU32Def(uint32_t *pu32Val, const char *pszCfgItem, RTJSONVAL hJsonCfg, size_t u32Def, PRTERRINFO pErrInfo) 246 { 247 int64_t i64Val = 0; 248 int rc = RTJsonValueQueryIntegerByName(hJsonCfg, pszCfgItem, &i64Val); 249 if (rc == VERR_NOT_FOUND) 250 { 251 *pu32Val = u32Def; 252 rc = VINF_SUCCESS; 253 } 254 else if (RT_FAILURE(rc)) 255 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query uint32_t value of \"%s\"", pszCfgItem); 256 else if (i64Val < 0 || (uint32_t)i64Val != (uint64_t)i64Val) 257 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_OUT_OF_RANGE, "JSON request malformed: Integer \"%s\" is out of range", pszCfgItem); 258 else 259 *pu32Val = (uint32_t)i64Val; 260 261 return rc; 262 } 263 264 265 /** 266 * Processes binary related configs for the given fuzzing run. 267 * 268 * @returns IPRT status code. 269 * @param pFuzzRun The fuzzing run. 270 * @param hJsonRoot The root node of the JSON request. 271 * @param pErrInfo Where to store the error information on failure, optional. 272 */ 273 static int rtFuzzCmdMasterFuzzRunProcessBinaryCfg(PRTFUZZRUN pFuzzRun, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo) 274 { 275 RTJSONVAL hJsonVal; 276 int rc = RTJsonValueQueryByName(hJsonRoot, "BinaryPath", &hJsonVal); 277 if (RT_SUCCESS(rc)) 278 { 279 const char *pszBinary = RTJsonValueGetString(hJsonVal); 280 if (RT_LIKELY(pszBinary)) 281 { 282 bool fFileInput = false; 283 rc = rtFuzzCmdMasterFuzzRunProcessCfgBoolDef(&fFileInput, "FileInput", hJsonRoot, false, pErrInfo); 96 284 if (RT_SUCCESS(rc)) 97 285 { 98 rc = RTFuzzObsSetTestBinary(hFuzzObs, pszBinary, fFlags); 286 uint32_t fFlags = 0; 287 if (fFileInput) 288 fFlags |= RTFUZZ_OBS_BINARY_F_INPUT_FILE; 289 rc = RTFuzzObsSetTestBinary(pFuzzRun->hFuzzObs, pszBinary, fFlags); 290 if (RT_FAILURE(rc)) 291 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Failed to add the binary path for the fuzzing run"); 292 } 293 } 294 else 295 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "JSON request malformed: \"BinaryPath\" is not a string"); 296 RTJsonValueRelease(hJsonVal); 297 } 298 else 299 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query value of \"BinaryPath\""); 300 301 return rc; 302 } 303 304 305 /** 306 * Processes argument related configs for the given fuzzing run. 307 * 308 * @returns IPRT status code. 309 * @param pFuzzRun The fuzzing run. 310 * @param hJsonRoot The root node of the JSON request. 311 * @param pErrInfo Where to store the error information on failure, optional. 312 */ 313 static int rtFuzzCmdMasterFuzzRunProcessArgCfg(PRTFUZZRUN pFuzzRun, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo) 314 { 315 RTJSONVAL hJsonValArgArray; 316 int rc = RTJsonValueQueryByName(hJsonRoot, "Arguments", &hJsonValArgArray); 317 if (RT_SUCCESS(rc)) 318 { 319 unsigned cArgs = 0; 320 rc = RTJsonValueQueryArraySize(hJsonValArgArray, &cArgs); 321 if (RT_SUCCESS(rc)) 322 { 323 if (cArgs > 0) 324 { 325 const char **papszArgs = (const char **)RTMemAllocZ(cArgs * sizeof(const char *)); 326 RTJSONVAL *pahJsonVal = (RTJSONVAL *)RTMemAllocZ(cArgs * sizeof(RTJSONVAL)); 327 if (RT_LIKELY(papszArgs && pahJsonVal)) 328 { 329 unsigned idx = 0; 330 331 for (idx = 0; idx < cArgs && RT_SUCCESS(rc); idx++) 332 { 333 rc = RTJsonValueQueryByIndex(hJsonValArgArray, idx, &pahJsonVal[idx]); 334 if (RT_SUCCESS(rc)) 335 { 336 papszArgs[idx] = RTJsonValueGetString(pahJsonVal[idx]); 337 if (RT_UNLIKELY(!papszArgs[idx])) 338 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "Argument %u is not a string", idx); 339 } 340 } 341 342 if (RT_SUCCESS(rc)) 343 { 344 rc = RTFuzzObsSetTestBinaryArgs(pFuzzRun->hFuzzObs, papszArgs, cArgs); 345 if (RT_FAILURE(rc)) 346 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Failed to set arguments for the fuzzing run"); 347 } 348 349 /* Release queried values. */ 350 while (idx > 0) 351 { 352 RTJsonValueRelease(pahJsonVal[idx - 1]); 353 idx--; 354 } 355 } 356 else 357 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_NO_MEMORY, "Out of memory allocating memory for the argument vector"); 358 359 if (papszArgs) 360 RTMemFree(papszArgs); 361 if (pahJsonVal) 362 RTMemFree(pahJsonVal); 363 } 364 } 365 else 366 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: \"Arguments\" is not an array"); 367 RTJsonValueRelease(hJsonValArgArray); 368 } 369 370 return rc; 371 } 372 373 374 /** 375 * Processes the given seed and adds it to the input corpus. 376 * 377 * @returns IPRT status code. 378 * @param hFuzzCtx The fuzzing context handle. 379 * @param pszCompression Compression used for the seed. 380 * @param pszSeed The seed as a base64 encoded string. 381 * @param pErrInfo Where to store the error information on failure, optional. 382 */ 383 static int rtFuzzCmdMasterFuzzRunProcessSeed(RTFUZZCTX hFuzzCtx, const char *pszCompression, const char *pszSeed, PRTERRINFO pErrInfo) 384 { 385 int rc = VINF_SUCCESS; 386 ssize_t cbSeedDecoded = RTBase64DecodedSize(pszSeed, NULL); 387 if (cbSeedDecoded > 0) 388 { 389 uint8_t *pbSeedDecoded = (uint8_t *)RTMemAllocZ(cbSeedDecoded); 390 if (RT_LIKELY(pbSeedDecoded)) 391 { 392 rc = RTBase64Decode(pszSeed, pbSeedDecoded, cbSeedDecoded, NULL, NULL); 393 if (RT_SUCCESS(rc)) 394 { 395 /* Decompress if applicable. */ 396 if (!RTStrICmp(pszCompression, "None")) 397 rc = RTFuzzCtxCorpusInputAdd(hFuzzCtx, pbSeedDecoded, cbSeedDecoded); 398 else 399 { 400 RTVFSIOSTREAM hVfsIosSeed; 401 rc = RTVfsIoStrmFromBuffer(RTFILE_O_READ, pbSeedDecoded, cbSeedDecoded, &hVfsIosSeed); 402 if (RT_SUCCESS(rc)) 403 { 404 RTVFSIOSTREAM hVfsDecomp; 405 406 if (!RTStrICmp(pszCompression, "Gzip")) 407 rc = RTZipGzipDecompressIoStream(hVfsIosSeed, RTZIPGZIPDECOMP_F_ALLOW_ZLIB_HDR, &hVfsDecomp); 408 else 409 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "Request error: Compression \"%s\" is not known", pszCompression); 410 411 if (RT_SUCCESS(rc)) 412 { 413 RTVFSFILE hVfsFile; 414 rc = RTVfsMemFileCreate(hVfsDecomp, 2 * _1M, &hVfsFile); 415 if (RT_SUCCESS(rc)) 416 { 417 rc = RTVfsFileSeek(hVfsFile, 0, RTFILE_SEEK_BEGIN, NULL); 418 if (RT_SUCCESS(rc)) 419 { 420 /* The VFS file contains the buffer for the seed now. */ 421 rc = RTFuzzCtxCorpusInputAddFromVfsFile(hFuzzCtx, hVfsFile); 422 if (RT_FAILURE(rc)) 423 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to add input seed"); 424 RTVfsFileRelease(hVfsFile); 425 } 426 else 427 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "Request error: Failed to seek to the beginning of the seed"); 428 } 429 else 430 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "Request error: Failed to decompress input seed"); 431 432 RTVfsIoStrmRelease(hVfsDecomp); 433 } 434 435 RTVfsIoStrmRelease(hVfsIosSeed); 436 } 437 else 438 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to create I/O stream from seed buffer"); 439 } 440 } 441 else 442 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to decode the seed string"); 443 444 RTMemFree(pbSeedDecoded); 445 } 446 else 447 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_NO_MEMORY, "Request error: Failed to allocate %zd bytes of memory for the seed", cbSeedDecoded); 448 } 449 else 450 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "JSON request malformed: Couldn't find \"Seed\" doesn't contain a base64 encoded value"); 451 452 return rc; 453 } 454 455 456 /** 457 * Processes a signle input seed for the given fuzzing run. 458 * 459 * @returns IPRT status code. 460 * @param pFuzzRun The fuzzing run. 461 * @param hJsonSeed The seed node of the JSON request. 462 * @param pErrInfo Where to store the error information on failure, optional. 463 */ 464 static int rtFuzzCmdMasterFuzzRunProcessInputSeedSingle(PRTFUZZRUN pFuzzRun, RTJSONVAL hJsonSeed, PRTERRINFO pErrInfo) 465 { 466 RTFUZZCTX hFuzzCtx; 467 int rc = RTFuzzObsQueryCtx(pFuzzRun->hFuzzObs, &hFuzzCtx); 468 if (RT_SUCCESS(rc)) 469 { 470 RTJSONVAL hJsonValComp; 471 rc = RTJsonValueQueryByName(hJsonSeed, "Compression", &hJsonValComp); 472 if (RT_SUCCESS(rc)) 473 { 474 const char *pszCompression = RTJsonValueGetString(hJsonValComp); 475 if (RT_LIKELY(pszCompression)) 476 { 477 RTJSONVAL hJsonValSeed; 478 rc = RTJsonValueQueryByName(hJsonSeed, "Seed", &hJsonValSeed); 99 479 if (RT_SUCCESS(rc)) 100 480 { 101 rc = RTFuzzObsSetTestBinaryArgs(hFuzzObs, papszClientArgs, cClientArgs); 481 const char *pszSeed = RTJsonValueGetString(hJsonValSeed); 482 if (RT_LIKELY(pszSeed)) 483 rc = rtFuzzCmdMasterFuzzRunProcessSeed(hFuzzCtx, pszCompression, pszSeed, pErrInfo); 484 else 485 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "JSON request malformed: \"Seed\" value is not a string"); 486 487 RTJsonValueRelease(hJsonValSeed); 488 } 489 else 490 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Couldn't find \"Seed\" value"); 491 } 492 else 493 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "JSON request malformed: \"Compression\" value is not a string"); 494 495 RTJsonValueRelease(hJsonValComp); 496 } 497 else 498 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Couldn't find \"Compression\" value"); 499 500 RTFuzzCtxRelease(hFuzzCtx); 501 } 502 else 503 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Failed to query fuzzing context from observer"); 504 505 return rc; 506 } 507 508 509 /** 510 * Processes input seed related configs for the given fuzzing run. 511 * 512 * @returns IPRT status code. 513 * @param pFuzzRun The fuzzing run. 514 * @param hJsonRoot The root node of the JSON request. 515 * @param pErrInfo Where to store the error information on failure, optional. 516 */ 517 static int rtFuzzCmdMasterFuzzRunProcessInputSeeds(PRTFUZZRUN pFuzzRun, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo) 518 { 519 RTJSONVAL hJsonValSeedArray; 520 int rc = RTJsonValueQueryByName(hJsonRoot, "InputSeeds", &hJsonValSeedArray); 521 if (RT_SUCCESS(rc)) 522 { 523 RTJSONIT hIt; 524 rc = RTJsonIteratorBegin(hJsonValSeedArray, &hIt); 525 if (RT_SUCCESS(rc)) 526 { 527 RTJSONVAL hJsonInpSeed; 528 while ( RT_SUCCESS(rc) 529 && RTJsonIteratorQueryValue(hIt, &hJsonInpSeed, NULL) != VERR_JSON_ITERATOR_END) 530 { 531 rc = rtFuzzCmdMasterFuzzRunProcessInputSeedSingle(pFuzzRun, hJsonInpSeed, pErrInfo); 532 RTJsonValueRelease(hJsonInpSeed); 533 if (RT_FAILURE(rc)) 534 break; 535 rc = RTJsonIteratorNext(hIt); 536 } 537 538 if (rc == VERR_JSON_ITERATOR_END) 539 rc = VINF_SUCCESS; 540 } 541 else 542 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to create array iterator"); 543 544 RTJsonValueRelease(hJsonValSeedArray); 545 } 546 547 return rc; 548 } 549 550 551 /** 552 * Processes miscellaneous config items. 553 * 554 * @returns IPRT status code. 555 * @param pFuzzRun The fuzzing run. 556 * @param hJsonRoot The root node of the JSON request. 557 * @param pErrInfo Where to store the error information on failure, optional. 558 */ 559 static int rtFuzzCmdMasterFuzzRunProcessMiscCfg(PRTFUZZRUN pFuzzRun, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo) 560 { 561 size_t cbTmp; 562 int rc = rtFuzzCmdMasterFuzzRunProcessCfgSizeDef(&cbTmp, "InputSeedMax", hJsonRoot, 0, pErrInfo); 563 if (RT_SUCCESS(rc)) 564 { 565 RTFUZZCTX hFuzzCtx; 566 rc = RTFuzzObsQueryCtx(pFuzzRun->hFuzzObs, &hFuzzCtx); 567 AssertRC(rc); 568 569 rc = RTFuzzCtxCfgSetInputSeedMaximum(hFuzzCtx, cbTmp); 570 if (RT_FAILURE(rc)) 571 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to set maximum input seed size to %zu", cbTmp); 572 } 573 574 if (RT_SUCCESS(rc)) 575 rc = rtFuzzCmdMasterFuzzRunProcessCfgU32Def(&pFuzzRun->cProcs, "FuzzingProcs", hJsonRoot, 0, pErrInfo); 576 577 return rc; 578 } 579 580 581 /** 582 * Creates a new fuzzing run with the given ID. 583 * 584 * @returns IPRT status code. 585 * @param pThis The fuzzing master command state. 586 * @param pszId The ID to use. 587 * @param hJsonRoot The root node of the JSON request. 588 * @param pErrInfo Where to store the error information on failure, optional. 589 */ 590 static int rtFuzzCmdMasterCreateFuzzRunWithId(PRTFUZZCMDMASTER pThis, const char *pszId, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo) 591 { 592 int rc = VINF_SUCCESS; 593 PRTFUZZRUN pFuzzRun = (PRTFUZZRUN)RTMemAllocZ(sizeof(*pFuzzRun)); 594 if (RT_LIKELY(pFuzzRun)) 595 { 596 pFuzzRun->pszId = RTStrDup(pszId); 597 if (RT_LIKELY(pFuzzRun->pszId)) 598 { 599 rc = RTFuzzObsCreate(&pFuzzRun->hFuzzObs); 600 if (RT_SUCCESS(rc)) 601 { 602 rc = rtFuzzCmdMasterFuzzRunProcessBinaryCfg(pFuzzRun, hJsonRoot, pErrInfo); 603 if (RT_SUCCESS(rc)) 604 rc = rtFuzzCmdMasterFuzzRunProcessArgCfg(pFuzzRun, hJsonRoot, pErrInfo); 605 if (RT_SUCCESS(rc)) 606 rc = rtFuzzCmdMasterFuzzRunProcessInputSeeds(pFuzzRun, hJsonRoot, pErrInfo); 607 if (RT_SUCCESS(rc)) 608 rc = rtFuzzCmdMasterFuzzRunProcessMiscCfg(pFuzzRun, hJsonRoot, pErrInfo); 609 if (RT_SUCCESS(rc)) 610 { 611 /* Create temp directories. */ 612 char szTmpDir[RTPATH_MAX]; 613 rc = RTPathJoin(&szTmpDir[0], sizeof(szTmpDir), pThis->pszTmpDir, pFuzzRun->pszId); 614 AssertRC(rc); 615 rc = RTDirCreate(szTmpDir, 0700, RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_SET 616 | RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_NOT_CRITICAL); 102 617 if (RT_SUCCESS(rc)) 103 618 { 104 rc = RTFuzz CtxCfgSetInputSeedMaximum(hFuzzCtx, cbInputMax);619 rc = RTFuzzObsSetTmpDirectory(pFuzzRun->hFuzzObs, szTmpDir); 105 620 if (RT_SUCCESS(rc)) 106 621 { 107 rc = RTFuzzCtxCorpusInputAddFromDirPath(hFuzzCtx, pszInpSeedDir); 622 rc = RTPathJoin(&szTmpDir[0], sizeof(szTmpDir), pThis->pszResultsDir, pFuzzRun->pszId); 623 AssertRC(rc); 624 rc = RTDirCreate(szTmpDir, 0700, RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_SET 625 | RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_NOT_CRITICAL); 108 626 if (RT_SUCCESS(rc)) 109 627 { 110 rc = RTFuzzObs ExecStart(hFuzzObs, cProcs);628 rc = RTFuzzObsSetResultDirectory(pFuzzRun->hFuzzObs, szTmpDir); 111 629 if (RT_SUCCESS(rc)) 112 630 { 113 RTThreadSleep(3600 * RT_MS_1SEC); 114 RTFuzzObsExecStop(hFuzzObs); 631 /* Start fuzzing. */ 632 RTListAppend(&pThis->LstFuzzed, &pFuzzRun->NdFuzzed); 633 rc = RTFuzzObsExecStart(pFuzzRun->hFuzzObs, pFuzzRun->cProcs); 634 if (RT_FAILURE(rc)) 635 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to start fuzzing with %Rrc", rc); 115 636 } 116 637 else 117 rc = rtFuzzCmdMasterErrorRc( NULL, rc, "Failed to start fuzzing observer: %Rrc\n", rc);638 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to set results directory to %s", szTmpDir); 118 639 } 119 640 else 120 rc = rtFuzzCmdMasterErrorRc( NULL, rc, "Failed to load corpus seeds from \"%s\": %Rrc\n", pszInpSeedDir, rc);641 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to create results directory %s", szTmpDir); 121 642 } 122 643 else 123 rc = rtFuzzCmdMasterErrorRc( NULL, rc, "Failed to set maximum input size to %zu: %Rrc\n", cbInputMax, rc);644 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to set temporary directory to %s", szTmpDir); 124 645 } 125 646 else 126 rc = rtFuzzCmdMasterErrorRc(NULL, rc, "Failed to set test program arguments: %Rrc\n", rc); 647 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to create temporary directory %s", szTmpDir); 648 } 649 } 650 } 651 else 652 rc = VERR_NO_STR_MEMORY; 653 } 654 else 655 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_NO_MEMORY, "Request error: Out of memory allocating the fuzzer state"); 656 657 return rc; 658 } 659 660 661 /** 662 * Resolves the fuzzing run from the given ID config item and the given JSON request. 663 * 664 * @returns IPRT status code. 665 * @param pThis The fuzzing master command state. 666 * @param hJsonRoot The root node of the JSON request. 667 * @param pszIdItem The JSON item which contains the ID of the fuzzing run. 668 * @param ppFuzzRun Where to store the pointer to the fuzzing run on success. 669 */ 670 static int rtFuzzCmdMasterQueryFuzzRunFromJson(PRTFUZZCMDMASTER pThis, RTJSONVAL hJsonRoot, const char *pszIdItem, PRTERRINFO pErrInfo, 671 PRTFUZZRUN *ppFuzzRun) 672 { 673 RTJSONVAL hJsonValId; 674 int rc = RTJsonValueQueryByName(hJsonRoot, pszIdItem, &hJsonValId); 675 if (RT_SUCCESS(rc)) 676 { 677 const char *pszId = RTJsonValueGetString(hJsonValId); 678 if (pszId) 679 { 680 PRTFUZZRUN pFuzzRun = rtFuzzCmdMasterGetFuzzerById(pThis, pszId); 681 if (pFuzzRun) 682 *ppFuzzRun = pFuzzRun; 683 else 684 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_NOT_FOUND, "Request error: The ID \"%s\" wasn't found", pszId); 685 } 686 else 687 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_JSON_VALUE_INVALID_TYPE, "JSON request malformed: \"Id\" is not a string value"); 688 689 RTJsonValueRelease(hJsonValId); 690 } 691 else 692 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Couldn't find \"Id\" value"); 693 return rc; 694 } 695 696 697 /** 698 * Processes the "StartFuzzing" request. 699 * 700 * @returns IPRT status code. 701 * @param pThis The fuzzing master command state. 702 * @param hJsonRoot The root node of the JSON request. 703 * @param pErrInfo Where to store the error information on failure, optional. 704 */ 705 static int rtFuzzCmdMasterProcessJsonReqStart(PRTFUZZCMDMASTER pThis, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo) 706 { 707 RTJSONVAL hJsonValId; 708 int rc = RTJsonValueQueryByName(hJsonRoot, "Id", &hJsonValId); 709 if (RT_SUCCESS(rc)) 710 { 711 const char *pszId = RTJsonValueGetString(hJsonValId); 712 if (pszId) 713 { 714 PRTFUZZRUN pFuzzRun = rtFuzzCmdMasterGetFuzzerById(pThis, pszId); 715 if (!pFuzzRun) 716 rc = rtFuzzCmdMasterCreateFuzzRunWithId(pThis, pszId, hJsonRoot, pErrInfo); 717 else 718 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_ALREADY_EXISTS, "Request error: The ID \"%s\" is already registered", pszId); 719 } 720 else 721 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_JSON_VALUE_INVALID_TYPE, "JSON request malformed: \"Id\" is not a string value"); 722 723 RTJsonValueRelease(hJsonValId); 724 } 725 else 726 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Couldn't find \"Id\" value"); 727 return rc; 728 } 729 730 731 /** 732 * Processes the "StopFuzzing" request. 733 * 734 * @returns IPRT status code. 735 * @param pThis The fuzzing master command state. 736 * @param hJsonValRoot The root node of the JSON request. 737 * @param pErrInfo Where to store the error information on failure, optional. 738 */ 739 static int rtFuzzCmdMasterProcessJsonReqStop(PRTFUZZCMDMASTER pThis, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo) 740 { 741 PRTFUZZRUN pFuzzRun; 742 int rc = rtFuzzCmdMasterQueryFuzzRunFromJson(pThis, hJsonRoot, "Id", pErrInfo, &pFuzzRun); 743 if (RT_SUCCESS(rc)) 744 { 745 RTListNodeRemove(&pFuzzRun->NdFuzzed); 746 RTFuzzObsExecStop(pFuzzRun->hFuzzObs); 747 RTFuzzObsDestroy(pFuzzRun->hFuzzObs); 748 RTStrFree(pFuzzRun->pszId); 749 RTMemFree(pFuzzRun); 750 } 751 752 return rc; 753 } 754 755 756 /** 757 * Processes the "SuspendFuzzing" request. 758 * 759 * @returns IPRT status code. 760 * @param pThis The fuzzing master command state. 761 * @param hJsonValRoot The root node of the JSON request. 762 * @param pErrInfo Where to store the error information on failure, optional. 763 */ 764 static int rtFuzzCmdMasterProcessJsonReqSuspend(PRTFUZZCMDMASTER pThis, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo) 765 { 766 PRTFUZZRUN pFuzzRun; 767 int rc = rtFuzzCmdMasterQueryFuzzRunFromJson(pThis, hJsonRoot, "Id", pErrInfo, &pFuzzRun); 768 if (RT_SUCCESS(rc)) 769 { 770 rc = RTFuzzObsExecStop(pFuzzRun->hFuzzObs); 771 if (RT_FAILURE(rc)) 772 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Suspending the fuzzing process failed"); 773 } 774 775 return rc; 776 } 777 778 779 /** 780 * Processes the "ResumeFuzzing" request. 781 * 782 * @returns IPRT status code. 783 * @param pThis The fuzzing master command state. 784 * @param hJsonValRoot The root node of the JSON request. 785 * @param pErrInfo Where to store the error information on failure, optional. 786 */ 787 static int rtFuzzCmdMasterProcessJsonReqResume(PRTFUZZCMDMASTER pThis, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo) 788 { 789 PRTFUZZRUN pFuzzRun; 790 int rc = rtFuzzCmdMasterQueryFuzzRunFromJson(pThis, hJsonRoot, "Id", pErrInfo, &pFuzzRun); 791 if (RT_SUCCESS(rc)) 792 { 793 rc = rtFuzzCmdMasterFuzzRunProcessCfgU32Def(&pFuzzRun->cProcs, "FuzzingProcs", hJsonRoot, pFuzzRun->cProcs, pErrInfo); 794 if (RT_SUCCESS(rc)) 795 { 796 rc = RTFuzzObsExecStart(pFuzzRun->hFuzzObs, pFuzzRun->cProcs); 797 if (RT_FAILURE(rc)) 798 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Resuming the fuzzing process failed"); 799 } 800 } 801 802 return rc; 803 } 804 805 806 /** 807 * Processes the "QueryStats" request. 808 * 809 * @returns IPRT status code. 810 * @param pThis The fuzzing master command state. 811 * @param hJsonValRoot The root node of the JSON request. 812 * @param pErrInfo Where to store the error information on failure, optional. 813 */ 814 static int rtFuzzCmdMasterProcessJsonReqQueryStats(PRTFUZZCMDMASTER pThis, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo) 815 { 816 RT_NOREF(pThis, hJsonRoot, pErrInfo); 817 return VERR_NOT_IMPLEMENTED; 818 } 819 820 821 /** 822 * Processes a JSON request. 823 * 824 * @returns IPRT status code. 825 * @param pThis The fuzzing master command state. 826 * @param hJsonValRoot The root node of the JSON request. 827 * @param pErrInfo Where to store the error information on failure, optional. 828 */ 829 static int rtFuzzCmdMasterProcessJsonReq(PRTFUZZCMDMASTER pThis, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo) 830 { 831 RTJSONVAL hJsonValReq; 832 int rc = RTJsonValueQueryByName(hJsonRoot, "Request", &hJsonValReq); 833 if (RT_SUCCESS(rc)) 834 { 835 const char *pszReq = RTJsonValueGetString(hJsonValReq); 836 if (pszReq) 837 { 838 if (!RTStrCmp(pszReq, "StartFuzzing")) 839 rc = rtFuzzCmdMasterProcessJsonReqStart(pThis, hJsonRoot, pErrInfo); 840 else if (!RTStrCmp(pszReq, "StopFuzzing")) 841 rc = rtFuzzCmdMasterProcessJsonReqStop(pThis, hJsonRoot, pErrInfo); 842 else if (!RTStrCmp(pszReq, "SuspendFuzzing")) 843 rc = rtFuzzCmdMasterProcessJsonReqSuspend(pThis, hJsonRoot, pErrInfo); 844 else if (!RTStrCmp(pszReq, "ResumeFuzzing")) 845 rc = rtFuzzCmdMasterProcessJsonReqResume(pThis, hJsonRoot, pErrInfo); 846 else if (!RTStrCmp(pszReq, "QueryStats")) 847 rc = rtFuzzCmdMasterProcessJsonReqQueryStats(pThis, hJsonRoot, pErrInfo); 848 else if (!RTStrCmp(pszReq, "Shutdown")) 849 pThis->fShutdown = true; 850 else 851 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_JSON_VALUE_INVALID_TYPE, "JSON request malformed: \"Request\" contains unknown value \"%s\"", pszReq); 852 } 853 else 854 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_JSON_VALUE_INVALID_TYPE, "JSON request malformed: \"Request\" is not a string value"); 855 856 RTJsonValueRelease(hJsonValReq); 857 } 858 else 859 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Couldn't find \"Request\" value"); 860 861 return rc; 862 } 863 864 865 /** 866 * Loads a fuzzing configuration for immediate startup from the given file. 867 * 868 * @returns IPRT status code. 869 * @param pThis The fuzzing master command state. 870 * @param pszFuzzCfg The fuzzing config to load. 871 */ 872 static int rtFuzzCmdMasterFuzzCfgLoadFromFile(PRTFUZZCMDMASTER pThis, const char *pszFuzzCfg) 873 { 874 RTJSONVAL hJsonRoot; 875 int rc = RTJsonParseFromFile(&hJsonRoot, pszFuzzCfg, NULL); 876 if (RT_SUCCESS(rc)) 877 { 878 rc = rtFuzzCmdMasterProcessJsonReqStart(pThis, hJsonRoot, NULL); 879 RTJsonValueRelease(hJsonRoot); 880 } 881 else 882 rc = rtFuzzCmdMasterErrorRc(NULL, rc, "JSON request malformed: Couldn't load file \"%s\"", pszFuzzCfg); 883 884 return rc; 885 } 886 887 888 /** 889 * Destroys all running fuzzers for the given master state. 890 * 891 * @returns nothing. 892 * @param pThis The fuzzing master command state. 893 */ 894 static void rtFuzzCmdMasterDestroy(PRTFUZZCMDMASTER pThis) 895 { 896 RT_NOREF(pThis); 897 } 898 899 900 /** 901 * Sends an ACK response to the client. 902 * 903 * @returns nothing. 904 * @param hSocket The socket handle to send the ACK to. 905 */ 906 static void rtFuzzCmdMasterTcpSendAck(RTSOCKET hSocket) 907 { 908 const char s_szSucc[] = "{ \"Status\": \"ACK\" }\n"; 909 RTTcpWrite(hSocket, s_szSucc, sizeof(s_szSucc)); 910 } 911 912 913 /** 914 * Sends an NACK response to the client. 915 * 916 * @returns nothing. 917 * @param hSocket The socket handle to send the ACK to. 918 * @param pErrInfo Optional error information to send along. 919 */ 920 static void rtFuzzCmdMasterTcpSendNAck(RTSOCKET hSocket, PRTERRINFO pErrInfo) 921 { 922 const char s_szFail[] = "{ \"Status\": \"NACK\" }\n"; 923 const char s_szFailInfo[] = "{ \"Status\": \"NACK\"\n \"Information\": \"%s\" }\n"; 924 925 if (pErrInfo) 926 { 927 char szTmp[1024]; 928 ssize_t cchResp = RTStrPrintf2(szTmp, sizeof(szTmp), s_szFailInfo, pErrInfo->pszMsg); 929 if (cchResp > 0) 930 RTTcpWrite(hSocket, szTmp, cchResp); 931 else 932 RTTcpWrite(hSocket, s_szFail, strlen(s_szFail)); 933 } 934 else 935 RTTcpWrite(hSocket, s_szFail, strlen(s_szFail)); 936 } 937 938 939 /** 940 * TCP server serving callback for a single connection. 941 * 942 * @returns IPRT status code. 943 * @param hSocket The socket handle of the connection. 944 * @param pvUser Opaque user data. 945 */ 946 static DECLCALLBACK(int) rtFuzzCmdMasterTcpServe(RTSOCKET hSocket, void *pvUser) 947 { 948 PRTFUZZCMDMASTER pThis = (PRTFUZZCMDMASTER)pvUser; 949 size_t cbReqMax = _32K; 950 size_t cbReq = 0; 951 uint8_t *pbReq = (uint8_t *)RTMemAllocZ(cbReqMax); 952 953 if (RT_LIKELY(pbReq)) 954 { 955 uint8_t *pbCur = pbReq; 956 957 for (;;) 958 { 959 size_t cbThisRead = cbReqMax - cbReq; 960 int rc = RTTcpRead(hSocket, pbCur, cbThisRead, &cbThisRead); 961 if (RT_SUCCESS(rc)) 962 { 963 cbReq += cbThisRead; 964 965 /* Check for a zero terminator marking the end of the request. */ 966 uint8_t *pbEnd = (uint8_t *)memchr(pbCur, 0, cbThisRead); 967 if (pbEnd) 968 { 969 /* Adjust request size, data coming after the zero terminiator is ignored right now. */ 970 cbReq -= cbThisRead - (pbEnd - pbCur) + 1; 971 972 RTJSONVAL hJsonReq; 973 RTERRINFOSTATIC ErrInfo; 974 RTErrInfoInitStatic(&ErrInfo); 975 976 rc = RTJsonParseFromBuf(&hJsonReq, pbReq, cbReq, &ErrInfo.Core); 977 if (RT_SUCCESS(rc)) 978 { 979 rc = rtFuzzCmdMasterProcessJsonReq(pThis, hJsonReq, &ErrInfo.Core); 980 if (RT_SUCCESS(rc)) 981 rtFuzzCmdMasterTcpSendAck(hSocket); 982 else 983 rtFuzzCmdMasterTcpSendNAck(hSocket, &ErrInfo.Core); 984 RTJsonValueRelease(hJsonReq); 985 } 986 else 987 rtFuzzCmdMasterTcpSendNAck(hSocket, &ErrInfo.Core); 988 break; 989 } 990 else if (cbReq == cbReqMax) 991 { 992 /* Try to increase the buffer. */ 993 uint8_t *pbReqNew = (uint8_t *)RTMemRealloc(pbReq, cbReqMax + _32K); 994 if (RT_LIKELY(pbReqNew)) 995 { 996 cbReqMax += _32K; 997 pbReq = pbReqNew; 998 pbCur = pbReq + cbReq; 999 } 1000 else 1001 rtFuzzCmdMasterTcpSendNAck(hSocket, NULL); 127 1002 } 128 1003 else 129 rc = rtFuzzCmdMasterErrorRc(NULL, rc, "Failed to set the specified binary as test program: %Rrc\n", rc);1004 pbCur += cbThisRead; 130 1005 } 131 132 RTFuzzCtxRelease(hFuzzCtx);1006 else 1007 break; 133 1008 } 134 else 135 rc = rtFuzzCmdMasterErrorRc(NULL, rc, "Error obtaining the fuzzing context from the observer: %Rrc\n", rc); 136 137 RTFuzzObsDestroy(hFuzzObs); 138 } 139 else 140 rc = rtFuzzCmdMasterErrorRc(NULL, rc, "Error creating observer instance: %Rrc\n", rc); 141 142 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; 1009 } 1010 else 1011 rtFuzzCmdMasterTcpSendNAck(hSocket, NULL); 1012 1013 if (pbReq) 1014 RTMemFree(pbReq); 1015 1016 return pThis->fShutdown ? VERR_TCP_SERVER_STOP : VINF_SUCCESS; 1017 } 1018 1019 1020 /** 1021 * Mainloop for the fuzzing master. 1022 * 1023 * @returns Process exit code. 1024 * @param pThis The fuzzing master command state. 1025 * @param pszLoadCfg Initial config to load. 1026 */ 1027 static RTEXITCODE rtFuzzCmdMasterRun(PRTFUZZCMDMASTER pThis, const char *pszLoadCfg) 1028 { 1029 if (pszLoadCfg) 1030 { 1031 int rc = rtFuzzCmdMasterFuzzCfgLoadFromFile(pThis, pszLoadCfg); 1032 if (RT_FAILURE(rc)) 1033 return RTEXITCODE_FAILURE; 1034 } 1035 1036 /* Start up the control server. */ 1037 int rc = RTTcpServerCreateEx(NULL, pThis->uPort, &pThis->hTcpSrv); 1038 if (RT_SUCCESS(rc)) 1039 { 1040 do 1041 { 1042 rc = RTTcpServerListen(pThis->hTcpSrv, rtFuzzCmdMasterTcpServe, pThis); 1043 } while (rc != VERR_TCP_SERVER_STOP); 1044 } 1045 1046 RTTcpServerDestroy(pThis->hTcpSrv); 1047 rtFuzzCmdMasterDestroy(pThis); 1048 return RTEXITCODE_SUCCESS; 143 1049 } 144 1050 … … 151 1057 static const RTGETOPTDEF s_aOptions[] = 152 1058 { 153 { "--binary", 'b', RTGETOPT_REQ_STRING }, 154 { "--processes", 'p', RTGETOPT_REQ_UINT32 }, 155 { "--input-as-file", 'f', RTGETOPT_REQ_STRING }, 156 { "--input-seed-file", 'i', RTGETOPT_REQ_STRING }, 157 { "--input-seed-dir", 's', RTGETOPT_REQ_STRING }, 158 { "--input-seed-size-max", 'm', RTGETOPT_REQ_UINT32 }, 1059 { "--fuzz-config", 'c', RTGETOPT_REQ_STRING }, 1060 { "--temp-dir", 't', RTGETOPT_REQ_STRING }, 159 1061 { "--results-dir", 'r', RTGETOPT_REQ_STRING }, 160 { "--args", 'a', RTGETOPT_REQ_STRING }, 1062 { "--listen-port", 'p', RTGETOPT_REQ_UINT16 }, 1063 { "--daemonize", 'd', RTGETOPT_REQ_NOTHING }, 1064 { "--daemonized", 'Z', RTGETOPT_REQ_NOTHING }, 161 1065 { "--help", 'h', RTGETOPT_REQ_NOTHING }, 162 1066 { "--version", 'V', RTGETOPT_REQ_NOTHING }, … … 170 1074 { 171 1075 /* Option variables: */ 172 const char *pszBinary = NULL; 173 uint32_t cProcs = 0; 174 const char *pszInpSeedDir = NULL; 175 int cClientArgs = 0; 176 size_t cbInputMax = 0; 177 char **papszClientArgs = NULL; 178 bool fInputFile = false; 179 const char *pszTmpDir = NULL; 180 const char *pszResultsDir = NULL; 1076 bool fDaemonize = false; 1077 bool fDaemonized = false; 1078 const char *pszLoadCfg = NULL; 1079 RTFUZZCMDMASTER This; 1080 1081 RTListInit(&This.LstFuzzed); 1082 This.hTcpSrv = NIL_RTTCPSERVER; 1083 This.uPort = 4242; 1084 This.pszTmpDir = NULL; 1085 This.pszResultsDir = NULL; 1086 This.fShutdown = false; 181 1087 182 1088 /* Argument parsing loop. */ … … 189 1095 { 190 1096 case 0: 191 rcExit = rtFuzzCmdMasterDoIt(pszBinary, cProcs, pszInpSeedDir, pszResultsDir, cbInputMax,192 papszClientArgs, cClientArgs, fInputFile, pszTmpDir);193 1097 fContinue = false; 194 1098 break; 195 1099 196 case ' b':197 psz Binary= ValueUnion.psz;1100 case 'c': 1101 pszLoadCfg = ValueUnion.psz; 198 1102 break; 199 1103 200 1104 case 'p': 201 cProcs = ValueUnion.u32;1105 This.uPort = ValueUnion.u16; 202 1106 break; 203 1107 204 case 'f': 205 pszTmpDir = ValueUnion.psz; 206 fInputFile = true; 1108 case 't': 1109 This.pszTmpDir = ValueUnion.psz; 207 1110 break; 208 1111 209 1112 case 'r': 210 pszResultsDir = ValueUnion.psz;1113 This.pszResultsDir = ValueUnion.psz; 211 1114 break; 212 1115 213 case ' a':214 rc = RTGetOptArgvFromString(&papszClientArgs, &cClientArgs, ValueUnion.psz, 0, NULL);1116 case 'd': 1117 fDaemonize = true; 215 1118 break; 216 1119 217 case 's': 218 pszInpSeedDir = ValueUnion.psz; 219 break; 220 221 case 'm': 222 cbInputMax = ValueUnion.u32; 1120 case 'Z': 1121 fDaemonized = true; 1122 fDaemonize = false; 223 1123 break; 224 1124 … … 241 1141 } 242 1142 } while (fContinue); 1143 1144 if (rcExit == RTEXITCODE_SUCCESS) 1145 { 1146 /* 1147 * Daemonize ourselves if asked to. 1148 */ 1149 if (fDaemonize) 1150 { 1151 rc = RTProcDaemonize(papszArgs, "--daemonized"); 1152 if (RT_FAILURE(rc)) 1153 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTProcDaemonize: %Rrc\n", rc); 1154 } 1155 else 1156 rcExit = rtFuzzCmdMasterRun(&This, pszLoadCfg); 1157 } 243 1158 } 244 1159 else
Note:
See TracChangeset
for help on using the changeset viewer.