VirtualBox

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

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

Runtime/fuzz: Add libFuzzer compatible wrapper to be able to evaluate our fuzzer against others

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