VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/fuzz/fuzzmastercmd.cpp@ 80346

Last change on this file since 80346 was 77758, checked in by vboxsync, 6 years ago

Runtime/common/fuzz: Updates, add possiblity to dump the recorded target state and make it configurable what to include when comparing target states for equality

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 64.4 KB
Line 
1/* $Id: fuzzmastercmd.cpp 77758 2019-03-18 13:17:30Z vboxsync $ */
2/** @file
3 * IPRT - Fuzzing framework API, master command.
4 */
5
6/*
7 * Copyright (C) 2018-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.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/base64.h>
37#include <iprt/buildconfig.h>
38#include <iprt/ctype.h>
39#include <iprt/env.h>
40#include <iprt/err.h>
41#include <iprt/file.h>
42#include <iprt/getopt.h>
43#include <iprt/json.h>
44#include <iprt/list.h>
45#include <iprt/mem.h>
46#include <iprt/message.h>
47#include <iprt/path.h>
48#include <iprt/process.h>
49#include <iprt/stream.h>
50#include <iprt/string.h>
51#include <iprt/tcp.h>
52#include <iprt/thread.h>
53#include <iprt/time.h>
54#include <iprt/vfs.h>
55#include <iprt/zip.h>
56
57
58/**
59 * A running fuzzer state.
60 */
61typedef struct RTFUZZRUN
62{
63 /** List node. */
64 RTLISTNODE NdFuzzed;
65 /** Identifier. */
66 char *pszId;
67 /** Number of processes. */
68 uint32_t cProcs;
69 /** Target recorder flags. */
70 uint32_t fTgtRecFlags;
71 /** The fuzzing observer state handle. */
72 RTFUZZOBS hFuzzObs;
73 /** Flag whether fuzzing was started. */
74 bool fStarted;
75 /** Time when this run was created. */
76 RTTIME TimeCreated;
77 /** Millisecond timestamp when the run was created. */
78 uint64_t tsCreatedMs;
79} RTFUZZRUN;
80/** Pointer to a running fuzzer state. */
81typedef RTFUZZRUN *PRTFUZZRUN;
82
83
84/**
85 * Fuzzing master command state.
86 */
87typedef struct RTFUZZCMDMASTER
88{
89 /** List of running fuzzers. */
90 RTLISTANCHOR LstFuzzed;
91 /** The port to listen on. */
92 uint16_t uPort;
93 /** The TCP server for requests. */
94 PRTTCPSERVER hTcpSrv;
95 /** The root temp directory. */
96 const char *pszTmpDir;
97 /** The root results directory. */
98 const char *pszResultsDir;
99 /** Flag whether to shutdown. */
100 bool fShutdown;
101 /** The response message. */
102 char *pszResponse;
103} RTFUZZCMDMASTER;
104/** Pointer to a fuzzing master command state. */
105typedef RTFUZZCMDMASTER *PRTFUZZCMDMASTER;
106
107
108/**
109 * Wrapper around RTErrInfoSetV / RTMsgErrorV.
110 *
111 * @returns @a rc
112 * @param pErrInfo Extended error info.
113 * @param rc The return code.
114 * @param pszFormat The message format.
115 * @param ... The message format arguments.
116 */
117static int rtFuzzCmdMasterErrorRc(PRTERRINFO pErrInfo, int rc, const char *pszFormat, ...)
118{
119 va_list va;
120 va_start(va, pszFormat);
121 if (pErrInfo)
122 RTErrInfoSetV(pErrInfo, rc, pszFormat, va);
123 else
124 RTMsgErrorV(pszFormat, va);
125 va_end(va);
126 return rc;
127}
128
129
130/**
131 * Returns a running fuzzer state by the given ID.
132 *
133 * @returns Pointer to the running fuzzer state or NULL if not found.
134 * @param pThis The fuzzing master command state.
135 * @param pszId The ID to look for.
136 */
137static PRTFUZZRUN rtFuzzCmdMasterGetFuzzerById(PRTFUZZCMDMASTER pThis, const char *pszId)
138{
139 PRTFUZZRUN pIt = NULL;
140 RTListForEach(&pThis->LstFuzzed, pIt, RTFUZZRUN, NdFuzzed)
141 {
142 if (!RTStrCmp(pIt->pszId, pszId))
143 return pIt;
144 }
145
146 return NULL;
147}
148
149
150#if 0 /* unused */
151/**
152 * Processes and returns the value of the given config item in the JSON request.
153 *
154 * @returns IPRT status code.
155 * @param ppszStr Where to store the pointer to the string on success.
156 * @param pszCfgItem The config item to resolve.
157 * @param hJsonCfg The JSON object containing the item.
158 * @param pErrInfo Where to store the error information on failure, optional.
159 */
160static int rtFuzzCmdMasterFuzzRunProcessCfgString(char **ppszStr, const char *pszCfgItem, RTJSONVAL hJsonCfg, PRTERRINFO pErrInfo)
161{
162 int rc = RTJsonValueQueryStringByName(hJsonCfg, pszCfgItem, ppszStr);
163 if (RT_FAILURE(rc))
164 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query string value of \"%s\"", pszCfgItem);
165
166 return rc;
167}
168
169
170/**
171 * Processes and returns the value of the given config item in the JSON request.
172 *
173 * @returns IPRT status code.
174 * @param pfVal Where to store the config value on success.
175 * @param pszCfgItem The config item to resolve.
176 * @param hJsonCfg The JSON object containing the item.
177 * @param pErrInfo Where to store the error information on failure, optional.
178 */
179static int rtFuzzCmdMasterFuzzRunProcessCfgBool(bool *pfVal, const char *pszCfgItem, RTJSONVAL hJsonCfg, PRTERRINFO pErrInfo)
180{
181 int rc = RTJsonValueQueryBooleanByName(hJsonCfg, pszCfgItem, pfVal);
182 if (RT_FAILURE(rc))
183 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query boolean value of \"%s\"", pszCfgItem);
184
185 return rc;
186}
187
188
189/**
190 * Processes and returns the value of the given config item in the JSON request.
191 *
192 * @returns IPRT status code.
193 * @param pfVal Where to store the config value on success.
194 * @param pszCfgItem The config item to resolve.
195 * @param hJsonCfg The JSON object containing the item.
196 * @param fDef Default value if the item wasn't found.
197 * @param pErrInfo Where to store the error information on failure, optional.
198 */
199static int rtFuzzCmdMasterFuzzRunProcessCfgBoolDef(bool *pfVal, const char *pszCfgItem, RTJSONVAL hJsonCfg, bool fDef, PRTERRINFO pErrInfo)
200{
201 int rc = RTJsonValueQueryBooleanByName(hJsonCfg, pszCfgItem, pfVal);
202 if (rc == VERR_NOT_FOUND)
203 {
204 *pfVal = fDef;
205 rc = VINF_SUCCESS;
206 }
207 else if (RT_FAILURE(rc))
208 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query boolean value of \"%s\"", pszCfgItem);
209
210 return rc;
211}
212#endif
213
214
215/**
216 * Processes and returns the value of the given config item in the JSON request.
217 *
218 * @returns IPRT status code.
219 * @param pcbVal Where to store the config value on success.
220 * @param pszCfgItem The config item to resolve.
221 * @param hJsonCfg The JSON object containing the item.
222 * @param cbDef Default value if the item wasn't found.
223 * @param pErrInfo Where to store the error information on failure, optional.
224 */
225static int rtFuzzCmdMasterFuzzRunProcessCfgSizeDef(size_t *pcbVal, const char *pszCfgItem, RTJSONVAL hJsonCfg, size_t cbDef, PRTERRINFO pErrInfo)
226{
227 *pcbVal = cbDef; /* Make GCC 6.3.0 happy. */
228
229 int64_t i64Val = 0;
230 int rc = RTJsonValueQueryIntegerByName(hJsonCfg, pszCfgItem, &i64Val);
231 if (rc == VERR_NOT_FOUND)
232 rc = VINF_SUCCESS;
233 else if (RT_FAILURE(rc))
234 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query size_t value of \"%s\"", pszCfgItem);
235 else if (i64Val < 0 || (size_t)i64Val != (uint64_t)i64Val)
236 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_OUT_OF_RANGE, "JSON request malformed: Integer \"%s\" is out of range", pszCfgItem);
237 else
238 *pcbVal = (size_t)i64Val;
239
240 return rc;
241}
242
243
244/**
245 * Processes and returns the value of the given config item in the JSON request.
246 *
247 * @returns IPRT status code.
248 * @param pcbVal Where to store the config value on success.
249 * @param pszCfgItem The config item to resolve.
250 * @param hJsonCfg The JSON object containing the item.
251 * @param cbDef Default value if the item wasn't found.
252 * @param pErrInfo Where to store the error information on failure, optional.
253 */
254static int rtFuzzCmdMasterFuzzRunProcessCfgU32Def(uint32_t *pu32Val, const char *pszCfgItem, RTJSONVAL hJsonCfg, uint32_t u32Def, PRTERRINFO pErrInfo)
255{
256 int64_t i64Val = 0;
257 int rc = RTJsonValueQueryIntegerByName(hJsonCfg, pszCfgItem, &i64Val);
258 if (rc == VERR_NOT_FOUND)
259 {
260 *pu32Val = u32Def;
261 rc = VINF_SUCCESS;
262 }
263 else if (RT_FAILURE(rc))
264 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query uint32_t value of \"%s\"", pszCfgItem);
265 else if (i64Val < 0 || (uint32_t)i64Val != (uint64_t)i64Val)
266 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_OUT_OF_RANGE, "JSON request malformed: Integer \"%s\" is out of range", pszCfgItem);
267 else
268 *pu32Val = (uint32_t)i64Val;
269
270 return rc;
271}
272
273
274/**
275 * Returns the configured input channel for the binary under test.
276 *
277 * @returns Selected input channel or RTFUZZOBSINPUTCHAN_INVALID if an error occurred.
278 * @param pszCfgItem The config item to resolve.
279 * @param hJsonCfg The JSON object containing the item.
280 * @param enmChanDef Default value if the item wasn't found.
281 * @param pErrInfo Where to store the error information on failure, optional.
282 */
283static RTFUZZOBSINPUTCHAN rtFuzzCmdMasterFuzzRunProcessCfgGetInputChan(const char *pszCfgItem, RTJSONVAL hJsonCfg, RTFUZZOBSINPUTCHAN enmChanDef, PRTERRINFO pErrInfo)
284{
285 RTFUZZOBSINPUTCHAN enmInputChan = RTFUZZOBSINPUTCHAN_INVALID;
286
287 RTJSONVAL hJsonVal;
288 int rc = RTJsonValueQueryByName(hJsonCfg, pszCfgItem, &hJsonVal);
289 if (rc == VERR_NOT_FOUND)
290 enmInputChan = enmChanDef;
291 else if (RT_SUCCESS(rc))
292 {
293 const char *pszBinary = RTJsonValueGetString(hJsonVal);
294 if (pszBinary)
295 {
296 if (!RTStrCmp(pszBinary, "File"))
297 enmInputChan = RTFUZZOBSINPUTCHAN_FILE;
298 else if (!RTStrCmp(pszBinary, "Stdin"))
299 enmInputChan = RTFUZZOBSINPUTCHAN_STDIN;
300 else if (!RTStrCmp(pszBinary, "FuzzingAware"))
301 enmInputChan = RTFUZZOBSINPUTCHAN_FUZZING_AWARE_CLIENT;
302 else
303 rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_PARAMETER, "JSON request malformed: \"%s\" for \"%s\" is not known", pszCfgItem, pszBinary);
304 }
305 else
306 rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "JSON request malformed: \"%s\" is not a string", pszCfgItem);
307
308 RTJsonValueRelease(hJsonVal);
309 }
310 else
311 rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query \"%s\"", pszCfgItem);
312
313 return enmInputChan;
314}
315
316
317/**
318 * Processes binary related configs for the given fuzzing run.
319 *
320 * @returns IPRT status code.
321 * @param pFuzzRun The fuzzing run.
322 * @param hJsonRoot The root node of the JSON request.
323 * @param pErrInfo Where to store the error information on failure, optional.
324 */
325static int rtFuzzCmdMasterFuzzRunProcessBinaryCfg(PRTFUZZRUN pFuzzRun, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
326{
327 RTJSONVAL hJsonVal;
328 int rc = RTJsonValueQueryByName(hJsonRoot, "BinaryPath", &hJsonVal);
329 if (RT_SUCCESS(rc))
330 {
331 const char *pszBinary = RTJsonValueGetString(hJsonVal);
332 if (RT_LIKELY(pszBinary))
333 {
334 RTFUZZOBSINPUTCHAN enmInputChan = rtFuzzCmdMasterFuzzRunProcessCfgGetInputChan("InputChannel", hJsonRoot, RTFUZZOBSINPUTCHAN_STDIN, pErrInfo);
335 if (enmInputChan != RTFUZZOBSINPUTCHAN_INVALID)
336 {
337 rc = RTFuzzObsSetTestBinary(pFuzzRun->hFuzzObs, pszBinary, enmInputChan);
338 if (RT_FAILURE(rc))
339 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Failed to add the binary path for the fuzzing run");
340 }
341 }
342 else
343 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "JSON request malformed: \"BinaryPath\" is not a string");
344 RTJsonValueRelease(hJsonVal);
345 }
346 else
347 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query value of \"BinaryPath\"");
348
349 return rc;
350}
351
352
353/**
354 * Processes argument related configs for the given fuzzing run.
355 *
356 * @returns IPRT status code.
357 * @param pFuzzRun The fuzzing run.
358 * @param hJsonRoot The root node of the JSON request.
359 * @param pErrInfo Where to store the error information on failure, optional.
360 */
361static int rtFuzzCmdMasterFuzzRunProcessArgCfg(PRTFUZZRUN pFuzzRun, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
362{
363 RTJSONVAL hJsonValArgArray;
364 int rc = RTJsonValueQueryByName(hJsonRoot, "Arguments", &hJsonValArgArray);
365 if (RT_SUCCESS(rc))
366 {
367 unsigned cArgs = 0;
368 rc = RTJsonValueQueryArraySize(hJsonValArgArray, &cArgs);
369 if (RT_SUCCESS(rc))
370 {
371 if (cArgs > 0)
372 {
373 const char **papszArgs = (const char **)RTMemAllocZ(cArgs * sizeof(const char *));
374 RTJSONVAL *pahJsonVal = (RTJSONVAL *)RTMemAllocZ(cArgs * sizeof(RTJSONVAL));
375 if (RT_LIKELY(papszArgs && pahJsonVal))
376 {
377 unsigned idx = 0;
378
379 for (idx = 0; idx < cArgs && RT_SUCCESS(rc); idx++)
380 {
381 rc = RTJsonValueQueryByIndex(hJsonValArgArray, idx, &pahJsonVal[idx]);
382 if (RT_SUCCESS(rc))
383 {
384 papszArgs[idx] = RTJsonValueGetString(pahJsonVal[idx]);
385 if (RT_UNLIKELY(!papszArgs[idx]))
386 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "Argument %u is not a string", idx);
387 }
388 }
389
390 if (RT_SUCCESS(rc))
391 {
392 rc = RTFuzzObsSetTestBinaryArgs(pFuzzRun->hFuzzObs, papszArgs, cArgs);
393 if (RT_FAILURE(rc))
394 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Failed to set arguments for the fuzzing run");
395 }
396
397 /* Release queried values. */
398 while (idx > 0)
399 {
400 RTJsonValueRelease(pahJsonVal[idx - 1]);
401 idx--;
402 }
403 }
404 else
405 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_NO_MEMORY, "Out of memory allocating memory for the argument vector");
406
407 if (papszArgs)
408 RTMemFree(papszArgs);
409 if (pahJsonVal)
410 RTMemFree(pahJsonVal);
411 }
412 }
413 else
414 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: \"Arguments\" is not an array");
415 RTJsonValueRelease(hJsonValArgArray);
416 }
417
418 return rc;
419}
420
421
422/**
423 * Processes process environment related configs for the given fuzzing run.
424 *
425 * @returns IPRT status code.
426 * @param pFuzzRun The fuzzing run.
427 * @param hJsonRoot The root node of the JSON request.
428 * @param pErrInfo Where to store the error information on failure, optional.
429 */
430static int rtFuzzCmdMasterFuzzRunProcessEnvironment(PRTFUZZRUN pFuzzRun, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
431{
432 RTJSONVAL hJsonValEnv;
433 int rc = RTJsonValueQueryByName(hJsonRoot, "Env", &hJsonValEnv);
434 if (RT_SUCCESS(rc))
435 {
436 bool fReplaceEnv = false; /* false means to append everything to the default block. */
437
438 rc = RTJsonValueQueryBooleanByName(hJsonRoot, "EnvReplace", &fReplaceEnv);
439 if ( RT_SUCCESS(rc)
440 || rc == VERR_NOT_FOUND)
441 {
442 RTJSONIT hEnvIt;
443 RTENV hEnv = NULL;
444
445 if (fReplaceEnv)
446 rc = RTEnvCreate(&hEnv);
447 else
448 rc = RTEnvClone(&hEnv, RTENV_DEFAULT);
449
450 if (RT_SUCCESS(rc))
451 {
452 rc = RTJsonIteratorBeginArray(hJsonValEnv, &hEnvIt);
453 if (RT_SUCCESS(rc))
454 {
455 do
456 {
457 RTJSONVAL hVal;
458 rc = RTJsonIteratorQueryValue(hEnvIt, &hVal, NULL);
459 if (RT_SUCCESS(rc))
460 {
461 const char *pszVar = RTJsonValueGetString(hVal);
462 if (RT_LIKELY(pszVar))
463 rc = RTEnvPutEx(hEnv, pszVar);
464 RTJsonValueRelease(hVal);
465 }
466 rc = RTJsonIteratorNext(hEnvIt);
467 } while (RT_SUCCESS(rc));
468
469 if ( rc == VERR_JSON_IS_EMPTY
470 || rc == VERR_JSON_ITERATOR_END)
471 rc = VINF_SUCCESS;
472 else
473 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to parse environment");
474
475 RTJsonIteratorFree(hEnvIt);
476 }
477 else if (rc == VERR_JSON_IS_EMPTY)
478 rc = VINF_SUCCESS;
479 else
480 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: \"Environment\" is not an array");
481
482 if (RT_SUCCESS(rc))
483 {
484 rc = RTFuzzObsSetTestBinaryEnv(pFuzzRun->hFuzzObs, hEnv);
485 AssertRC(rc);
486 }
487 else if (hEnv)
488 RTEnvDestroy(hEnv);
489 }
490 else
491 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to create environment block");
492 }
493 else
494 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query \"EnvReplace\"");
495
496 RTJsonValueRelease(hJsonValEnv);
497 }
498 else if (rc == VERR_NOT_FOUND)
499 rc = VINF_SUCCESS; /* Just keep using the default environment. */
500 else
501 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query the \"Environment\"");
502
503 return rc;
504}
505
506
507/**
508 * Processes process environment related configs for the given fuzzing run.
509 *
510 * @returns IPRT status code.
511 * @param pFuzzRun The fuzzing run.
512 * @param hJsonRoot The root node of the JSON request.
513 * @param pErrInfo Where to store the error information on failure, optional.
514 */
515static int rtFuzzCmdMasterFuzzRunProcessSanitizers(PRTFUZZRUN pFuzzRun, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
516{
517 RTJSONVAL hJsonValSan;
518 int rc = RTJsonValueQueryByName(hJsonRoot, "Sanitizers", &hJsonValSan);
519 if (RT_SUCCESS(rc))
520 {
521 uint32_t fSanitizers = 0;
522 RTJSONIT hSanIt;
523 rc = RTJsonIteratorBeginArray(hJsonValSan, &hSanIt);
524 if (RT_SUCCESS(rc))
525 {
526 do
527 {
528 RTJSONVAL hVal;
529 rc = RTJsonIteratorQueryValue(hSanIt, &hVal, NULL);
530 if (RT_SUCCESS(rc))
531 {
532 const char *pszSan = RTJsonValueGetString(hVal);
533 if (!RTStrICmp(pszSan, "Asan"))
534 fSanitizers |= RTFUZZOBS_SANITIZER_F_ASAN;
535 else if (!RTStrICmp(pszSan, "SanCov"))
536 fSanitizers |= RTFUZZOBS_SANITIZER_F_SANCOV;
537 else
538 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_NOT_FOUND, "JSON request malformed: The sanitizer '%s' is not known", pszSan);
539 RTJsonValueRelease(hVal);
540 }
541 rc = RTJsonIteratorNext(hSanIt);
542 } while (RT_SUCCESS(rc));
543
544 if ( rc == VERR_JSON_IS_EMPTY
545 || rc == VERR_JSON_ITERATOR_END)
546 rc = VINF_SUCCESS;
547 else
548 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to parse sanitizers");
549
550 RTJsonIteratorFree(hSanIt);
551 }
552 else if (rc == VERR_JSON_IS_EMPTY)
553 rc = VINF_SUCCESS;
554 else
555 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: \"Sanitizers\" is not an array");
556
557 if (RT_SUCCESS(rc))
558 {
559 rc = RTFuzzObsSetTestBinarySanitizers(pFuzzRun->hFuzzObs, fSanitizers);
560 AssertRC(rc);
561 }
562
563 RTJsonValueRelease(hJsonValSan);
564 }
565 else if (rc == VERR_NOT_FOUND)
566 rc = VINF_SUCCESS; /* Just keep using the defaults. */
567 else
568 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query the \"Sanitizers\"");
569
570 return rc;
571}
572
573
574/**
575 * Processes the given seed and adds it to the input corpus.
576 *
577 * @returns IPRT status code.
578 * @param hFuzzCtx The fuzzing context handle.
579 * @param pszCompression Compression used for the seed.
580 * @param pszSeed The seed as a base64 encoded string.
581 * @param pErrInfo Where to store the error information on failure, optional.
582 */
583static int rtFuzzCmdMasterFuzzRunProcessSeed(RTFUZZCTX hFuzzCtx, const char *pszCompression, const char *pszSeed, PRTERRINFO pErrInfo)
584{
585 int rc = VINF_SUCCESS;
586 ssize_t cbSeedDecoded = RTBase64DecodedSize(pszSeed, NULL);
587 if (cbSeedDecoded > 0)
588 {
589 uint8_t *pbSeedDecoded = (uint8_t *)RTMemAllocZ(cbSeedDecoded);
590 if (RT_LIKELY(pbSeedDecoded))
591 {
592 rc = RTBase64Decode(pszSeed, pbSeedDecoded, cbSeedDecoded, NULL, NULL);
593 if (RT_SUCCESS(rc))
594 {
595 /* Decompress if applicable. */
596 if (!RTStrICmp(pszCompression, "None"))
597 rc = RTFuzzCtxCorpusInputAdd(hFuzzCtx, pbSeedDecoded, cbSeedDecoded);
598 else
599 {
600 RTVFSIOSTREAM hVfsIosSeed;
601 rc = RTVfsIoStrmFromBuffer(RTFILE_O_READ, pbSeedDecoded, cbSeedDecoded, &hVfsIosSeed);
602 if (RT_SUCCESS(rc))
603 {
604 RTVFSIOSTREAM hVfsDecomp = NIL_RTVFSIOSTREAM;
605
606 if (!RTStrICmp(pszCompression, "Gzip"))
607 rc = RTZipGzipDecompressIoStream(hVfsIosSeed, RTZIPGZIPDECOMP_F_ALLOW_ZLIB_HDR, &hVfsDecomp);
608 else
609 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "Request error: Compression \"%s\" is not known", pszCompression);
610
611 if (RT_SUCCESS(rc))
612 {
613 RTVFSFILE hVfsFile;
614 rc = RTVfsMemFileCreate(hVfsDecomp, 2 * _1M, &hVfsFile);
615 if (RT_SUCCESS(rc))
616 {
617 rc = RTVfsFileSeek(hVfsFile, 0, RTFILE_SEEK_BEGIN, NULL);
618 if (RT_SUCCESS(rc))
619 {
620 /* The VFS file contains the buffer for the seed now. */
621 rc = RTFuzzCtxCorpusInputAddFromVfsFile(hFuzzCtx, hVfsFile);
622 if (RT_FAILURE(rc))
623 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to add input seed");
624 RTVfsFileRelease(hVfsFile);
625 }
626 else
627 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "Request error: Failed to seek to the beginning of the seed");
628 }
629 else
630 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "Request error: Failed to decompress input seed");
631
632 RTVfsIoStrmRelease(hVfsDecomp);
633 }
634
635 RTVfsIoStrmRelease(hVfsIosSeed);
636 }
637 else
638 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to create I/O stream from seed buffer");
639 }
640 }
641 else
642 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to decode the seed string");
643
644 RTMemFree(pbSeedDecoded);
645 }
646 else
647 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_NO_MEMORY, "Request error: Failed to allocate %zd bytes of memory for the seed", cbSeedDecoded);
648 }
649 else
650 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "JSON request malformed: Couldn't find \"Seed\" doesn't contain a base64 encoded value");
651
652 return rc;
653}
654
655
656/**
657 * Processes a signle input seed for the given fuzzing run.
658 *
659 * @returns IPRT status code.
660 * @param pFuzzRun The fuzzing run.
661 * @param hJsonSeed The seed node of the JSON request.
662 * @param pErrInfo Where to store the error information on failure, optional.
663 */
664static int rtFuzzCmdMasterFuzzRunProcessInputSeedSingle(PRTFUZZRUN pFuzzRun, RTJSONVAL hJsonSeed, PRTERRINFO pErrInfo)
665{
666 RTFUZZCTX hFuzzCtx;
667 int rc = RTFuzzObsQueryCtx(pFuzzRun->hFuzzObs, &hFuzzCtx);
668 if (RT_SUCCESS(rc))
669 {
670 RTJSONVAL hJsonValComp;
671 rc = RTJsonValueQueryByName(hJsonSeed, "Compression", &hJsonValComp);
672 if (RT_SUCCESS(rc))
673 {
674 const char *pszCompression = RTJsonValueGetString(hJsonValComp);
675 if (RT_LIKELY(pszCompression))
676 {
677 RTJSONVAL hJsonValSeed;
678 rc = RTJsonValueQueryByName(hJsonSeed, "Seed", &hJsonValSeed);
679 if (RT_SUCCESS(rc))
680 {
681 const char *pszSeed = RTJsonValueGetString(hJsonValSeed);
682 if (RT_LIKELY(pszSeed))
683 rc = rtFuzzCmdMasterFuzzRunProcessSeed(hFuzzCtx, pszCompression, pszSeed, pErrInfo);
684 else
685 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "JSON request malformed: \"Seed\" value is not a string");
686
687 RTJsonValueRelease(hJsonValSeed);
688 }
689 else
690 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Couldn't find \"Seed\" value");
691 }
692 else
693 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_INVALID_STATE, "JSON request malformed: \"Compression\" value is not a string");
694
695 RTJsonValueRelease(hJsonValComp);
696 }
697 else
698 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Couldn't find \"Compression\" value");
699
700 RTFuzzCtxRelease(hFuzzCtx);
701 }
702 else
703 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Failed to query fuzzing context from observer");
704
705 return rc;
706}
707
708
709/**
710 * Processes input seed related configs for the given fuzzing run.
711 *
712 * @returns IPRT status code.
713 * @param pFuzzRun The fuzzing run.
714 * @param hJsonRoot The root node of the JSON request.
715 * @param pErrInfo Where to store the error information on failure, optional.
716 */
717static int rtFuzzCmdMasterFuzzRunProcessInputSeeds(PRTFUZZRUN pFuzzRun, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
718{
719 RTJSONVAL hJsonValSeedArray;
720 int rc = RTJsonValueQueryByName(hJsonRoot, "InputSeeds", &hJsonValSeedArray);
721 if (RT_SUCCESS(rc))
722 {
723 RTJSONIT hIt;
724 rc = RTJsonIteratorBegin(hJsonValSeedArray, &hIt);
725 if (RT_SUCCESS(rc))
726 {
727 RTJSONVAL hJsonInpSeed;
728 while ( RT_SUCCESS(rc)
729 && RTJsonIteratorQueryValue(hIt, &hJsonInpSeed, NULL) != VERR_JSON_ITERATOR_END)
730 {
731 rc = rtFuzzCmdMasterFuzzRunProcessInputSeedSingle(pFuzzRun, hJsonInpSeed, pErrInfo);
732 RTJsonValueRelease(hJsonInpSeed);
733 if (RT_FAILURE(rc))
734 break;
735 rc = RTJsonIteratorNext(hIt);
736 }
737
738 if (rc == VERR_JSON_ITERATOR_END)
739 rc = VINF_SUCCESS;
740 }
741 else
742 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to create array iterator");
743
744 RTJsonValueRelease(hJsonValSeedArray);
745 }
746
747 return rc;
748}
749
750
751/**
752 * Processes miscellaneous config items.
753 *
754 * @returns IPRT status code.
755 * @param pFuzzRun The fuzzing run.
756 * @param hJsonRoot The root node of the JSON request.
757 * @param pErrInfo Where to store the error information on failure, optional.
758 */
759static int rtFuzzCmdMasterFuzzRunProcessMiscCfg(PRTFUZZRUN pFuzzRun, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
760{
761 size_t cbTmp;
762 int rc = rtFuzzCmdMasterFuzzRunProcessCfgSizeDef(&cbTmp, "InputSeedMax", hJsonRoot, 0, pErrInfo);
763 if (RT_SUCCESS(rc))
764 {
765 RTFUZZCTX hFuzzCtx;
766 rc = RTFuzzObsQueryCtx(pFuzzRun->hFuzzObs, &hFuzzCtx);
767 AssertRC(rc);
768
769 rc = RTFuzzCtxCfgSetInputSeedMaximum(hFuzzCtx, cbTmp);
770 if (RT_FAILURE(rc))
771 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to set maximum input seed size to %zu", cbTmp);
772 }
773
774 if (RT_SUCCESS(rc))
775 rc = rtFuzzCmdMasterFuzzRunProcessCfgU32Def(&pFuzzRun->cProcs, "FuzzingProcs", hJsonRoot, 0, pErrInfo);
776 if (RT_SUCCESS(rc))
777 {
778 uint32_t msTimeoutMax = 0;
779 rc = rtFuzzCmdMasterFuzzRunProcessCfgU32Def(&msTimeoutMax, "TimeoutMax", hJsonRoot, 1000, pErrInfo);
780 if (RT_SUCCESS(rc))
781 rc = RTFuzzObsSetTestBinaryTimeout(pFuzzRun->hFuzzObs, msTimeoutMax);
782 }
783
784 return rc;
785}
786
787
788/**
789 * Processes target recording related configs for the given fuzzing run.
790 *
791 * @returns IPRT status code.
792 * @param pFuzzRun The fuzzing run.
793 * @param hJsonRoot The root node of the JSON request.
794 * @param pErrInfo Where to store the error information on failure, optional.
795 */
796static int rtFuzzCmdMasterFuzzRunProcessTgtRecFlags(PRTFUZZRUN pFuzzRun, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
797{
798 RTJSONVAL hJsonValTgt;
799 int rc = RTJsonValueQueryByName(hJsonRoot, "TgtRec", &hJsonValTgt);
800 if (RT_SUCCESS(rc))
801 {
802 uint32_t fTgtRecFlags = 0;
803 RTJSONIT hTgtIt;
804 rc = RTJsonIteratorBeginArray(hJsonValTgt, &hTgtIt);
805 if (RT_SUCCESS(rc))
806 {
807 do
808 {
809 RTJSONVAL hVal;
810 rc = RTJsonIteratorQueryValue(hTgtIt, &hVal, NULL);
811 if (RT_SUCCESS(rc))
812 {
813 const char *pszTgtRec = RTJsonValueGetString(hVal);
814 if (!RTStrICmp(pszTgtRec, "StdOut"))
815 fTgtRecFlags |= RTFUZZTGT_REC_STATE_F_STDOUT;
816 else if (!RTStrICmp(pszTgtRec, "StdErr"))
817 fTgtRecFlags |= RTFUZZTGT_REC_STATE_F_STDERR;
818 else if (!RTStrICmp(pszTgtRec, "ProcSts"))
819 fTgtRecFlags |= RTFUZZTGT_REC_STATE_F_PROCSTATUS;
820 else if (!RTStrICmp(pszTgtRec, "SanCov"))
821 fTgtRecFlags |= RTFUZZTGT_REC_STATE_F_SANCOV;
822 else
823 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_NOT_FOUND, "JSON request malformed: The recording flags '%s' is not known", pszTgtRec);
824 RTJsonValueRelease(hVal);
825 }
826 rc = RTJsonIteratorNext(hTgtIt);
827 } while (RT_SUCCESS(rc));
828
829 if ( rc == VERR_JSON_IS_EMPTY
830 || rc == VERR_JSON_ITERATOR_END)
831 rc = VINF_SUCCESS;
832 else
833 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to parse target recording flags");
834
835 RTJsonIteratorFree(hTgtIt);
836 }
837 else if (rc == VERR_JSON_IS_EMPTY)
838 rc = VINF_SUCCESS;
839 else
840 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: \"TgtRec\" is not an array");
841
842 pFuzzRun->fTgtRecFlags = fTgtRecFlags;
843
844 RTJsonValueRelease(hJsonValTgt);
845 }
846 else if (rc == VERR_NOT_FOUND)
847 {
848 pFuzzRun->fTgtRecFlags = RTFUZZTGT_REC_STATE_F_PROCSTATUS;
849 rc = VINF_SUCCESS; /* Just keep using the defaults. */
850 }
851 else
852 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Failed to query \"TgtRec\"");
853
854 return rc;
855}
856
857
858/**
859 * Sets up the directories for the given fuzzing run.
860 *
861 * @returns IPRT status code.
862 * @param pThis The fuzzing master command state.
863 * @param pFuzzRun The fuzzing run to setup the directories for.
864 * @param pErrInfo Where to store the error information on failure, optional.
865 */
866static int rtFuzzCmdMasterFuzzRunSetupDirectories(PRTFUZZCMDMASTER pThis, PRTFUZZRUN pFuzzRun, PRTERRINFO pErrInfo)
867{
868 /* Create temp directories. */
869 char szTmpDir[RTPATH_MAX];
870 int rc = RTPathJoin(&szTmpDir[0], sizeof(szTmpDir), pThis->pszTmpDir, pFuzzRun->pszId);
871 AssertRC(rc);
872 rc = RTDirCreate(szTmpDir, 0700, RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_SET
873 | RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_NOT_CRITICAL);
874 if (rc == VERR_ALREADY_EXISTS)
875 {
876 /* Clear the directory. */
877 rc = RTDirRemoveRecursive(szTmpDir, RTDIRRMREC_F_CONTENT_ONLY);
878 }
879
880 if (RT_SUCCESS(rc))
881 {
882 rc = RTFuzzObsSetTmpDirectory(pFuzzRun->hFuzzObs, szTmpDir);
883 if (RT_SUCCESS(rc))
884 {
885 rc = RTPathJoin(&szTmpDir[0], sizeof(szTmpDir), pThis->pszResultsDir, pFuzzRun->pszId);
886 AssertRC(rc);
887 rc = RTDirCreate(szTmpDir, 0700, RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_SET
888 | RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_NOT_CRITICAL);
889 if (RT_SUCCESS(rc) || rc == VERR_ALREADY_EXISTS)
890 {
891 rc = RTFuzzObsSetResultDirectory(pFuzzRun->hFuzzObs, szTmpDir);
892 if (RT_FAILURE(rc))
893 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to set results directory to %s", szTmpDir);
894 }
895 else
896 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to create results directory %s", szTmpDir);
897 }
898 else
899 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to set temporary directory to %s", szTmpDir);
900 }
901 else
902 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to create temporary directory %s", szTmpDir);
903
904 return rc;
905}
906
907
908/**
909 * Creates a new fuzzing run with the given ID.
910 *
911 * @returns IPRT status code.
912 * @param pThis The fuzzing master command state.
913 * @param pszId The ID to use.
914 * @param hJsonRoot The root node of the JSON request.
915 * @param pErrInfo Where to store the error information on failure, optional.
916 */
917static int rtFuzzCmdMasterCreateFuzzRunWithId(PRTFUZZCMDMASTER pThis, const char *pszId, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
918{
919 int rc = VINF_SUCCESS;
920 PRTFUZZRUN pFuzzRun = (PRTFUZZRUN)RTMemAllocZ(sizeof(*pFuzzRun));
921 if (RT_LIKELY(pFuzzRun))
922 {
923 pFuzzRun->pszId = RTStrDup(pszId);
924 if (RT_LIKELY(pFuzzRun->pszId))
925 {
926 rc = rtFuzzCmdMasterFuzzRunProcessTgtRecFlags(pFuzzRun, hJsonRoot, pErrInfo);
927 if (RT_SUCCESS(rc))
928 {
929 rc = RTFuzzObsCreate(&pFuzzRun->hFuzzObs, RTFUZZCTXTYPE_BLOB, pFuzzRun->fTgtRecFlags);
930 if (RT_SUCCESS(rc))
931 {
932 rc = rtFuzzCmdMasterFuzzRunProcessBinaryCfg(pFuzzRun, hJsonRoot, pErrInfo);
933 if (RT_SUCCESS(rc))
934 rc = rtFuzzCmdMasterFuzzRunProcessArgCfg(pFuzzRun, hJsonRoot, pErrInfo);
935 if (RT_SUCCESS(rc))
936 rc = rtFuzzCmdMasterFuzzRunProcessEnvironment(pFuzzRun, hJsonRoot, pErrInfo);
937 if (RT_SUCCESS(rc))
938 rc = rtFuzzCmdMasterFuzzRunProcessInputSeeds(pFuzzRun, hJsonRoot, pErrInfo);
939 if (RT_SUCCESS(rc))
940 rc = rtFuzzCmdMasterFuzzRunProcessMiscCfg(pFuzzRun, hJsonRoot, pErrInfo);
941 if (RT_SUCCESS(rc))
942 rc = rtFuzzCmdMasterFuzzRunProcessSanitizers(pFuzzRun, hJsonRoot, pErrInfo);
943 if (RT_SUCCESS(rc))
944 rc = rtFuzzCmdMasterFuzzRunSetupDirectories(pThis, pFuzzRun, pErrInfo);
945
946 if (RT_SUCCESS(rc))
947 {
948 /* Start fuzzing. */
949 RTListAppend(&pThis->LstFuzzed, &pFuzzRun->NdFuzzed);
950 rc = RTFuzzObsExecStart(pFuzzRun->hFuzzObs, pFuzzRun->cProcs);
951 if (RT_SUCCESS(rc))
952 {
953 RTTIMESPEC TimeSpec;
954 RTTimeNow(&TimeSpec);
955 RTTimeLocalExplode(&pFuzzRun->TimeCreated, &TimeSpec);
956 pFuzzRun->tsCreatedMs = RTTimeMilliTS();
957 pFuzzRun->fStarted = true;
958 }
959 else
960 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to start fuzzing with %Rrc", rc);
961 }
962 }
963 }
964 }
965 else
966 rc = VERR_NO_STR_MEMORY;
967 }
968 else
969 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_NO_MEMORY, "Request error: Out of memory allocating the fuzzer state");
970
971 return rc;
972}
973
974
975/**
976 * Resolves the fuzzing run from the given ID config item and the given JSON request.
977 *
978 * @returns IPRT status code.
979 * @param pThis The fuzzing master command state.
980 * @param hJsonRoot The root node of the JSON request.
981 * @param pszIdItem The JSON item which contains the ID of the fuzzing run.
982 * @param ppFuzzRun Where to store the pointer to the fuzzing run on success.
983 */
984static int rtFuzzCmdMasterQueryFuzzRunFromJson(PRTFUZZCMDMASTER pThis, RTJSONVAL hJsonRoot, const char *pszIdItem, PRTERRINFO pErrInfo,
985 PRTFUZZRUN *ppFuzzRun)
986{
987 RTJSONVAL hJsonValId;
988 int rc = RTJsonValueQueryByName(hJsonRoot, pszIdItem, &hJsonValId);
989 if (RT_SUCCESS(rc))
990 {
991 const char *pszId = RTJsonValueGetString(hJsonValId);
992 if (pszId)
993 {
994 PRTFUZZRUN pFuzzRun = rtFuzzCmdMasterGetFuzzerById(pThis, pszId);
995 if (pFuzzRun)
996 *ppFuzzRun = pFuzzRun;
997 else
998 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_NOT_FOUND, "Request error: The ID \"%s\" wasn't found", pszId);
999 }
1000 else
1001 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_JSON_VALUE_INVALID_TYPE, "JSON request malformed: \"Id\" is not a string value");
1002
1003 RTJsonValueRelease(hJsonValId);
1004 }
1005 else
1006 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Couldn't find \"Id\" value");
1007 return rc;
1008}
1009
1010
1011/**
1012 * Processes the "StartFuzzing" request.
1013 *
1014 * @returns IPRT status code.
1015 * @param pThis The fuzzing master command state.
1016 * @param hJsonRoot The root node of the JSON request.
1017 * @param pErrInfo Where to store the error information on failure, optional.
1018 */
1019static int rtFuzzCmdMasterProcessJsonReqStart(PRTFUZZCMDMASTER pThis, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
1020{
1021 RTJSONVAL hJsonValId;
1022 int rc = RTJsonValueQueryByName(hJsonRoot, "Id", &hJsonValId);
1023 if (RT_SUCCESS(rc))
1024 {
1025 const char *pszId = RTJsonValueGetString(hJsonValId);
1026 if (pszId)
1027 {
1028 PRTFUZZRUN pFuzzRun = rtFuzzCmdMasterGetFuzzerById(pThis, pszId);
1029 if (!pFuzzRun)
1030 rc = rtFuzzCmdMasterCreateFuzzRunWithId(pThis, pszId, hJsonRoot, pErrInfo);
1031 else
1032 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_ALREADY_EXISTS, "Request error: The ID \"%s\" is already registered", pszId);
1033 }
1034 else
1035 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_JSON_VALUE_INVALID_TYPE, "JSON request malformed: \"Id\" is not a string value");
1036
1037 RTJsonValueRelease(hJsonValId);
1038 }
1039 else
1040 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Couldn't find \"Id\" value");
1041 return rc;
1042}
1043
1044
1045/**
1046 * Processes the "StopFuzzing" request.
1047 *
1048 * @returns IPRT status code.
1049 * @param pThis The fuzzing master command state.
1050 * @param hJsonValRoot The root node of the JSON request.
1051 * @param pErrInfo Where to store the error information on failure, optional.
1052 */
1053static int rtFuzzCmdMasterProcessJsonReqStop(PRTFUZZCMDMASTER pThis, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
1054{
1055 PRTFUZZRUN pFuzzRun;
1056 int rc = rtFuzzCmdMasterQueryFuzzRunFromJson(pThis, hJsonRoot, "Id", pErrInfo, &pFuzzRun);
1057 if (RT_SUCCESS(rc))
1058 {
1059 RTListNodeRemove(&pFuzzRun->NdFuzzed);
1060 RTFuzzObsExecStop(pFuzzRun->hFuzzObs);
1061 RTFuzzObsDestroy(pFuzzRun->hFuzzObs);
1062 RTStrFree(pFuzzRun->pszId);
1063 RTMemFree(pFuzzRun);
1064 }
1065
1066 return rc;
1067}
1068
1069
1070/**
1071 * Processes the "SuspendFuzzing" request.
1072 *
1073 * @returns IPRT status code.
1074 * @param pThis The fuzzing master command state.
1075 * @param hJsonValRoot The root node of the JSON request.
1076 * @param pErrInfo Where to store the error information on failure, optional.
1077 */
1078static int rtFuzzCmdMasterProcessJsonReqSuspend(PRTFUZZCMDMASTER pThis, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
1079{
1080 PRTFUZZRUN pFuzzRun;
1081 int rc = rtFuzzCmdMasterQueryFuzzRunFromJson(pThis, hJsonRoot, "Id", pErrInfo, &pFuzzRun);
1082 if (RT_SUCCESS(rc))
1083 {
1084 if (pFuzzRun->fStarted)
1085 {
1086 rc = RTFuzzObsExecStop(pFuzzRun->hFuzzObs);
1087 if (RT_SUCCESS(rc))
1088 pFuzzRun->fStarted = false;
1089 else
1090 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Suspending the fuzzing process failed");
1091 }
1092 }
1093
1094 return rc;
1095}
1096
1097
1098/**
1099 * Processes the "ResumeFuzzing" request.
1100 *
1101 * @returns IPRT status code.
1102 * @param pThis The fuzzing master command state.
1103 * @param hJsonValRoot The root node of the JSON request.
1104 * @param pErrInfo Where to store the error information on failure, optional.
1105 */
1106static int rtFuzzCmdMasterProcessJsonReqResume(PRTFUZZCMDMASTER pThis, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
1107{
1108 PRTFUZZRUN pFuzzRun;
1109 int rc = rtFuzzCmdMasterQueryFuzzRunFromJson(pThis, hJsonRoot, "Id", pErrInfo, &pFuzzRun);
1110 if (RT_SUCCESS(rc))
1111 {
1112 if (!pFuzzRun->fStarted)
1113 {
1114 rc = rtFuzzCmdMasterFuzzRunProcessCfgU32Def(&pFuzzRun->cProcs, "FuzzingProcs", hJsonRoot, pFuzzRun->cProcs, pErrInfo);
1115 if (RT_SUCCESS(rc))
1116 {
1117 rc = RTFuzzObsExecStart(pFuzzRun->hFuzzObs, pFuzzRun->cProcs);
1118 if (RT_SUCCESS(rc))
1119 pFuzzRun->fStarted = true;
1120 else
1121 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Resuming the fuzzing process failed");
1122 }
1123 }
1124 }
1125
1126 return rc;
1127}
1128
1129
1130/**
1131 * Processes the "SaveFuzzingState" request.
1132 *
1133 * @returns IPRT status code.
1134 * @param pThis The fuzzing master command state.
1135 * @param hJsonValRoot The root node of the JSON request.
1136 * @param pErrInfo Where to store the error information on failure, optional.
1137 */
1138static int rtFuzzCmdMasterProcessJsonReqSaveState(PRTFUZZCMDMASTER pThis, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
1139{
1140 PRTFUZZRUN pFuzzRun;
1141 int rc = rtFuzzCmdMasterQueryFuzzRunFromJson(pThis, hJsonRoot, "Id", pErrInfo, &pFuzzRun);
1142 if (RT_SUCCESS(rc))
1143 {
1144 /* Suspend fuzzing, save and resume if not stopped. */
1145 if (pFuzzRun->fStarted)
1146 {
1147 rc = RTFuzzObsExecStop(pFuzzRun->hFuzzObs);
1148 if (RT_FAILURE(rc))
1149 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Suspending the fuzzing process failed");
1150 }
1151
1152 if (RT_SUCCESS(rc))
1153 {
1154 RTFUZZCTX hFuzzCtx;
1155 rc = RTFuzzObsQueryCtx(pFuzzRun->hFuzzObs, &hFuzzCtx);
1156 AssertRC(rc);
1157
1158 void *pvState = NULL;
1159 size_t cbState = 0;
1160 rc = RTFuzzCtxStateExportToMem(hFuzzCtx, &pvState, &cbState);
1161 if (RT_SUCCESS(rc))
1162 {
1163 /* Encode to base64. */
1164 size_t cbStateStr = RTBase64EncodedLength(cbState) + 1;
1165 char *pszState = (char *)RTMemAllocZ(cbStateStr);
1166 if (pszState)
1167 {
1168 rc = RTBase64Encode(pvState, cbState, pszState, cbStateStr, &cbStateStr);
1169 if (RT_SUCCESS(rc))
1170 {
1171 /* Strip all new lines from the srting. */
1172 size_t offStr = 0;
1173 while (offStr < cbStateStr)
1174 {
1175#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
1176 char *pszEol = strchr(&pszState[offStr], '\r');
1177#else
1178 char *pszEol = strchr(&pszState[offStr], '\n');
1179#endif
1180 if (pszEol)
1181 {
1182 offStr += pszEol - &pszState[offStr];
1183 memmove(pszEol, &pszEol[RTBASE64_EOL_SIZE], cbStateStr - offStr - RTBASE64_EOL_SIZE);
1184 cbStateStr -= RTBASE64_EOL_SIZE;
1185 }
1186 else
1187 break;
1188 }
1189
1190 const char s_szState[] = "{ \"State\": %s }";
1191 pThis->pszResponse = RTStrAPrintf2(s_szState, pszState);
1192 if (RT_UNLIKELY(!pThis->pszResponse))
1193 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_BUFFER_OVERFLOW, "Request error: Response data buffer overflow", rc);
1194 }
1195 else
1196 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to encode the state as a base64 string");
1197 RTMemFree(pszState);
1198 }
1199 else
1200 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_NO_STR_MEMORY, "Request error: Failed to allocate a state string for the response");
1201 RTMemFree(pvState);
1202 }
1203 else
1204 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Exporting the state failed");
1205 }
1206
1207 if (pFuzzRun->fStarted)
1208 {
1209 int rc2 = RTFuzzObsExecStart(pFuzzRun->hFuzzObs, pFuzzRun->cProcs);
1210 if (RT_FAILURE(rc2))
1211 rtFuzzCmdMasterErrorRc(pErrInfo, rc2, "Request error: Resuming the fuzzing process failed");
1212 }
1213 }
1214
1215 return rc;
1216}
1217
1218
1219/**
1220 * Queries the statistics for the given fuzzing run and adds the result to the response.
1221 *
1222 * @returns IPRT static code.
1223 * @param pThis The fuzzing master command state.
1224 * @param pFuzzRun The fuzzing run.
1225 * @param pszIndent Indentation to use.
1226 * @param fLast Flags whether this is the last element in the list.
1227 * @param pErrInfo Where to store the error information on failure, optional.
1228 */
1229static int rtFuzzCmdMasterProcessQueryRunStats(PRTFUZZCMDMASTER pThis, PRTFUZZRUN pFuzzRun,
1230 const char *pszIndent, bool fLast, PRTERRINFO pErrInfo)
1231{
1232 RTFUZZOBSSTATS ObsStats;
1233 RTFUZZCTXSTATS CtxStats;
1234 RTFUZZCTX hFuzzCtx;
1235 RT_ZERO(ObsStats); RT_ZERO(CtxStats);
1236
1237 int rc = RTFuzzObsQueryCtx(pFuzzRun->hFuzzObs, &hFuzzCtx);
1238 if (RT_SUCCESS(rc))
1239 {
1240 rc = RTFuzzCtxQueryStats(hFuzzCtx, &CtxStats);
1241 RTFuzzCtxRelease(hFuzzCtx);
1242 }
1243
1244 if (RT_SUCCESS(rc))
1245 rc = RTFuzzObsQueryStats(pFuzzRun->hFuzzObs, &ObsStats);
1246 if (RT_SUCCESS(rc))
1247 {
1248 const char s_szStatsFmt[] = "%s{ \n"
1249 "%s \"Id\": \"%s\"\n"
1250 "%s \"TimeCreated\": \"%s\"\n"
1251 "%s \"UptimeSec\": %llu\n"
1252 "%s \"FuzzedInputsPerSec\": %u\n"
1253 "%s \"FuzzedInputs\": %u\n"
1254 "%s \"FuzzedInputsHang\": %u\n"
1255 "%s \"FuzzedInputsCrash\": %u\n"
1256 "%s \"MemoryUsage\": %zu\n"
1257 "%s \"CorpusSize\": %llu\n"
1258 "%s}%s\n";
1259 char aszTime[_1K]; RT_ZERO(aszTime);
1260 char aszStats[_4K]; RT_ZERO(aszStats);
1261
1262 if (RTTimeToString(&pFuzzRun->TimeCreated, aszTime, sizeof(aszTime)))
1263 {
1264 ssize_t cchStats = RTStrPrintf2(&aszStats[0], sizeof(aszStats),
1265 s_szStatsFmt, pszIndent,
1266 pszIndent, pFuzzRun->pszId,
1267 pszIndent, aszTime,
1268 pszIndent, (RTTimeMilliTS() - pFuzzRun->tsCreatedMs) / RT_MS_1SEC_64,
1269 pszIndent, ObsStats.cFuzzedInputsPerSec,
1270 pszIndent, ObsStats.cFuzzedInputs,
1271 pszIndent, ObsStats.cFuzzedInputsHang,
1272 pszIndent, ObsStats.cFuzzedInputsCrash,
1273 pszIndent, CtxStats.cbMemory,
1274 pszIndent, CtxStats.cMutations,
1275 pszIndent, fLast ? "" : ",");
1276 if (RT_LIKELY(cchStats > 0))
1277 {
1278 rc = RTStrAAppend(&pThis->pszResponse, &aszStats[0]);
1279 if (RT_FAILURE(rc))
1280 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to build statistics response", rc);
1281 }
1282 else
1283 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_BUFFER_OVERFLOW, "Request error: Response data buffer overflow");
1284 }
1285 else
1286 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_BUFFER_OVERFLOW, "Request error: Buffer overflow conerting time to string");
1287 }
1288 else
1289 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "Request error: Failed to query fuzzing statistics with %Rrc", rc);
1290
1291 return rc;
1292}
1293
1294
1295/**
1296 * Processes the "QueryStats" request.
1297 *
1298 * @returns IPRT status code.
1299 * @param pThis The fuzzing master command state.
1300 * @param hJsonValRoot The root node of the JSON request.
1301 * @param pErrInfo Where to store the error information on failure, optional.
1302 */
1303static int rtFuzzCmdMasterProcessJsonReqQueryStats(PRTFUZZCMDMASTER pThis, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
1304{
1305 RTJSONVAL hJsonValId;
1306 int rc = RTJsonValueQueryByName(hJsonRoot, "Id", &hJsonValId);
1307 if (RT_SUCCESS(rc))
1308 {
1309 RTJsonValueRelease(hJsonValId);
1310 PRTFUZZRUN pFuzzRun;
1311 rc = rtFuzzCmdMasterQueryFuzzRunFromJson(pThis, hJsonRoot, "Id", pErrInfo, &pFuzzRun);
1312 if (RT_SUCCESS(rc))
1313 rc = rtFuzzCmdMasterProcessQueryRunStats(pThis, pFuzzRun, " ",
1314 true /*fLast*/, pErrInfo);
1315 }
1316 else if (rc == VERR_NOT_FOUND)
1317 {
1318 /* Id is not there, so collect statistics of all running jobs. */
1319 rc = RTStrAAppend(&pThis->pszResponse, " [\n");
1320 if (RT_SUCCESS(rc))
1321 {
1322 PRTFUZZRUN pRun = NULL;
1323 RTListForEach(&pThis->LstFuzzed, pRun, RTFUZZRUN, NdFuzzed)
1324 {
1325 bool fLast = RTListNodeIsLast(&pThis->LstFuzzed, &pRun->NdFuzzed);
1326 rc = rtFuzzCmdMasterProcessQueryRunStats(pThis, pRun, " ", fLast, pErrInfo);
1327 if (RT_FAILURE(rc))
1328 break;
1329 }
1330 if (RT_SUCCESS(rc))
1331 rc = RTStrAAppend(&pThis->pszResponse, " ]\n");
1332 }
1333 }
1334 else
1335 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Couldn't get \"Id\" value");
1336
1337 return rc;
1338}
1339
1340
1341/**
1342 * Processes a JSON request.
1343 *
1344 * @returns IPRT status code.
1345 * @param pThis The fuzzing master command state.
1346 * @param hJsonValRoot The root node of the JSON request.
1347 * @param pErrInfo Where to store the error information on failure, optional.
1348 */
1349static int rtFuzzCmdMasterProcessJsonReq(PRTFUZZCMDMASTER pThis, RTJSONVAL hJsonRoot, PRTERRINFO pErrInfo)
1350{
1351 RTJSONVAL hJsonValReq;
1352 int rc = RTJsonValueQueryByName(hJsonRoot, "Request", &hJsonValReq);
1353 if (RT_SUCCESS(rc))
1354 {
1355 const char *pszReq = RTJsonValueGetString(hJsonValReq);
1356 if (pszReq)
1357 {
1358 if (!RTStrCmp(pszReq, "StartFuzzing"))
1359 rc = rtFuzzCmdMasterProcessJsonReqStart(pThis, hJsonRoot, pErrInfo);
1360 else if (!RTStrCmp(pszReq, "StopFuzzing"))
1361 rc = rtFuzzCmdMasterProcessJsonReqStop(pThis, hJsonRoot, pErrInfo);
1362 else if (!RTStrCmp(pszReq, "SuspendFuzzing"))
1363 rc = rtFuzzCmdMasterProcessJsonReqSuspend(pThis, hJsonRoot, pErrInfo);
1364 else if (!RTStrCmp(pszReq, "ResumeFuzzing"))
1365 rc = rtFuzzCmdMasterProcessJsonReqResume(pThis, hJsonRoot, pErrInfo);
1366 else if (!RTStrCmp(pszReq, "SaveFuzzingState"))
1367 rc = rtFuzzCmdMasterProcessJsonReqSaveState(pThis, hJsonRoot, pErrInfo);
1368 else if (!RTStrCmp(pszReq, "QueryStats"))
1369 rc = rtFuzzCmdMasterProcessJsonReqQueryStats(pThis, hJsonRoot, pErrInfo);
1370 else if (!RTStrCmp(pszReq, "Shutdown"))
1371 pThis->fShutdown = true;
1372 else
1373 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_JSON_VALUE_INVALID_TYPE, "JSON request malformed: \"Request\" contains unknown value \"%s\"", pszReq);
1374 }
1375 else
1376 rc = rtFuzzCmdMasterErrorRc(pErrInfo, VERR_JSON_VALUE_INVALID_TYPE, "JSON request malformed: \"Request\" is not a string value");
1377
1378 RTJsonValueRelease(hJsonValReq);
1379 }
1380 else
1381 rc = rtFuzzCmdMasterErrorRc(pErrInfo, rc, "JSON request malformed: Couldn't find \"Request\" value");
1382
1383 return rc;
1384}
1385
1386
1387/**
1388 * Loads a fuzzing configuration for immediate startup from the given file.
1389 *
1390 * @returns IPRT status code.
1391 * @param pThis The fuzzing master command state.
1392 * @param pszFuzzCfg The fuzzing config to load.
1393 */
1394static int rtFuzzCmdMasterFuzzCfgLoadFromFile(PRTFUZZCMDMASTER pThis, const char *pszFuzzCfg)
1395{
1396 RTJSONVAL hJsonRoot;
1397 int rc = RTJsonParseFromFile(&hJsonRoot, pszFuzzCfg, NULL);
1398 if (RT_SUCCESS(rc))
1399 {
1400 rc = rtFuzzCmdMasterProcessJsonReqStart(pThis, hJsonRoot, NULL);
1401 RTJsonValueRelease(hJsonRoot);
1402 }
1403 else
1404 rc = rtFuzzCmdMasterErrorRc(NULL, rc, "JSON request malformed: Couldn't load file \"%s\"", pszFuzzCfg);
1405
1406 return rc;
1407}
1408
1409
1410/**
1411 * Destroys all running fuzzers for the given master state.
1412 *
1413 * @returns nothing.
1414 * @param pThis The fuzzing master command state.
1415 */
1416static void rtFuzzCmdMasterDestroy(PRTFUZZCMDMASTER pThis)
1417{
1418 RT_NOREF(pThis);
1419}
1420
1421
1422/**
1423 * Sends an ACK response to the client.
1424 *
1425 * @returns nothing.
1426 * @param hSocket The socket handle to send the ACK to.
1427 * @param pszResponse Additional response data.
1428 */
1429static void rtFuzzCmdMasterTcpSendAck(RTSOCKET hSocket, const char *pszResponse)
1430{
1431 const char s_szSucc[] = "{ \"Status\": \"ACK\" }\n";
1432 const char s_szSuccResp[] = "{ \"Status\": \"ACK\"\n \"Response\":\n";
1433 const char s_szSuccRespClose[] = "\n }\n";
1434 if (pszResponse)
1435 {
1436 RTSGSEG aSegs[3];
1437 RTSGBUF SgBuf;
1438 aSegs[0].pvSeg = (void *)s_szSuccResp;
1439 aSegs[0].cbSeg = sizeof(s_szSuccResp) - 1;
1440 aSegs[1].pvSeg = (void *)pszResponse;
1441 aSegs[1].cbSeg = strlen(pszResponse);
1442 aSegs[2].pvSeg = (void *)s_szSuccRespClose;
1443 aSegs[2].cbSeg = sizeof(s_szSuccRespClose) - 1;
1444
1445 RTSgBufInit(&SgBuf, &aSegs[0], RT_ELEMENTS(aSegs));
1446 RTTcpSgWrite(hSocket, &SgBuf);
1447 }
1448 else
1449 RTTcpWrite(hSocket, s_szSucc, sizeof(s_szSucc));
1450}
1451
1452
1453/**
1454 * Sends an NACK response to the client.
1455 *
1456 * @returns nothing.
1457 * @param hSocket The socket handle to send the ACK to.
1458 * @param pErrInfo Optional error information to send along.
1459 */
1460static void rtFuzzCmdMasterTcpSendNAck(RTSOCKET hSocket, PRTERRINFO pErrInfo)
1461{
1462 const char s_szFail[] = "{ \"Status\": \"NACK\" }\n";
1463 const char s_szFailInfo[] = "{ \"Status\": \"NACK\"\n \"Information\": \"%s\" }\n";
1464
1465 if (pErrInfo)
1466 {
1467 char szTmp[_1K];
1468 ssize_t cchResp = RTStrPrintf2(szTmp, sizeof(szTmp), s_szFailInfo, pErrInfo->pszMsg);
1469 if (cchResp > 0)
1470 RTTcpWrite(hSocket, szTmp, cchResp);
1471 else
1472 RTTcpWrite(hSocket, s_szFail, strlen(s_szFail));
1473 }
1474 else
1475 RTTcpWrite(hSocket, s_szFail, strlen(s_szFail));
1476}
1477
1478
1479/**
1480 * TCP server serving callback for a single connection.
1481 *
1482 * @returns IPRT status code.
1483 * @param hSocket The socket handle of the connection.
1484 * @param pvUser Opaque user data.
1485 */
1486static DECLCALLBACK(int) rtFuzzCmdMasterTcpServe(RTSOCKET hSocket, void *pvUser)
1487{
1488 PRTFUZZCMDMASTER pThis = (PRTFUZZCMDMASTER)pvUser;
1489 size_t cbReqMax = _32K;
1490 size_t cbReq = 0;
1491 uint8_t *pbReq = (uint8_t *)RTMemAllocZ(cbReqMax);
1492
1493 if (RT_LIKELY(pbReq))
1494 {
1495 uint8_t *pbCur = pbReq;
1496
1497 for (;;)
1498 {
1499 size_t cbThisRead = cbReqMax - cbReq;
1500 int rc = RTTcpRead(hSocket, pbCur, cbThisRead, &cbThisRead);
1501 if ( RT_SUCCESS(rc)
1502 && cbThisRead)
1503 {
1504 cbReq += cbThisRead;
1505
1506 /* Check for a zero terminator marking the end of the request. */
1507 uint8_t *pbEnd = (uint8_t *)memchr(pbCur, 0, cbThisRead);
1508 if (pbEnd)
1509 {
1510 /* Adjust request size, data coming after the zero terminiator is ignored right now. */
1511 cbReq -= cbThisRead - (pbEnd - pbCur) + 1;
1512
1513 RTJSONVAL hJsonReq;
1514 RTERRINFOSTATIC ErrInfo;
1515 RTErrInfoInitStatic(&ErrInfo);
1516
1517 rc = RTJsonParseFromBuf(&hJsonReq, pbReq, cbReq, &ErrInfo.Core);
1518 if (RT_SUCCESS(rc))
1519 {
1520 rc = rtFuzzCmdMasterProcessJsonReq(pThis, hJsonReq, &ErrInfo.Core);
1521 if (RT_SUCCESS(rc))
1522 rtFuzzCmdMasterTcpSendAck(hSocket, pThis->pszResponse);
1523 else
1524 rtFuzzCmdMasterTcpSendNAck(hSocket, &ErrInfo.Core);
1525 RTJsonValueRelease(hJsonReq);
1526 }
1527 else
1528 rtFuzzCmdMasterTcpSendNAck(hSocket, &ErrInfo.Core);
1529
1530 if (pThis->pszResponse)
1531 {
1532 RTStrFree(pThis->pszResponse);
1533 pThis->pszResponse = NULL;
1534 }
1535 break;
1536 }
1537 else if (cbReq == cbReqMax)
1538 {
1539 /* Try to increase the buffer. */
1540 uint8_t *pbReqNew = (uint8_t *)RTMemRealloc(pbReq, cbReqMax + _32K);
1541 if (RT_LIKELY(pbReqNew))
1542 {
1543 cbReqMax += _32K;
1544 pbReq = pbReqNew;
1545 pbCur = pbReq + cbReq;
1546 }
1547 else
1548 rtFuzzCmdMasterTcpSendNAck(hSocket, NULL);
1549 }
1550 else
1551 pbCur += cbThisRead;
1552 }
1553 else
1554 break;
1555 }
1556 }
1557 else
1558 rtFuzzCmdMasterTcpSendNAck(hSocket, NULL);
1559
1560 if (pbReq)
1561 RTMemFree(pbReq);
1562
1563 return pThis->fShutdown ? VERR_TCP_SERVER_STOP : VINF_SUCCESS;
1564}
1565
1566
1567/**
1568 * Mainloop for the fuzzing master.
1569 *
1570 * @returns Process exit code.
1571 * @param pThis The fuzzing master command state.
1572 * @param pszLoadCfg Initial config to load.
1573 */
1574static RTEXITCODE rtFuzzCmdMasterRun(PRTFUZZCMDMASTER pThis, const char *pszLoadCfg)
1575{
1576 if (pszLoadCfg)
1577 {
1578 int rc = rtFuzzCmdMasterFuzzCfgLoadFromFile(pThis, pszLoadCfg);
1579 if (RT_FAILURE(rc))
1580 return RTEXITCODE_FAILURE;
1581 }
1582
1583 /* Start up the control server. */
1584 int rc = RTTcpServerCreateEx(NULL, pThis->uPort, &pThis->hTcpSrv);
1585 if (RT_SUCCESS(rc))
1586 {
1587 do
1588 {
1589 rc = RTTcpServerListen(pThis->hTcpSrv, rtFuzzCmdMasterTcpServe, pThis);
1590 } while (rc != VERR_TCP_SERVER_STOP);
1591 }
1592
1593 RTTcpServerDestroy(pThis->hTcpSrv);
1594 rtFuzzCmdMasterDestroy(pThis);
1595 return RTEXITCODE_SUCCESS;
1596}
1597
1598
1599RTR3DECL(RTEXITCODE) RTFuzzCmdMaster(unsigned cArgs, char **papszArgs)
1600{
1601 /*
1602 * Parse the command line.
1603 */
1604 static const RTGETOPTDEF s_aOptions[] =
1605 {
1606 { "--fuzz-config", 'c', RTGETOPT_REQ_STRING },
1607 { "--temp-dir", 't', RTGETOPT_REQ_STRING },
1608 { "--results-dir", 'r', RTGETOPT_REQ_STRING },
1609 { "--listen-port", 'p', RTGETOPT_REQ_UINT16 },
1610 { "--daemonize", 'd', RTGETOPT_REQ_NOTHING },
1611 { "--daemonized", 'Z', RTGETOPT_REQ_NOTHING },
1612 { "--help", 'h', RTGETOPT_REQ_NOTHING },
1613 { "--version", 'V', RTGETOPT_REQ_NOTHING },
1614 };
1615
1616 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
1617 RTGETOPTSTATE GetState;
1618 int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1,
1619 RTGETOPTINIT_FLAGS_OPTS_FIRST);
1620 if (RT_SUCCESS(rc))
1621 {
1622 /* Option variables: */
1623 bool fDaemonize = false;
1624 bool fDaemonized = false;
1625 const char *pszLoadCfg = NULL;
1626 RTFUZZCMDMASTER This;
1627
1628 RTListInit(&This.LstFuzzed);
1629 This.hTcpSrv = NIL_RTTCPSERVER;
1630 This.uPort = 4242;
1631 This.pszTmpDir = NULL;
1632 This.pszResultsDir = NULL;
1633 This.fShutdown = false;
1634 This.pszResponse = NULL;
1635
1636 /* Argument parsing loop. */
1637 bool fContinue = true;
1638 do
1639 {
1640 RTGETOPTUNION ValueUnion;
1641 int chOpt = RTGetOpt(&GetState, &ValueUnion);
1642 switch (chOpt)
1643 {
1644 case 0:
1645 fContinue = false;
1646 break;
1647
1648 case 'c':
1649 pszLoadCfg = ValueUnion.psz;
1650 break;
1651
1652 case 'p':
1653 This.uPort = ValueUnion.u16;
1654 break;
1655
1656 case 't':
1657 This.pszTmpDir = ValueUnion.psz;
1658 break;
1659
1660 case 'r':
1661 This.pszResultsDir = ValueUnion.psz;
1662 break;
1663
1664 case 'd':
1665 fDaemonize = true;
1666 break;
1667
1668 case 'Z':
1669 fDaemonized = true;
1670 fDaemonize = false;
1671 break;
1672
1673 case 'h':
1674 RTPrintf("Usage: to be written\nOption dump:\n");
1675 for (unsigned i = 0; i < RT_ELEMENTS(s_aOptions); i++)
1676 RTPrintf(" -%c,%s\n", s_aOptions[i].iShort, s_aOptions[i].pszLong);
1677 fContinue = false;
1678 break;
1679
1680 case 'V':
1681 RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
1682 fContinue = false;
1683 break;
1684
1685 default:
1686 rcExit = RTGetOptPrintError(chOpt, &ValueUnion);
1687 fContinue = false;
1688 break;
1689 }
1690 } while (fContinue);
1691
1692 if (rcExit == RTEXITCODE_SUCCESS)
1693 {
1694 /*
1695 * Daemonize ourselves if asked to.
1696 */
1697 if (fDaemonize)
1698 {
1699 rc = RTProcDaemonize(papszArgs, "--daemonized");
1700 if (RT_FAILURE(rc))
1701 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTProcDaemonize: %Rrc\n", rc);
1702 }
1703 else
1704 rcExit = rtFuzzCmdMasterRun(&This, pszLoadCfg);
1705 }
1706 }
1707 else
1708 rcExit = RTMsgErrorExit(RTEXITCODE_SYNTAX, "RTGetOptInit: %Rrc", rc);
1709 return rcExit;
1710}
1711
Note: See TracBrowser for help on using the repository browser.

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