Changeset 72465 in vbox for trunk/src/VBox/Runtime/common
- Timestamp:
- Jun 6, 2018 9:12:23 PM (7 years ago)
- Location:
- trunk/src/VBox/Runtime/common/fuzz
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/fuzz/fuzz-observer.cpp
r72454 r72465 35 35 #include <iprt/assert.h> 36 36 #include <iprt/ctype.h> 37 #include <iprt/dir.h> 37 38 #include <iprt/err.h> 38 39 #include <iprt/env.h> … … 43 44 #include <iprt/path.h> 44 45 #include <iprt/pipe.h> 46 #include <iprt/poll.h> 45 47 #include <iprt/process.h> 46 48 #include <iprt/semaphore.h> … … 49 51 #include <iprt/time.h> 50 52 #include <iprt/thread.h> 53 54 55 /** Poll ID for the reading end of the stdout pipe from the client process. */ 56 #define RTFUZZOBS_EXEC_CTX_POLL_ID_STDOUT 0 57 /** Poll ID for the reading end of the stderr pipe from the client process. */ 58 #define RTFUZZOBS_EXEC_CTX_POLL_ID_STDERR 1 59 /** Poll ID for the writing end of the stdin pipe to the client process. */ 60 #define RTFUZZOBS_EXEC_CTX_POLL_ID_STDIN 2 51 61 52 62 … … 91 101 /** Temp directory for input files. */ 92 102 char *pszTmpDir; 103 /** Results directory. */ 104 char *pszResultsDir; 93 105 /** The binary to run. */ 94 106 char *pszBinary; … … 97 109 /** Number of arguments. */ 98 110 uint32_t cArgs; 111 /** Maximum time to wait for the client to terminate until it is considered hung and killed. */ 112 RTMSINTERVAL msWaitMax; 99 113 /** Flags controlling how the binary is executed. */ 100 114 uint32_t fFlags; … … 114 128 115 129 130 /** 131 * Stdout/Stderr buffer. 132 */ 133 typedef struct RTFUZZOBSSTDOUTERRBUF 134 { 135 /** Current amount buffered. */ 136 size_t cbBuf; 137 /** Maxmium amount to buffer. */ 138 size_t cbBufMax; 139 /** Base pointer to the data buffer. */ 140 uint8_t *pbBase; 141 } RTFUZZOBSSTDOUTERRBUF; 142 /** Pointer to a stdout/stderr buffer. */ 143 typedef RTFUZZOBSSTDOUTERRBUF *PRTFUZZOBSSTDOUTERRBUF; 144 145 146 /** 147 * Worker execution context. 148 */ 149 typedef struct RTFUZZOBSEXECCTX 150 { 151 /** The stdout pipe handle - reading end. */ 152 RTPIPE hPipeStdoutR; 153 /** The stdout pipe handle - writing end. */ 154 RTPIPE hPipeStdoutW; 155 /** The stderr pipe handle - reading end. */ 156 RTPIPE hPipeStderrR; 157 /** The stderr pipe handle - writing end. */ 158 RTPIPE hPipeStderrW; 159 /** The stdin pipe handle - reading end. */ 160 RTPIPE hPipeStdinR; 161 /** The stind pipe handle - writing end. */ 162 RTPIPE hPipeStdinW; 163 /** The stdout handle. */ 164 RTHANDLE StdoutHandle; 165 /** The stderr handle. */ 166 RTHANDLE StderrHandle; 167 /** The stdin handle. */ 168 RTHANDLE StdinHandle; 169 /** The pollset to monitor. */ 170 RTPOLLSET hPollSet; 171 /** The process to monitor. */ 172 RTPROCESS hProc; 173 /** Execution time of the process. */ 174 RTMSINTERVAL msExec; 175 /** Current input data pointer. */ 176 uint8_t *pbInputCur; 177 /** Number of bytes left for the input. */ 178 size_t cbInputLeft; 179 /** The stdout data buffer. */ 180 RTFUZZOBSSTDOUTERRBUF StdOutBuf; 181 /** The stderr data buffer. */ 182 RTFUZZOBSSTDOUTERRBUF StdErrBuf; 183 /** Modified arguments vector - variable in size. */ 184 char *apszArgs[1]; 185 } RTFUZZOBSEXECCTX; 186 /** Pointer to an execution context. */ 187 typedef RTFUZZOBSEXECCTX *PRTFUZZOBSEXECCTX; 188 /** Pointer to an execution context pointer. */ 189 typedef PRTFUZZOBSEXECCTX *PPRTFUZZOBSEXECCTX; 190 191 192 /** 193 * A variable descriptor. 194 */ 195 typedef struct RTFUZZOBSVARIABLE 196 { 197 /** The variable. */ 198 const char *pszVar; 199 /** Length of the variable in characters - excluding the terminator. */ 200 uint32_t cchVar; 201 /** The replacement value. */ 202 const char *pszVal; 203 } RTFUZZOBSVARIABLE; 204 /** Pointer to a variable descriptor. */ 205 typedef RTFUZZOBSVARIABLE *PRTFUZZOBSVARIABLE; 206 207 208 /** 209 * Initializes the given stdout/stderr buffer. 210 * 211 * @returns nothing. 212 * @param pBuf The buffer to initialize. 213 */ 214 static void rtFuzzObsStdOutErrBufInit(PRTFUZZOBSSTDOUTERRBUF pBuf) 215 { 216 pBuf->cbBuf = 0; 217 pBuf->cbBufMax = 0; 218 pBuf->pbBase = NULL; 219 } 220 221 222 /** 223 * Frees all allocated resources in the given stdout/stderr buffer. 224 * 225 * @returns nothing. 226 * @param pBuf The buffer to free. 227 */ 228 static void rtFuzzObsStdOutErrBufFree(PRTFUZZOBSSTDOUTERRBUF pBuf) 229 { 230 if (pBuf->pbBase) 231 RTMemFree(pBuf->pbBase); 232 } 233 234 235 /** 236 * Clears the given stdout/stderr buffer. 237 * 238 * @returns nothing. 239 * @param pBuf The buffer to clear. 240 */ 241 static void rtFuzzObsStdOutErrBufClear(PRTFUZZOBSSTDOUTERRBUF pBuf) 242 { 243 pBuf->cbBuf = 0; 244 } 245 246 247 /** 248 * Fills the given stdout/stderr buffer from the given pipe. 249 * 250 * @returns IPRT status code. 251 * @param pBuf The buffer to fill. 252 * @param hPipeRead The pipe to read from. 253 */ 254 static int rtFuzzObsStdOutErrBufFill(PRTFUZZOBSSTDOUTERRBUF pBuf, RTPIPE hPipeRead) 255 { 256 int rc = VINF_SUCCESS; 257 258 size_t cbRead = 0; 259 size_t cbThisRead = 0; 260 do 261 { 262 cbThisRead = pBuf->cbBufMax - pBuf->cbBuf; 263 if (!cbThisRead) 264 { 265 /* Try to increase the buffer. */ 266 uint8_t *pbNew = (uint8_t *)RTMemRealloc(pBuf->pbBase, pBuf->cbBufMax + _4K); 267 if (RT_LIKELY(pbNew)) 268 { 269 pBuf->cbBufMax += _4K; 270 pBuf->pbBase = pbNew; 271 } 272 cbThisRead = pBuf->cbBufMax - pBuf->cbBuf; 273 } 274 275 if (cbThisRead) 276 { 277 rc = RTPipeRead(hPipeRead, pBuf->pbBase + pBuf->cbBuf, cbThisRead, &cbRead); 278 if (RT_SUCCESS(rc)) 279 pBuf->cbBuf += cbRead; 280 } 281 else 282 rc = VERR_NO_MEMORY; 283 } while ( RT_SUCCESS(rc) 284 && cbRead == cbThisRead); 285 286 return rc; 287 } 288 289 290 /** 291 * Writes the given stdout/stderr buffer to the given filename. 292 * 293 * @returns IPRT status code. 294 * @param pBuf The buffer to write. 295 * @param pszFilename The filename to write the buffer to. 296 */ 297 static int rtFuzzStdOutErrBufWriteToFile(PRTFUZZOBSSTDOUTERRBUF pBuf, const char *pszFilename) 298 { 299 RTFILE hFile; 300 int rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE); 301 if (RT_SUCCESS(rc)) 302 { 303 rc = RTFileWrite(hFile, pBuf->pbBase, pBuf->cbBuf, NULL); 304 AssertRC(rc); 305 RTFileClose(hFile); 306 307 if (RT_FAILURE(rc)) 308 RTFileDelete(pszFilename); 309 } 310 311 return rc; 312 } 313 314 315 /** 316 * Replaces a variable with its value. 317 * 318 * @returns VINF_SUCCESS or VERR_NO_STR_MEMORY. 319 * @param ppszNew In/Out. 320 * @param pcchNew In/Out. (Messed up on failure.) 321 * @param offVar Variable offset. 322 * @param cchVar Variable length. 323 * @param pszValue The value. 324 * @param cchValue Value length. 325 */ 326 static int rtFuzzObsReplaceStringVariable(char **ppszNew, size_t *pcchNew, size_t offVar, size_t cchVar, 327 const char *pszValue, size_t cchValue) 328 { 329 size_t const cchAfter = *pcchNew - offVar - cchVar; 330 if (cchVar < cchValue) 331 { 332 *pcchNew += cchValue - cchVar; 333 int rc = RTStrRealloc(ppszNew, *pcchNew + 1); 334 if (RT_FAILURE(rc)) 335 return rc; 336 } 337 338 char *pszNew = *ppszNew; 339 memmove(&pszNew[offVar + cchValue], &pszNew[offVar + cchVar], cchAfter + 1); 340 memcpy(&pszNew[offVar], pszValue, cchValue); 341 return VINF_SUCCESS; 342 } 343 344 345 /** 346 * Replace the variables found in the source string, returning a new string that 347 * lives on the string heap. 348 * 349 * @returns IPRT status code. 350 * @param pszSrc The source string. 351 * @param paVars Pointer to the array of known variables. 352 * @param ppszNew Where to return the new string. 353 */ 354 static int rtFuzzObsReplaceStringVariables(const char *pszSrc, PRTFUZZOBSVARIABLE paVars, char **ppszNew) 355 { 356 /* Lazy approach that employs memmove. */ 357 int rc = VINF_SUCCESS; 358 size_t cchNew = strlen(pszSrc); 359 char *pszNew = RTStrDup(pszSrc); 360 361 if (paVars) 362 { 363 char *pszDollar = pszNew; 364 while ((pszDollar = strchr(pszDollar, '$')) != NULL) 365 { 366 if (pszDollar[1] == '{') 367 { 368 const char *pszEnd = strchr(&pszDollar[2], '}'); 369 if (pszEnd) 370 { 371 size_t const cchVar = pszEnd - pszDollar + 1; /* includes "${}" */ 372 size_t offDollar = pszDollar - pszNew; 373 PRTFUZZOBSVARIABLE pVar = paVars; 374 while (pVar->pszVar != NULL) 375 { 376 if ( cchVar == pVar->cchVar 377 && !memcmp(pszDollar, pVar->pszVar, cchVar)) 378 { 379 size_t const cchValue = strlen(pVar->pszVal); 380 rc = rtFuzzObsReplaceStringVariable(&pszNew, &cchNew, offDollar, 381 cchVar, pVar->pszVal, cchValue); 382 offDollar += cchValue; 383 break; 384 } 385 386 pVar++; 387 } 388 389 pszDollar = &pszNew[offDollar]; 390 391 if (RT_FAILURE(rc)) 392 { 393 RTStrFree(pszNew); 394 *ppszNew = NULL; 395 return rc; 396 } 397 } 398 } 399 } 400 } 401 402 *ppszNew = pszNew; 403 return rc; 404 } 405 406 /** 407 * Prepares the argument vector for the child process. 408 * 409 * @returns IPRT status code. 410 * @param pThis The internal fuzzing observer state. 411 * @param pExecCtx The execution context to prepare the argument vector for. 412 * @param paVars Pointer to the array of known variables. 413 */ 414 static int rtFuzzObsExecCtxArgvPrepare(PRTFUZZOBSINT pThis, PRTFUZZOBSEXECCTX pExecCtx, PRTFUZZOBSVARIABLE paVars) 415 { 416 int rc = VINF_SUCCESS; 417 for (unsigned i = 0; i < pThis->cArgs && RT_SUCCESS(rc); i++) 418 rc = rtFuzzObsReplaceStringVariables(pThis->papszArgs[i], paVars, &pExecCtx->apszArgs[i]); 419 420 return rc; 421 } 422 423 424 /** 425 * Creates a new execution context. 426 * 427 * @returns IPRT status code. 428 * @param ppExecCtx Where to store the pointer to the execution context on success. 429 * @param pThis The internal fuzzing observer state. 430 */ 431 static int rtFuzzObsExecCtxCreate(PPRTFUZZOBSEXECCTX ppExecCtx, PRTFUZZOBSINT pThis) 432 { 433 int rc = VINF_SUCCESS; 434 PRTFUZZOBSEXECCTX pExecCtx = (PRTFUZZOBSEXECCTX)RTMemAllocZ(RT_OFFSETOF(RTFUZZOBSEXECCTX, apszArgs[pThis->cArgs + 1])); 435 if (RT_LIKELY(pExecCtx)) 436 { 437 pExecCtx->hPipeStdoutR = NIL_RTPIPE; 438 pExecCtx->hPipeStdoutW = NIL_RTPIPE; 439 pExecCtx->hPipeStderrR = NIL_RTPIPE; 440 pExecCtx->hPipeStderrW = NIL_RTPIPE; 441 pExecCtx->hPipeStdinR = NIL_RTPIPE; 442 pExecCtx->hPipeStdinW = NIL_RTPIPE; 443 pExecCtx->hPollSet = NIL_RTPOLLSET; 444 pExecCtx->hProc = NIL_RTPROCESS; 445 pExecCtx->msExec = 0; 446 rtFuzzObsStdOutErrBufInit(&pExecCtx->StdOutBuf); 447 rtFuzzObsStdOutErrBufInit(&pExecCtx->StdErrBuf); 448 449 rc = RTPollSetCreate(&pExecCtx->hPollSet); 450 if (RT_SUCCESS(rc)) 451 { 452 rc = RTPipeCreate(&pExecCtx->hPipeStdoutR, &pExecCtx->hPipeStdoutW, RTPIPE_C_INHERIT_WRITE); 453 if (RT_SUCCESS(rc)) 454 { 455 RTHANDLE Handle; 456 Handle.enmType = RTHANDLETYPE_PIPE; 457 Handle.u.hPipe = pExecCtx->hPipeStdoutR; 458 rc = RTPollSetAdd(pExecCtx->hPollSet, &Handle, RTPOLL_EVT_READ, RTFUZZOBS_EXEC_CTX_POLL_ID_STDOUT); 459 AssertRC(rc); 460 461 rc = RTPipeCreate(&pExecCtx->hPipeStderrR, &pExecCtx->hPipeStderrW, RTPIPE_C_INHERIT_WRITE); 462 if (RT_SUCCESS(rc)) 463 { 464 Handle.u.hPipe = pExecCtx->hPipeStderrR; 465 rc = RTPollSetAdd(pExecCtx->hPollSet, &Handle, RTPOLL_EVT_READ, RTFUZZOBS_EXEC_CTX_POLL_ID_STDERR); 466 AssertRC(rc); 467 468 /* Create the stdin pipe handles if not a file input. */ 469 if (!(pThis->fFlags & RTFUZZ_OBS_BINARY_F_INPUT_FILE)) 470 { 471 rc = RTPipeCreate(&pExecCtx->hPipeStdinR, &pExecCtx->hPipeStdinW, RTPIPE_C_INHERIT_READ); 472 if (RT_SUCCESS(rc)) 473 { 474 pExecCtx->StdinHandle.enmType = RTHANDLETYPE_PIPE; 475 pExecCtx->StdinHandle.u.hPipe = pExecCtx->hPipeStdinR; 476 477 Handle.u.hPipe = pExecCtx->hPipeStdinW; 478 rc = RTPollSetAdd(pExecCtx->hPollSet, &Handle, RTPOLL_EVT_WRITE, RTFUZZOBS_EXEC_CTX_POLL_ID_STDIN); 479 AssertRC(rc); 480 } 481 } 482 else 483 { 484 pExecCtx->StdinHandle.enmType = RTHANDLETYPE_PIPE; 485 pExecCtx->StdinHandle.u.hPipe = NIL_RTPIPE; 486 } 487 488 if (RT_SUCCESS(rc)) 489 { 490 pExecCtx->StdoutHandle.enmType = RTHANDLETYPE_PIPE; 491 pExecCtx->StdoutHandle.u.hPipe = pExecCtx->hPipeStdoutW; 492 pExecCtx->StderrHandle.enmType = RTHANDLETYPE_PIPE; 493 pExecCtx->StderrHandle.u.hPipe = pExecCtx->hPipeStderrW; 494 *ppExecCtx = pExecCtx; 495 return VINF_SUCCESS; 496 } 497 498 RTPipeClose(pExecCtx->hPipeStderrR); 499 RTPipeClose(pExecCtx->hPipeStderrW); 500 } 501 502 RTPipeClose(pExecCtx->hPipeStdoutR); 503 RTPipeClose(pExecCtx->hPipeStdoutW); 504 } 505 506 RTPollSetDestroy(pExecCtx->hPollSet); 507 } 508 509 RTMemFree(pExecCtx); 510 } 511 else 512 rc = VERR_NO_MEMORY; 513 514 return rc; 515 } 516 517 518 /** 519 * Destroys the given execution context. 520 * 521 * @returns nothing. 522 * @param pThis The internal fuzzing observer state. 523 * @param pExecCtx The execution context to destroy. 524 */ 525 static void rtFuzzObsExecCtxDestroy(PRTFUZZOBSINT pThis, PRTFUZZOBSEXECCTX pExecCtx) 526 { 527 RTPipeClose(pExecCtx->hPipeStdoutR); 528 RTPipeClose(pExecCtx->hPipeStdoutW); 529 RTPipeClose(pExecCtx->hPipeStderrR); 530 RTPipeClose(pExecCtx->hPipeStderrW); 531 532 if (!(pThis->fFlags & RTFUZZ_OBS_BINARY_F_INPUT_FILE)) 533 { 534 RTPipeClose(pExecCtx->hPipeStdinR); 535 RTPipeClose(pExecCtx->hPipeStdinW); 536 } 537 538 RTPollSetDestroy(pExecCtx->hPollSet); 539 char **ppszArg = &pExecCtx->apszArgs[0]; 540 while (*ppszArg != NULL) 541 { 542 RTStrFree(*ppszArg); 543 ppszArg++; 544 } 545 546 rtFuzzObsStdOutErrBufFree(&pExecCtx->StdOutBuf); 547 rtFuzzObsStdOutErrBufFree(&pExecCtx->StdErrBuf); 548 RTMemFree(pExecCtx); 549 } 550 551 552 /** 553 * Runs the client binary pumping all data back and forth waiting for the client to finish. 554 * 555 * @returns IPRT status code. 556 * @retval VERR_TIMEOUT if the client didn't finish in the given deadline and was killed. 557 * @param pThis The internal fuzzing observer state. 558 * @param pExecCtx The execution context. 559 * @param pProcStat Where to store the process exit status on success. 560 */ 561 static int rtFuzzObsExecCtxClientRun(PRTFUZZOBSINT pThis, PRTFUZZOBSEXECCTX pExecCtx, PRTPROCSTATUS pProcStat) 562 { 563 rtFuzzObsStdOutErrBufClear(&pExecCtx->StdOutBuf); 564 rtFuzzObsStdOutErrBufClear(&pExecCtx->StdErrBuf); 565 566 int rc = RTProcCreateEx(pThis->pszBinary, &pExecCtx->apszArgs[0], RTENV_DEFAULT, 0 /*fFlags*/, &pExecCtx->StdinHandle, 567 &pExecCtx->StdoutHandle, &pExecCtx->StderrHandle, NULL, NULL, &pExecCtx->hProc); 568 if (RT_SUCCESS(rc)) 569 { 570 uint64_t tsMilliesStart = RTTimeSystemMilliTS(); 571 for (;;) 572 { 573 /* Wait a bit for something to happen on one of the pipes. */ 574 uint32_t fEvtsRecv = 0; 575 uint32_t idEvt = 0; 576 rc = RTPoll(pExecCtx->hPollSet, 10 /*cMillies*/, &fEvtsRecv, &idEvt); 577 if (RT_SUCCESS(rc)) 578 { 579 if (idEvt == RTFUZZOBS_EXEC_CTX_POLL_ID_STDOUT) 580 { 581 Assert(fEvtsRecv & RTPOLL_EVT_READ); 582 rc = rtFuzzObsStdOutErrBufFill(&pExecCtx->StdOutBuf, pExecCtx->hPipeStdoutR); 583 AssertRC(rc); 584 } 585 else if (idEvt == RTFUZZOBS_EXEC_CTX_POLL_ID_STDERR) 586 { 587 Assert(fEvtsRecv & RTPOLL_EVT_READ); 588 rc = rtFuzzObsStdOutErrBufFill(&pExecCtx->StdErrBuf, pExecCtx->hPipeStderrR); 589 AssertRC(rc); 590 } 591 else if (idEvt == RTFUZZOBS_EXEC_CTX_POLL_ID_STDIN) 592 { 593 /* Feed the next input. */ 594 Assert(fEvtsRecv & RTPOLL_EVT_WRITE); 595 size_t cbWritten = 0; 596 rc = RTPipeWrite(pExecCtx->hPipeStdinW, pExecCtx->pbInputCur, pExecCtx->cbInputLeft, &cbWritten); 597 if (RT_SUCCESS(rc)) 598 { 599 pExecCtx->cbInputLeft -= cbWritten; 600 if (!pExecCtx->cbInputLeft) 601 { 602 /* Close stdin pipe. */ 603 rc = RTPollSetRemove(pExecCtx->hPollSet, RTFUZZOBS_EXEC_CTX_POLL_ID_STDIN); 604 AssertRC(rc); 605 RTPipeClose(pExecCtx->hPipeStdinW); 606 } 607 } 608 } 609 else 610 AssertMsgFailed(("Invalid poll ID returned: %u!\n", idEvt)); 611 } 612 else 613 Assert(rc == VERR_TIMEOUT); 614 615 /* Check the process status. */ 616 rc = RTProcWait(pExecCtx->hProc, RTPROCWAIT_FLAGS_NOBLOCK, pProcStat); 617 if (RT_SUCCESS(rc)) 618 break; 619 else 620 { 621 Assert(rc == VERR_PROCESS_RUNNING); 622 /* Check whether we reached the limit. */ 623 if (RTTimeSystemMilliTS() - tsMilliesStart > pThis->msWaitMax) 624 { 625 rc = VERR_TIMEOUT; 626 break; 627 } 628 } 629 } /* for (;;) */ 630 631 /* Kill the process on a timeout. */ 632 if (rc == VERR_TIMEOUT) 633 { 634 int rc2 = RTProcTerminate(pExecCtx->hProc); 635 AssertRC(rc2); 636 } 637 } 638 639 return rc; 640 } 641 642 643 /** 644 * Adds the input to the results directory. 645 * 646 * @returns IPRT status code. 647 * @param pThis The internal fuzzing observer state. 648 * @param hFuzzInput Fuzzing input handle to write. 649 * @param pExecCtx Execution context. 650 */ 651 static int rtFuzzObsAddInputToResults(PRTFUZZOBSINT pThis, RTFUZZINPUT hFuzzInput, PRTFUZZOBSEXECCTX pExecCtx) 652 { 653 char aszDigest[RTMD5_STRING_LEN + 1]; 654 int rc = RTFuzzInputQueryDigestString(hFuzzInput, &aszDigest[0], sizeof(aszDigest)); 655 if (RT_SUCCESS(rc)) 656 { 657 /* Create a directory. */ 658 char szPath[RTPATH_MAX]; 659 rc = RTPathJoin(szPath, sizeof(szPath), pThis->pszResultsDir, &aszDigest[0]); 660 AssertRC(rc); 661 662 rc = RTDirCreate(&szPath[0], 0700, 0 /*fCreate*/); 663 if (RT_SUCCESS(rc)) 664 { 665 /* Write the input. */ 666 char szTmp[RTPATH_MAX]; 667 rc = RTPathJoin(szTmp, sizeof(szTmp), &szPath[0], "input"); 668 AssertRC(rc); 669 670 rc = RTFuzzInputWriteToFile(hFuzzInput, &szTmp[0]); 671 if (RT_SUCCESS(rc)) 672 { 673 /* Stdout and Stderr. */ 674 rc = RTPathJoin(szTmp, sizeof(szTmp), &szPath[0], "stdout"); 675 AssertRC(rc); 676 rc = rtFuzzStdOutErrBufWriteToFile(&pExecCtx->StdOutBuf, &szTmp[0]); 677 if (RT_SUCCESS(rc)) 678 { 679 rc = RTPathJoin(szTmp, sizeof(szTmp), &szPath[0], "stderr"); 680 AssertRC(rc); 681 rc = rtFuzzStdOutErrBufWriteToFile(&pExecCtx->StdOutBuf, &szTmp[0]); 682 } 683 } 684 } 685 } 686 687 return rc; 688 } 689 116 690 117 691 /** … … 119 693 * 120 694 * @returns IPRT status code. 121 * @param hThr ead The thread handle.695 * @param hThrd The thread handle. 122 696 * @param pvUser Opaque user data. 123 697 */ 124 static DECLCALLBACK(int) rtFuzzObsWorkerLoop(RTTHREAD hThr ead, void *pvUser)698 static DECLCALLBACK(int) rtFuzzObsWorkerLoop(RTTHREAD hThrd, void *pvUser) 125 699 { 126 700 PRTFUZZOBSTHRD pObsThrd = (PRTFUZZOBSTHRD)pvUser; 127 701 PRTFUZZOBSINT pThis = pObsThrd->pFuzzObs; 128 char **papszArgs = NULL; 129 RTHANDLE NilHandle; 130 NilHandle.enmType = RTHANDLETYPE_PIPE; 131 NilHandle.u.hPipe = NIL_RTPIPE; 132 133 if (!(pThis->fFlags & RTFUZZ_OBS_BINARY_F_INPUT_FILE)) 134 { 135 papszArgs = (char **)RTMemAllocZ((pThis->cArgs + 1) * sizeof(char *)); 136 if (RT_LIKELY(papszArgs)) 137 { 138 for (uint32_t i = 0; i < pThis->cArgs; i++) 139 papszArgs[i] = pThis->papszArgs[i]; 140 } 141 } 142 else 143 papszArgs = pThis->papszArgs; 702 PRTFUZZOBSEXECCTX pExecCtx = NULL; 703 704 int rc = rtFuzzObsExecCtxCreate(&pExecCtx, pThis); 705 if (RT_FAILURE(rc)) 706 return rc; 144 707 145 708 while (!pObsThrd->fShutdown) 146 709 { 710 char szInput[RTPATH_MAX]; 711 147 712 /* Wait for work. */ 148 int rc = RTThreadUserWait(hThread, RT_INDEFINITE_WAIT);713 rc = RTThreadUserWait(hThrd, RT_INDEFINITE_WAIT); 149 714 AssertRC(rc); 150 715 … … 152 717 break; 153 718 154 bool f = ASMAtomicXchgBool(&pObsThrd->fNewInput, false); 155 if (!f) 719 if (!ASMAtomicXchgBool(&pObsThrd->fNewInput, false)) 156 720 continue; 157 721 158 722 AssertPtr(pObsThrd->hFuzzInput); 159 723 160 /* Create the stdout/stderr pipe. */ 161 RTPIPE hPipeStdOutErrR; 162 RTPIPE hPipeStdOutErrW; 163 rc = RTPipeCreate(&hPipeStdOutErrR, &hPipeStdOutErrW, RTPIPE_C_INHERIT_WRITE); 724 if (pThis->fFlags & RTFUZZ_OBS_BINARY_F_INPUT_FILE) 725 { 726 char szFilename[32]; 727 728 ssize_t cbBuf = RTStrPrintf2(&szFilename[0], sizeof(szFilename), "%u", pObsThrd->idObs); 729 Assert(cbBuf > 0); RT_NOREF(cbBuf); 730 731 RT_ZERO(szInput); 732 rc = RTPathJoin(szInput, sizeof(szInput), pThis->pszTmpDir, &szFilename[0]); 733 AssertRC(rc); 734 735 rc = RTFuzzInputWriteToFile(pObsThrd->hFuzzInput, &szInput[0]); 736 if (RT_SUCCESS(rc)) 737 { 738 RTFUZZOBSVARIABLE aVar[2] = { 739 { "${INPUT}", sizeof("${INPUT}") - 1, &szInput[0] }, 740 { NULL, 0, NULL } 741 }; 742 rc = rtFuzzObsExecCtxArgvPrepare(pThis, pExecCtx, &aVar[0]); 743 } 744 } 745 else 746 { 747 rc = RTFuzzInputQueryData(pObsThrd->hFuzzInput, (void **)&pExecCtx->pbInputCur, &pExecCtx->cbInputLeft); 748 if (RT_SUCCESS(rc)) 749 rc = rtFuzzObsExecCtxArgvPrepare(pThis, pExecCtx, NULL); 750 } 751 164 752 if (RT_SUCCESS(rc)) 165 753 { 166 RTHANDLE HandleStdOutErr; 167 HandleStdOutErr.enmType = RTHANDLETYPE_PIPE; 168 HandleStdOutErr.u.hPipe = hPipeStdOutErrW; 754 RTPROCSTATUS ProcSts; 755 rc = rtFuzzObsExecCtxClientRun(pThis, pExecCtx, &ProcSts); 756 if (RT_SUCCESS(rc)) 757 { 758 if (ProcSts.enmReason != RTPROCEXITREASON_NORMAL) 759 rc = rtFuzzObsAddInputToResults(pThis, pObsThrd->hFuzzInput, pExecCtx); 760 } 761 else if (rc == VERR_TIMEOUT) 762 rc = rtFuzzObsAddInputToResults(pThis, pObsThrd->hFuzzInput, pExecCtx); 763 else 764 AssertFailed(); 169 765 170 766 if (pThis->fFlags & RTFUZZ_OBS_BINARY_F_INPUT_FILE) 171 { 172 char szInput[RTPATH_MAX]; 173 char szDigest[RTMD5_STRING_LEN + 1]; 174 char szFilename[sizeof(szDigest) + 32]; 175 176 rc = RTFuzzInputQueryDigestString(pObsThrd->hFuzzInput, &szDigest[0], sizeof(szDigest)); 177 AssertRC(rc); 178 179 ssize_t cbBuf = RTStrPrintf2(&szFilename[0], sizeof(szFilename), "%u-%s", pObsThrd->idObs, &szDigest[0]); 180 Assert(cbBuf > 0); RT_NOREF(cbBuf); 181 182 RT_ZERO(szInput); 183 rc = RTPathJoin(szInput, sizeof(szInput), pThis->pszTmpDir, &szFilename[0]); 184 AssertRC(rc); 185 186 rc = RTFuzzInputWriteToFile(pObsThrd->hFuzzInput, &szInput[0]); 187 if (RT_SUCCESS(rc)) 188 { 189 papszArgs[pThis->cArgs - 1] = &szInput[0]; 190 191 RTPROCESS hProc = NIL_RTPROCESS; 192 rc = RTProcCreateEx(pThis->pszBinary, papszArgs, RTENV_DEFAULT, 0 /*fFlags*/, &NilHandle, 193 NULL, NULL, NULL, NULL, &hProc); 194 if (RT_SUCCESS(rc)) 195 { 196 RTPipeClose(hPipeStdOutErrW); 197 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND }; 198 rc = RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus); 199 if (RT_SUCCESS(rc)) 200 { 201 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL) 202 { 203 pObsThrd->fKeepInput = true; 204 RTPrintf("Abnormal exit detected!\n"); 205 } 206 else 207 { 208 /* 209 * Fuzzed inputs are only added if the client signalled a success in parsing the input. 210 * Inputs which lead to errors are not added because it is assumed that the target 211 * successfully verified the input data. 212 */ 213 //if (ProcStatus.iStatus == RTEXITCODE_SUCCESS) 214 // pObsThrd->fKeepInput = true; 215 } 216 } 217 else 218 AssertFailed(); 219 } 220 else 221 AssertFailed(); 222 223 rc = RTFileDelete(&szInput[0]); 224 AssertRC(rc); 225 } 226 else 227 AssertFailed(); 228 } 229 else 230 { 231 RTPIPE hPipeR; 232 RTPIPE hPipeW; 233 rc = RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_READ); 234 if (RT_SUCCESS(rc)) 235 { 236 RTPROCESS hProc = NIL_RTPROCESS; 237 RTHANDLE Handle; 238 Handle.enmType = RTHANDLETYPE_PIPE; 239 Handle.u.hPipe = hPipeR; 240 rc = RTProcCreateEx(pThis->pszBinary, papszArgs, RTENV_DEFAULT, 0 /*fFlags*/, &Handle, 241 &HandleStdOutErr, &HandleStdOutErr, NULL, NULL, &hProc); 242 if (RT_SUCCESS(rc)) 243 { 244 /* Pump the input data. */ 245 RTPipeClose(hPipeStdOutErrW); 246 247 uint8_t *pbInput; 248 size_t cbInput; 249 rc = RTFuzzInputQueryData(pObsThrd->hFuzzInput, (void **)&pbInput, &cbInput); 250 if (RT_SUCCESS(rc)) 251 { 252 rc = RTPipeWriteBlocking(hPipeW, pbInput, cbInput, NULL); 253 RTPipeClose(hPipeW); 254 255 RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND }; 256 rc = RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus); 257 if (RT_SUCCESS(rc)) 258 { 259 if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL) 260 { 261 pObsThrd->fKeepInput = true; 262 RTPrintf("Abnormal exit detected!\n"); 263 } 264 else 265 { 266 /* 267 * Fuzzed inputs are only added if the client signalled a success in parsing the input. 268 * Inputs which lead to errors are not added because it is assumed that the target 269 * successfully verified the input data. 270 */ 271 if (ProcStatus.iStatus == RTEXITCODE_SUCCESS) 272 pObsThrd->fKeepInput = true; 273 } 274 } 275 } 276 } 277 278 RTPipeClose(hPipeW); 279 } 280 } 281 282 RTPipeClose(hPipeStdOutErrR); 283 } 284 else 285 AssertFailed(); 767 RTFileDelete(&szInput[0]); 768 } 286 769 287 770 ASMAtomicBitSet(&pThis->bmEvt, pObsThrd->idObs); … … 289 772 } 290 773 774 rtFuzzObsExecCtxDestroy(pThis, pExecCtx); 291 775 return VINF_SUCCESS; 292 776 } … … 443 927 if (RT_LIKELY(pThis)) 444 928 { 445 pThis->pszBinary = NULL; 446 pThis->papszArgs = NULL; 447 pThis->fFlags = 0; 929 pThis->pszBinary = NULL; 930 pThis->papszArgs = NULL; 931 pThis->fFlags = 0; 932 pThis->msWaitMax = 1000; 448 933 pThis->hThreadGlobal = NIL_RTTHREAD; 449 pThis->hEvtGlobal = NIL_RTSEMEVENT;450 pThis->bmEvt = 0;451 pThis->cThreads = 0;934 pThis->hEvtGlobal = NIL_RTSEMEVENT; 935 pThis->bmEvt = 0; 936 pThis->cThreads = 0; 452 937 pThis->paObsThreads = NULL; 453 938 rc = RTFuzzCtxCreate(&pThis->hFuzzCtx); … … 503 988 RTSemEventDestroy(pThis->hEvtGlobal); 504 989 990 if (pThis->pszResultsDir) 991 RTStrFree(pThis->pszResultsDir); 992 if (pThis->pszTmpDir) 993 RTStrFree(pThis->pszTmpDir); 505 994 if (pThis->pszBinary) 506 995 RTStrFree(pThis->pszBinary); … … 532 1021 pThis->pszTmpDir = RTStrDup(pszTmp); 533 1022 if (!pThis->pszTmpDir) 1023 rc = VERR_NO_STR_MEMORY; 1024 return rc; 1025 } 1026 1027 1028 RTDECL(int) RTFuzzObsSetResultDirectory(RTFUZZOBS hFuzzObs, const char *pszResults) 1029 { 1030 PRTFUZZOBSINT pThis = hFuzzObs; 1031 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 1032 AssertPtrReturn(pszResults, VERR_INVALID_POINTER); 1033 1034 int rc = VINF_SUCCESS; 1035 pThis->pszResultsDir = RTStrDup(pszResults); 1036 if (!pThis->pszResultsDir) 534 1037 rc = VERR_NO_STR_MEMORY; 535 1038 return rc; -
trunk/src/VBox/Runtime/common/fuzz/fuzzmastercmd.cpp
r72454 r72465 71 71 */ 72 72 static RTEXITCODE rtFuzzCmdMasterDoIt(const char *pszBinary, uint32_t cProcs, const char *pszInpSeedDir, 73 size_t cbInputMax, const char * const *papszClientArgs, unsigned cClientArgs,74 bool fInputFile, const char *pszTmpDir)73 const char *pszResultsDir, size_t cbInputMax, const char * const *papszClientArgs, 74 unsigned cClientArgs, bool fInputFile, const char *pszTmpDir) 75 75 { 76 76 RTFUZZOBS hFuzzObs; … … 93 93 94 94 if (RT_SUCCESS(rc)) 95 rc = RTFuzzObsSet TestBinary(hFuzzObs, pszBinary, fFlags);95 rc = RTFuzzObsSetResultDirectory(hFuzzObs, pszResultsDir); 96 96 if (RT_SUCCESS(rc)) 97 97 { 98 rc = RTFuzzObsSetTestBinary Args(hFuzzObs, papszClientArgs, cClientArgs);98 rc = RTFuzzObsSetTestBinary(hFuzzObs, pszBinary, fFlags); 99 99 if (RT_SUCCESS(rc)) 100 100 { 101 rc = RTFuzz CtxCfgSetInputSeedMaximum(hFuzzCtx, cbInputMax);101 rc = RTFuzzObsSetTestBinaryArgs(hFuzzObs, papszClientArgs, cClientArgs); 102 102 if (RT_SUCCESS(rc)) 103 103 { 104 rc = RTFuzzCtxC orpusInputAddFromDirPath(hFuzzCtx, pszInpSeedDir);104 rc = RTFuzzCtxCfgSetInputSeedMaximum(hFuzzCtx, cbInputMax); 105 105 if (RT_SUCCESS(rc)) 106 106 { 107 rc = RTFuzz ObsExecStart(hFuzzObs, cProcs);107 rc = RTFuzzCtxCorpusInputAddFromDirPath(hFuzzCtx, pszInpSeedDir); 108 108 if (RT_SUCCESS(rc)) 109 109 { 110 RTThreadSleep(3600 * RT_MS_1SEC); 111 RTFuzzObsExecStop(hFuzzObs); 110 rc = RTFuzzObsExecStart(hFuzzObs, cProcs); 111 if (RT_SUCCESS(rc)) 112 { 113 RTThreadSleep(3600 * RT_MS_1SEC); 114 RTFuzzObsExecStop(hFuzzObs); 115 } 116 else 117 rc = rtFuzzCmdMasterErrorRc(NULL, rc, "Failed to start fuzzing observer: %Rrc\n", rc); 112 118 } 113 119 else 114 rc = rtFuzzCmdMasterErrorRc(NULL, rc, "Failed to start fuzzing observer: %Rrc\n", rc);120 rc = rtFuzzCmdMasterErrorRc(NULL, rc, "Failed to load corpus seeds from \"%s\": %Rrc\n", pszInpSeedDir, rc); 115 121 } 116 122 else 117 rc = rtFuzzCmdMasterErrorRc(NULL, rc, "Failed to load corpus seeds from \"%s\": %Rrc\n", pszInpSeedDir, rc);123 rc = rtFuzzCmdMasterErrorRc(NULL, rc, "Failed to set maximum input size to %zu: %Rrc\n", cbInputMax, rc); 118 124 } 119 125 else 120 rc = rtFuzzCmdMasterErrorRc(NULL, rc, "Failed to set maximum input size to %zu: %Rrc\n", cbInputMax, rc);126 rc = rtFuzzCmdMasterErrorRc(NULL, rc, "Failed to set test program arguments: %Rrc\n", rc); 121 127 } 122 128 else 123 rc = rtFuzzCmdMasterErrorRc(NULL, rc, "Failed to set t est program arguments: %Rrc\n", rc);129 rc = rtFuzzCmdMasterErrorRc(NULL, rc, "Failed to set the specified binary as test program: %Rrc\n", rc); 124 130 } 125 else126 rc = rtFuzzCmdMasterErrorRc(NULL, rc, "Failed to set the specified binary as test program: %Rrc\n", rc);127 131 128 132 RTFuzzCtxRelease(hFuzzCtx); … … 153 157 { "--input-seed-dir", 's', RTGETOPT_REQ_STRING }, 154 158 { "--input-seed-size-max", 'm', RTGETOPT_REQ_UINT32 }, 159 { "--results-dir", 'r', RTGETOPT_REQ_STRING }, 155 160 { "--args", 'a', RTGETOPT_REQ_STRING }, 156 161 { "--help", 'h', RTGETOPT_REQ_NOTHING }, … … 173 178 bool fInputFile = false; 174 179 const char *pszTmpDir = NULL; 180 const char *pszResultsDir = NULL; 175 181 176 182 /* Argument parsing loop. */ … … 183 189 { 184 190 case 0: 185 rcExit = rtFuzzCmdMasterDoIt(pszBinary, cProcs, pszInpSeedDir, cbInputMax,191 rcExit = rtFuzzCmdMasterDoIt(pszBinary, cProcs, pszInpSeedDir, pszResultsDir, cbInputMax, 186 192 papszClientArgs, cClientArgs, fInputFile, pszTmpDir); 187 193 fContinue = false; … … 199 205 pszTmpDir = ValueUnion.psz; 200 206 fInputFile = true; 207 break; 208 209 case 'r': 210 pszResultsDir = ValueUnion.psz; 201 211 break; 202 212
Note:
See TracChangeset
for help on using the changeset viewer.