VirtualBox

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

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

Runtime/fuzz: Updates

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 55.9 KB
Line 
1/* $Id: fuzz.cpp 77509 2019-02-28 19:14:03Z vboxsync $ */
2/** @file
3 * IPRT - Fuzzing framework API, core.
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.215389.xyz. 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/list.h>
42#include <iprt/md5.h>
43#include <iprt/mem.h>
44#include <iprt/path.h>
45#include <iprt/rand.h>
46#include <iprt/semaphore.h>
47#include <iprt/string.h>
48#include <iprt/time.h>
49#include <iprt/vfs.h>
50
51
52#define RTFUZZCTX_MAGIC UINT32_C(0xdeadc0de) /** @todo */
53
54
55/*********************************************************************************************************************************
56* Structures and Typedefs *
57*********************************************************************************************************************************/
58/** Pointer to the internal fuzzer state. */
59typedef struct RTFUZZCTXINT *PRTFUZZCTXINT;
60/** Pointer to a fuzzed mutation. */
61typedef struct RTFUZZMUTATION *PRTFUZZMUTATION;
62/** Pointer to a fuzzed mutation pointer. */
63typedef PRTFUZZMUTATION *PPRTFUZZMUTATION;
64/** Pointer to a const mutation. */
65typedef const struct RTFUZZMUTATION *PCRTFUZZMUTATION;
66
67
68/**
69 * Mutator preparation callback.
70 *
71 * @returns IPRT status code.
72 * @param pThis The fuzzer context instance.
73 * @param offStart Where the mutation should start.
74 * @param pMutationParent The parent mutation to start working from.
75 * @param ppMutation Where to store the created mutation on success.
76 */
77typedef DECLCALLBACK(int) FNRTFUZZCTXMUTATORPREP(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
78 PPRTFUZZMUTATION ppMutation);
79/** Pointer to a mutator preparation callback. */
80typedef FNRTFUZZCTXMUTATORPREP *PFNRTFUZZCTXMUTATORPREP;
81
82
83/**
84 * Mutator execution callback.
85 *
86 * @returns IPRT status code.
87 * @param pThis The fuzzer context instance.
88 * @param pMutation The mutation to work on.
89 * @param pvMutation Mutation dependent data.
90 * @param pbBuf The buffer to work on.
91 * @param cbBuf Size of the remaining buffer.
92 */
93typedef DECLCALLBACK(int) FNRTFUZZCTXMUTATOREXEC(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
94 uint8_t *pbBuf, size_t cbBuf);
95/** Pointer to a mutator execution callback. */
96typedef FNRTFUZZCTXMUTATOREXEC *PFNRTFUZZCTXMUTATOREXEC;
97
98
99/**
100 * Mutator export callback.
101 *
102 * @returns IPRT status code.
103 * @param pThis The fuzzer context instance.
104 * @param pMutation The mutation to work on.
105 * @param pvMutation Mutation dependent data.
106 * @param pfnExport The export callback.
107 * @param pvUser Opaque user data to pass to the export callback.
108 */
109typedef DECLCALLBACK(int) FNRTFUZZCTXMUTATOREXPORT(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
110 PFNRTFUZZCTXEXPORT pfnExport, void *pvUser);
111/** Pointer to a mutator export callback. */
112typedef FNRTFUZZCTXMUTATOREXPORT *PFNRTFUZZCTXMUTATOREXPORT;
113
114
115/**
116 * Mutator import callback.
117 *
118 * @returns IPRT status code.
119 * @param pThis The fuzzer context instance.
120 * @param pMutation The mutation to work on.
121 * @param pvMutation Mutation dependent data.
122 * @param pfnExport The import callback.
123 * @param pvUser Opaque user data to pass to the import callback.
124 */
125typedef DECLCALLBACK(int) FNRTFUZZCTXMUTATORIMPORT(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, void *pvMutation,
126 PFNRTFUZZCTXIMPORT pfnImport, void *pvUser);
127/** Pointer to a mutator import callback. */
128typedef FNRTFUZZCTXMUTATORIMPORT *PFNRTFUZZCTXMUTATORIMPORT;
129
130
131/**
132 * A fuzzing mutator descriptor.
133 */
134typedef struct RTFUZZMUTATOR
135{
136 /** Id of the mutator. */
137 const char *pszId;
138 /** Mutator description. */
139 const char *pszDesc;
140 /** Mutator index. */
141 uint32_t uMutator;
142 /** Additional flags for the mutator, controlling the behavior. */
143 uint64_t fFlags;
144 /** The preparation callback. */
145 PFNRTFUZZCTXMUTATORPREP pfnPrep;
146 /** The execution callback. */
147 PFNRTFUZZCTXMUTATOREXEC pfnExec;
148 /** The export callback. */
149 PFNRTFUZZCTXMUTATOREXPORT pfnExport;
150 /** The import callback. */
151 PFNRTFUZZCTXMUTATORIMPORT pfnImport;
152} RTFUZZMUTATOR;
153/** Pointer to a fuzzing mutator descriptor. */
154typedef RTFUZZMUTATOR *PRTFUZZMUTATOR;
155/** Pointer to a const fuzzing mutator descriptor. */
156typedef const RTFUZZMUTATOR *PCRTFUZZMUTATOR;
157
158/** The special corpus mutator. */
159#define RTFUZZMUTATOR_ID_CORPUS UINT32_C(0xffffffff)
160
161/** Mutator always works from the end of the buffer (no starting offset generation). */
162#define RTFUZZMUTATOR_F_END_OF_BUF RT_BIT_64(0)
163/** Default flags. */
164#define RTFUZZMUTATOR_F_DEFAULT (0)
165
166
167/**
168 * A fuzzed mutation.
169 */
170typedef struct RTFUZZMUTATION
171{
172 /** The AVL tree core. */
173 AVLU64NODECORE Core;
174 /** Magic identifying this structure. */
175 uint32_t u32Magic;
176 /** Reference counter. */
177 volatile uint32_t cRefs;
178 /** The fuzzer this mutation belongs to. */
179 PRTFUZZCTXINT pFuzzer;
180 /** Parent mutation (reference is held), NULL means root or original data. */
181 PCRTFUZZMUTATION pMutationParent;
182 /** Mutation level. */
183 uint32_t iLvl;
184 /** The mutator causing this mutation, NULL if original input data. */
185 PCRTFUZZMUTATOR pMutator;
186 /** Byte offset where the mutation starts. */
187 uint64_t offMutation;
188 /** Size of the generated input data in bytes after the mutation was applied. */
189 size_t cbInput;
190 /** Size of the mutation dependent data. */
191 size_t cbMutation;
192 /** Mutation dependent data, variable in size. */
193 uint8_t abMutation[1];
194} RTFUZZMUTATION;
195
196
197/**
198 * A fuzzing input seed.
199 */
200typedef struct RTFUZZINPUTINT
201{
202 /** Magic identifying this structure. */
203 uint32_t u32Magic;
204 /** Reference counter. */
205 volatile uint32_t cRefs;
206 /** The fuzzer this input belongs to. */
207 PRTFUZZCTXINT pFuzzer;
208 /** The top mutation to work from (reference held). */
209 PRTFUZZMUTATION pMutationTop;
210 /** Fuzzer context type dependent data. */
211 union
212 {
213 /** Blob data. */
214 struct
215 {
216 /** Size to allocate initially. */
217 size_t cbAlloc;
218 /** Input data size. */
219 size_t cbInput;
220 /** Pointer to the input data if created. */
221 void *pvInput;
222 } Blob;
223 /** Stream state. */
224 struct
225 {
226 /** Number of bytes seen so far. */
227 size_t cbSeen;
228 } Stream;
229 } u;
230 /** Array holding all the individual mutations, variable in size. */
231 PCRTFUZZMUTATION apMutations[1];
232} RTFUZZINPUTINT;
233/** Pointer to the internal input state. */
234typedef RTFUZZINPUTINT *PRTFUZZINPUTINT;
235/** Pointer to an internal input state pointer. */
236typedef PRTFUZZINPUTINT *PPRTFUZZINPUTINT;
237
238
239/**
240 * The fuzzer state.
241 */
242typedef struct RTFUZZCTXINT
243{
244 /** Magic value for identification. */
245 uint32_t u32Magic;
246 /** Reference counter. */
247 volatile uint32_t cRefs;
248 /** The random number generator. */
249 RTRAND hRand;
250 /** Fuzzing context type. */
251 RTFUZZCTXTYPE enmType;
252 /** Semaphore protecting the mutations tree. */
253 RTSEMRW hSemRwMutations;
254 /** The AVL tree for indexing the mutations (keyed by counter). */
255 AVLU64TREE TreeMutations;
256 /** Number of inputs currently in the tree. */
257 volatile uint64_t cMutations;
258 /** The maximum size of one input seed to generate. */
259 size_t cbInputMax;
260 /** Behavioral flags. */
261 uint32_t fFlagsBehavioral;
262 /** Number of enabled mutators. */
263 uint32_t cMutators;
264 /** Pointer to the mutator descriptors. */
265 PRTFUZZMUTATOR paMutators;
266 /** Total number of bytes of memory currently allocated in total for this context. */
267 volatile size_t cbMemTotal;
268} RTFUZZCTXINT;
269
270
271/**
272 * The fuzzer state to be exported - all members are stored in little endian form.
273 */
274typedef struct RTFUZZCTXSTATE
275{
276 /** Magic value for identification. */
277 uint32_t u32Magic;
278 /** Context type. */
279 uint32_t uCtxType;
280 /** Size of the PRNG state following in bytes. */
281 uint32_t cbPrng;
282 /** Number of mutator descriptors following. */
283 uint32_t cMutators;
284 /** Number of mutation descriptors following. */
285 uint32_t cMutations;
286 /** Behavioral flags. */
287 uint32_t fFlagsBehavioral;
288 /** Maximum input size to generate. */
289 uint64_t cbInputMax;
290} RTFUZZCTXSTATE;
291/** Pointer to a fuzzing context state. */
292typedef RTFUZZCTXSTATE *PRTFUZZCTXSTATE;
293
294/** BLOB context type. */
295#define RTFUZZCTX_STATE_TYPE_BLOB UINT32_C(0)
296/** Stream context type. */
297#define RTFUZZCTX_STATE_TYPE_STREAM UINT32_C(1)
298
299
300/**
301 * The fuzzer mutation state to be exported - all members are stored in little endian form.
302 */
303typedef struct RTFUZZMUTATIONSTATE
304{
305 /** The mutation identifier. */
306 uint64_t u64Id;
307 /** The mutation identifier of the parent, 0 for no parent. */
308 uint64_t u64IdParent;
309 /** The byte offset where the mutation starts. */
310 uint64_t u64OffMutation;
311 /** Size of input data after mutation was applied. */
312 uint64_t cbInput;
313 /** Size of mutation dependent data following. */
314 uint64_t cbMutation;
315 /** The mutator ID. */
316 uint32_t u32IdMutator;
317 /** The mutation level. */
318 uint32_t iLvl;
319 /** Magic value for identification. */
320 uint32_t u32Magic;
321} RTFUZZMUTATIONSTATE;
322
323
324/**
325 * Fuzzing context memory header.
326 */
327typedef struct RTFUZZMEMHDR
328{
329 /** Size of the memory area following. */
330 size_t cb;
331#if HC_ARCH_BITS == 32
332 /** Some padding. */
333 uint32_t uPadding0;
334#elif HC_ARCH_BITS == 64
335#else
336 /** Some padding. */
337 uint64_t uPadding0;
338# error "Port me"
339#endif
340} RTFUZZMEMHDR;
341/** Pointer to a memory header. */
342typedef RTFUZZMEMHDR *PRTFUZZMEMHDR;
343
344
345/**
346 * Fuzzing context export AVL arguments.
347 */
348typedef struct RTFUZZEXPORTARGS
349{
350 /** Pointer to the export callback. */
351 PFNRTFUZZCTXEXPORT pfnExport;
352 /** Opaque user data to pass to the callback. */
353 void *pvUser;
354} RTFUZZEXPORTARGS;
355/** Pointer to the export arguments. */
356typedef RTFUZZEXPORTARGS *PRTFUZZEXPORTARGS;
357/** Pointer to the constant export arguments. */
358typedef const RTFUZZEXPORTARGS *PCRTFUZZEXPORTARGS;
359
360
361/*********************************************************************************************************************************
362* Internal Functions *
363*********************************************************************************************************************************/
364static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlipPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
365 PPRTFUZZMUTATION ppMutation);
366static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplacePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
367 PPRTFUZZMUTATION ppMutation);
368static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsertAppendPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
369 PPRTFUZZMUTATION ppMutation);
370static DECLCALLBACK(int) rtFuzzCtxMutatorByteDeletePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
371 PPRTFUZZMUTATION ppMutation);
372static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDeletePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
373 PPRTFUZZMUTATION ppMutation);
374
375static DECLCALLBACK(int) rtFuzzCtxMutatorCorpusExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
376 uint8_t *pbBuf, size_t cbBuf);
377static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlipExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
378 uint8_t *pbBuf, size_t cbBuf);
379static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplaceExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
380 uint8_t *pbBuf, size_t cbBuf);
381static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsertAppendExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
382 uint8_t *pbBuf, size_t cbBuf);
383static DECLCALLBACK(int) rtFuzzCtxMutatorByteDeleteExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
384 uint8_t *pbBuf, size_t cbBuf);
385static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDeleteExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
386 uint8_t *pbBuf, size_t cbBuf);
387
388static DECLCALLBACK(int) rtFuzzCtxMutatorExportDefault(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
389 PFNRTFUZZCTXEXPORT pfnExport, void *pvUser);
390static DECLCALLBACK(int) rtFuzzCtxMutatorImportDefault(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, void *pvMutation,
391 PFNRTFUZZCTXIMPORT pfnImport, void *pvUser);
392
393/*********************************************************************************************************************************
394* Global Variables *
395*********************************************************************************************************************************/
396/**
397 * The special corpus mutator for the original data.
398 */
399static RTFUZZMUTATOR const g_MutatorCorpus =
400{
401 /** pszId */
402 "Corpus",
403 /** pszDesc */
404 "Special mutator, which is assigned to the initial corpus",
405 /** uMutator. */
406 RTFUZZMUTATOR_ID_CORPUS,
407 /** fFlags */
408 RTFUZZMUTATOR_F_DEFAULT,
409 /** pfnPrep */
410 NULL,
411 /** pfnExec */
412 rtFuzzCtxMutatorCorpusExec,
413 /** pfnExport */
414 rtFuzzCtxMutatorExportDefault,
415 /** pfnImport */
416 rtFuzzCtxMutatorImportDefault
417};
418
419/**
420 * Array of all available mutators.
421 */
422static RTFUZZMUTATOR const g_aMutators[] =
423{
424 /* pszId pszDesc uMutator fFlags pfnPrep pfnExec pfnExport pfnImport */
425 { "BitFlip", "Flips a single bit in the input", 0, RTFUZZMUTATOR_F_DEFAULT, rtFuzzCtxMutatorBitFlipPrep, rtFuzzCtxMutatorBitFlipExec, rtFuzzCtxMutatorExportDefault, rtFuzzCtxMutatorImportDefault },
426 { "ByteReplace", "Replaces a single byte in the input", 1, RTFUZZMUTATOR_F_DEFAULT, rtFuzzCtxMutatorByteReplacePrep, rtFuzzCtxMutatorByteReplaceExec, rtFuzzCtxMutatorExportDefault, rtFuzzCtxMutatorImportDefault },
427 { "ByteSeqIns", "Inserts a byte sequence in the input", 2, RTFUZZMUTATOR_F_DEFAULT, rtFuzzCtxMutatorByteSequenceInsertAppendPrep, rtFuzzCtxMutatorByteSequenceInsertAppendExec, rtFuzzCtxMutatorExportDefault, rtFuzzCtxMutatorImportDefault },
428 { "ByteSeqApp", "Appends a byte sequence to the input", 3, RTFUZZMUTATOR_F_END_OF_BUF, rtFuzzCtxMutatorByteSequenceInsertAppendPrep, rtFuzzCtxMutatorByteSequenceInsertAppendExec, rtFuzzCtxMutatorExportDefault, rtFuzzCtxMutatorImportDefault },
429 { "ByteDelete", "Deletes a single byte sequence from the input", 4, RTFUZZMUTATOR_F_DEFAULT, rtFuzzCtxMutatorByteDeletePrep, rtFuzzCtxMutatorByteDeleteExec, NULL, NULL },
430 { "ByteSeqDel", "Deletes a byte sequence from the input", 5, RTFUZZMUTATOR_F_DEFAULT, rtFuzzCtxMutatorByteSequenceDeletePrep, rtFuzzCtxMutatorByteSequenceDeleteExec, NULL, NULL }
431};
432
433
434/**
435 * Allocates the given number of bytes.
436 *
437 * @returns Pointer to the allocated memory
438 * @param pThis The fuzzer context instance.
439 * @param cb How much to allocate.
440 */
441static void *rtFuzzCtxMemoryAlloc(PRTFUZZCTXINT pThis, size_t cb)
442{
443 PRTFUZZMEMHDR pMemHdr = (PRTFUZZMEMHDR)RTMemAllocZ(cb + sizeof(RTFUZZMEMHDR));
444 if (RT_LIKELY(pMemHdr))
445 {
446 pMemHdr->cb = cb;
447 size_t cbIgn = ASMAtomicAddZ(&pThis->cbMemTotal, cb + sizeof(RTFUZZMEMHDR)); RT_NOREF(cbIgn);
448 return pMemHdr + 1;
449 }
450
451 return NULL;
452}
453
454
455/**
456 * Frees the given memory.
457 *
458 * @returns nothing.
459 * @param pThis The fuzzer context instance.
460 * @param pv Pointer to the memory area to free.
461 */
462static void rtFuzzCtxMemoryFree(PRTFUZZCTXINT pThis, void *pv)
463{
464 PRTFUZZMEMHDR pMemHdr = ((PRTFUZZMEMHDR)pv) - 1;
465
466 size_t cbIgn = ASMAtomicSubZ(&pThis->cbMemTotal, pMemHdr->cb + sizeof(RTFUZZMEMHDR)); RT_NOREF(cbIgn);
467 RTMemFree(pMemHdr);
468}
469
470
471/**
472 * Retains an external reference to the given mutation.
473 *
474 * @returns New reference count on success.
475 * @param pMutation The mutation to retain.
476 */
477static uint32_t rtFuzzMutationRetain(PRTFUZZMUTATION pMutation)
478{
479 uint32_t cRefs = ASMAtomicIncU32(&pMutation->cRefs);
480 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pMutation));
481 return cRefs;
482}
483
484#if 0 /* unused */
485/**
486 * Releases an external reference from the given mutation.
487 *
488 * @returns New reference count on success.
489 * @param pMutation The mutation to retain.
490 */
491static uint32_t rtFuzzMutationRelease(PRTFUZZMUTATION pMutation)
492{
493 uint32_t cRefs = ASMAtomicDecU32(&pMutation->cRefs);
494 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pMutation));
495 return cRefs;
496}
497#endif
498
499/**
500 * Adds the given mutation to the corpus of the given fuzzer context.
501 *
502 * @returns IPRT status code.
503 * @param pThis The fuzzer context instance.
504 * @param pMutation The mutation to add.
505 */
506static int rtFuzzCtxMutationAdd(PRTFUZZCTXINT pThis, PRTFUZZMUTATION pMutation)
507{
508 int rc = VINF_SUCCESS;
509
510 pMutation->Core.Key = ASMAtomicIncU64(&pThis->cMutations);
511 rc = RTSemRWRequestWrite(pThis->hSemRwMutations, RT_INDEFINITE_WAIT);
512 AssertRC(rc); RT_NOREF(rc);
513 bool fIns = RTAvlU64Insert(&pThis->TreeMutations, &pMutation->Core);
514 Assert(fIns); RT_NOREF(fIns);
515 rc = RTSemRWReleaseWrite(pThis->hSemRwMutations);
516 AssertRC(rc); RT_NOREF(rc);
517
518 return rc;
519}
520
521
522/**
523 * Returns a random mutation from the corpus of the given fuzzer context.
524 *
525 * @returns Pointer to a randomly picked mutation (reference count is increased).
526 * @param pThis The fuzzer context instance.
527 */
528static PRTFUZZMUTATION rtFuzzCtxMutationPickRnd(PRTFUZZCTXINT pThis)
529{
530 uint64_t idxMutation = RTRandAdvU64Ex(pThis->hRand, 0, ASMAtomicReadU64(&pThis->cMutations));
531
532 int rc = RTSemRWRequestRead(pThis->hSemRwMutations, RT_INDEFINITE_WAIT);
533 AssertRC(rc); RT_NOREF(rc);
534
535 /*
536 * Using best fit getter here as there might be a racing mutation insertion and the mutation counter has increased
537 * already but the mutation is not yet in the tree.
538 */
539 PRTFUZZMUTATION pMutation = (PRTFUZZMUTATION)RTAvlU64GetBestFit(&pThis->TreeMutations, idxMutation, false /*fAbove*/);
540 AssertPtr(pMutation);
541
542 /* Increase reference count of the mutation. */
543 rtFuzzMutationRetain(pMutation);
544 rc = RTSemRWReleaseRead(pThis->hSemRwMutations);
545 AssertRC(rc); RT_NOREF(rc);
546
547 return pMutation;
548}
549
550
551/**
552 * Creates a new mutation capable of holding the additional number of bytes.
553 *
554 * @returns Pointer to the newly created mutation or NULL if out of memory.
555 * @param pThis The fuzzer context instance.
556 * @param offMutation The starting offset for the mutation.
557 * @param pMutationParent The parent mutation, can be NULL.
558 * @param cbAdditional Additional number of bytes to allocate after the core structure.
559 * @param ppvMutation Where to store the pointer to the mutation dependent data on success.
560 */
561static PRTFUZZMUTATION rtFuzzMutationCreate(PRTFUZZCTXINT pThis, uint64_t offMutation, PRTFUZZMUTATION pMutationParent,
562 size_t cbAdditional, void **ppvMutation)
563{
564 PRTFUZZMUTATION pMutation = (PRTFUZZMUTATION)rtFuzzCtxMemoryAlloc(pThis, sizeof(RTFUZZMUTATION) + cbAdditional);
565 if (RT_LIKELY(pMutation))
566 {
567 pMutation->u32Magic = 0; /** @todo */
568 pMutation->pFuzzer = pThis;
569 pMutation->cRefs = 1;
570 pMutation->iLvl = 0;
571 pMutation->offMutation = offMutation;
572 pMutation->pMutationParent = pMutationParent;
573 pMutation->cbMutation = cbAdditional;
574
575 if (pMutationParent)
576 pMutation->iLvl = pMutationParent->iLvl + 1;
577 if (ppvMutation)
578 *ppvMutation = &pMutation->abMutation[0];
579 }
580
581 return pMutation;
582}
583
584
585/**
586 * Destroys the given mutation.
587 *
588 * @returns nothing.
589 * @param pMutation The mutation to destroy.
590 */
591static void rtFuzzMutationDestroy(PRTFUZZMUTATION pMutation)
592{
593 rtFuzzCtxMemoryFree(pMutation->pFuzzer, pMutation);
594}
595
596
597/**
598 * Destorys the given fuzzer context freeing all allocated resources.
599 *
600 * @returns nothing.
601 * @param pThis The fuzzer context instance.
602 */
603static void rtFuzzCtxDestroy(PRTFUZZCTXINT pThis)
604{
605 RT_NOREF(pThis);
606}
607
608
609/**
610 * Default mutator export callback (just writing the raw data).
611 */
612static DECLCALLBACK(int) rtFuzzCtxMutatorExportDefault(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
613 PFNRTFUZZCTXEXPORT pfnExport, void *pvUser)
614{
615 return pfnExport(pThis, pvMutation, pMutation->cbMutation, pvUser);
616}
617
618
619/**
620 * Default mutator import callback (just reading the raw data).
621 */
622static DECLCALLBACK(int) rtFuzzCtxMutatorImportDefault(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, void *pvMutation,
623 PFNRTFUZZCTXIMPORT pfnImport, void *pvUser)
624{
625 return pfnImport(pThis, pvMutation, pMutation->cbMutation, NULL, pvUser);
626}
627
628
629static DECLCALLBACK(int) rtFuzzCtxMutatorCorpusExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
630 uint8_t *pbBuf, size_t cbBuf)
631{
632 RT_NOREF(pThis, cbBuf, pvMutation);
633 memcpy(pbBuf, pvMutation, pMutation->cbInput);
634 return VINF_SUCCESS;
635}
636
637
638/**
639 * Mutator callback - flips a single bit in the input.
640 */
641static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlipPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
642 PPRTFUZZMUTATION ppMutation)
643{
644 int rc = VINF_SUCCESS;
645 uint8_t *pidxBitFlip = 0;
646 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, sizeof(*pidxBitFlip), (void **)&pidxBitFlip);
647 if (RT_LIKELY(pMutation))
648 {
649 pMutation->cbInput = pMutationParent->cbInput; /* Bit flips don't change the input size. */
650 *pidxBitFlip = (uint8_t)RTRandAdvU32Ex(pThis->hRand, 0, sizeof(uint8_t) * 8 - 1);
651 *ppMutation = pMutation;
652 }
653 else
654 rc = VERR_NO_MEMORY;
655
656 return rc;
657}
658
659
660static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlipExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
661 uint8_t *pbBuf, size_t cbBuf)
662{
663 RT_NOREF(pThis, cbBuf, pMutation);
664 uint8_t idxBitFlip = *(uint8_t *)pvMutation;
665 ASMBitToggle(pbBuf, idxBitFlip);
666 return VINF_SUCCESS;
667}
668
669
670/**
671 * Mutator callback - replaces a single byte in the input.
672 */
673static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplacePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
674 PPRTFUZZMUTATION ppMutation)
675{
676 int rc = VINF_SUCCESS;
677 uint8_t *pbReplace = 0;
678 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, sizeof(*pbReplace), (void **)&pbReplace);
679 if (RT_LIKELY(pMutation))
680 {
681 pMutation->cbInput = pMutationParent->cbInput; /* Byte replacements don't change the input size. */
682 RTRandAdvBytes(pThis->hRand, pbReplace, 1); /** @todo Filter out same values. */
683 *ppMutation = pMutation;
684 }
685 else
686 rc = VERR_NO_MEMORY;
687
688 return rc;
689}
690
691
692static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplaceExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
693 uint8_t *pbBuf, size_t cbBuf)
694{
695 RT_NOREF(pThis, cbBuf, pMutation);
696 uint8_t bReplace = *(uint8_t *)pvMutation;
697 *pbBuf = bReplace;
698 return VINF_SUCCESS;
699}
700
701
702/**
703 * Mutator callback - inserts a byte sequence into the input.
704 */
705static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsertAppendPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
706 PPRTFUZZMUTATION ppMutation)
707{
708 int rc = VINF_SUCCESS;
709 if (pMutationParent->cbInput < pThis->cbInputMax)
710 {
711 size_t cbInputMutated = (size_t)RTRandAdvU64Ex(pThis->hRand, pMutationParent->cbInput + 1, pThis->cbInputMax);
712 size_t cbInsert = cbInputMutated - pMutationParent->cbInput;
713 uint8_t *pbAdd = NULL;
714
715 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, cbInsert, (void **)&pbAdd);
716 if (RT_LIKELY(pMutation))
717 {
718 pMutation->cbInput = cbInputMutated;
719 RTRandAdvBytes(pThis->hRand, pbAdd, cbInsert);
720 *ppMutation = pMutation;
721 }
722 else
723 rc = VERR_NO_MEMORY;
724 }
725
726 return rc;
727}
728
729
730static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsertAppendExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
731 uint8_t *pbBuf, size_t cbBuf)
732{
733 RT_NOREF(pThis);
734 size_t cbInsert = pMutation->cbInput - pMutation->pMutationParent->cbInput;
735
736 /* Move any remaining data to the end. */
737 if (cbBuf)
738 memmove(pbBuf + cbInsert, pbBuf, cbBuf);
739
740 memcpy(pbBuf, pvMutation, cbInsert);
741 return VINF_SUCCESS;
742}
743
744
745/**
746 * Mutator callback - deletes a single byte in the input.
747 */
748static DECLCALLBACK(int) rtFuzzCtxMutatorByteDeletePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
749 PPRTFUZZMUTATION ppMutation)
750{
751 int rc = VINF_SUCCESS;
752 if (pMutationParent->cbInput - offStart >= 1)
753 {
754 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, 0 /*cbAdditional*/, NULL);
755 if (RT_LIKELY(pMutation))
756 {
757 pMutation->cbInput = pMutationParent->cbInput - 1;
758 *ppMutation = pMutation;
759 }
760 else
761 rc = VERR_NO_MEMORY;
762 }
763
764 return rc;
765}
766
767
768static DECLCALLBACK(int) rtFuzzCtxMutatorByteDeleteExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
769 uint8_t *pbBuf, size_t cbBuf)
770{
771 RT_NOREF(pThis, pMutation, pvMutation);
772
773 /* Just move the residual data to the front. */
774 memmove(pbBuf, pbBuf + 1, cbBuf - 1);
775 return VINF_SUCCESS;
776}
777
778
779
780/**
781 * Mutator callback - deletes a byte sequence in the input.
782 */
783static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDeletePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
784 PPRTFUZZMUTATION ppMutation)
785{
786 int rc = VINF_SUCCESS;
787 if (pMutationParent->cbInput > 1)
788 {
789 size_t cbInputMutated = (size_t)RTRandAdvU64Ex(pThis->hRand, offStart, pMutationParent->cbInput - 1);
790
791 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, 0 /*cbAdditional*/, NULL);
792 if (RT_LIKELY(pMutation))
793 {
794 pMutation->cbInput = cbInputMutated;
795 *ppMutation = pMutation;
796 }
797 else
798 rc = VERR_NO_MEMORY;
799 }
800
801 return rc;
802}
803
804
805static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDeleteExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
806 uint8_t *pbBuf, size_t cbBuf)
807{
808 RT_NOREF(pThis, pvMutation);
809 Assert(pMutation->pMutationParent->cbInput > pMutation->cbInput);
810 size_t cbDel = pMutation->pMutationParent->cbInput - pMutation->cbInput;
811
812 /* Just move the residual data to the front. */
813 memmove(pbBuf, pbBuf + cbDel, cbBuf - cbDel);
814 return VINF_SUCCESS;
815}
816
817
818/**
819 * Creates an empty fuzzing context.
820 *
821 * @returns IPRT status code.
822 * @param ppThis Where to store the pointer to the internal fuzzing context instance on success.
823 * @param enmType Fuzzing context type.
824 */
825static int rtFuzzCtxCreateEmpty(PRTFUZZCTXINT *ppThis, RTFUZZCTXTYPE enmType)
826{
827 int rc;
828 PRTFUZZCTXINT pThis = (PRTFUZZCTXINT)RTMemAllocZ(sizeof(*pThis));
829 if (RT_LIKELY(pThis))
830 {
831 pThis->u32Magic = RTFUZZCTX_MAGIC;
832 pThis->cRefs = 1;
833 pThis->enmType = enmType;
834 pThis->TreeMutations = NULL;
835 pThis->cbInputMax = UINT32_MAX;
836 pThis->cMutations = 0;
837 pThis->fFlagsBehavioral = 0;
838 pThis->cbMemTotal = 0;
839
840 /* Copy the default mutator descriptors over. */
841 pThis->paMutators = (PRTFUZZMUTATOR)RTMemAllocZ(RT_ELEMENTS(g_aMutators) * sizeof(RTFUZZMUTATOR));
842 if (RT_LIKELY(pThis->paMutators))
843 {
844 pThis->cMutators = RT_ELEMENTS(g_aMutators);
845 memcpy(&pThis->paMutators[0], &g_aMutators[0], RT_ELEMENTS(g_aMutators) * sizeof(RTFUZZMUTATOR));
846
847 rc = RTSemRWCreate(&pThis->hSemRwMutations);
848 if (RT_SUCCESS(rc))
849 {
850 rc = RTRandAdvCreateParkMiller(&pThis->hRand);
851 if (RT_SUCCESS(rc))
852 {
853 RTRandAdvSeed(pThis->hRand, RTTimeSystemNanoTS());
854 *ppThis = pThis;
855 return VINF_SUCCESS;
856 }
857
858 RTSemRWDestroy(pThis->hSemRwMutations);
859 }
860 }
861 else
862 rc = VERR_NO_MEMORY;
863
864 RTMemFree(pThis);
865 }
866 else
867 rc = VERR_NO_MEMORY;
868
869 return rc;
870}
871
872
873/**
874 * Destroys the given fuzzing input.
875 *
876 * @returns nothing.
877 * @param pThis The fuzzing input to destroy.
878 */
879static void rtFuzzInputDestroy(PRTFUZZINPUTINT pThis)
880{
881 PRTFUZZCTXINT pFuzzer = pThis->pFuzzer;
882
883 if ( pFuzzer->enmType == RTFUZZCTXTYPE_BLOB
884 && pThis->u.Blob.pvInput)
885 rtFuzzCtxMemoryFree(pFuzzer, pThis->u.Blob.pvInput);
886
887 rtFuzzCtxMemoryFree(pFuzzer, pThis);
888 RTFuzzCtxRelease(pFuzzer);
889}
890
891
892/**
893 * Creates the final input data applying all accumulated mutations.
894 *
895 * @returns IPRT status code.
896 * @param pThis The fuzzing input to finalize.
897 */
898static int rtFuzzInputDataFinalize(PRTFUZZINPUTINT pThis)
899{
900 Assert(!pThis->u.Blob.pvInput);
901
902 int rc = VINF_SUCCESS;
903 uint8_t *pbBuf = (uint8_t *)rtFuzzCtxMemoryAlloc(pThis->pFuzzer, pThis->u.Blob.cbAlloc);
904 if (RT_LIKELY(pbBuf))
905 {
906 pThis->u.Blob.pvInput = pbBuf;
907 pThis->u.Blob.cbInput = pThis->pMutationTop->cbInput;
908
909 size_t cbInputNow = pThis->apMutations[0]->cbInput;
910 for (uint32_t i = 0; i < pThis->pMutationTop->iLvl + 1; i++)
911 {
912 PCRTFUZZMUTATION pMutation = pThis->apMutations[i];
913 pMutation->pMutator->pfnExec(pThis->pFuzzer, pMutation, (void *)&pMutation->abMutation[0],
914 pbBuf + pMutation->offMutation,
915 cbInputNow - pMutation->offMutation);
916
917 cbInputNow = pMutation->cbInput;
918 }
919
920 Assert(cbInputNow == pThis->u.Blob.cbInput);
921 }
922 else
923 rc = VERR_NO_MEMORY;
924
925 return rc;
926}
927
928
929RTDECL(int) RTFuzzCtxCreate(PRTFUZZCTX phFuzzCtx, RTFUZZCTXTYPE enmType)
930{
931 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
932
933 return rtFuzzCtxCreateEmpty(phFuzzCtx, enmType);
934}
935
936
937RTDECL(int) RTFuzzCtxCreateFromState(PRTFUZZCTX phFuzzCtx, PFNRTFUZZCTXIMPORT pfnImport, void *pvUser)
938{
939 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
940 AssertPtrReturn(pfnImport, VERR_INVALID_POINTER);
941
942#if 0
943 int rc = VINF_SUCCESS;
944 if (cbState >= sizeof(RTFUZZCTXSTATE))
945 {
946 RTFUZZCTXSTATE StateImport;
947
948 memcpy(&StateImport, pvState, sizeof(RTFUZZCTXSTATE));
949 if ( RT_LE2H_U32(StateImport.u32Magic) == RTFUZZCTX_MAGIC
950 && RT_LE2H_U32(StateImport.cbPrng) <= cbState - sizeof(RTFUZZCTXSTATE))
951 {
952 PRTFUZZCTXINT pThis = rtFuzzCtxCreateEmpty();
953 if (RT_LIKELY(pThis))
954 {
955 pThis->cbInputMax = (size_t)RT_LE2H_U64(StateImport.cbInputMax);
956 pThis->fFlagsBehavioral = RT_LE2H_U32(StateImport.fFlagsBehavioral);
957
958 uint8_t *pbState = (uint8_t *)pvState;
959 uint32_t cInputs = RT_LE2H_U32(StateImport.cInputs);
960 rc = RTRandAdvRestoreState(pThis->hRand, (const char *)&pbState[sizeof(RTFUZZCTXSTATE)]);
961 if (RT_SUCCESS(rc))
962 {
963 /* Go through the inputs and add them. */
964 pbState += sizeof(RTFUZZCTXSTATE) + RT_LE2H_U32(StateImport.cbPrng);
965 cbState -= sizeof(RTFUZZCTXSTATE) + RT_LE2H_U32(StateImport.cbPrng);
966
967 uint32_t idx = 0;
968 while ( idx < cInputs
969 && RT_SUCCESS(rc))
970 {
971 size_t cbInput = 0;
972 if (cbState >= sizeof(uint32_t))
973 {
974 memcpy(&cbInput, pbState, sizeof(uint32_t));
975 cbInput = RT_LE2H_U32(cbInput);
976 pbState += sizeof(uint32_t);
977 }
978
979 if ( cbInput
980 && cbInput <= cbState)
981 {
982 PRTFUZZINPUTINT pInput = rtFuzzCtxInputCreate(pThis, cbInput);
983 if (RT_LIKELY(pInput))
984 {
985 memcpy(&pInput->abInput[0], pbState, cbInput);
986 RTMd5(&pInput->abInput[0], pInput->cbInput, &pInput->abMd5Hash[0]);
987 rc = rtFuzzCtxInputAdd(pThis, pInput);
988 if (RT_FAILURE(rc))
989 RTMemFree(pInput);
990 pbState += cbInput;
991 }
992 }
993 else
994 rc = VERR_INVALID_STATE;
995
996 idx++;
997 }
998
999 if (RT_SUCCESS(rc))
1000 {
1001 *phFuzzCtx = pThis;
1002 return VINF_SUCCESS;
1003 }
1004 }
1005
1006 rtFuzzCtxDestroy(pThis);
1007 }
1008 else
1009 rc = VERR_NO_MEMORY;
1010 }
1011 else
1012 rc = VERR_INVALID_MAGIC;
1013 }
1014 else
1015 rc = VERR_INVALID_MAGIC;
1016
1017 return rc;
1018#else
1019 RT_NOREF(pvUser);
1020 return VERR_NOT_IMPLEMENTED;
1021#endif
1022}
1023
1024
1025RTDECL(int) RTFuzzCtxCreateFromStateMem(PRTFUZZCTX phFuzzCtx, const void *pvState, size_t cbState)
1026{
1027 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
1028 AssertPtrReturn(pvState, VERR_INVALID_POINTER);
1029 AssertPtrReturn(cbState, VERR_INVALID_POINTER);
1030
1031 return VERR_NOT_IMPLEMENTED;
1032}
1033
1034
1035RTDECL(int) RTFuzzCtxCreateFromStateFile(PRTFUZZCTX phFuzzCtx, const char *pszFilename)
1036{
1037 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
1038 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1039
1040 void *pv = NULL;
1041 size_t cb = 0;
1042 int rc = RTFileReadAll(pszFilename, &pv, &cb);
1043 if (RT_SUCCESS(rc))
1044 {
1045 rc = RTFuzzCtxCreateFromStateMem(phFuzzCtx, pv, cb);
1046 RTFileReadAllFree(pv, cb);
1047 }
1048
1049 return rc;
1050}
1051
1052
1053RTDECL(uint32_t) RTFuzzCtxRetain(RTFUZZCTX hFuzzCtx)
1054{
1055 PRTFUZZCTXINT pThis = hFuzzCtx;
1056
1057 AssertPtrReturn(pThis, UINT32_MAX);
1058
1059 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1060 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1061 return cRefs;
1062}
1063
1064
1065RTDECL(uint32_t) RTFuzzCtxRelease(RTFUZZCTX hFuzzCtx)
1066{
1067 PRTFUZZCTXINT pThis = hFuzzCtx;
1068 if (pThis == NIL_RTFUZZCTX)
1069 return 0;
1070 AssertPtrReturn(pThis, UINT32_MAX);
1071
1072 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1073 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1074 if (cRefs == 0)
1075 rtFuzzCtxDestroy(pThis);
1076 return cRefs;
1077}
1078
1079
1080/**
1081 * Fuzzing context export callback for a single mutation.
1082 */
1083static DECLCALLBACK(int) rtFuzzCtxStateExportMutations(PAVLU64NODECORE pCore, void *pvParam)
1084{
1085 PRTFUZZMUTATION pMutation = (PRTFUZZMUTATION)pCore;
1086 PCRTFUZZMUTATOR pMutator = pMutation->pMutator;
1087 PCRTFUZZEXPORTARGS pArgs = (PCRTFUZZEXPORTARGS)pvParam;
1088 RTFUZZMUTATIONSTATE MutationState;
1089
1090 MutationState.u64Id = RT_H2LE_U64(pMutation->Core.Key);
1091 if (pMutation->pMutationParent)
1092 MutationState.u64IdParent = RT_H2LE_U64(pMutation->pMutationParent->Core.Key);
1093 else
1094 MutationState.u64IdParent = RT_H2LE_U64(0);
1095 MutationState.u64OffMutation = RT_H2LE_U64(pMutation->offMutation);
1096 MutationState.cbInput = RT_H2LE_U64((uint64_t)pMutation->cbInput);
1097 MutationState.cbMutation = RT_H2LE_U64((uint64_t)pMutation->cbMutation);
1098 MutationState.u32IdMutator = RT_H2LE_U32(pMutator->uMutator);
1099 MutationState.iLvl = RT_H2LE_U32(pMutation->iLvl);
1100 MutationState.u32Magic = RT_H2LE_U32(pMutation->u32Magic);
1101
1102 int rc = pArgs->pfnExport(pMutation->pFuzzer, &MutationState, sizeof(MutationState), pArgs->pvUser);
1103 if ( RT_SUCCESS(rc)
1104 && pMutator->pfnExport)
1105 rc = pMutator->pfnExport(pMutation->pFuzzer, pMutation, &pMutation->abMutation[0], pArgs->pfnExport, pArgs->pvUser);
1106 return rc;
1107}
1108
1109
1110RTDECL(int) RTFuzzCtxStateExport(RTFUZZCTX hFuzzCtx, PFNRTFUZZCTXEXPORT pfnExport, void *pvUser)
1111{
1112 PRTFUZZCTXINT pThis = hFuzzCtx;
1113 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1114 AssertPtrReturn(pfnExport, VERR_INVALID_POINTER);
1115
1116 char aszPrngExport[_4K]; /* Should be plenty of room here. */
1117 size_t cbPrng = sizeof(aszPrngExport);
1118 int rc = RTRandAdvSaveState(pThis->hRand, &aszPrngExport[0], &cbPrng);
1119 if (RT_SUCCESS(rc))
1120 {
1121 RTFUZZCTXSTATE StateExport;
1122
1123 StateExport.u32Magic = RT_H2LE_U32(RTFUZZCTX_MAGIC);
1124 switch (pThis->enmType)
1125 {
1126 case RTFUZZCTXTYPE_BLOB:
1127 StateExport.uCtxType = RT_H2LE_U32(RTFUZZCTX_STATE_TYPE_BLOB);
1128 break;
1129 case RTFUZZCTXTYPE_STREAM:
1130 StateExport.uCtxType = RT_H2LE_U32(RTFUZZCTX_STATE_TYPE_STREAM);
1131 break;
1132 default:
1133 AssertFailed();
1134 break;
1135 }
1136 StateExport.cbPrng = RT_H2LE_U32((uint32_t)cbPrng);
1137 StateExport.cMutations = RT_H2LE_U32(pThis->cMutations);
1138 StateExport.cMutators = RT_H2LE_U32(pThis->cMutators);
1139 StateExport.fFlagsBehavioral = RT_H2LE_U32(pThis->fFlagsBehavioral);
1140 StateExport.cbInputMax = RT_H2LE_U64(pThis->cbInputMax);
1141
1142 /* Write the context state and PRNG state first. */
1143 rc = pfnExport(pThis, &StateExport, sizeof(StateExport), pvUser);
1144 if (RT_SUCCESS(rc))
1145 rc = pfnExport(pThis, &aszPrngExport[0], cbPrng, pvUser);
1146 if (RT_SUCCESS(rc))
1147 {
1148 /* Write the mutator descriptors next. */
1149 for (uint32_t i = 0; i < pThis->cMutators && RT_SUCCESS(rc); i++)
1150 {
1151 PRTFUZZMUTATOR pMutator = &pThis->paMutators[i];
1152 uint32_t cchId = (uint32_t)strlen(pMutator->pszId) + 1;
1153 uint32_t cchIdW = RT_H2LE_U32(cchId);
1154
1155 rc = pfnExport(pThis, &cchIdW, sizeof(cchIdW), pvUser);
1156 if (RT_SUCCESS(rc))
1157 rc = pfnExport(pThis, &pMutator->pszId[0], cchId, pvUser);
1158 }
1159 }
1160
1161 /* Write the mutations last. */
1162 if (RT_SUCCESS(rc))
1163 {
1164 RTFUZZEXPORTARGS Args;
1165
1166 Args.pfnExport = pfnExport;
1167 Args.pvUser = pvUser;
1168 rc = RTAvlU64DoWithAll(&pThis->TreeMutations, true /*fFromLeft*/, rtFuzzCtxStateExportMutations, &Args);
1169 }
1170 }
1171
1172 return rc;
1173}
1174
1175
1176RTDECL(int) RTFuzzCtxStateExportToMem(RTFUZZCTX hFuzzCtx, void **ppvState, size_t *pcbState)
1177{
1178 PRTFUZZCTXINT pThis = hFuzzCtx;
1179 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1180 AssertPtrReturn(ppvState, VERR_INVALID_POINTER);
1181 AssertPtrReturn(pcbState, VERR_INVALID_POINTER);
1182
1183 return VERR_NOT_IMPLEMENTED;
1184}
1185
1186
1187/**
1188 * Export to file callback.
1189 */
1190DECLCALLBACK(int) rtFuzzCtxStateExportFile(RTFUZZCTX hFuzzCtx, const void *pvBuf, size_t cbWrite, void *pvUser)
1191{
1192 RT_NOREF(hFuzzCtx);
1193
1194 RTFILE hFile = (RTFILE)pvUser;
1195 return RTFileWrite(hFile, pvBuf, cbWrite, NULL);
1196}
1197
1198
1199RTDECL(int) RTFuzzCtxStateExportToFile(RTFUZZCTX hFuzzCtx, const char *pszFilename)
1200{
1201 PRTFUZZCTXINT pThis = hFuzzCtx;
1202 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1203 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1204
1205 RTFILE hFile;
1206 int rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
1207 if (RT_SUCCESS(rc))
1208 {
1209 rc = RTFuzzCtxStateExport(hFuzzCtx, rtFuzzCtxStateExportFile, hFile);
1210 RTFileClose(hFile);
1211 if (RT_FAILURE(rc))
1212 RTFileDelete(pszFilename);
1213 }
1214
1215 return rc;
1216}
1217
1218
1219RTDECL(int) RTFuzzCtxCorpusInputAdd(RTFUZZCTX hFuzzCtx, const void *pvInput, size_t cbInput)
1220{
1221 PRTFUZZCTXINT pThis = hFuzzCtx;
1222 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1223 AssertPtrReturn(pvInput, VERR_INVALID_POINTER);
1224 AssertReturn(cbInput, VERR_INVALID_POINTER);
1225
1226 int rc = VINF_SUCCESS;
1227 void *pvCorpus = NULL;
1228 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, 0, NULL, cbInput, &pvCorpus);
1229 if (RT_LIKELY(pMutation))
1230 {
1231 pMutation->pMutator = &g_MutatorCorpus;
1232 pMutation->cbInput = cbInput;
1233 memcpy(pvCorpus, pvInput, cbInput);
1234 rc = rtFuzzCtxMutationAdd(pThis, pMutation);
1235 if (RT_FAILURE(rc))
1236 rtFuzzMutationDestroy(pMutation);
1237 }
1238 else
1239 rc = VERR_NO_MEMORY;
1240
1241 return rc;
1242}
1243
1244
1245RTDECL(int) RTFuzzCtxCorpusInputAddFromFile(RTFUZZCTX hFuzzCtx, const char *pszFilename)
1246{
1247 PRTFUZZCTXINT pThis = hFuzzCtx;
1248 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1249 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1250
1251 void *pv = NULL;
1252 size_t cb = 0;
1253 int rc = RTFileReadAll(pszFilename, &pv, &cb);
1254 if (RT_SUCCESS(rc))
1255 {
1256 rc = RTFuzzCtxCorpusInputAdd(hFuzzCtx, pv, cb);
1257 RTFileReadAllFree(pv, cb);
1258 }
1259
1260 return rc;
1261}
1262
1263
1264RTDECL(int) RTFuzzCtxCorpusInputAddFromVfsFile(RTFUZZCTX hFuzzCtx, RTVFSFILE hVfsFile)
1265{
1266 PRTFUZZCTXINT pThis = hFuzzCtx;
1267 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1268 AssertReturn(hVfsFile != NIL_RTVFSFILE, VERR_INVALID_HANDLE);
1269
1270 uint64_t cbFile = 0;
1271 void *pvCorpus = NULL;
1272 int rc = RTVfsFileGetSize(hVfsFile, &cbFile);
1273 if (RT_SUCCESS(rc))
1274 {
1275 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, 0, NULL, cbFile, &pvCorpus);
1276 if (RT_LIKELY(pMutation))
1277 {
1278 pMutation->pMutator = &g_MutatorCorpus;
1279 pMutation->cbInput = cbFile;
1280 rc = RTVfsFileRead(hVfsFile, pvCorpus, cbFile, NULL);
1281 if (RT_SUCCESS(rc))
1282 rc = rtFuzzCtxMutationAdd(pThis, pMutation);
1283
1284 if (RT_FAILURE(rc))
1285 rtFuzzMutationDestroy(pMutation);
1286 }
1287 }
1288
1289 return rc;
1290}
1291
1292
1293RTDECL(int) RTFuzzCtxCorpusInputAddFromDirPath(RTFUZZCTX hFuzzCtx, const char *pszDirPath)
1294{
1295 PRTFUZZCTXINT pThis = hFuzzCtx;
1296 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1297 AssertPtrReturn(pszDirPath, VERR_INVALID_POINTER);
1298
1299 RTDIR hDir;
1300 int rc = RTDirOpen(&hDir, pszDirPath);
1301 if (RT_SUCCESS(rc))
1302 {
1303 for (;;)
1304 {
1305 RTDIRENTRY DirEntry;
1306 rc = RTDirRead(hDir, &DirEntry, NULL);
1307 if (RT_FAILURE(rc))
1308 break;
1309
1310 /* Skip '.', '..' and other non-files. */
1311 if ( DirEntry.enmType != RTDIRENTRYTYPE_UNKNOWN
1312 && DirEntry.enmType != RTDIRENTRYTYPE_FILE)
1313 continue;
1314 if (RTDirEntryIsStdDotLink(&DirEntry))
1315 continue;
1316
1317 /* Compose the full path, result 'unknown' entries and skip non-files. */
1318 char szFile[RTPATH_MAX];
1319 RT_ZERO(szFile);
1320 rc = RTPathJoin(szFile, sizeof(szFile), pszDirPath, DirEntry.szName);
1321 if (RT_FAILURE(rc))
1322 break;
1323
1324 if (DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN)
1325 {
1326 RTDirQueryUnknownType(szFile, false, &DirEntry.enmType);
1327 if (DirEntry.enmType != RTDIRENTRYTYPE_FILE)
1328 continue;
1329 }
1330
1331 /* Okay, it's a file we can add. */
1332 rc = RTFuzzCtxCorpusInputAddFromFile(hFuzzCtx, szFile);
1333 if (RT_FAILURE(rc))
1334 break;
1335 }
1336 if (rc == VERR_NO_MORE_FILES)
1337 rc = VINF_SUCCESS;
1338 RTDirClose(hDir);
1339 }
1340
1341 return rc;
1342}
1343
1344
1345RTDECL(int) RTFuzzCtxCfgSetInputSeedMaximum(RTFUZZCTX hFuzzCtx, size_t cbMax)
1346{
1347 PRTFUZZCTXINT pThis = hFuzzCtx;
1348 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1349
1350 pThis->cbInputMax = cbMax;
1351 return VINF_SUCCESS;
1352}
1353
1354
1355RTDECL(size_t) RTFuzzCtxCfgGetInputSeedMaximum(RTFUZZCTX hFuzzCtx)
1356{
1357 PRTFUZZCTXINT pThis = hFuzzCtx;
1358 AssertPtrReturn(pThis, 0);
1359
1360 return pThis->cbInputMax;
1361}
1362
1363
1364RTDECL(int) RTFuzzCtxCfgSetBehavioralFlags(RTFUZZCTX hFuzzCtx, uint32_t fFlags)
1365{
1366 PRTFUZZCTXINT pThis = hFuzzCtx;
1367 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1368 AssertReturn(!(fFlags & ~RTFUZZCTX_F_BEHAVIORAL_VALID), VERR_INVALID_PARAMETER);
1369
1370 pThis->fFlagsBehavioral = fFlags;
1371 return VINF_SUCCESS;
1372}
1373
1374
1375RTDECL(uint32_t) RTFuzzCfgGetBehavioralFlags(RTFUZZCTX hFuzzCtx)
1376{
1377 PRTFUZZCTXINT pThis = hFuzzCtx;
1378 AssertPtrReturn(pThis, 0);
1379
1380 return pThis->fFlagsBehavioral;
1381}
1382
1383
1384RTDECL(int) RTFuzzCtxCfgSetTmpDirectory(RTFUZZCTX hFuzzCtx, const char *pszPathTmp)
1385{
1386 PRTFUZZCTXINT pThis = hFuzzCtx;
1387 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1388 AssertPtrReturn(pszPathTmp, VERR_INVALID_POINTER);
1389
1390 return VERR_NOT_IMPLEMENTED;
1391}
1392
1393
1394RTDECL(const char *) RTFuzzCtxCfgGetTmpDirectory(RTFUZZCTX hFuzzCtx)
1395{
1396 PRTFUZZCTXINT pThis = hFuzzCtx;
1397 AssertPtrReturn(pThis, NULL);
1398
1399 return NULL;
1400}
1401
1402
1403RTDECL(int) RTFuzzCtxReseed(RTFUZZCTX hFuzzCtx, uint64_t uSeed)
1404{
1405 PRTFUZZCTXINT pThis = hFuzzCtx;
1406 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1407
1408 RTRandAdvSeed(pThis->hRand, uSeed);
1409 return VINF_SUCCESS;
1410}
1411
1412
1413RTDECL(int) RTFuzzCtxInputGenerate(RTFUZZCTX hFuzzCtx, PRTFUZZINPUT phFuzzInput)
1414{
1415 int rc = VINF_SUCCESS;
1416 PRTFUZZCTXINT pThis = hFuzzCtx;
1417 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1418 AssertPtrReturn(phFuzzInput, VERR_INVALID_POINTER);
1419
1420 uint32_t cTries = 0;
1421 PRTFUZZMUTATION pMutationParent = rtFuzzCtxMutationPickRnd(pThis);
1422 do
1423 {
1424 uint32_t idxMutator = RTRandAdvU32Ex(pThis->hRand, 0, pThis->cMutators - 1);
1425 PCRTFUZZMUTATOR pMutator = &pThis->paMutators[idxMutator];
1426 PRTFUZZMUTATION pMutation = NULL;
1427
1428 uint64_t offStart = 0;
1429 if (!(pMutator->fFlags & RTFUZZMUTATOR_F_END_OF_BUF))
1430 offStart = RTRandAdvU64Ex(pThis->hRand, 0, pMutationParent->cbInput);
1431 else
1432 offStart = pMutationParent->cbInput;
1433
1434 rc = pMutator->pfnPrep(pThis, offStart, pMutationParent, &pMutation);
1435 if ( RT_SUCCESS(rc)
1436 && VALID_PTR(pMutation))
1437 {
1438 pMutation->pMutator = pMutator;
1439
1440 if (pThis->fFlagsBehavioral & RTFUZZCTX_F_BEHAVIORAL_ADD_INPUT_AUTOMATICALLY_TO_CORPUS)
1441 rtFuzzCtxMutationAdd(pThis, pMutation);
1442
1443 /* Create a new input. */
1444 PRTFUZZINPUTINT pInput = (PRTFUZZINPUTINT)rtFuzzCtxMemoryAlloc(pThis, RT_UOFFSETOF_DYN(RTFUZZINPUTINT, apMutations[pMutation->iLvl + 1]));
1445 if (RT_LIKELY(pInput))
1446 {
1447 pInput->u32Magic = 0; /** @todo */
1448 pInput->cRefs = 1;
1449 pInput->pFuzzer = pThis;
1450 pInput->pMutationTop = pMutation;
1451 RTFuzzCtxRetain(pThis);
1452
1453 /* Traverse the mutations top to bottom and insert into the array. */
1454 uint32_t idx = pMutation->iLvl + 1;
1455 PCRTFUZZMUTATION pMutationCur = pMutation;
1456 size_t cbAlloc = 0;
1457 while (idx > 0)
1458 {
1459 pInput->apMutations[idx - 1] = pMutationCur;
1460 cbAlloc = RT_MAX(cbAlloc, pMutationCur->cbInput);
1461 pMutationCur = pMutationCur->pMutationParent;
1462 idx--;
1463 }
1464
1465 pInput->u.Blob.cbAlloc = cbAlloc;
1466 *phFuzzInput = pInput;
1467 return rc;
1468 }
1469 else
1470 rc = VERR_NO_MEMORY;
1471 }
1472 } while (++cTries <= 50);
1473
1474 if (RT_SUCCESS(rc))
1475 rc = VERR_INVALID_STATE;
1476
1477 return rc;
1478}
1479
1480
1481RTDECL(int) RTFuzzInputQueryBlobData(RTFUZZINPUT hFuzzInput, void **ppv, size_t *pcb)
1482{
1483 PRTFUZZINPUTINT pThis = hFuzzInput;
1484 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1485 AssertReturn(pThis->pFuzzer->enmType == RTFUZZCTXTYPE_BLOB, VERR_INVALID_STATE);
1486
1487 int rc = VINF_SUCCESS;
1488 if (!pThis->u.Blob.pvInput)
1489 rc = rtFuzzInputDataFinalize(pThis);
1490
1491 if (RT_SUCCESS(rc))
1492 {
1493 AssertPtr(pThis->u.Blob.pvInput);
1494 Assert(pThis->u.Blob.cbInput > 0);
1495
1496 *ppv = pThis->u.Blob.pvInput;
1497 *pcb = pThis->u.Blob.cbInput;
1498 }
1499
1500 return rc;
1501}
1502
1503
1504RTDECL(int) RTFuzzInputMutateStreamData(RTFUZZINPUT hFuzzInput, void *pvBuf, size_t cbBuf)
1505{
1506 PRTFUZZINPUTINT pThis = hFuzzInput;
1507 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1508 AssertReturn(pThis->pFuzzer->enmType == RTFUZZCTXTYPE_STREAM, VERR_INVALID_STATE);
1509
1510 RT_NOREF(pvBuf, cbBuf);
1511 return VERR_NOT_IMPLEMENTED;
1512}
1513
1514
1515RTDECL(uint32_t) RTFuzzInputRetain(RTFUZZINPUT hFuzzInput)
1516{
1517 PRTFUZZINPUTINT pThis = hFuzzInput;
1518
1519 AssertPtrReturn(pThis, UINT32_MAX);
1520
1521 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1522 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1523 return cRefs;
1524}
1525
1526
1527RTDECL(uint32_t) RTFuzzInputRelease(RTFUZZINPUT hFuzzInput)
1528{
1529 PRTFUZZINPUTINT pThis = hFuzzInput;
1530 if (pThis == NIL_RTFUZZINPUT)
1531 return 0;
1532 AssertPtrReturn(pThis, UINT32_MAX);
1533
1534 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1535 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1536 if (cRefs == 0)
1537 rtFuzzInputDestroy(pThis);
1538 return cRefs;
1539}
1540
1541
1542RTDECL(int) RTFuzzInputQueryDigestString(RTFUZZINPUT hFuzzInput, char *pszDigest, size_t cchDigest)
1543{
1544 PRTFUZZINPUTINT pThis = hFuzzInput;
1545 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1546 AssertReturn(pThis->pFuzzer->enmType == RTFUZZCTXTYPE_BLOB, VERR_INVALID_STATE);
1547 AssertPtrReturn(pszDigest, VERR_INVALID_POINTER);
1548 AssertReturn(cchDigest >= RTMD5_STRING_LEN + 1, VERR_INVALID_PARAMETER);
1549
1550 int rc = VINF_SUCCESS;
1551 if (!pThis->u.Blob.pvInput)
1552 rc = rtFuzzInputDataFinalize(pThis);
1553
1554 if (RT_SUCCESS(rc))
1555 {
1556 uint8_t abHash[RTMD5_HASH_SIZE];
1557 RTMd5(pThis->u.Blob.pvInput, pThis->u.Blob.cbInput, &abHash[0]);
1558 rc = RTMd5ToString(&abHash[0], pszDigest, cchDigest);
1559 }
1560
1561 return rc;
1562}
1563
1564
1565RTDECL(int) RTFuzzInputWriteToFile(RTFUZZINPUT hFuzzInput, const char *pszFilename)
1566{
1567 PRTFUZZINPUTINT pThis = hFuzzInput;
1568 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1569 AssertReturn(pThis->pFuzzer->enmType == RTFUZZCTXTYPE_BLOB, VERR_INVALID_STATE);
1570 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1571
1572 int rc = VINF_SUCCESS;
1573 if (!pThis->u.Blob.pvInput)
1574 rc = rtFuzzInputDataFinalize(pThis);
1575
1576 if (RT_SUCCESS(rc))
1577 {
1578 RTFILE hFile;
1579 rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
1580 if (RT_SUCCESS(rc))
1581 {
1582 rc = RTFileWrite(hFile, pThis->u.Blob.pvInput, pThis->u.Blob.cbInput, NULL);
1583 AssertRC(rc);
1584 RTFileClose(hFile);
1585
1586 if (RT_FAILURE(rc))
1587 RTFileDelete(pszFilename);
1588 }
1589 }
1590
1591 return rc;
1592}
1593
1594
1595RTDECL(int) RTFuzzInputAddToCtxCorpus(RTFUZZINPUT hFuzzInput)
1596{
1597 PRTFUZZINPUTINT pThis = hFuzzInput;
1598 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1599
1600 return rtFuzzCtxMutationAdd(pThis->pFuzzer, pThis->pMutationTop);
1601}
1602
1603
1604RTDECL(int) RTFuzzInputRemoveFromCtxCorpus(RTFUZZINPUT hFuzzInput)
1605{
1606 PRTFUZZINPUTINT pThis = hFuzzInput;
1607 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1608
1609#if 0
1610 int rc = VINF_SUCCESS;
1611 PRTFUZZINTERMEDIATE pIntermediate = NULL;
1612 PRTFUZZINPUTINT pInputLoc = rtFuzzCtxInputLocate(pThis->pFuzzer, &pThis->abMd5Hash[0], true /*fExact*/,
1613 &pIntermediate);
1614 if (pInputLoc)
1615 {
1616 AssertPtr(pIntermediate);
1617 Assert(pInputLoc == pThis);
1618
1619 uint64_t u64Md5Low = *(uint64_t *)&pThis->abMd5Hash[0];
1620 RTAvlU64Remove(&pIntermediate->TreeSeedsLow, u64Md5Low);
1621 RTFuzzInputRelease(hFuzzInput);
1622 }
1623 else
1624 rc = VERR_NOT_FOUND;
1625#endif
1626
1627 return VERR_NOT_IMPLEMENTED;
1628}
1629
Note: See TracBrowser for help on using the repository browser.

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