VirtualBox

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

Last change on this file since 72778 was 72649, checked in by vboxsync, 7 years ago

Runtime/fuzzing: Add some simple statistics

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