VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/fuzz/fuzzclientcmd.cpp@ 91495

Last change on this file since 91495 was 85121, checked in by vboxsync, 4 years ago

iprt/cdefs.h: Refactored the typedef use of DECLCALLBACK as well as DECLCALLBACKMEMBER to wrap the whole expression, similar to the DECLR?CALLBACKMEMBER macros. This allows adding a throw() at the end when compiling with the VC++ compiler to indicate that the callbacks won't throw anything, so we can stop supressing the C5039 warning about passing functions that can potential throw C++ exceptions to extern C code that can't necessarily cope with such (unwind,++). Introduced a few _EX variations that allows specifying different/no calling convention too, as that's handy when dynamically resolving host APIs. Fixed numerous places missing DECLCALLBACK and such. Left two angry @todos regarding use of CreateThread. bugref:9794

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.9 KB
Line 
1/* $Id: fuzzclientcmd.cpp 85121 2020-07-08 19:33:26Z vboxsync $ */
2/** @file
3 * IPRT - Fuzzing framework API, fuzzed client command.
4 */
5
6/*
7 * Copyright (C) 2018-2020 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/assert.h>
35#include <iprt/buildconfig.h>
36#include <iprt/errcore.h>
37#include <iprt/file.h>
38#include <iprt/getopt.h>
39#include <iprt/ldr.h>
40#include <iprt/mem.h>
41#include <iprt/message.h>
42#include <iprt/stream.h>
43#include <iprt/string.h>
44#include <iprt/types.h>
45#include <iprt/vfs.h>
46
47
48/*********************************************************************************************************************************
49* Structures and Typedefs *
50*********************************************************************************************************************************/
51typedef DECLCALLBACKTYPE(int, FNLLVMFUZZERTESTONEINPUT,(const uint8_t *pbData, size_t cbData));
52typedef FNLLVMFUZZERTESTONEINPUT *PFNLLVMFUZZERTESTONEINPUT;
53
54
55/**
56 * Fuzzing client command state.
57 */
58typedef struct RTFUZZCMDCLIENT
59{
60 /** Our own fuzzing context containing all the data. */
61 RTFUZZCTX hFuzzCtx;
62 /** Consumption callback. */
63 PFNFUZZCLIENTCONSUME pfnConsume;
64 /** Opaque user data to pass to the consumption callback. */
65 void *pvUser;
66 /** The LLVM libFuzzer compatible entry point if configured */
67 PFNLLVMFUZZERTESTONEINPUT pfnLlvmFuzzerTestOneInput;
68 /** The selected input channel. */
69 RTFUZZOBSINPUTCHAN enmInputChan;
70 /** Standard input VFS handle. */
71 RTVFSIOSTREAM hVfsStdIn;
72 /** Standard output VFS handle. */
73 RTVFSIOSTREAM hVfsStdOut;
74} RTFUZZCMDCLIENT;
75/** Pointer to a fuzzing client command state. */
76typedef RTFUZZCMDCLIENT *PRTFUZZCMDCLIENT;
77
78
79
80/**
81 * Runs the appropriate consumption callback with the provided data.
82 *
83 * @returns Status code, 0 for success.
84 * @param pThis The fuzzing client command state.
85 * @param pvData The data to consume.
86 * @param cbData Size of the data in bytes.
87 */
88static int rtFuzzCmdClientConsume(PRTFUZZCMDCLIENT pThis, const void *pvData, size_t cbData)
89{
90 if (pThis->pfnLlvmFuzzerTestOneInput)
91 return pThis->pfnLlvmFuzzerTestOneInput((const uint8_t *)pvData, cbData);
92 else
93 return pThis->pfnConsume(pvData, cbData, pThis->pvUser);
94}
95
96
97/**
98 * The fuzzing client mainloop.
99 *
100 * @returns IPRT status code.
101 * @param pThis The fuzzing client command state.
102 */
103static int rtFuzzCmdClientMainloop(PRTFUZZCMDCLIENT pThis)
104{
105 int rc = VINF_SUCCESS;
106 bool fShutdown = false;
107
108 while ( !fShutdown
109 && RT_SUCCESS(rc))
110 {
111 RTFUZZINPUT hFuzzInput;
112
113 rc = RTFuzzCtxInputGenerate(pThis->hFuzzCtx, &hFuzzInput);
114 if (RT_SUCCESS(rc))
115 {
116 void *pv = NULL;
117 size_t cb = 0;
118 rc = RTFuzzInputQueryBlobData(hFuzzInput, &pv, &cb);
119 if (RT_SUCCESS(rc))
120 {
121 char bResp = '.';
122 int rc2 = rtFuzzCmdClientConsume(pThis, pv, cb);
123 if (RT_SUCCESS(rc2))
124 {
125 rc = RTFuzzInputAddToCtxCorpus(hFuzzInput);
126 bResp = 'A';
127 }
128
129 if (RT_SUCCESS(rc))
130 rc = RTVfsIoStrmWrite(pThis->hVfsStdOut, &bResp, 1, true /*fBlocking*/, NULL);
131 }
132
133 RTFuzzInputRelease(hFuzzInput);
134 }
135 }
136
137 return rc;
138}
139
140
141/**
142 * Run the fuzzing client.
143 *
144 * @returns Process exit status.
145 * @param pThis The fuzzing client command state.
146 */
147static RTEXITCODE rtFuzzCmdClientRun(PRTFUZZCMDCLIENT pThis)
148{
149 int rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_INPUT, 0, true /*fLeaveOpen*/, &pThis->hVfsStdIn);
150 if (RT_SUCCESS(rc))
151 {
152 rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT, 0, true /*fLeaveOpen*/, &pThis->hVfsStdOut);
153 if (RT_SUCCESS(rc))
154 {
155 /* Read the initial input fuzzer state from the standard input. */
156 uint32_t cbFuzzCtxState;
157 rc = RTVfsIoStrmRead(pThis->hVfsStdIn, &cbFuzzCtxState, sizeof(cbFuzzCtxState), true /*fBlocking*/, NULL);
158 if (RT_SUCCESS(rc))
159 {
160 void *pvFuzzCtxState = RTMemAllocZ(cbFuzzCtxState);
161 if (RT_LIKELY(pvFuzzCtxState))
162 {
163 rc = RTVfsIoStrmRead(pThis->hVfsStdIn, pvFuzzCtxState, cbFuzzCtxState, true /*fBlocking*/, NULL);
164 if (RT_SUCCESS(rc))
165 {
166 rc = RTFuzzCtxCreateFromStateMem(&pThis->hFuzzCtx, pvFuzzCtxState, cbFuzzCtxState);
167 if (RT_SUCCESS(rc))
168 rc = rtFuzzCmdClientMainloop(pThis);
169 }
170
171 RTMemFree(pvFuzzCtxState);
172 }
173 else
174 rc = VERR_NO_MEMORY;
175 }
176 }
177 }
178
179 if (RT_SUCCESS(rc))
180 return RTEXITCODE_SUCCESS;
181
182 return RTEXITCODE_FAILURE;
183}
184
185
186/**
187 * Run a single iteration of the fuzzing client and return.
188 *
189 * @returns Process exit status.
190 * @param pThis The fuzzing client command state.
191 */
192static RTEXITCODE rtFuzzCmdClientRunFile(PRTFUZZCMDCLIENT pThis, const char *pszFilename)
193{
194 void *pv = NULL;
195 size_t cbFile = 0;
196 int rc = RTFileReadAll(pszFilename, &pv, &cbFile);
197 if (RT_SUCCESS(rc))
198 {
199 rtFuzzCmdClientConsume(pThis, pv, cbFile);
200 RTFileReadAllFree(pv, cbFile);
201 return RTEXITCODE_SUCCESS;
202 }
203
204 return RTEXITCODE_FAILURE;
205}
206
207
208RTR3DECL(RTEXITCODE) RTFuzzCmdFuzzingClient(unsigned cArgs, char **papszArgs, PFNFUZZCLIENTCONSUME pfnConsume, void *pvUser)
209{
210 /*
211 * Parse the command line.
212 */
213 static const RTGETOPTDEF s_aOptions[] =
214 {
215 { "--help", 'h', RTGETOPT_REQ_NOTHING },
216 { "--version", 'V', RTGETOPT_REQ_NOTHING },
217 { "--llvm-input", 'l', RTGETOPT_REQ_STRING },
218 { "--file", 'f', RTGETOPT_REQ_STRING },
219 };
220
221 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
222 RTGETOPTSTATE GetState;
223 int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1,
224 RTGETOPTINIT_FLAGS_OPTS_FIRST);
225 if (RT_SUCCESS(rc))
226 {
227 /* Option variables: */
228 RTFUZZCMDCLIENT This;
229 RTLDRMOD hLlvmMod = NIL_RTLDRMOD;
230 const char *pszFilename = NULL;
231
232 This.pfnConsume = pfnConsume;
233 This.pvUser = pvUser;
234 This.enmInputChan = RTFUZZOBSINPUTCHAN_FUZZING_AWARE_CLIENT;
235
236 /* Argument parsing loop. */
237 bool fContinue = true;
238 bool fExit = false;
239 do
240 {
241 RTGETOPTUNION ValueUnion;
242 int chOpt = RTGetOpt(&GetState, &ValueUnion);
243 switch (chOpt)
244 {
245 case 0:
246 fContinue = false;
247 break;
248
249 case 'f':
250 {
251 pszFilename = ValueUnion.psz;
252 This.enmInputChan = RTFUZZOBSINPUTCHAN_FILE;
253 break;
254 }
255
256 case 'l':
257 {
258 /*
259 * Load the indicated library and try to resolve LLVMFuzzerTestOneInput,
260 * which will act as the input callback.
261 */
262 rc = RTLdrLoad(ValueUnion.psz, &hLlvmMod);
263 if (RT_SUCCESS(rc))
264 {
265 rc = RTLdrGetSymbol(hLlvmMod, "LLVMFuzzerTestOneInput", (void **)&This.pfnLlvmFuzzerTestOneInput);
266 if (RT_FAILURE(rc))
267 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to query '%s' from '%s': %Rrc",
268 "LLVMFuzzerTestOneInput",
269 ValueUnion.psz,
270 rc);
271 }
272 break;
273 }
274
275 case 'h':
276 RTPrintf("Usage: to be written\nOption dump:\n");
277 for (unsigned i = 0; i < RT_ELEMENTS(s_aOptions); i++)
278 RTPrintf(" -%c,%s\n", s_aOptions[i].iShort, s_aOptions[i].pszLong);
279 fContinue = false;
280 fExit = true;
281 break;
282
283 case 'V':
284 RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
285 fContinue = false;
286 fExit = true;
287 break;
288
289 default:
290 rcExit = RTGetOptPrintError(chOpt, &ValueUnion);
291 fContinue = false;
292 break;
293 }
294 } while (fContinue);
295
296 if ( rcExit == RTEXITCODE_SUCCESS
297 && !fExit)
298 {
299 switch (This.enmInputChan)
300 {
301 case RTFUZZOBSINPUTCHAN_FUZZING_AWARE_CLIENT:
302 rcExit = rtFuzzCmdClientRun(&This);
303 break;
304 case RTFUZZOBSINPUTCHAN_FILE:
305 rcExit = rtFuzzCmdClientRunFile(&This, pszFilename);
306 break;
307 default:
308 rcExit = RTMsgErrorExit(RTEXITCODE_SYNTAX, "Input channel unknown/not implemented yet");
309 }
310 }
311
312 if (hLlvmMod != NIL_RTLDRMOD)
313 RTLdrClose(hLlvmMod);
314 }
315 else
316 rcExit = RTMsgErrorExit(RTEXITCODE_SYNTAX, "RTGetOptInit: %Rrc", rc);
317 return rcExit;
318}
319
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