VirtualBox

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

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

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).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.5 KB
Line 
1/* $Id: fuzz.cpp 72571 2018-06-15 20:36:17Z vboxsync $ */
2/** @file
3 * IPRT - Fuzzing framework API, core.
4 */
5
6/*
7 * Copyright (C) 2018 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/fuzz.h>
32#include "internal/iprt.h"
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/avl.h>
37#include <iprt/ctype.h>
38#include <iprt/dir.h>
39#include <iprt/err.h>
40#include <iprt/file.h>
41#include <iprt/md5.h>
42#include <iprt/mem.h>
43#include <iprt/path.h>
44#include <iprt/rand.h>
45#include <iprt/string.h>
46#include <iprt/time.h>
47#include <iprt/vfs.h>
48
49
50/*********************************************************************************************************************************
51* Structures and Typedefs *
52*********************************************************************************************************************************/
53/** Pointer to the internal fuzzer state. */
54typedef struct RTFUZZCTXINT *PRTFUZZCTXINT;
55
56/**
57 * A fuzzing input seed.
58 */
59typedef struct RTFUZZINPUTINT
60{
61 /** The AVL tree core. */
62 AVLU64NODECORE Core;
63 /** Reference counter. */
64 volatile uint32_t cRefs;
65/** @todo add magic here (unused padding space on 64-bit hosts). */
66 /** The fuzzer this input belongs to. */
67 PRTFUZZCTXINT pFuzzer;
68 /** Complete MD5 hash of the input data. */
69 uint8_t abMd5Hash[RTMD5_HASH_SIZE];
70 /** Size of the input data. */
71 size_t cbInput;
72 /** Input data - variable in size. */
73 uint8_t abInput[1];
74} RTFUZZINPUTINT;
75/** Pointer to the internal input state. */
76typedef RTFUZZINPUTINT *PRTFUZZINPUTINT;
77/** Pointer to an internal input state pointer. */
78typedef PRTFUZZINPUTINT *PPRTFUZZINPUTINT;
79
80
81/**
82 * Intermediate indexing structure.
83 */
84typedef struct RTFUZZINTERMEDIATE
85{
86 /** The AVL tree core. */
87 AVLU64NODECORE Core;
88 /** The AVL tree for indexing the input seeds (keyed by the lower half of the MD5). */
89 AVLU64TREE TreeSeedsLow;
90} RTFUZZINTERMEDIATE;
91/** Pointer to an intermediate indexing state. */
92typedef RTFUZZINTERMEDIATE *PRTFUZZINTERMEDIATE;
93/** Pointer to an intermediate indexing state pointer. */
94typedef PRTFUZZINTERMEDIATE *PPRTFUZZINTERMEDIATE;
95
96/**
97 * The fuzzer state.
98 */
99typedef struct RTFUZZCTXINT
100{
101 /** Magic value for identification. */
102 uint32_t u32Magic;
103 /** Reference counter. */
104 volatile uint32_t cRefs;
105 /** The random number generator. */
106 RTRAND hRand;
107 /** The AVL tree for indexing the input seeds (keyed by the upper half of the MD5). */
108 AVLU64TREE TreeSeedsHigh;
109 /** The maximum size of one input seed to generate. */
110 size_t cbInputMax;
111 /** Behavioral flags. */
112 uint32_t fFlagsBehavioral;
113} RTFUZZCTXINT;
114
115
116/**
117 * Available mutators enum.
118 */
119typedef enum RTFUZZCTXMUTATOR
120{
121 /** Invalid mutator, not used. */
122 RTFUZZCTXMUTATOR_INVALID = 0,
123 /** Flips a single bit in the input. */
124 RTFUZZCTXMUTATOR_BIT_FLIP,
125 /** Replaces a single byte in the input. */
126 RTFUZZCTXMUTATOR_BYTE_REPLACE,
127 /** Inserts a byte sequence into the input. */
128 RTFUZZCTXMUTATOR_BYTE_SEQUENCE_INSERT,
129 /** Appends a byte sequence to the input. */
130 RTFUZZCTXMUTATOR_BYTE_SEQUENCE_APPEND,
131 /** Deletes a single byte from the input. */
132 RTFUZZCTXMUTATOR_BYTE_DELETE,
133 /** Deletes a sequence of bytes from the input. */
134 RTFUZZCTXMUTATOR_BYTE_SEQUENCE_DELETE,
135 /** Last valid mutator. */
136 RTFUZZCTXMUTATOR_LAST = RTFUZZCTXMUTATOR_BYTE_SEQUENCE_DELETE,
137 /** 32bit hack. */
138 RTFUZZCTXMUTATOR_32BIT_HACK = 0x7fffffff
139} RTFUZZCTXMUTATOR;
140/** Pointer to a mutator enum. */
141typedef RTFUZZCTXMUTATOR *PRTFUZZCTXMUTATOR;
142
143
144/**
145 * Mutator callback.
146 *
147 * @returns IPRT status code.
148 * @param pThis The fuzzer context instance.
149 * @param ppInputMutated Where to store the pointer to the mutated input success.
150 */
151typedef DECLCALLBACK(int) FNRTFUZZCTXMUTATOR(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated);
152/** Pointer to a mutator callback. */
153typedef FNRTFUZZCTXMUTATOR *PFNRTFUZZCTXMUTATOR;
154
155
156
157/*********************************************************************************************************************************
158* Internal Functions *
159*********************************************************************************************************************************/
160static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlip(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated);
161static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplace(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated);
162static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsert(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated);
163static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceAppend(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated);
164static DECLCALLBACK(int) rtFuzzCtxMutatorByteDelete(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated);
165static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDelete(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated);
166
167
168/*********************************************************************************************************************************
169* Global Variables *
170*********************************************************************************************************************************/
171/**
172 * Array of all available mutators.
173 */
174static PFNRTFUZZCTXMUTATOR const g_apfnMutators[] =
175{
176 NULL,
177 rtFuzzCtxMutatorBitFlip,
178 rtFuzzCtxMutatorByteReplace,
179 rtFuzzCtxMutatorByteSequenceInsert,
180 rtFuzzCtxMutatorByteSequenceAppend,
181 rtFuzzCtxMutatorByteDelete,
182 rtFuzzCtxMutatorByteSequenceDelete,
183 NULL
184};
185
186
187
188/**
189 * Tries to locate an input seed with the given input MD5 seed.
190 *
191 * @returns Pointer to the input seed on success or NULL if not found.
192 * @param pThis The fuzzer context instance.
193 * @param pbMd5Hash The MD5 hash to search for.
194 * @param fExact Flag whether to search for an exact match or return the next best fit if no match exists.
195 * @param ppIntermediate Where to store the pointer to the intermediate layer upon success, optional.
196 */
197static PRTFUZZINPUTINT rtFuzzCtxInputLocate(PRTFUZZCTXINT pThis, uint8_t *pbMd5Hash, bool fExact, PPRTFUZZINTERMEDIATE ppIntermediate)
198{
199 PRTFUZZINPUTINT pInput = NULL;
200 uint64_t u64Md5High = *(uint64_t *)&pbMd5Hash[RTMD5_HASH_SIZE / 2];
201 uint64_t u64Md5Low = *(uint64_t *)&pbMd5Hash[0];
202 PRTFUZZINTERMEDIATE pIntermediate = (PRTFUZZINTERMEDIATE)RTAvlU64Get(&pThis->TreeSeedsHigh, u64Md5High);
203 if (!fExact && !pIntermediate)
204 pIntermediate = (PRTFUZZINTERMEDIATE)RTAvlU64GetBestFit(&pThis->TreeSeedsHigh, u64Md5High, true /*fAbove*/);
205 if (!fExact && !pIntermediate)
206 pIntermediate = (PRTFUZZINTERMEDIATE)RTAvlU64GetBestFit(&pThis->TreeSeedsHigh, u64Md5High, false /*fAbove*/);
207
208 if (pIntermediate)
209 {
210 /* 2nd level lookup. */
211 pInput = (PRTFUZZINPUTINT)RTAvlU64Get(&pIntermediate->TreeSeedsLow, u64Md5Low);
212 if (!fExact && !pInput)
213 pInput = (PRTFUZZINPUTINT)RTAvlU64GetBestFit(&pIntermediate->TreeSeedsLow, u64Md5Low, true /*fAbove*/);
214 if (!fExact && !pInput)
215 pInput = (PRTFUZZINPUTINT)RTAvlU64GetBestFit(&pIntermediate->TreeSeedsLow, u64Md5Low, false /*fAbove*/);
216 }
217
218 if (ppIntermediate)
219 *ppIntermediate = pIntermediate;
220
221 return pInput;
222}
223
224
225/**
226 * Adds the given input to the corpus of the given fuzzer context.
227 *
228 * @returns IPRT status code.
229 * @param pThis The fuzzer context instance.
230 * @param pInput The input to add.
231 */
232static int rtFuzzCtxInputAdd(PRTFUZZCTXINT pThis, PRTFUZZINPUTINT pInput)
233{
234 int rc = VINF_SUCCESS;
235 uint64_t u64Md5High = *(uint64_t *)&pInput->abMd5Hash[RTMD5_HASH_SIZE / 2];
236 uint64_t u64Md5Low = *(uint64_t *)&pInput->abMd5Hash[0];
237
238 pInput->Core.Key = u64Md5Low;
239 PRTFUZZINTERMEDIATE pIntermediate = (PRTFUZZINTERMEDIATE)RTAvlU64Get(&pThis->TreeSeedsHigh, u64Md5High);
240 if (!pIntermediate)
241 {
242 pIntermediate = (PRTFUZZINTERMEDIATE)RTMemAllocZ(sizeof(*pIntermediate));
243 if (RT_LIKELY(pIntermediate))
244 {
245 pIntermediate->Core.Key = u64Md5High;
246 pIntermediate->TreeSeedsLow = NULL;
247 bool fIns = RTAvlU64Insert(&pThis->TreeSeedsHigh, &pIntermediate->Core);
248 Assert(fIns); RT_NOREF(fIns);
249 }
250 else
251 rc = VERR_NO_MEMORY;
252 }
253
254 if (RT_SUCCESS(rc))
255 {
256 AssertPtr(pIntermediate);
257 bool fIns = RTAvlU64Insert(&pIntermediate->TreeSeedsLow, &pInput->Core);
258 if (!fIns)
259 rc = VERR_ALREADY_EXISTS;
260 else
261 RTFuzzInputRetain(pInput);
262 }
263
264 return rc;
265}
266
267
268/**
269 * Returns a random input from the corpus of the given fuzzer context.
270 *
271 * @returns Pointer to a randomly picked input.
272 * @param pThis The fuzzer context instance.
273 */
274static PRTFUZZINPUTINT rtFuzzCtxInputPickRnd(PRTFUZZCTXINT pThis)
275{
276 /* Generate a random MD5 hash and do a non exact localisation. */
277 uint8_t abDigestRnd[RTMD5_HASH_SIZE];
278 RTRandAdvBytes(pThis->hRand, &abDigestRnd[0], sizeof(abDigestRnd));
279
280 return rtFuzzCtxInputLocate(pThis, &abDigestRnd[0], false /*fExact*/, NULL /*ppIntermediate*/);
281}
282
283
284/**
285 * Clones a given input.
286 *
287 * @returns Pointer to the cloned input or NULL if out of memory.
288 * @param pInput The input to clone.
289 */
290static PRTFUZZINPUTINT rtFuzzCtxInputClone(PRTFUZZINPUTINT pInput)
291{
292 PRTFUZZINPUTINT pInpClone = (PRTFUZZINPUTINT)RTMemDup(pInput, RT_OFFSETOF(RTFUZZINPUTINT, abInput[pInput->cbInput]));
293 if (RT_LIKELY(pInpClone))
294 {
295 pInpClone->cRefs = 1;
296 pInpClone->Core.Key = 0;
297 }
298
299 return pInpClone;
300}
301
302
303/**
304 * Creates an empty input seed capable of holding the given number of bytes.
305 *
306 * @returns Pointer to the newly created input seed.
307 * @param pThis The fuzzer context instance.
308 * @param cbInput Input seed size in bytes.
309 */
310static PRTFUZZINPUTINT rtFuzzCtxInputCreate(PRTFUZZCTXINT pThis, size_t cbInput)
311{
312 PRTFUZZINPUTINT pInput = (PRTFUZZINPUTINT)RTMemAllocZ(RT_OFFSETOF(RTFUZZINPUTINT, abInput[cbInput]));
313 if (RT_LIKELY(pInput))
314 {
315 pInput->pFuzzer = pThis;
316 pInput->cRefs = 1;
317 pInput->cbInput = cbInput;
318 }
319
320 return pInput;
321}
322
323
324/**
325 * Destroys the given input.
326 *
327 * @returns nothing.
328 * @param pInput The input to destroy.
329 */
330static void rtFuzzInputDestroy(PRTFUZZINPUTINT pInput)
331{
332 RTMemFree(pInput);
333}
334
335
336/**
337 * Destorys the given fuzzer context freeing all allocated resources.
338 *
339 * @returns nothing.
340 * @param pThis The fuzzer context instance.
341 */
342static void rtFuzzCtxDestroy(PRTFUZZCTXINT pThis)
343{
344 RT_NOREF(pThis);
345}
346
347
348/**
349 * Mutator callback - flips a single bit in the input.
350 */
351static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlip(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated)
352{
353 int rc = VINF_SUCCESS;
354 PRTFUZZINPUTINT pInput = rtFuzzCtxInputPickRnd(pThis);
355 PRTFUZZINPUTINT pInputMutated = rtFuzzCtxInputClone(pInput);
356 if (RT_LIKELY(pInputMutated))
357 {
358 int32_t iBit = RTRandAdvS32Ex(pThis->hRand, 0, (uint32_t)pInput->cbInput * 8 - 1);
359 ASMBitToggle(&pInputMutated->abInput[0], iBit);
360 RTMd5(&pInputMutated->abInput[0], pInputMutated->cbInput, &pInputMutated->abMd5Hash[0]);
361 *ppInputMutated = pInputMutated;
362 }
363 else
364 rc = VERR_NO_MEMORY;
365
366 return rc;
367}
368
369
370/**
371 * Mutator callback - replaces a single byte in the input.
372 */
373static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplace(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated)
374{
375 int rc = VINF_SUCCESS;
376 PRTFUZZINPUTINT pInput = rtFuzzCtxInputPickRnd(pThis);
377 PRTFUZZINPUTINT pInputMutated = rtFuzzCtxInputClone(pInput);
378 if (RT_LIKELY(pInputMutated))
379 {
380 uint32_t offByte = RTRandAdvU32Ex(pThis->hRand, 0, (uint32_t)pInput->cbInput - 1);
381 RTRandAdvBytes(pThis->hRand, &pInputMutated->abInput[offByte], 1);
382 if (pInput->abInput[offByte] != pInputMutated->abInput[offByte])
383 {
384 RTMd5(&pInputMutated->abInput[0], pInputMutated->cbInput, &pInputMutated->abMd5Hash[0]);
385 *ppInputMutated = pInputMutated;
386 }
387 else
388 RTMemFree(pInputMutated);
389 }
390 else
391 rc = VERR_NO_MEMORY;
392
393 return rc;
394}
395
396
397/**
398 * Mutator callback - inserts a byte sequence into the input.
399 */
400static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsert(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated)
401{
402 int rc = VINF_SUCCESS;
403 PRTFUZZINPUTINT pInput = rtFuzzCtxInputPickRnd(pThis);
404 if (pInput->cbInput < pThis->cbInputMax)
405 {
406 size_t cbInputMutated = RTRandAdvU32Ex(pThis->hRand, (uint32_t)pInput->cbInput + 1, (uint32_t)pThis->cbInputMax);
407 size_t cbInsert = cbInputMutated - pInput->cbInput;
408 uint32_t offInsert = RTRandAdvU32Ex(pThis->hRand, 0, (uint32_t)pInput->cbInput);
409 PRTFUZZINPUTINT pInputMutated = rtFuzzCtxInputCreate(pThis, cbInputMutated);
410 if (RT_LIKELY(pInputMutated))
411 {
412 if (offInsert)
413 memcpy(&pInputMutated->abInput[0], &pInput->abInput[0], offInsert);
414 RTRandAdvBytes(pThis->hRand, &pInputMutated->abInput[offInsert], cbInsert);
415 memcpy(&pInputMutated->abInput[offInsert + cbInsert], &pInput->abInput[offInsert], pInput->cbInput - offInsert);
416 RTMd5(&pInputMutated->abInput[0], pInputMutated->cbInput, &pInputMutated->abMd5Hash[0]);
417 *ppInputMutated = pInputMutated;
418 }
419 else
420 rc = VERR_NO_MEMORY;
421 }
422
423 return rc;
424}
425
426
427/**
428 * Mutator callback - appends a byte sequence to the input.
429 */
430static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceAppend(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated)
431{
432 int rc = VINF_SUCCESS;
433 PRTFUZZINPUTINT pInput = rtFuzzCtxInputPickRnd(pThis);
434 if (pInput->cbInput < pThis->cbInputMax)
435 {
436 size_t cbInputMutated = RTRandAdvU32Ex(pThis->hRand, (uint32_t)pInput->cbInput + 1, (uint32_t)pThis->cbInputMax);
437 size_t cbInsert = cbInputMutated - pInput->cbInput;
438 PRTFUZZINPUTINT pInputMutated = rtFuzzCtxInputCreate(pThis, cbInputMutated);
439 if (RT_LIKELY(pInputMutated))
440 {
441 memcpy(&pInputMutated->abInput[0], &pInput->abInput[0], pInput->cbInput);
442 RTRandAdvBytes(pThis->hRand, &pInputMutated->abInput[pInput->cbInput], cbInsert);
443 RTMd5(&pInputMutated->abInput[0], pInputMutated->cbInput, &pInputMutated->abMd5Hash[0]);
444 *ppInputMutated = pInputMutated;
445 }
446 else
447 rc = VERR_NO_MEMORY;
448 }
449
450 return rc;
451}
452
453
454/**
455 * Mutator callback - deletes a single byte in the input.
456 */
457static DECLCALLBACK(int) rtFuzzCtxMutatorByteDelete(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated)
458{
459 int rc = VINF_SUCCESS;
460 PRTFUZZINPUTINT pInput = rtFuzzCtxInputPickRnd(pThis);
461 if (pInput->cbInput > 1)
462 {
463 uint32_t offDelete = RTRandAdvU32Ex(pThis->hRand, 0, (uint32_t)pInput->cbInput - 1);
464 PRTFUZZINPUTINT pInputMutated = rtFuzzCtxInputCreate(pThis, pInput->cbInput - 1);
465 if (RT_LIKELY(pInputMutated))
466 {
467 if (offDelete)
468 memcpy(&pInputMutated->abInput[0], &pInput->abInput[0], offDelete);
469 if (offDelete < pInput->cbInput - 1)
470 memcpy(&pInputMutated->abInput[offDelete], &pInput->abInput[offDelete + 1], pInput->cbInput - offDelete - 1);
471 RTMd5(&pInputMutated->abInput[0], pInputMutated->cbInput, &pInputMutated->abMd5Hash[0]);
472 *ppInputMutated = pInputMutated;
473 }
474 else
475 rc = VERR_NO_MEMORY;
476 }
477
478 return rc;
479}
480
481
482/**
483 * Mutator callback - deletes a byte sequence in the input.
484 */
485static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDelete(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated)
486{
487 RT_NOREF(pThis, ppInputMutated);
488 return VERR_NOT_IMPLEMENTED;
489}
490
491
492RTDECL(int) RTFuzzCtxCreate(PRTFUZZCTX phFuzzCtx)
493{
494 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
495
496 int rc = VINF_SUCCESS;
497 PRTFUZZCTXINT pThis = (PRTFUZZCTXINT)RTMemAllocZ(sizeof(*pThis));
498 if (RT_LIKELY(pThis))
499 {
500 pThis->u32Magic = 0xdeadc0de; /** @todo */
501 pThis->cRefs = 1;
502 pThis->TreeSeedsHigh = NULL;
503 pThis->cbInputMax = UINT32_MAX;
504 pThis->fFlagsBehavioral = 0;
505 rc = RTRandAdvCreateParkMiller(&pThis->hRand);
506 if (RT_SUCCESS(rc))
507 {
508 RTRandAdvSeed(pThis->hRand, RTTimeSystemNanoTS()); /** @todo */
509 *phFuzzCtx = pThis;
510 return VINF_SUCCESS;
511 }
512
513 RTMemFree(pThis);
514 }
515 else
516 rc = VERR_NO_MEMORY;
517
518 return rc;
519}
520
521
522RTDECL(int) RTFuzzCtxCreateFromState(PRTFUZZCTX phFuzzCtx, const void *pvState, size_t cbState)
523{
524 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
525 AssertPtrReturn(pvState, VERR_INVALID_POINTER);
526 AssertReturn(cbState > 0, VERR_INVALID_PARAMETER);
527
528 return VERR_NOT_IMPLEMENTED;
529}
530
531
532RTDECL(int) RTFuzzCtxCreateFromStateFile(PRTFUZZCTX phFuzzCtx, const char *pszFilename)
533{
534 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
535 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
536
537 return VERR_NOT_IMPLEMENTED;
538}
539
540
541RTDECL(uint32_t) RTFuzzCtxRetain(RTFUZZCTX hFuzzCtx)
542{
543 PRTFUZZCTXINT pThis = hFuzzCtx;
544
545 AssertPtrReturn(pThis, UINT32_MAX);
546
547 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
548 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
549 return cRefs;
550}
551
552
553RTDECL(uint32_t) RTFuzzCtxRelease(RTFUZZCTX hFuzzCtx)
554{
555 PRTFUZZCTXINT pThis = hFuzzCtx;
556 if (pThis == NIL_RTFUZZCTX)
557 return 0;
558 AssertPtrReturn(pThis, UINT32_MAX);
559
560 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
561 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
562 if (cRefs == 0)
563 rtFuzzCtxDestroy(pThis);
564 return cRefs;
565}
566
567
568RTDECL(int) RTFuzzCtxStateExport(RTFUZZCTX hFuzzCtx, void **ppvState, size_t *pcbState)
569{
570 PRTFUZZCTXINT pThis = hFuzzCtx;
571 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
572 AssertPtrReturn(ppvState, VERR_INVALID_POINTER);
573 AssertPtrReturn(pcbState, VERR_INVALID_POINTER);
574
575 return VERR_NOT_IMPLEMENTED;
576}
577
578
579RTDECL(int) RTFuzzCtxStateExportToFile(RTFUZZCTX hFuzzCtx, const char *pszFilename)
580{
581 PRTFUZZCTXINT pThis = hFuzzCtx;
582 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
583 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
584
585 return VERR_NOT_IMPLEMENTED;
586}
587
588
589RTDECL(int) RTFuzzCtxCorpusInputAdd(RTFUZZCTX hFuzzCtx, const void *pvInput, size_t cbInput)
590{
591 PRTFUZZCTXINT pThis = hFuzzCtx;
592 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
593 AssertPtrReturn(pvInput, VERR_INVALID_POINTER);
594 AssertReturn(cbInput, VERR_INVALID_POINTER);
595
596 /* Generate MD5 checksum and try to locate input. */
597 int rc = VINF_SUCCESS;
598 uint8_t abDigest[RTMD5_HASH_SIZE];
599 RTMd5(pvInput, cbInput, &abDigest[0]);
600
601 PRTFUZZINPUTINT pInput = rtFuzzCtxInputLocate(pThis, &abDigest[0], true /*fExact*/, NULL /*ppIntermediate*/);
602 if (!pInput)
603 {
604 pInput = (PRTFUZZINPUTINT)RTMemAllocZ(RT_OFFSETOF(RTFUZZINPUTINT, abInput[cbInput]));
605 if (RT_LIKELY(pInput))
606 {
607 pInput->cRefs = 1;
608 pInput->pFuzzer = pThis;
609 pInput->cbInput = cbInput;
610 memcpy(&pInput->abInput[0], pvInput, cbInput);
611 memcpy(&pInput->abMd5Hash[0], &abDigest[0], sizeof(abDigest));
612 rc = rtFuzzCtxInputAdd(pThis, pInput);
613 if (RT_FAILURE(rc))
614 RTMemFree(pInput);
615 }
616 else
617 rc = VERR_NO_MEMORY;
618 }
619 else
620 rc = VERR_ALREADY_EXISTS;
621
622 return rc;
623}
624
625
626RTDECL(int) RTFuzzCtxCorpusInputAddFromFile(RTFUZZCTX hFuzzCtx, const char *pszFilename)
627{
628 PRTFUZZCTXINT pThis = hFuzzCtx;
629 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
630 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
631
632 void *pv = NULL;
633 size_t cb = 0;
634 int rc = RTFileReadAll(pszFilename, &pv, &cb);
635 if (RT_SUCCESS(rc))
636 {
637 rc = RTFuzzCtxCorpusInputAdd(hFuzzCtx, pv, cb);
638 RTFileReadAllFree(pv, cb);
639 }
640
641 return rc;
642}
643
644
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
689RTDECL(int) RTFuzzCtxCorpusInputAddFromDirPath(RTFUZZCTX hFuzzCtx, const char *pszDirPath)
690{
691 PRTFUZZCTXINT pThis = hFuzzCtx;
692 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
693 AssertPtrReturn(pszDirPath, VERR_INVALID_POINTER);
694
695 RTDIR hDir;
696 int rc = RTDirOpen(&hDir, pszDirPath);
697 if (RT_SUCCESS(rc))
698 {
699 for (;;)
700 {
701 RTDIRENTRY DirEntry;
702 rc = RTDirRead(hDir, &DirEntry, NULL);
703 if (RT_FAILURE(rc))
704 break;
705
706 /* Skip '.', '..' and other non-files. */
707 if ( DirEntry.enmType != RTDIRENTRYTYPE_UNKNOWN
708 && DirEntry.enmType != RTDIRENTRYTYPE_FILE)
709 continue;
710 if (RTDirEntryIsStdDotLink(&DirEntry))
711 continue;
712
713 /* Compose the full path, result 'unknown' entries and skip non-files. */
714 char szFile[RTPATH_MAX];
715 RT_ZERO(szFile);
716 rc = RTPathJoin(szFile, sizeof(szFile), pszDirPath, DirEntry.szName);
717 if (RT_FAILURE(rc))
718 break;
719
720 if (DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN)
721 {
722 RTDirQueryUnknownType(szFile, false, &DirEntry.enmType);
723 if (DirEntry.enmType != RTDIRENTRYTYPE_FILE)
724 continue;
725 }
726
727 /* Okay, it's a file we can add. */
728 rc = RTFuzzCtxCorpusInputAddFromFile(hFuzzCtx, szFile);
729 if (RT_FAILURE(rc))
730 break;
731 }
732 if (rc == VERR_NO_MORE_FILES)
733 rc = VINF_SUCCESS;
734 RTDirClose(hDir);
735 }
736
737 return rc;
738}
739
740
741RTDECL(int) RTFuzzCtxCfgSetInputSeedMaximum(RTFUZZCTX hFuzzCtx, size_t cbMax)
742{
743 PRTFUZZCTXINT pThis = hFuzzCtx;
744 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
745
746 pThis->cbInputMax = cbMax;
747 return VINF_SUCCESS;
748}
749
750
751RTDECL(size_t) RTFuzzCtxCfgGetInputSeedMaximum(RTFUZZCTX hFuzzCtx)
752{
753 PRTFUZZCTXINT pThis = hFuzzCtx;
754 AssertPtrReturn(pThis, 0);
755
756 return pThis->cbInputMax;
757}
758
759
760RTDECL(int) RTFuzzCtxCfgSetBehavioralFlags(RTFUZZCTX hFuzzCtx, uint32_t fFlags)
761{
762 PRTFUZZCTXINT pThis = hFuzzCtx;
763 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
764 AssertReturn(!(fFlags & ~RTFUZZCTX_F_BEHAVIORAL_VALID), VERR_INVALID_PARAMETER);
765
766 pThis->fFlagsBehavioral = fFlags;
767 return VINF_SUCCESS;
768}
769
770
771RTDECL(uint32_t) RTFuzzCfgGetBehavioralFlags(RTFUZZCTX hFuzzCtx)
772{
773 PRTFUZZCTXINT pThis = hFuzzCtx;
774 AssertPtrReturn(pThis, 0);
775
776 return pThis->fFlagsBehavioral;
777}
778
779
780RTDECL(int) RTFuzzCtxCfgSetTmpDirectory(RTFUZZCTX hFuzzCtx, const char *pszPathTmp)
781{
782 PRTFUZZCTXINT pThis = hFuzzCtx;
783 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
784 AssertPtrReturn(pszPathTmp, VERR_INVALID_POINTER);
785
786 return VERR_NOT_IMPLEMENTED;
787}
788
789
790RTDECL(const char *) RTFuzzCtxCfgGetTmpDirectory(RTFUZZCTX hFuzzCtx)
791{
792 PRTFUZZCTXINT pThis = hFuzzCtx;
793 AssertPtrReturn(pThis, NULL);
794
795 return NULL;
796}
797
798
799RTDECL(int) RTFuzzCtxInputGenerate(RTFUZZCTX hFuzzCtx, PRTFUZZINPUT phFuzzInput)
800{
801 int rc = VINF_SUCCESS;
802 PRTFUZZCTXINT pThis = hFuzzCtx;
803 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
804 AssertPtrReturn(phFuzzInput, VERR_INVALID_POINTER);
805
806 uint32_t cTries = 0;
807 do
808 {
809 RTFUZZCTXMUTATOR enmMutator = (RTFUZZCTXMUTATOR)RTRandAdvU32Ex(pThis->hRand, 1, RTFUZZCTXMUTATOR_LAST);
810 PRTFUZZINPUTINT pInput = NULL;
811 rc = g_apfnMutators[enmMutator](pThis, &pInput);
812 if ( RT_SUCCESS(rc)
813 && VALID_PTR(pInput))
814 {
815 if (pThis->fFlagsBehavioral & RTFUZZCTX_F_BEHAVIORAL_ADD_INPUT_AUTOMATICALLY_TO_CORPUS)
816 rtFuzzCtxInputAdd(pThis, pInput);
817 *phFuzzInput = pInput;
818 return rc;
819 }
820 } while (++cTries <= 50);
821
822 if (RT_SUCCESS(rc))
823 rc = VERR_INVALID_STATE;
824
825 return rc;
826}
827
828
829RTDECL(uint32_t) RTFuzzInputRetain(RTFUZZINPUT hFuzzInput)
830{
831 PRTFUZZINPUTINT pThis = hFuzzInput;
832
833 AssertPtrReturn(pThis, UINT32_MAX);
834
835 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
836 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
837 return cRefs;
838}
839
840
841RTDECL(uint32_t) RTFuzzInputRelease(RTFUZZINPUT hFuzzInput)
842{
843 PRTFUZZINPUTINT pThis = hFuzzInput;
844 if (pThis == NIL_RTFUZZINPUT)
845 return 0;
846 AssertPtrReturn(pThis, UINT32_MAX);
847
848 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
849 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
850 if (cRefs == 0)
851 rtFuzzInputDestroy(pThis);
852 return cRefs;
853}
854
855
856RTDECL(int) RTFuzzInputQueryData(RTFUZZINPUT hFuzzInput, void **ppv, size_t *pcb)
857{
858 PRTFUZZINPUTINT pThis = hFuzzInput;
859 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
860 AssertPtrReturn(ppv, VERR_INVALID_POINTER);
861 AssertPtrReturn(pcb, VERR_INVALID_POINTER);
862
863 *ppv = &pThis->abInput[0];
864 *pcb = pThis->cbInput;
865 return VINF_SUCCESS;
866}
867
868
869RTDECL(int) RTFuzzInputQueryDigestString(RTFUZZINPUT hFuzzInput, char *pszDigest, size_t cchDigest)
870{
871 PRTFUZZINPUTINT pThis = hFuzzInput;
872 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
873 AssertPtrReturn(pszDigest, VERR_INVALID_POINTER);
874 AssertReturn(cchDigest >= RTMD5_STRING_LEN + 1, VERR_INVALID_PARAMETER);
875
876 return RTMd5ToString(&pThis->abMd5Hash[0], pszDigest, cchDigest);
877}
878
879
880RTDECL(int) RTFuzzInputWriteToFile(RTFUZZINPUT hFuzzInput, const char *pszFilename)
881{
882 PRTFUZZINPUTINT pThis = hFuzzInput;
883 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
884 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
885
886 RTFILE hFile;
887 int rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
888 if (RT_SUCCESS(rc))
889 {
890 rc = RTFileWrite(hFile, &pThis->abInput[0], pThis->cbInput, NULL);
891 AssertRC(rc);
892 RTFileClose(hFile);
893
894 if (RT_FAILURE(rc))
895 RTFileDelete(pszFilename);
896 }
897
898 return rc;
899}
900
901
902RTDECL(int) RTFuzzInputAddToCtxCorpus(RTFUZZINPUT hFuzzInput)
903{
904 PRTFUZZINPUTINT pThis = hFuzzInput;
905 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
906
907 return rtFuzzCtxInputAdd(pThis->pFuzzer, pThis);
908}
909
910
911RTDECL(int) RTFuzzInputRemoveFromCtxCorpus(RTFUZZINPUT hFuzzInput)
912{
913 PRTFUZZINPUTINT pThis = hFuzzInput;
914 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
915
916 int rc = VINF_SUCCESS;
917 PRTFUZZINTERMEDIATE pIntermediate = NULL;
918 PRTFUZZINPUTINT pInputLoc = rtFuzzCtxInputLocate(pThis->pFuzzer, &pThis->abMd5Hash[0], true /*fExact*/,
919 &pIntermediate);
920 if (pInputLoc)
921 {
922 AssertPtr(pIntermediate);
923 Assert(pInputLoc == pThis);
924
925 uint64_t u64Md5Low = *(uint64_t *)&pThis->abMd5Hash[0];
926 RTAvlU64Remove(&pIntermediate->TreeSeedsLow, u64Md5Low);
927 RTFuzzInputRelease(hFuzzInput);
928 }
929 else
930 rc = VERR_NOT_FOUND;
931
932 return rc;
933}
934
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