VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

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