VirtualBox

Changeset 72571 in vbox for trunk


Ignore:
Timestamp:
Jun 15, 2018 8:36:17 PM (7 years ago)
Author:
vboxsync
Message:

Runtime/RTFuzz: Started to extend the master command to provide a network interface for controlling the fuzzing process. The interface uses JSON requests and responses to control the fuzzing process, like creating a new fuzzing run and suspending, resuming and stopping it. The JSON request contains everything required (except for the binary itself) for easier control of multiple masters on different hosts via a central control mechanism (later integration into the validation kit).

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/fuzz.h

    r72465 r72571  
    150150
    151151/**
     152 * Adds a new seed to the input corpus of the given fuzzing context from the given VFS file.
     153 *
     154 * @returns IPRT status code.
     155 * @param   hFuzzCtx            The fuzzing context handle.
     156 * @param   hVfsFile            The VFS file handle to load the seed from.
     157 */
     158RTDECL(int) RTFuzzCtxCorpusInputAddFromVfsFile(RTFUZZCTX hFuzzCtx, RTVFSFILE hVfsFile);
     159
     160/**
    152161 * Adds new seeds to the input corpus of the given fuzzing context from the given directory.
    153162 *
     
    368377 * @param   hFuzzObs            The fuzzing observer handle.
    369378 * @param   cProcs              Number of processes to run simulteanously,
    370  *                              0 will create as manny processes as there are CPUs available.
     379 *                              0 will create as many processes as there are CPUs available.
    371380 */
    372381RTDECL(int) RTFuzzObsExecStart(RTFUZZOBS hFuzzObs, uint32_t cProcs);
  • trunk/include/iprt/mangling.h

    r72465 r72571  
    10181018# define RTFuzzCtxCorpusInputAddFromDirPath             RT_MANGLER(RTFuzzCtxCorpusInputAddFromDirPath)
    10191019# define RTFuzzCtxCorpusInputAddFromFile                RT_MANGLER(RTFuzzCtxCorpusInputAddFromFile)
     1020# define RTFuzzCtxCorpusInputAddFromVfsFile             RT_MANGLER(RTFuzzCtxCorpusInputAddFromVfsFile)
    10201021# define RTFuzzCtxCreate                                RT_MANGLER(RTFuzzCtxCreate)
    10211022# define RTFuzzCtxCreateFromState                       RT_MANGLER(RTFuzzCtxCreateFromState)
  • trunk/src/VBox/Runtime/common/fuzz/fuzz-observer.cpp

    r72465 r72571  
    880880
    881881        if (RT_SUCCESS(rc))
     882        {
    882883            pThis->paObsThreads = paObsThreads;
     884            pThis->cThreads     = cThreads;
     885        }
    883886        else
    884887            RTMemFree(paObsThreads);
     
    957960    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    958961
    959     /* Wait for the master thread to terminate. */
    960     if (pThis->hThreadGlobal != NIL_RTTHREAD)
    961     {
    962         ASMAtomicXchgBool(&pThis->fShutdown, true);
    963         RTThreadWait(pThis->hThreadGlobal, RT_INDEFINITE_WAIT, NULL);
    964     }
    965 
    966     /* Clean up the workers. */
    967     if (pThis->paObsThreads)
    968     {
    969         for (unsigned i = 0; i < pThis->cThreads; i++)
    970         {
    971             PRTFUZZOBSTHRD pThrd = &pThis->paObsThreads[i];
    972             ASMAtomicXchgBool(&pThrd->fShutdown, true);
    973             RTThreadWait(pThrd->hThread, RT_INDEFINITE_WAIT, NULL);
    974             if (pThrd->hFuzzInput)
    975                 RTFuzzInputRelease(pThrd->hFuzzInput);
    976         }
    977         RTMemFree(pThis->paObsThreads);
    978         pThis->paObsThreads = NULL;
    979     }
     962    RTFuzzObsExecStop(hFuzzObs);
    980963
    981964    /* Clean up all acquired resources. */
     
    11451128RTDECL(int) RTFuzzObsExecStop(RTFUZZOBS hFuzzObs)
    11461129{
    1147     RT_NOREF(hFuzzObs);
    1148     return VERR_NOT_IMPLEMENTED;
    1149 }
    1150 
     1130    PRTFUZZOBSINT pThis = hFuzzObs;
     1131    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     1132
     1133    /* Wait for the master thread to terminate. */
     1134    if (pThis->hThreadGlobal != NIL_RTTHREAD)
     1135    {
     1136        ASMAtomicXchgBool(&pThis->fShutdown, true);
     1137        RTSemEventSignal(pThis->hEvtGlobal);
     1138        RTThreadWait(pThis->hThreadGlobal, RT_INDEFINITE_WAIT, NULL);
     1139        pThis->hThreadGlobal = NIL_RTTHREAD;
     1140    }
     1141
     1142    /* Destroy the workers. */
     1143    if (pThis->paObsThreads)
     1144    {
     1145        for (unsigned i = 0; i < pThis->cThreads; i++)
     1146        {
     1147            PRTFUZZOBSTHRD pThrd = &pThis->paObsThreads[i];
     1148            ASMAtomicXchgBool(&pThrd->fShutdown, true);
     1149            RTThreadUserSignal(pThrd->hThread);
     1150            RTThreadWait(pThrd->hThread, RT_INDEFINITE_WAIT, NULL);
     1151            if (pThrd->hFuzzInput)
     1152                RTFuzzInputRelease(pThrd->hFuzzInput);
     1153        }
     1154
     1155        RTMemFree(pThis->paObsThreads);
     1156        pThis->paObsThreads = NULL;
     1157        pThis->cThreads     = 0;
     1158    }
     1159
     1160    RTSemEventDestroy(pThis->hEvtGlobal);
     1161    pThis->hEvtGlobal = NIL_RTSEMEVENT;
     1162    return VINF_SUCCESS;
     1163}
     1164
  • trunk/src/VBox/Runtime/common/fuzz/fuzz.cpp

    r72454 r72571  
    4545#include <iprt/string.h>
    4646#include <iprt/time.h>
     47#include <iprt/vfs.h>
    4748
    4849
     
    642643
    643644
     645RTDECL(int) RTFuzzCtxCorpusInputAddFromVfsFile(RTFUZZCTX hFuzzCtx, RTVFSFILE hVfsFile)
     646{
     647    PRTFUZZCTXINT pThis = hFuzzCtx;
     648    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     649    AssertReturn(hVfsFile != NIL_RTVFSFILE, VERR_INVALID_HANDLE);
     650
     651    uint64_t cbFile = 0;
     652    int rc = RTVfsFileGetSize(hVfsFile, &cbFile);
     653    if (RT_SUCCESS(rc))
     654    {
     655        PRTFUZZINPUTINT pInput = (PRTFUZZINPUTINT)RTMemAllocZ(RT_OFFSETOF(RTFUZZINPUTINT, abInput[cbFile]));
     656        if (RT_LIKELY(pInput))
     657        {
     658            pInput->cRefs   = 1;
     659            pInput->pFuzzer = pThis;
     660            pInput->cbInput = cbFile;
     661
     662            rc = RTVfsFileRead(hVfsFile, &pInput->abInput[0], cbFile, NULL);
     663            if (RT_SUCCESS(rc))
     664            {
     665                /* Generate MD5 checksum and try to locate input. */
     666                uint8_t abDigest[RTMD5_HASH_SIZE];
     667                RTMd5(&pInput->abInput[0], cbFile, &abDigest[0]);
     668
     669                if (!rtFuzzCtxInputLocate(pThis, &abDigest[0], true /*fExact*/, NULL /*ppIntermediate*/))
     670                {
     671                    memcpy(&pInput->abMd5Hash[0], &abDigest[0], sizeof(abDigest));
     672                    rc = rtFuzzCtxInputAdd(pThis, pInput);
     673                }
     674                else
     675                    rc = VERR_ALREADY_EXISTS;
     676            }
     677
     678            if (RT_FAILURE(rc))
     679                RTMemFree(pInput);
     680        }
     681        else
     682            rc = VERR_NO_MEMORY;
     683    }
     684
     685    return rc;
     686}
     687
     688
    644689RTDECL(int) RTFuzzCtxCorpusInputAddFromDirPath(RTFUZZCTX hFuzzCtx, const char *pszDirPath)
    645690{
     
    698743    PRTFUZZCTXINT pThis = hFuzzCtx;
    699744    AssertPtrReturn(pThis, VERR_INVALID_POINTER);
    700     AssertReturn(cbMax, VERR_INVALID_PARAMETER);
    701745
    702746    pThis->cbInputMax = cbMax;
  • trunk/src/VBox/Runtime/common/fuzz/fuzzmastercmd.cpp

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

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