VirtualBox

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

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

Runtime/fuzz: build fix

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