VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/fuzz/fuzz-observer.cpp@ 72942

最後變更 在這個檔案從72942是 72942,由 vboxsync 提交於 7 年 前

Runtime/RTFuzz: Some updates, add a mode where the client is aware of being fuzzed for improved efficiency. The input data is fuzzed in the client and fed to the consumer until the program crashes upon the master can reconstruct the input causing the crash because we work with deterministic random number generators. This eliminates the overhead of constantly spawning new client processes. [build fix]

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 44.2 KB
 
1/* $Id: fuzz-observer.cpp 72942 2018-07-07 13:58:16Z vboxsync $ */
2/** @file
3 * IPRT - Fuzzing framework API, observer.
4 */
5
6/*
7 * Copyright (C) 2018 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/fuzz.h>
32#include "internal/iprt.h"
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/ctype.h>
37#include <iprt/dir.h>
38#include <iprt/err.h>
39#include <iprt/env.h>
40#include <iprt/file.h>
41#include <iprt/md5.h>
42#include <iprt/mem.h>
43#include <iprt/mp.h>
44#include <iprt/path.h>
45#include <iprt/pipe.h>
46#include <iprt/poll.h>
47#include <iprt/process.h>
48#include <iprt/semaphore.h>
49#include <iprt/stream.h>
50#include <iprt/string.h>
51#include <iprt/time.h>
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
61
62
63/*********************************************************************************************************************************
64* Structures and Typedefs *
65*********************************************************************************************************************************/
66/** Pointer to the internal fuzzing observer state. */
67typedef struct RTFUZZOBSINT *PRTFUZZOBSINT;
68
69
70/**
71 * Observer thread state for one process.
72 */
73typedef struct RTFUZZOBSTHRD
74{
75 /** The thread handle. */
76 RTTHREAD hThread;
77 /** The observer ID. */
78 uint32_t idObs;
79 /** Flag whether to shutdown. */
80 volatile bool fShutdown;
81 /** Pointer to te global observer state. */
82 PRTFUZZOBSINT pFuzzObs;
83 /** Current fuzzer input. */
84 RTFUZZINPUT hFuzzInput;
85 /** Flag whether to keep the input. */
86 bool fKeepInput;
87 /** Flag whether a new input is waiting. */
88 volatile bool fNewInput;
89} RTFUZZOBSTHRD;
90/** Pointer to an observer thread state. */
91typedef RTFUZZOBSTHRD *PRTFUZZOBSTHRD;
92
93
94/**
95 * Internal fuzzing observer state.
96 */
97typedef struct RTFUZZOBSINT
98{
99 /** The fuzzing context used for this observer. */
100 RTFUZZCTX hFuzzCtx;
101 /** Temp directory for input files. */
102 char *pszTmpDir;
103 /** Results directory. */
104 char *pszResultsDir;
105 /** The binary to run. */
106 char *pszBinary;
107 /** Arguments to run the binary with, terminated by a NULL entry. */
108 char **papszArgs;
109 /** Number of arguments. */
110 uint32_t cArgs;
111 /** Maximum time to wait for the client to terminate until it is considered hung and killed. */
112 RTMSINTERVAL msWaitMax;
113 /** The channel the binary expects the input. */
114 RTFUZZOBSINPUTCHAN enmInputChan;
115 /** Flag whether to shutdown the master and all workers. */
116 volatile bool fShutdown;
117 /** Global observer thread handle. */
118 RTTHREAD hThreadGlobal;
119 /** The event semaphore handle for the global observer thread. */
120 RTSEMEVENT hEvtGlobal;
121 /** Notification event bitmap. */
122 volatile uint64_t bmEvt;
123 /** Number of threads created - one for each process. */
124 uint32_t cThreads;
125 /** Pointer to the array of observer thread states. */
126 PRTFUZZOBSTHRD paObsThreads;
127 /** Timestamp of the last stats query. */
128 uint64_t tsLastStats;
129 /** Last number of fuzzed inputs per second if we didn't gather enough data in between
130 * statistic queries. */
131 uint32_t cFuzzedInputsPerSecLast;
132 /** Fuzzing statistics. */
133 RTFUZZOBSSTATS Stats;
134} RTFUZZOBSINT;
135
136
137/**
138 * Stdout/Stderr buffer.
139 */
140typedef struct RTFUZZOBSSTDOUTERRBUF
141{
142 /** Current amount buffered. */
143 size_t cbBuf;
144 /** Maxmium amount to buffer. */
145 size_t cbBufMax;
146 /** Base pointer to the data buffer. */
147 uint8_t *pbBase;
148} RTFUZZOBSSTDOUTERRBUF;
149/** Pointer to a stdout/stderr buffer. */
150typedef RTFUZZOBSSTDOUTERRBUF *PRTFUZZOBSSTDOUTERRBUF;
151
152
153/**
154 * Worker execution context.
155 */
156typedef struct RTFUZZOBSEXECCTX
157{
158 /** The stdout pipe handle - reading end. */
159 RTPIPE hPipeStdoutR;
160 /** The stdout pipe handle - writing end. */
161 RTPIPE hPipeStdoutW;
162 /** The stderr pipe handle - reading end. */
163 RTPIPE hPipeStderrR;
164 /** The stderr pipe handle - writing end. */
165 RTPIPE hPipeStderrW;
166 /** The stdin pipe handle - reading end. */
167 RTPIPE hPipeStdinR;
168 /** The stind pipe handle - writing end. */
169 RTPIPE hPipeStdinW;
170 /** The stdout handle. */
171 RTHANDLE StdoutHandle;
172 /** The stderr handle. */
173 RTHANDLE StderrHandle;
174 /** The stdin handle. */
175 RTHANDLE StdinHandle;
176 /** The pollset to monitor. */
177 RTPOLLSET hPollSet;
178 /** The process to monitor. */
179 RTPROCESS hProc;
180 /** Execution time of the process. */
181 RTMSINTERVAL msExec;
182 /** Current input data pointer. */
183 uint8_t *pbInputCur;
184 /** Number of bytes left for the input. */
185 size_t cbInputLeft;
186 /** The stdout data buffer. */
187 RTFUZZOBSSTDOUTERRBUF StdOutBuf;
188 /** The stderr data buffer. */
189 RTFUZZOBSSTDOUTERRBUF StdErrBuf;
190 /** Modified arguments vector - variable in size. */
191 char *apszArgs[1];
192} RTFUZZOBSEXECCTX;
193/** Pointer to an execution context. */
194typedef RTFUZZOBSEXECCTX *PRTFUZZOBSEXECCTX;
195/** Pointer to an execution context pointer. */
196typedef PRTFUZZOBSEXECCTX *PPRTFUZZOBSEXECCTX;
197
198
199/**
200 * A variable descriptor.
201 */
202typedef struct RTFUZZOBSVARIABLE
203{
204 /** The variable. */
205 const char *pszVar;
206 /** Length of the variable in characters - excluding the terminator. */
207 uint32_t cchVar;
208 /** The replacement value. */
209 const char *pszVal;
210} RTFUZZOBSVARIABLE;
211/** Pointer to a variable descriptor. */
212typedef RTFUZZOBSVARIABLE *PRTFUZZOBSVARIABLE;
213
214
215/**
216 * Initializes the given stdout/stderr buffer.
217 *
218 * @returns nothing.
219 * @param pBuf The buffer to initialize.
220 */
221static void rtFuzzObsStdOutErrBufInit(PRTFUZZOBSSTDOUTERRBUF pBuf)
222{
223 pBuf->cbBuf = 0;
224 pBuf->cbBufMax = 0;
225 pBuf->pbBase = NULL;
226}
227
228
229/**
230 * Frees all allocated resources in the given stdout/stderr buffer.
231 *
232 * @returns nothing.
233 * @param pBuf The buffer to free.
234 */
235static void rtFuzzObsStdOutErrBufFree(PRTFUZZOBSSTDOUTERRBUF pBuf)
236{
237 if (pBuf->pbBase)
238 RTMemFree(pBuf->pbBase);
239}
240
241
242/**
243 * Clears the given stdout/stderr buffer.
244 *
245 * @returns nothing.
246 * @param pBuf The buffer to clear.
247 */
248static void rtFuzzObsStdOutErrBufClear(PRTFUZZOBSSTDOUTERRBUF pBuf)
249{
250 pBuf->cbBuf = 0;
251}
252
253
254/**
255 * Fills the given stdout/stderr buffer from the given pipe.
256 *
257 * @returns IPRT status code.
258 * @param pBuf The buffer to fill.
259 * @param hPipeRead The pipe to read from.
260 */
261static int rtFuzzObsStdOutErrBufFill(PRTFUZZOBSSTDOUTERRBUF pBuf, RTPIPE hPipeRead)
262{
263 int rc = VINF_SUCCESS;
264
265 size_t cbRead = 0;
266 size_t cbThisRead = 0;
267 do
268 {
269 cbThisRead = pBuf->cbBufMax - pBuf->cbBuf;
270 if (!cbThisRead)
271 {
272 /* Try to increase the buffer. */
273 uint8_t *pbNew = (uint8_t *)RTMemRealloc(pBuf->pbBase, pBuf->cbBufMax + _4K);
274 if (RT_LIKELY(pbNew))
275 {
276 pBuf->cbBufMax += _4K;
277 pBuf->pbBase = pbNew;
278 }
279 cbThisRead = pBuf->cbBufMax - pBuf->cbBuf;
280 }
281
282 if (cbThisRead)
283 {
284 rc = RTPipeRead(hPipeRead, pBuf->pbBase + pBuf->cbBuf, cbThisRead, &cbRead);
285 if (RT_SUCCESS(rc))
286 pBuf->cbBuf += cbRead;
287 }
288 else
289 rc = VERR_NO_MEMORY;
290 } while ( RT_SUCCESS(rc)
291 && cbRead == cbThisRead);
292
293 return rc;
294}
295
296
297/**
298 * Writes the given stdout/stderr buffer to the given filename.
299 *
300 * @returns IPRT status code.
301 * @param pBuf The buffer to write.
302 * @param pszFilename The filename to write the buffer to.
303 */
304static int rtFuzzStdOutErrBufWriteToFile(PRTFUZZOBSSTDOUTERRBUF pBuf, const char *pszFilename)
305{
306 RTFILE hFile;
307 int rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
308 if (RT_SUCCESS(rc))
309 {
310 rc = RTFileWrite(hFile, pBuf->pbBase, pBuf->cbBuf, NULL);
311 AssertRC(rc);
312 RTFileClose(hFile);
313
314 if (RT_FAILURE(rc))
315 RTFileDelete(pszFilename);
316 }
317
318 return rc;
319}
320
321
322/**
323 * Replaces a variable with its value.
324 *
325 * @returns VINF_SUCCESS or VERR_NO_STR_MEMORY.
326 * @param ppszNew In/Out.
327 * @param pcchNew In/Out. (Messed up on failure.)
328 * @param offVar Variable offset.
329 * @param cchVar Variable length.
330 * @param pszValue The value.
331 * @param cchValue Value length.
332 */
333static int rtFuzzObsReplaceStringVariable(char **ppszNew, size_t *pcchNew, size_t offVar, size_t cchVar,
334 const char *pszValue, size_t cchValue)
335{
336 size_t const cchAfter = *pcchNew - offVar - cchVar;
337 if (cchVar < cchValue)
338 {
339 *pcchNew += cchValue - cchVar;
340 int rc = RTStrRealloc(ppszNew, *pcchNew + 1);
341 if (RT_FAILURE(rc))
342 return rc;
343 }
344
345 char *pszNew = *ppszNew;
346 memmove(&pszNew[offVar + cchValue], &pszNew[offVar + cchVar], cchAfter + 1);
347 memcpy(&pszNew[offVar], pszValue, cchValue);
348 return VINF_SUCCESS;
349}
350
351
352/**
353 * Replace the variables found in the source string, returning a new string that
354 * lives on the string heap.
355 *
356 * @returns IPRT status code.
357 * @param pszSrc The source string.
358 * @param paVars Pointer to the array of known variables.
359 * @param ppszNew Where to return the new string.
360 */
361static int rtFuzzObsReplaceStringVariables(const char *pszSrc, PRTFUZZOBSVARIABLE paVars, char **ppszNew)
362{
363 /* Lazy approach that employs memmove. */
364 int rc = VINF_SUCCESS;
365 size_t cchNew = strlen(pszSrc);
366 char *pszNew = RTStrDup(pszSrc);
367
368 if (paVars)
369 {
370 char *pszDollar = pszNew;
371 while ((pszDollar = strchr(pszDollar, '$')) != NULL)
372 {
373 if (pszDollar[1] == '{')
374 {
375 const char *pszEnd = strchr(&pszDollar[2], '}');
376 if (pszEnd)
377 {
378 size_t const cchVar = pszEnd - pszDollar + 1; /* includes "${}" */
379 size_t offDollar = pszDollar - pszNew;
380 PRTFUZZOBSVARIABLE pVar = paVars;
381 while (pVar->pszVar != NULL)
382 {
383 if ( cchVar == pVar->cchVar
384 && !memcmp(pszDollar, pVar->pszVar, cchVar))
385 {
386 size_t const cchValue = strlen(pVar->pszVal);
387 rc = rtFuzzObsReplaceStringVariable(&pszNew, &cchNew, offDollar,
388 cchVar, pVar->pszVal, cchValue);
389 offDollar += cchValue;
390 break;
391 }
392
393 pVar++;
394 }
395
396 pszDollar = &pszNew[offDollar];
397
398 if (RT_FAILURE(rc))
399 {
400 RTStrFree(pszNew);
401 *ppszNew = NULL;
402 return rc;
403 }
404 }
405 }
406 }
407 }
408
409 *ppszNew = pszNew;
410 return rc;
411}
412
413/**
414 * Prepares the argument vector for the child process.
415 *
416 * @returns IPRT status code.
417 * @param pThis The internal fuzzing observer state.
418 * @param pExecCtx The execution context to prepare the argument vector for.
419 * @param paVars Pointer to the array of known variables.
420 */
421static int rtFuzzObsExecCtxArgvPrepare(PRTFUZZOBSINT pThis, PRTFUZZOBSEXECCTX pExecCtx, PRTFUZZOBSVARIABLE paVars)
422{
423 int rc = VINF_SUCCESS;
424 for (unsigned i = 0; i < pThis->cArgs && RT_SUCCESS(rc); i++)
425 rc = rtFuzzObsReplaceStringVariables(pThis->papszArgs[i], paVars, &pExecCtx->apszArgs[i]);
426
427 return rc;
428}
429
430
431/**
432 * Creates a new execution context.
433 *
434 * @returns IPRT status code.
435 * @param ppExecCtx Where to store the pointer to the execution context on success.
436 * @param pThis The internal fuzzing observer state.
437 */
438static int rtFuzzObsExecCtxCreate(PPRTFUZZOBSEXECCTX ppExecCtx, PRTFUZZOBSINT pThis)
439{
440 int rc = VINF_SUCCESS;
441 PRTFUZZOBSEXECCTX pExecCtx = (PRTFUZZOBSEXECCTX)RTMemAllocZ(RT_OFFSETOF(RTFUZZOBSEXECCTX, apszArgs[pThis->cArgs + 1]));
442 if (RT_LIKELY(pExecCtx))
443 {
444 pExecCtx->hPipeStdoutR = NIL_RTPIPE;
445 pExecCtx->hPipeStdoutW = NIL_RTPIPE;
446 pExecCtx->hPipeStderrR = NIL_RTPIPE;
447 pExecCtx->hPipeStderrW = NIL_RTPIPE;
448 pExecCtx->hPipeStdinR = NIL_RTPIPE;
449 pExecCtx->hPipeStdinW = NIL_RTPIPE;
450 pExecCtx->hPollSet = NIL_RTPOLLSET;
451 pExecCtx->hProc = NIL_RTPROCESS;
452 pExecCtx->msExec = 0;
453 rtFuzzObsStdOutErrBufInit(&pExecCtx->StdOutBuf);
454 rtFuzzObsStdOutErrBufInit(&pExecCtx->StdErrBuf);
455
456 rc = RTPollSetCreate(&pExecCtx->hPollSet);
457 if (RT_SUCCESS(rc))
458 {
459 rc = RTPipeCreate(&pExecCtx->hPipeStdoutR, &pExecCtx->hPipeStdoutW, RTPIPE_C_INHERIT_WRITE);
460 if (RT_SUCCESS(rc))
461 {
462 RTHANDLE Handle;
463 Handle.enmType = RTHANDLETYPE_PIPE;
464 Handle.u.hPipe = pExecCtx->hPipeStdoutR;
465 rc = RTPollSetAdd(pExecCtx->hPollSet, &Handle, RTPOLL_EVT_READ, RTFUZZOBS_EXEC_CTX_POLL_ID_STDOUT);
466 AssertRC(rc);
467
468 rc = RTPipeCreate(&pExecCtx->hPipeStderrR, &pExecCtx->hPipeStderrW, RTPIPE_C_INHERIT_WRITE);
469 if (RT_SUCCESS(rc))
470 {
471 Handle.u.hPipe = pExecCtx->hPipeStderrR;
472 rc = RTPollSetAdd(pExecCtx->hPollSet, &Handle, RTPOLL_EVT_READ, RTFUZZOBS_EXEC_CTX_POLL_ID_STDERR);
473 AssertRC(rc);
474
475 /* Create the stdin pipe handles if not a file input. */
476 if (pThis->enmInputChan == RTFUZZOBSINPUTCHAN_STDIN || pThis->enmInputChan == RTFUZZOBSINPUTCHAN_FUZZING_AWARE_CLIENT)
477 {
478 rc = RTPipeCreate(&pExecCtx->hPipeStdinR, &pExecCtx->hPipeStdinW, RTPIPE_C_INHERIT_READ);
479 if (RT_SUCCESS(rc))
480 {
481 pExecCtx->StdinHandle.enmType = RTHANDLETYPE_PIPE;
482 pExecCtx->StdinHandle.u.hPipe = pExecCtx->hPipeStdinR;
483
484 Handle.u.hPipe = pExecCtx->hPipeStdinW;
485 rc = RTPollSetAdd(pExecCtx->hPollSet, &Handle, RTPOLL_EVT_WRITE, RTFUZZOBS_EXEC_CTX_POLL_ID_STDIN);
486 AssertRC(rc);
487 }
488 }
489 else
490 {
491 pExecCtx->StdinHandle.enmType = RTHANDLETYPE_PIPE;
492 pExecCtx->StdinHandle.u.hPipe = NIL_RTPIPE;
493 }
494
495 if (RT_SUCCESS(rc))
496 {
497 pExecCtx->StdoutHandle.enmType = RTHANDLETYPE_PIPE;
498 pExecCtx->StdoutHandle.u.hPipe = pExecCtx->hPipeStdoutW;
499 pExecCtx->StderrHandle.enmType = RTHANDLETYPE_PIPE;
500 pExecCtx->StderrHandle.u.hPipe = pExecCtx->hPipeStderrW;
501 *ppExecCtx = pExecCtx;
502 return VINF_SUCCESS;
503 }
504
505 RTPipeClose(pExecCtx->hPipeStderrR);
506 RTPipeClose(pExecCtx->hPipeStderrW);
507 }
508
509 RTPipeClose(pExecCtx->hPipeStdoutR);
510 RTPipeClose(pExecCtx->hPipeStdoutW);
511 }
512
513 RTPollSetDestroy(pExecCtx->hPollSet);
514 }
515
516 RTMemFree(pExecCtx);
517 }
518 else
519 rc = VERR_NO_MEMORY;
520
521 return rc;
522}
523
524
525/**
526 * Destroys the given execution context.
527 *
528 * @returns nothing.
529 * @param pThis The internal fuzzing observer state.
530 * @param pExecCtx The execution context to destroy.
531 */
532static void rtFuzzObsExecCtxDestroy(PRTFUZZOBSINT pThis, PRTFUZZOBSEXECCTX pExecCtx)
533{
534 RTPipeClose(pExecCtx->hPipeStdoutR);
535 RTPipeClose(pExecCtx->hPipeStdoutW);
536 RTPipeClose(pExecCtx->hPipeStderrR);
537 RTPipeClose(pExecCtx->hPipeStderrW);
538
539 if ( pThis->enmInputChan == RTFUZZOBSINPUTCHAN_STDIN
540 || pThis->enmInputChan == RTFUZZOBSINPUTCHAN_FUZZING_AWARE_CLIENT)
541 {
542 RTPipeClose(pExecCtx->hPipeStdinR);
543 RTPipeClose(pExecCtx->hPipeStdinW);
544 }
545
546 RTPollSetDestroy(pExecCtx->hPollSet);
547 char **ppszArg = &pExecCtx->apszArgs[0];
548 while (*ppszArg != NULL)
549 {
550 RTStrFree(*ppszArg);
551 ppszArg++;
552 }
553
554 rtFuzzObsStdOutErrBufFree(&pExecCtx->StdOutBuf);
555 rtFuzzObsStdOutErrBufFree(&pExecCtx->StdErrBuf);
556 RTMemFree(pExecCtx);
557}
558
559
560/**
561 * Runs the client binary pumping all data back and forth waiting for the client to finish.
562 *
563 * @returns IPRT status code.
564 * @retval VERR_TIMEOUT if the client didn't finish in the given deadline and was killed.
565 * @param pThis The internal fuzzing observer state.
566 * @param pExecCtx The execution context.
567 * @param pProcStat Where to store the process exit status on success.
568 */
569static int rtFuzzObsExecCtxClientRun(PRTFUZZOBSINT pThis, PRTFUZZOBSEXECCTX pExecCtx, PRTPROCSTATUS pProcStat)
570{
571 rtFuzzObsStdOutErrBufClear(&pExecCtx->StdOutBuf);
572 rtFuzzObsStdOutErrBufClear(&pExecCtx->StdErrBuf);
573
574 int rc = RTProcCreateEx(pThis->pszBinary, &pExecCtx->apszArgs[0], RTENV_DEFAULT, 0 /*fFlags*/, &pExecCtx->StdinHandle,
575 &pExecCtx->StdoutHandle, &pExecCtx->StderrHandle, NULL, NULL, &pExecCtx->hProc);
576 if (RT_SUCCESS(rc))
577 {
578 uint64_t tsMilliesStart = RTTimeSystemMilliTS();
579 for (;;)
580 {
581 /* Wait a bit for something to happen on one of the pipes. */
582 uint32_t fEvtsRecv = 0;
583 uint32_t idEvt = 0;
584 rc = RTPoll(pExecCtx->hPollSet, 10 /*cMillies*/, &fEvtsRecv, &idEvt);
585 if (RT_SUCCESS(rc))
586 {
587 if (idEvt == RTFUZZOBS_EXEC_CTX_POLL_ID_STDOUT)
588 {
589 Assert(fEvtsRecv & RTPOLL_EVT_READ);
590 rc = rtFuzzObsStdOutErrBufFill(&pExecCtx->StdOutBuf, pExecCtx->hPipeStdoutR);
591 AssertRC(rc);
592 }
593 else if (idEvt == RTFUZZOBS_EXEC_CTX_POLL_ID_STDERR)
594 {
595 Assert(fEvtsRecv & RTPOLL_EVT_READ);
596 rc = rtFuzzObsStdOutErrBufFill(&pExecCtx->StdErrBuf, pExecCtx->hPipeStderrR);
597 AssertRC(rc);
598 }
599 else if (idEvt == RTFUZZOBS_EXEC_CTX_POLL_ID_STDIN)
600 {
601 /* Feed the next input. */
602 Assert(fEvtsRecv & RTPOLL_EVT_WRITE);
603 size_t cbWritten = 0;
604 rc = RTPipeWrite(pExecCtx->hPipeStdinW, pExecCtx->pbInputCur, pExecCtx->cbInputLeft, &cbWritten);
605 if (RT_SUCCESS(rc))
606 {
607 pExecCtx->cbInputLeft -= cbWritten;
608 if (!pExecCtx->cbInputLeft)
609 {
610 /* Close stdin pipe. */
611 rc = RTPollSetRemove(pExecCtx->hPollSet, RTFUZZOBS_EXEC_CTX_POLL_ID_STDIN);
612 AssertRC(rc);
613 RTPipeClose(pExecCtx->hPipeStdinW);
614 }
615 }
616 }
617 else
618 AssertMsgFailed(("Invalid poll ID returned: %u!\n", idEvt));
619 }
620 else
621 Assert(rc == VERR_TIMEOUT);
622
623 /* Check the process status. */
624 rc = RTProcWait(pExecCtx->hProc, RTPROCWAIT_FLAGS_NOBLOCK, pProcStat);
625 if (RT_SUCCESS(rc))
626 break;
627 else
628 {
629 Assert(rc == VERR_PROCESS_RUNNING);
630 /* Check whether we reached the limit. */
631 if (RTTimeSystemMilliTS() - tsMilliesStart > pThis->msWaitMax)
632 {
633 rc = VERR_TIMEOUT;
634 break;
635 }
636 }
637 } /* for (;;) */
638
639 /* Kill the process on a timeout. */
640 if (rc == VERR_TIMEOUT)
641 {
642 int rc2 = RTProcTerminate(pExecCtx->hProc);
643 AssertRC(rc2);
644 }
645 }
646
647 return rc;
648}
649
650
651/**
652 * Runs the fuzzing aware client binary pumping all data back and forth waiting for the client to crash.
653 *
654 * @returns IPRT status code.
655 * @retval VERR_TIMEOUT if the client didn't finish in the given deadline and was killed.
656 * @param pThis The internal fuzzing observer state.
657 * @param pExecCtx The execution context.
658 * @param pProcStat Where to store the process exit status on success.
659 */
660static int rtFuzzObsExecCtxClientRunFuzzingAware(PRTFUZZOBSINT pThis, PRTFUZZOBSEXECCTX pExecCtx, PRTPROCSTATUS pProcStat)
661{
662 rtFuzzObsStdOutErrBufClear(&pExecCtx->StdOutBuf);
663 rtFuzzObsStdOutErrBufClear(&pExecCtx->StdErrBuf);
664
665 int rc = RTProcCreateEx(pThis->pszBinary, &pExecCtx->apszArgs[0], RTENV_DEFAULT, 0 /*fFlags*/, &pExecCtx->StdinHandle,
666 &pExecCtx->StdoutHandle, &pExecCtx->StderrHandle, NULL, NULL, &pExecCtx->hProc);
667 if (RT_SUCCESS(rc))
668 {
669 /* Send the initial fuzzing context state over to the client. */
670 void *pvState = NULL;
671 size_t cbState = 0;
672 rc = RTFuzzCtxStateExport(pThis->hFuzzCtx, &pvState, &cbState);
673 if (RT_SUCCESS(rc))
674 {
675 uint32_t cbStateWr = (uint32_t)cbState;
676 rc = RTPipeWriteBlocking(pExecCtx->hPipeStdinW, &cbStateWr, sizeof(cbStateWr), NULL);
677 rc = RTPipeWriteBlocking(pExecCtx->hPipeStdinW, pvState, cbState, NULL);
678 if (RT_SUCCESS(rc))
679 {
680 rc = RTPollSetRemove(pExecCtx->hPollSet, RTFUZZOBS_EXEC_CTX_POLL_ID_STDIN);
681 AssertRC(rc);
682
683 uint64_t tsMilliesLastSignal = RTTimeSystemMilliTS();
684 uint32_t cFuzzedInputs = 0;
685 for (;;)
686 {
687 /* Wait a bit for something to happen on one of the pipes. */
688 uint32_t fEvtsRecv = 0;
689 uint32_t idEvt = 0;
690 rc = RTPoll(pExecCtx->hPollSet, 10 /*cMillies*/, &fEvtsRecv, &idEvt);
691 if (RT_SUCCESS(rc))
692 {
693 if (idEvt == RTFUZZOBS_EXEC_CTX_POLL_ID_STDOUT)
694 {
695 Assert(fEvtsRecv & RTPOLL_EVT_READ);
696 for (;;)
697 {
698 char achBuf[512];
699 size_t cbRead = 0;
700 rc = RTPipeRead(pExecCtx->hPipeStdoutR, &achBuf[0], sizeof(achBuf), &cbRead);
701 if (RT_SUCCESS(rc))
702 {
703 if (!cbRead)
704 break;
705
706 tsMilliesLastSignal = RTTimeMilliTS();
707 for (unsigned i = 0; i < cbRead; i++)
708 {
709 ASMAtomicIncU32(&pThis->Stats.cFuzzedInputs);
710 ASMAtomicIncU32(&pThis->Stats.cFuzzedInputsPerSec);
711
712 if (achBuf[i] == '.')
713 cFuzzedInputs++;
714 else if (achBuf[i] == 'A')
715 {
716 /** @todo Advance our fuzzer to get the added input. */
717 }
718 }
719 }
720 else
721 break;
722 }
723 AssertRC(rc);
724 }
725 else if (idEvt == RTFUZZOBS_EXEC_CTX_POLL_ID_STDERR)
726 {
727 Assert(fEvtsRecv & RTPOLL_EVT_READ);
728 rc = rtFuzzObsStdOutErrBufFill(&pExecCtx->StdErrBuf, pExecCtx->hPipeStderrR);
729 AssertRC(rc);
730 }
731 else
732 AssertMsgFailed(("Invalid poll ID returned: %u!\n", idEvt));
733 }
734 else
735 Assert(rc == VERR_TIMEOUT);
736
737 /* Check the process status. */
738 rc = RTProcWait(pExecCtx->hProc, RTPROCWAIT_FLAGS_NOBLOCK, pProcStat);
739 if (RT_SUCCESS(rc))
740 break;
741 else
742 {
743 Assert(rc == VERR_PROCESS_RUNNING);
744 /* Check when the last response from the client was. */
745 if (RTTimeSystemMilliTS() - tsMilliesLastSignal > pThis->msWaitMax)
746 {
747 rc = VERR_TIMEOUT;
748 break;
749 }
750 }
751 } /* for (;;) */
752
753 /* Kill the process on a timeout. */
754 if (rc == VERR_TIMEOUT)
755 {
756 int rc2 = RTProcTerminate(pExecCtx->hProc);
757 AssertRC(rc2);
758 }
759 }
760 }
761 }
762
763 RTHANDLE Handle;
764 Handle.enmType = RTHANDLETYPE_PIPE;
765 Handle.u.hPipe = pExecCtx->hPipeStdinW;
766 rc = RTPollSetAdd(pExecCtx->hPollSet, &Handle, RTPOLL_EVT_WRITE, RTFUZZOBS_EXEC_CTX_POLL_ID_STDIN);
767 AssertRC(rc);
768
769 return rc;
770}
771
772
773/**
774 * Adds the input to the results directory.
775 *
776 * @returns IPRT status code.
777 * @param pThis The internal fuzzing observer state.
778 * @param hFuzzInput Fuzzing input handle to write.
779 * @param pExecCtx Execution context.
780 */
781static int rtFuzzObsAddInputToResults(PRTFUZZOBSINT pThis, RTFUZZINPUT hFuzzInput, PRTFUZZOBSEXECCTX pExecCtx)
782{
783 char aszDigest[RTMD5_STRING_LEN + 1];
784 int rc = RTFuzzInputQueryDigestString(hFuzzInput, &aszDigest[0], sizeof(aszDigest));
785 if (RT_SUCCESS(rc))
786 {
787 /* Create a directory. */
788 char szPath[RTPATH_MAX];
789 rc = RTPathJoin(szPath, sizeof(szPath), pThis->pszResultsDir, &aszDigest[0]);
790 AssertRC(rc);
791
792 rc = RTDirCreate(&szPath[0], 0700, 0 /*fCreate*/);
793 if (RT_SUCCESS(rc))
794 {
795 /* Write the input. */
796 char szTmp[RTPATH_MAX];
797 rc = RTPathJoin(szTmp, sizeof(szTmp), &szPath[0], "input");
798 AssertRC(rc);
799
800 rc = RTFuzzInputWriteToFile(hFuzzInput, &szTmp[0]);
801 if (RT_SUCCESS(rc))
802 {
803 /* Stdout and Stderr. */
804 rc = RTPathJoin(szTmp, sizeof(szTmp), &szPath[0], "stdout");
805 AssertRC(rc);
806 rc = rtFuzzStdOutErrBufWriteToFile(&pExecCtx->StdOutBuf, &szTmp[0]);
807 if (RT_SUCCESS(rc))
808 {
809 rc = RTPathJoin(szTmp, sizeof(szTmp), &szPath[0], "stderr");
810 AssertRC(rc);
811 rc = rtFuzzStdOutErrBufWriteToFile(&pExecCtx->StdOutBuf, &szTmp[0]);
812 }
813 }
814 }
815 }
816
817 return rc;
818}
819
820
821/**
822 * Fuzzing observer worker loop.
823 *
824 * @returns IPRT status code.
825 * @param hThrd The thread handle.
826 * @param pvUser Opaque user data.
827 */
828static DECLCALLBACK(int) rtFuzzObsWorkerLoop(RTTHREAD hThrd, void *pvUser)
829{
830 PRTFUZZOBSTHRD pObsThrd = (PRTFUZZOBSTHRD)pvUser;
831 PRTFUZZOBSINT pThis = pObsThrd->pFuzzObs;
832 PRTFUZZOBSEXECCTX pExecCtx = NULL;
833
834 int rc = rtFuzzObsExecCtxCreate(&pExecCtx, pThis);
835 if (RT_FAILURE(rc))
836 return rc;
837
838 while (!pObsThrd->fShutdown)
839 {
840 char szInput[RTPATH_MAX];
841
842 /* Wait for work. */
843 rc = RTThreadUserWait(hThrd, RT_INDEFINITE_WAIT);
844 AssertRC(rc);
845
846 if (pObsThrd->fShutdown)
847 break;
848
849 if (!ASMAtomicXchgBool(&pObsThrd->fNewInput, false))
850 continue;
851
852 AssertPtr(pObsThrd->hFuzzInput);
853
854 if (pThis->enmInputChan == RTFUZZOBSINPUTCHAN_FILE)
855 {
856 char szFilename[32];
857
858 ssize_t cbBuf = RTStrPrintf2(&szFilename[0], sizeof(szFilename), "%u", pObsThrd->idObs);
859 Assert(cbBuf > 0); RT_NOREF(cbBuf);
860
861 RT_ZERO(szInput);
862 rc = RTPathJoin(szInput, sizeof(szInput), pThis->pszTmpDir, &szFilename[0]);
863 AssertRC(rc);
864
865 rc = RTFuzzInputWriteToFile(pObsThrd->hFuzzInput, &szInput[0]);
866 if (RT_SUCCESS(rc))
867 {
868 RTFUZZOBSVARIABLE aVar[2] = {
869 { "${INPUT}", sizeof("${INPUT}") - 1, &szInput[0] },
870 { NULL, 0, NULL }
871 };
872 rc = rtFuzzObsExecCtxArgvPrepare(pThis, pExecCtx, &aVar[0]);
873 }
874 }
875 else if (pThis->enmInputChan == RTFUZZOBSINPUTCHAN_STDIN)
876 {
877 rc = RTFuzzInputQueryData(pObsThrd->hFuzzInput, (void **)&pExecCtx->pbInputCur, &pExecCtx->cbInputLeft);
878 if (RT_SUCCESS(rc))
879 rc = rtFuzzObsExecCtxArgvPrepare(pThis, pExecCtx, NULL);
880 }
881
882 if (RT_SUCCESS(rc))
883 {
884 RTPROCSTATUS ProcSts;
885 if (pThis->enmInputChan == RTFUZZOBSINPUTCHAN_FUZZING_AWARE_CLIENT)
886 rc = rtFuzzObsExecCtxClientRunFuzzingAware(pThis, pExecCtx, &ProcSts);
887 else
888 {
889 rc = rtFuzzObsExecCtxClientRun(pThis, pExecCtx, &ProcSts);
890 ASMAtomicIncU32(&pThis->Stats.cFuzzedInputs);
891 ASMAtomicIncU32(&pThis->Stats.cFuzzedInputsPerSec);
892 }
893
894 if (RT_SUCCESS(rc))
895 {
896 if (ProcSts.enmReason != RTPROCEXITREASON_NORMAL)
897 {
898 ASMAtomicIncU32(&pThis->Stats.cFuzzedInputsCrash);
899 rc = rtFuzzObsAddInputToResults(pThis, pObsThrd->hFuzzInput, pExecCtx);
900 }
901 }
902 else if (rc == VERR_TIMEOUT)
903 {
904 ASMAtomicIncU32(&pThis->Stats.cFuzzedInputsHang);
905 rc = rtFuzzObsAddInputToResults(pThis, pObsThrd->hFuzzInput, pExecCtx);
906 }
907 else
908 AssertFailed();
909
910 if (pThis->enmInputChan == RTFUZZOBSINPUTCHAN_FILE)
911 RTFileDelete(&szInput[0]);
912 }
913
914 ASMAtomicBitSet(&pThis->bmEvt, pObsThrd->idObs);
915 RTSemEventSignal(pThis->hEvtGlobal);
916 }
917
918 rtFuzzObsExecCtxDestroy(pThis, pExecCtx);
919 return VINF_SUCCESS;
920}
921
922
923/**
924 * Fuzzing observer master worker loop.
925 *
926 * @returns IPRT status code.
927 * @param hThread The thread handle.
928 * @param pvUser Opaque user data.
929 */
930static DECLCALLBACK(int) rtFuzzObsMasterLoop(RTTHREAD hThread, void *pvUser)
931{
932 RT_NOREF(hThread);
933 int rc = VINF_SUCCESS;
934 PRTFUZZOBSINT pThis = (PRTFUZZOBSINT)pvUser;
935
936 RTThreadUserSignal(hThread);
937
938 while ( !pThis->fShutdown
939 && RT_SUCCESS(rc))
940 {
941 uint64_t bmEvt = ASMAtomicXchgU64(&pThis->bmEvt, 0);
942 uint32_t idxObs = 0;
943 while (bmEvt != 0)
944 {
945 if (bmEvt & 0x1)
946 {
947 /* Create a new input for this observer and kick it. */
948 PRTFUZZOBSTHRD pObsThrd = &pThis->paObsThreads[idxObs];
949
950 /* Release the old input. */
951 if (pObsThrd->hFuzzInput)
952 {
953 if (pObsThrd->fKeepInput)
954 {
955 int rc2 = RTFuzzInputAddToCtxCorpus(pObsThrd->hFuzzInput);
956 Assert(RT_SUCCESS(rc2) || rc2 == VERR_ALREADY_EXISTS); RT_NOREF(rc2);
957 pObsThrd->fKeepInput= false;
958 }
959 RTFuzzInputRelease(pObsThrd->hFuzzInput);
960 }
961
962 rc = RTFuzzCtxInputGenerate(pThis->hFuzzCtx, &pObsThrd->hFuzzInput);
963 if (RT_SUCCESS(rc))
964 {
965 ASMAtomicWriteBool(&pObsThrd->fNewInput, true);
966 RTThreadUserSignal(pObsThrd->hThread);
967 }
968 }
969
970 idxObs++;
971 bmEvt >>= 1;
972 }
973
974 rc = RTSemEventWait(pThis->hEvtGlobal, RT_INDEFINITE_WAIT);
975 }
976
977 return VINF_SUCCESS;
978}
979
980
981/**
982 * Initializes the given worker thread structure.
983 *
984 * @returns IPRT status code.
985 * @param pThis The internal fuzzing observer state.
986 * @param iObs Observer ID.
987 * @param pObsThrd The observer thread structure.
988 */
989static int rtFuzzObsWorkerThreadInit(PRTFUZZOBSINT pThis, uint32_t idObs, PRTFUZZOBSTHRD pObsThrd)
990{
991 pObsThrd->pFuzzObs = pThis;
992 pObsThrd->hFuzzInput = NULL;
993 pObsThrd->idObs = idObs;
994 pObsThrd->fShutdown = false;
995
996 ASMAtomicBitSet(&pThis->bmEvt, idObs);
997 return RTThreadCreate(&pObsThrd->hThread, rtFuzzObsWorkerLoop, pObsThrd, 0, RTTHREADTYPE_IO,
998 RTTHREADFLAGS_WAITABLE, "Fuzz-Worker");
999}
1000
1001
1002/**
1003 * Creates the given amount of worker threads and puts them into waiting state.
1004 *
1005 * @returns IPRT status code.
1006 * @param pThis The internal fuzzing observer state.
1007 * @param cThreads Number of worker threads to create.
1008 */
1009static int rtFuzzObsWorkersCreate(PRTFUZZOBSINT pThis, uint32_t cThreads)
1010{
1011 int rc = VINF_SUCCESS;
1012 PRTFUZZOBSTHRD paObsThreads = (PRTFUZZOBSTHRD)RTMemAllocZ(cThreads * sizeof(RTFUZZOBSTHRD));
1013 if (RT_LIKELY(paObsThreads))
1014 {
1015 for (unsigned i = 0; i < cThreads && RT_SUCCESS(rc); i++)
1016 {
1017 rc = rtFuzzObsWorkerThreadInit(pThis, i, &paObsThreads[i]);
1018 if (RT_FAILURE(rc))
1019 {
1020 /* Rollback. */
1021
1022 }
1023 }
1024
1025 if (RT_SUCCESS(rc))
1026 {
1027 pThis->paObsThreads = paObsThreads;
1028 pThis->cThreads = cThreads;
1029 }
1030 else
1031 RTMemFree(paObsThreads);
1032 }
1033
1034 return rc;
1035}
1036
1037
1038/**
1039 * Creates the global worker thread managing the input creation and other worker threads.
1040 *
1041 * @returns IPRT status code.
1042 * @param pThis The internal fuzzing observer state.
1043 */
1044static int rtFuzzObsMasterCreate(PRTFUZZOBSINT pThis)
1045{
1046 pThis->fShutdown = false;
1047
1048 int rc = RTSemEventCreate(&pThis->hEvtGlobal);
1049 if (RT_SUCCESS(rc))
1050 {
1051 rc = RTThreadCreate(&pThis->hThreadGlobal, rtFuzzObsMasterLoop, pThis, 0, RTTHREADTYPE_IO,
1052 RTTHREADFLAGS_WAITABLE, "Fuzz-Master");
1053 if (RT_SUCCESS(rc))
1054 {
1055 RTThreadUserWait(pThis->hThreadGlobal, RT_INDEFINITE_WAIT);
1056 }
1057 else
1058 {
1059 RTSemEventDestroy(pThis->hEvtGlobal);
1060 pThis->hEvtGlobal = NIL_RTSEMEVENT;
1061 }
1062 }
1063
1064 return rc;
1065}
1066
1067
1068RTDECL(int) RTFuzzObsCreate(PRTFUZZOBS phFuzzObs)
1069{
1070 AssertPtrReturn(phFuzzObs, VERR_INVALID_POINTER);
1071
1072 int rc = VINF_SUCCESS;
1073 PRTFUZZOBSINT pThis = (PRTFUZZOBSINT)RTMemAllocZ(sizeof(*pThis));
1074 if (RT_LIKELY(pThis))
1075 {
1076 pThis->pszBinary = NULL;
1077 pThis->papszArgs = NULL;
1078 pThis->msWaitMax = 1000;
1079 pThis->hThreadGlobal = NIL_RTTHREAD;
1080 pThis->hEvtGlobal = NIL_RTSEMEVENT;
1081 pThis->bmEvt = 0;
1082 pThis->cThreads = 0;
1083 pThis->paObsThreads = NULL;
1084 pThis->tsLastStats = RTTimeMilliTS();
1085 pThis->Stats.cFuzzedInputsPerSec = 0;
1086 pThis->Stats.cFuzzedInputs = 0;
1087 pThis->Stats.cFuzzedInputsHang = 0;
1088 pThis->Stats.cFuzzedInputsCrash = 0;
1089 rc = RTFuzzCtxCreate(&pThis->hFuzzCtx);
1090 if (RT_SUCCESS(rc))
1091 {
1092 *phFuzzObs = pThis;
1093 return VINF_SUCCESS;
1094 }
1095
1096 RTMemFree(pThis);
1097 }
1098 else
1099 rc = VERR_NO_MEMORY;
1100
1101 return rc;
1102}
1103
1104
1105RTDECL(int) RTFuzzObsDestroy(RTFUZZOBS hFuzzObs)
1106{
1107 PRTFUZZOBSINT pThis = hFuzzObs;
1108 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1109
1110 RTFuzzObsExecStop(hFuzzObs);
1111
1112 /* Clean up all acquired resources. */
1113 for (unsigned i = 0; i < pThis->cArgs; i++)
1114 RTStrFree(pThis->papszArgs[i]);
1115
1116 RTMemFree(pThis->papszArgs);
1117
1118 if (pThis->hEvtGlobal != NIL_RTSEMEVENT)
1119 RTSemEventDestroy(pThis->hEvtGlobal);
1120
1121 if (pThis->pszResultsDir)
1122 RTStrFree(pThis->pszResultsDir);
1123 if (pThis->pszTmpDir)
1124 RTStrFree(pThis->pszTmpDir);
1125 if (pThis->pszBinary)
1126 RTStrFree(pThis->pszBinary);
1127 RTFuzzCtxRelease(pThis->hFuzzCtx);
1128 RTMemFree(pThis);
1129 return VINF_SUCCESS;
1130}
1131
1132
1133RTDECL(int) RTFuzzObsQueryCtx(RTFUZZOBS hFuzzObs, PRTFUZZCTX phFuzzCtx)
1134{
1135 PRTFUZZOBSINT pThis = hFuzzObs;
1136 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1137 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
1138
1139 RTFuzzCtxRetain(pThis->hFuzzCtx);
1140 *phFuzzCtx = pThis->hFuzzCtx;
1141 return VINF_SUCCESS;
1142}
1143
1144
1145RTDECL(int) RTFuzzObsQueryStats(RTFUZZOBS hFuzzObs, PRTFUZZOBSSTATS pStats)
1146{
1147 PRTFUZZOBSINT pThis = hFuzzObs;
1148 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1149 AssertPtrReturn(pStats, VERR_INVALID_POINTER);
1150
1151 uint64_t tsStatsQuery = RTTimeMilliTS();
1152 uint32_t cFuzzedInputsPerSec = ASMAtomicXchgU32(&pThis->Stats.cFuzzedInputsPerSec, 0);
1153
1154 pStats->cFuzzedInputsCrash = ASMAtomicReadU32(&pThis->Stats.cFuzzedInputsCrash);
1155 pStats->cFuzzedInputsHang = ASMAtomicReadU32(&pThis->Stats.cFuzzedInputsHang);
1156 pStats->cFuzzedInputs = ASMAtomicReadU32(&pThis->Stats.cFuzzedInputs);
1157 uint64_t cPeriodSec = (tsStatsQuery - pThis->tsLastStats) / 1000;
1158 if (cPeriodSec)
1159 {
1160 pStats->cFuzzedInputsPerSec = cFuzzedInputsPerSec / cPeriodSec;
1161 pThis->cFuzzedInputsPerSecLast = pStats->cFuzzedInputsPerSec;
1162 pThis->tsLastStats = tsStatsQuery;
1163 }
1164 else
1165 pStats->cFuzzedInputsPerSec = pThis->cFuzzedInputsPerSecLast;
1166 return VINF_SUCCESS;
1167}
1168
1169
1170RTDECL(int) RTFuzzObsSetTmpDirectory(RTFUZZOBS hFuzzObs, const char *pszTmp)
1171{
1172 PRTFUZZOBSINT pThis = hFuzzObs;
1173 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1174 AssertPtrReturn(pszTmp, VERR_INVALID_POINTER);
1175
1176 int rc = VINF_SUCCESS;
1177 pThis->pszTmpDir = RTStrDup(pszTmp);
1178 if (!pThis->pszTmpDir)
1179 rc = VERR_NO_STR_MEMORY;
1180 return rc;
1181}
1182
1183
1184RTDECL(int) RTFuzzObsSetResultDirectory(RTFUZZOBS hFuzzObs, const char *pszResults)
1185{
1186 PRTFUZZOBSINT pThis = hFuzzObs;
1187 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1188 AssertPtrReturn(pszResults, VERR_INVALID_POINTER);
1189
1190 int rc = VINF_SUCCESS;
1191 pThis->pszResultsDir = RTStrDup(pszResults);
1192 if (!pThis->pszResultsDir)
1193 rc = VERR_NO_STR_MEMORY;
1194 return rc;
1195}
1196
1197
1198RTDECL(int) RTFuzzObsSetTestBinary(RTFUZZOBS hFuzzObs, const char *pszBinary, RTFUZZOBSINPUTCHAN enmInputChan)
1199{
1200 PRTFUZZOBSINT pThis = hFuzzObs;
1201 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1202 AssertPtrReturn(pszBinary, VERR_INVALID_POINTER);
1203
1204 int rc = VINF_SUCCESS;
1205 pThis->enmInputChan = enmInputChan;
1206 pThis->pszBinary = RTStrDup(pszBinary);
1207 if (RT_UNLIKELY(!pThis->pszBinary))
1208 rc = VERR_NO_STR_MEMORY;
1209 return rc;
1210}
1211
1212
1213RTDECL(int) RTFuzzObsSetTestBinaryArgs(RTFUZZOBS hFuzzObs, const char * const *papszArgs, unsigned cArgs)
1214{
1215 PRTFUZZOBSINT pThis = hFuzzObs;
1216 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1217
1218 int rc = VINF_SUCCESS;
1219 char **papszArgsOld = pThis->papszArgs;
1220 if (papszArgs)
1221 {
1222 pThis->papszArgs = (char **)RTMemAllocZ(sizeof(char **) * (cArgs + 1));
1223 if (RT_LIKELY(pThis->papszArgs))
1224 {
1225 for (unsigned i = 0; i < cArgs; i++)
1226 {
1227 pThis->papszArgs[i] = RTStrDup(papszArgs[i]);
1228 if (RT_UNLIKELY(!pThis->papszArgs[i]))
1229 {
1230 while (i > 0)
1231 {
1232 i--;
1233 RTStrFree(pThis->papszArgs[i]);
1234 }
1235 break;
1236 }
1237 }
1238
1239 if (RT_FAILURE(rc))
1240 RTMemFree(pThis->papszArgs);
1241 }
1242 else
1243 rc = VERR_NO_MEMORY;
1244
1245 if (RT_FAILURE(rc))
1246 pThis->papszArgs = papszArgsOld;
1247 else
1248 pThis->cArgs = cArgs;
1249 }
1250 else
1251 {
1252 pThis->papszArgs = NULL;
1253 pThis->cArgs = 0;
1254 if (papszArgsOld)
1255 {
1256 char **ppsz = papszArgsOld;
1257 while (*ppsz != NULL)
1258 {
1259 RTStrFree(*ppsz);
1260 ppsz++;
1261 }
1262 RTMemFree(papszArgsOld);
1263 }
1264 }
1265
1266 return rc;
1267}
1268
1269
1270RTDECL(int) RTFuzzObsExecStart(RTFUZZOBS hFuzzObs, uint32_t cProcs)
1271{
1272 PRTFUZZOBSINT pThis = hFuzzObs;
1273 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1274 AssertReturn(cProcs <= sizeof(uint64_t) * 8, VERR_INVALID_PARAMETER);
1275 AssertReturn( pThis->enmInputChan == RTFUZZOBSINPUTCHAN_FILE
1276 || pThis->pszTmpDir != NULL,
1277 VERR_INVALID_STATE);
1278
1279 int rc = VINF_SUCCESS;
1280 if (!cProcs)
1281 cProcs = RT_MIN(RTMpGetPresentCoreCount(), sizeof(uint64_t) * 8);
1282
1283 /* Spin up the worker threads first. */
1284 rc = rtFuzzObsWorkersCreate(pThis, cProcs);
1285 if (RT_SUCCESS(rc))
1286 {
1287 /* Spin up the global thread. */
1288 rc = rtFuzzObsMasterCreate(pThis);
1289 }
1290
1291 return rc;
1292}
1293
1294
1295RTDECL(int) RTFuzzObsExecStop(RTFUZZOBS hFuzzObs)
1296{
1297 PRTFUZZOBSINT pThis = hFuzzObs;
1298 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1299
1300 /* Wait for the master thread to terminate. */
1301 if (pThis->hThreadGlobal != NIL_RTTHREAD)
1302 {
1303 ASMAtomicXchgBool(&pThis->fShutdown, true);
1304 RTSemEventSignal(pThis->hEvtGlobal);
1305 RTThreadWait(pThis->hThreadGlobal, RT_INDEFINITE_WAIT, NULL);
1306 pThis->hThreadGlobal = NIL_RTTHREAD;
1307 }
1308
1309 /* Destroy the workers. */
1310 if (pThis->paObsThreads)
1311 {
1312 for (unsigned i = 0; i < pThis->cThreads; i++)
1313 {
1314 PRTFUZZOBSTHRD pThrd = &pThis->paObsThreads[i];
1315 ASMAtomicXchgBool(&pThrd->fShutdown, true);
1316 RTThreadUserSignal(pThrd->hThread);
1317 RTThreadWait(pThrd->hThread, RT_INDEFINITE_WAIT, NULL);
1318 if (pThrd->hFuzzInput)
1319 RTFuzzInputRelease(pThrd->hFuzzInput);
1320 }
1321
1322 RTMemFree(pThis->paObsThreads);
1323 pThis->paObsThreads = NULL;
1324 pThis->cThreads = 0;
1325 }
1326
1327 RTSemEventDestroy(pThis->hEvtGlobal);
1328 pThis->hEvtGlobal = NIL_RTSEMEVENT;
1329 return VINF_SUCCESS;
1330}
1331
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette