VirtualBox

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

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

scm 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 77511 2019-02-28 19:21:30Z 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
393#if 0 /* unused */
394/**
395 * Releases an external reference from the given mutation.
396 *
397 * @returns New reference count on success.
398 * @param pMutation The mutation to retain.
399 */
400static uint32_t rtFuzzMutationRelease(PRTFUZZMUTATION pMutation)
401{
402 uint32_t cRefs = ASMAtomicDecU32(&pMutation->cRefs);
403 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pMutation));
404 return cRefs;
405}
406#endif
407
408
409/**
410 * Adds the given mutation to the corpus of the given fuzzer context.
411 *
412 * @returns IPRT status code.
413 * @param pThis The fuzzer context instance.
414 * @param pMutation The mutation to add.
415 */
416static int rtFuzzCtxMutationAdd(PRTFUZZCTXINT pThis, PRTFUZZMUTATION pMutation)
417{
418 int rc = VINF_SUCCESS;
419
420 pMutation->Core.Key = ASMAtomicIncU64(&pThis->cMutations) - 1;
421 rc = RTSemRWRequestWrite(pThis->hSemRwMutations, RT_INDEFINITE_WAIT);
422 AssertRC(rc); RT_NOREF(rc);
423 bool fIns = RTAvlU64Insert(&pThis->TreeMutations, &pMutation->Core);
424 Assert(fIns); RT_NOREF(fIns);
425 rc = RTSemRWReleaseWrite(pThis->hSemRwMutations);
426 AssertRC(rc); RT_NOREF(rc);
427
428 return rc;
429}
430
431
432/**
433 * Returns a random mutation from the corpus of the given fuzzer context.
434 *
435 * @returns Pointer to a randomly picked mutation (reference count is increased).
436 * @param pThis The fuzzer context instance.
437 */
438static PRTFUZZMUTATION rtFuzzCtxMutationPickRnd(PRTFUZZCTXINT pThis)
439{
440 uint64_t idxMutation = RTRandAdvU64Ex(pThis->hRand, 0, ASMAtomicReadU64(&pThis->cMutations));
441
442 int rc = RTSemRWRequestRead(pThis->hSemRwMutations, RT_INDEFINITE_WAIT);
443 AssertRC(rc); RT_NOREF(rc);
444
445 /*
446 * Using best fit getter here as there might be a racing mutation insertion and the mutation counter has increased
447 * already but the mutation is not yet in the tree.
448 */
449 PRTFUZZMUTATION pMutation = (PRTFUZZMUTATION)RTAvlU64GetBestFit(&pThis->TreeMutations, idxMutation, false /*fAbove*/);
450 AssertPtr(pMutation);
451
452 /* Increase reference count of the mutation. */
453 rtFuzzMutationRetain(pMutation);
454 rc = RTSemRWReleaseRead(pThis->hSemRwMutations);
455 AssertRC(rc); RT_NOREF(rc);
456
457 return pMutation;
458}
459
460
461/**
462 * Creates a new mutation capable of holding the additional number of bytes.
463 *
464 * @returns Pointer to the newly created mutation or NULL if out of memory.
465 * @param pThis The fuzzer context instance.
466 * @param offMutation The starting offset for the mutation.
467 * @param pMutationParent The parent mutation, can be NULL.
468 * @param cbAdditional Additional number of bytes to allocate after the core structure.
469 */
470static PRTFUZZMUTATION rtFuzzMutationCreate(PRTFUZZCTXINT pThis, uint64_t offMutation, PRTFUZZMUTATION pMutationParent, size_t cbAdditional)
471{
472 PRTFUZZMUTATION pMutation = (PRTFUZZMUTATION)rtFuzzCtxMemoryAlloc(pThis, sizeof(RTFUZZMUTATION) + cbAdditional);
473 if (RT_LIKELY(pMutation))
474 {
475 pMutation->u32Magic = 0; /** @todo */
476 pMutation->pFuzzer = pThis;
477 pMutation->cRefs = 1;
478 pMutation->iLvl = 0;
479 pMutation->offMutation = offMutation;
480 pMutation->pMutationParent = pMutationParent;
481
482 if (pMutationParent)
483 pMutation->iLvl = pMutationParent->iLvl + 1;
484 }
485
486 return pMutation;
487}
488
489
490/**
491 * Destroys the given mutation.
492 *
493 * @returns nothing.
494 * @param pMutation The mutation to destroy.
495 */
496static void rtFuzzMutationDestroy(PRTFUZZMUTATION pMutation)
497{
498 rtFuzzCtxMemoryFree(pMutation->pFuzzer, pMutation);
499}
500
501
502/**
503 * Destorys the given fuzzer context freeing all allocated resources.
504 *
505 * @returns nothing.
506 * @param pThis The fuzzer context instance.
507 */
508static void rtFuzzCtxDestroy(PRTFUZZCTXINT pThis)
509{
510 RT_NOREF(pThis);
511}
512
513
514static DECLCALLBACK(int) rtFuzzCtxMutatorCorpusExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation,
515 uint8_t *pbBuf, size_t cbBuf)
516{
517 RT_NOREF(pThis, cbBuf);
518 memcpy(pbBuf, &pMutation->u.abCorpus[0], pMutation->cbInput);
519 return VINF_SUCCESS;
520}
521
522
523/**
524 * Mutator callback - flips a single bit in the input.
525 */
526static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlipPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
527 PPRTFUZZMUTATION ppMutation)
528{
529 int rc = VINF_SUCCESS;
530 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, 0 /*cbAdditional*/);
531 if (RT_LIKELY(pMutation))
532 {
533 pMutation->cbInput = pMutationParent->cbInput; /* Bit flips don't change the input size. */
534 pMutation->u.idxBitFlip = RTRandAdvS32Ex(pThis->hRand, 0, sizeof(uint8_t) * 8 - 1);
535 *ppMutation = pMutation;
536 }
537 else
538 rc = VERR_NO_MEMORY;
539
540 return rc;
541}
542
543
544static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlipExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation,
545 uint8_t *pbBuf, size_t cbBuf)
546{
547 RT_NOREF(pThis, cbBuf);
548 ASMBitToggle(pbBuf, pMutation->u.idxBitFlip);
549 return VINF_SUCCESS;
550}
551
552
553/**
554 * Mutator callback - replaces a single byte in the input.
555 */
556static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplacePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
557 PPRTFUZZMUTATION ppMutation)
558{
559 int rc = VINF_SUCCESS;
560 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, 0 /*cbAdditional*/);
561 if (RT_LIKELY(pMutation))
562 {
563 pMutation->cbInput = pMutationParent->cbInput; /* Byte replacements don't change the input size. */
564 RTRandAdvBytes(pThis->hRand, &pMutation->u.bByteReplace, 1); /** @todo Filter out same values. */
565 *ppMutation = pMutation;
566 }
567 else
568 rc = VERR_NO_MEMORY;
569
570 return rc;
571}
572
573
574static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplaceExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation,
575 uint8_t *pbBuf, size_t cbBuf)
576{
577 RT_NOREF(pThis, cbBuf);
578 *pbBuf = pMutation->u.bByteReplace;
579 return VINF_SUCCESS;
580}
581
582
583/**
584 * Mutator callback - inserts a byte sequence into the input.
585 */
586static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsertAppendPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
587 PPRTFUZZMUTATION ppMutation)
588{
589 int rc = VINF_SUCCESS;
590 if (pMutationParent->cbInput < pThis->cbInputMax)
591 {
592 size_t cbInputMutated = (size_t)RTRandAdvU64Ex(pThis->hRand, pMutationParent->cbInput + 1, pThis->cbInputMax);
593 size_t cbInsert = cbInputMutated - pMutationParent->cbInput;
594
595 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, cbInsert);
596 if (RT_LIKELY(pMutation))
597 {
598 pMutation->cbInput = cbInputMutated;
599 RTRandAdvBytes(pThis->hRand, &pMutation->u.abAdd[0], cbInsert);
600 *ppMutation = pMutation;
601 }
602 else
603 rc = VERR_NO_MEMORY;
604 }
605
606 return rc;
607}
608
609
610static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsertAppendExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation,
611 uint8_t *pbBuf, size_t cbBuf)
612{
613 RT_NOREF(pThis);
614 size_t cbInsert = pMutation->cbInput - pMutation->pMutationParent->cbInput;
615
616 /* Move any remaining data to the end. */
617 if (cbBuf)
618 memmove(pbBuf + cbInsert, pbBuf, cbBuf);
619
620 memcpy(pbBuf, &pMutation->u.abAdd[0], cbInsert);
621 return VINF_SUCCESS;
622}
623
624
625/**
626 * Mutator callback - deletes a single byte in the input.
627 */
628static DECLCALLBACK(int) rtFuzzCtxMutatorByteDeletePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
629 PPRTFUZZMUTATION ppMutation)
630{
631 int rc = VINF_SUCCESS;
632 if (pMutationParent->cbInput - offStart >= 1)
633 {
634 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, 0 /*cbAdditional*/);
635 if (RT_LIKELY(pMutation))
636 {
637 pMutation->cbInput = pMutationParent->cbInput - 1;
638 *ppMutation = pMutation;
639 }
640 else
641 rc = VERR_NO_MEMORY;
642 }
643
644 return rc;
645}
646
647
648static DECLCALLBACK(int) rtFuzzCtxMutatorByteDeleteExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation,
649 uint8_t *pbBuf, size_t cbBuf)
650{
651 RT_NOREF(pThis, pMutation);
652
653 /* Just move the residual data to the front. */
654 memmove(pbBuf, pbBuf + 1, cbBuf - 1);
655 return VINF_SUCCESS;
656}
657
658
659
660/**
661 * Mutator callback - deletes a byte sequence in the input.
662 */
663static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDeletePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
664 PPRTFUZZMUTATION ppMutation)
665{
666 int rc = VINF_SUCCESS;
667 if (pMutationParent->cbInput > 1)
668 {
669 size_t cbInputMutated = (size_t)RTRandAdvU64Ex(pThis->hRand, offStart, pMutationParent->cbInput - 1);
670
671 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, 0 /*cbAdditional*/);
672 if (RT_LIKELY(pMutation))
673 {
674 pMutation->cbInput = cbInputMutated;
675 *ppMutation = pMutation;
676 }
677 else
678 rc = VERR_NO_MEMORY;
679 }
680
681 return rc;
682}
683
684
685static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDeleteExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation,
686 uint8_t *pbBuf, size_t cbBuf)
687{
688 RT_NOREF(pThis);
689 Assert(pMutation->pMutationParent->cbInput > pMutation->cbInput);
690 size_t cbDel = pMutation->pMutationParent->cbInput - pMutation->cbInput;
691
692 /* Just move the residual data to the front. */
693 memmove(pbBuf, pbBuf + cbDel, cbBuf - cbDel);
694 return VINF_SUCCESS;
695}
696
697
698/**
699 * Creates an empty fuzzing context.
700 *
701 * @returns IPRT status code.
702 * @param ppThis Where to store the pointer to the internal fuzzing context instance on success.
703 * @param enmType Fuzzing context type.
704 */
705static int rtFuzzCtxCreateEmpty(PRTFUZZCTXINT *ppThis, RTFUZZCTXTYPE enmType)
706{
707 int rc;
708 PRTFUZZCTXINT pThis = (PRTFUZZCTXINT)RTMemAllocZ(sizeof(*pThis));
709 if (RT_LIKELY(pThis))
710 {
711 pThis->u32Magic = RTFUZZCTX_MAGIC;
712 pThis->cRefs = 1;
713 pThis->enmType = enmType;
714 pThis->TreeMutations = NULL;
715 pThis->cbInputMax = UINT32_MAX;
716 pThis->cMutations = 0;
717 pThis->fFlagsBehavioral = 0;
718 pThis->cbMemTotal = 0;
719
720 /* Copy the default mutator descriptors over. */
721 pThis->paMutators = (PRTFUZZMUTATOR)RTMemAllocZ(RT_ELEMENTS(g_aMutators) * sizeof(RTFUZZMUTATOR));
722 if (RT_LIKELY(pThis->paMutators))
723 {
724 pThis->cMutators = RT_ELEMENTS(g_aMutators);
725 memcpy(&pThis->paMutators[0], &g_aMutators[0], RT_ELEMENTS(g_aMutators) * sizeof(RTFUZZMUTATOR));
726
727 rc = RTSemRWCreate(&pThis->hSemRwMutations);
728 if (RT_SUCCESS(rc))
729 {
730 rc = RTRandAdvCreateParkMiller(&pThis->hRand);
731 if (RT_SUCCESS(rc))
732 {
733 RTRandAdvSeed(pThis->hRand, RTTimeSystemNanoTS());
734 *ppThis = pThis;
735 return VINF_SUCCESS;
736 }
737
738 RTSemRWDestroy(pThis->hSemRwMutations);
739 }
740 }
741 else
742 rc = VERR_NO_MEMORY;
743
744 RTMemFree(pThis);
745 }
746 else
747 rc = VERR_NO_MEMORY;
748
749 return rc;
750}
751
752
753/**
754 * Destroys the given fuzzing input.
755 *
756 * @returns nothing.
757 * @param pThis The fuzzing input to destroy.
758 */
759static void rtFuzzInputDestroy(PRTFUZZINPUTINT pThis)
760{
761 PRTFUZZCTXINT pFuzzer = pThis->pFuzzer;
762
763 if ( pFuzzer->enmType == RTFUZZCTXTYPE_BLOB
764 && pThis->u.Blob.pvInput)
765 rtFuzzCtxMemoryFree(pFuzzer, pThis->u.Blob.pvInput);
766
767 rtFuzzCtxMemoryFree(pFuzzer, pThis);
768 RTFuzzCtxRelease(pFuzzer);
769}
770
771
772/**
773 * Creates the final input data applying all accumulated mutations.
774 *
775 * @returns IPRT status code.
776 * @param pThis The fuzzing input to finalize.
777 */
778static int rtFuzzInputDataFinalize(PRTFUZZINPUTINT pThis)
779{
780 Assert(!pThis->u.Blob.pvInput);
781
782 int rc = VINF_SUCCESS;
783 uint8_t *pbBuf = (uint8_t *)rtFuzzCtxMemoryAlloc(pThis->pFuzzer, pThis->u.Blob.cbAlloc);
784 if (RT_LIKELY(pbBuf))
785 {
786 pThis->u.Blob.pvInput = pbBuf;
787 pThis->u.Blob.cbInput = pThis->pMutationTop->cbInput;
788
789 size_t cbInputNow = pThis->apMutations[0]->cbInput;
790 for (uint32_t i = 0; i < pThis->pMutationTop->iLvl + 1; i++)
791 {
792 PCRTFUZZMUTATION pMutation = pThis->apMutations[i];
793 pMutation->pMutator->pfnExec(pThis->pFuzzer, pMutation, pbBuf + pMutation->offMutation,
794 cbInputNow - pMutation->offMutation);
795
796 cbInputNow = pMutation->cbInput;
797 }
798
799 Assert(cbInputNow == pThis->u.Blob.cbInput);
800 }
801 else
802 rc = VERR_NO_MEMORY;
803
804 return rc;
805}
806
807
808RTDECL(int) RTFuzzCtxCreate(PRTFUZZCTX phFuzzCtx, RTFUZZCTXTYPE enmType)
809{
810 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
811
812 return rtFuzzCtxCreateEmpty(phFuzzCtx, enmType);
813}
814
815
816RTDECL(int) RTFuzzCtxCreateFromState(PRTFUZZCTX phFuzzCtx, const void *pvState, size_t cbState)
817{
818 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
819 AssertPtrReturn(pvState, VERR_INVALID_POINTER);
820 AssertReturn(cbState > 0, VERR_INVALID_PARAMETER);
821
822#if 0
823 int rc = VINF_SUCCESS;
824 if (cbState >= sizeof(RTFUZZCTXSTATE))
825 {
826 RTFUZZCTXSTATE StateImport;
827
828 memcpy(&StateImport, pvState, sizeof(RTFUZZCTXSTATE));
829 if ( RT_LE2H_U32(StateImport.u32Magic) == RTFUZZCTX_MAGIC
830 && RT_LE2H_U32(StateImport.cbPrng) <= cbState - sizeof(RTFUZZCTXSTATE))
831 {
832 PRTFUZZCTXINT pThis = rtFuzzCtxCreateEmpty();
833 if (RT_LIKELY(pThis))
834 {
835 pThis->cbInputMax = (size_t)RT_LE2H_U64(StateImport.cbInputMax);
836 pThis->fFlagsBehavioral = RT_LE2H_U32(StateImport.fFlagsBehavioral);
837
838 uint8_t *pbState = (uint8_t *)pvState;
839 uint32_t cInputs = RT_LE2H_U32(StateImport.cInputs);
840 rc = RTRandAdvRestoreState(pThis->hRand, (const char *)&pbState[sizeof(RTFUZZCTXSTATE)]);
841 if (RT_SUCCESS(rc))
842 {
843 /* Go through the inputs and add them. */
844 pbState += sizeof(RTFUZZCTXSTATE) + RT_LE2H_U32(StateImport.cbPrng);
845 cbState -= sizeof(RTFUZZCTXSTATE) + RT_LE2H_U32(StateImport.cbPrng);
846
847 uint32_t idx = 0;
848 while ( idx < cInputs
849 && RT_SUCCESS(rc))
850 {
851 size_t cbInput = 0;
852 if (cbState >= sizeof(uint32_t))
853 {
854 memcpy(&cbInput, pbState, sizeof(uint32_t));
855 cbInput = RT_LE2H_U32(cbInput);
856 pbState += sizeof(uint32_t);
857 }
858
859 if ( cbInput
860 && cbInput <= cbState)
861 {
862 PRTFUZZINPUTINT pInput = rtFuzzCtxInputCreate(pThis, cbInput);
863 if (RT_LIKELY(pInput))
864 {
865 memcpy(&pInput->abInput[0], pbState, cbInput);
866 RTMd5(&pInput->abInput[0], pInput->cbInput, &pInput->abMd5Hash[0]);
867 rc = rtFuzzCtxInputAdd(pThis, pInput);
868 if (RT_FAILURE(rc))
869 RTMemFree(pInput);
870 pbState += cbInput;
871 }
872 }
873 else
874 rc = VERR_INVALID_STATE;
875
876 idx++;
877 }
878
879 if (RT_SUCCESS(rc))
880 {
881 *phFuzzCtx = pThis;
882 return VINF_SUCCESS;
883 }
884 }
885
886 rtFuzzCtxDestroy(pThis);
887 }
888 else
889 rc = VERR_NO_MEMORY;
890 }
891 else
892 rc = VERR_INVALID_MAGIC;
893 }
894 else
895 rc = VERR_INVALID_MAGIC;
896
897 return rc;
898#else
899 return VERR_NOT_IMPLEMENTED;
900#endif
901}
902
903
904RTDECL(int) RTFuzzCtxCreateFromStateFile(PRTFUZZCTX phFuzzCtx, const char *pszFilename)
905{
906 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
907 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
908
909 void *pv = NULL;
910 size_t cb = 0;
911 int rc = RTFileReadAll(pszFilename, &pv, &cb);
912 if (RT_SUCCESS(rc))
913 {
914 rc = RTFuzzCtxCreateFromState(phFuzzCtx, pv, cb);
915 RTFileReadAllFree(pv, cb);
916 }
917
918 return rc;
919}
920
921
922RTDECL(uint32_t) RTFuzzCtxRetain(RTFUZZCTX hFuzzCtx)
923{
924 PRTFUZZCTXINT pThis = hFuzzCtx;
925
926 AssertPtrReturn(pThis, UINT32_MAX);
927
928 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
929 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
930 return cRefs;
931}
932
933
934RTDECL(uint32_t) RTFuzzCtxRelease(RTFUZZCTX hFuzzCtx)
935{
936 PRTFUZZCTXINT pThis = hFuzzCtx;
937 if (pThis == NIL_RTFUZZCTX)
938 return 0;
939 AssertPtrReturn(pThis, UINT32_MAX);
940
941 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
942 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
943 if (cRefs == 0)
944 rtFuzzCtxDestroy(pThis);
945 return cRefs;
946}
947
948
949RTDECL(int) RTFuzzCtxStateExport(RTFUZZCTX hFuzzCtx, void **ppvState, size_t *pcbState)
950{
951 PRTFUZZCTXINT pThis = hFuzzCtx;
952 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
953 AssertPtrReturn(ppvState, VERR_INVALID_POINTER);
954 AssertPtrReturn(pcbState, VERR_INVALID_POINTER);
955
956#if 0
957 char aszPrngExport[_4K]; /* Should be plenty of room here. */
958 size_t cbPrng = sizeof(aszPrngExport);
959 int rc = RTRandAdvSaveState(pThis->hRand, &aszPrngExport[0], &cbPrng);
960 if (RT_SUCCESS(rc))
961 {
962 RTFUZZCTXSTATE StateExport;
963
964 StateExport.u32Magic = RT_H2LE_U32(RTFUZZCTX_MAGIC);
965 StateExport.cbPrng = RT_H2LE_U32((uint32_t)cbPrng);
966 StateExport.cInputs = RT_H2LE_U32(pThis->cInputs);
967 StateExport.fFlagsBehavioral = RT_H2LE_U32(pThis->fFlagsBehavioral);
968 StateExport.cbInputMax = RT_H2LE_U64(pThis->cbInputMax);
969
970 /* Estimate the size of the required state. */
971 size_t cbState = sizeof(StateExport)
972 + cbPrng
973 + pThis->cInputs * ((pThis->cbInputMax < _1M ? pThis->cbInputMax : _64K) + sizeof(uint32_t)); /* For the size indicator before each input. */
974 uint8_t *pbState = (uint8_t *)RTMemAllocZ(cbState);
975 if (RT_LIKELY(pbState))
976 {
977 size_t offState = 0;
978 memcpy(pbState, &StateExport, sizeof(StateExport));
979 offState += sizeof(StateExport);
980 memcpy(&pbState[offState], &aszPrngExport[0], cbPrng);
981 offState += cbPrng;
982
983 /* Export each input. */
984 PRTFUZZINPUTINT pIt;
985 RTListForEach(&pThis->LstInputs, pIt, RTFUZZINPUTINT, NdInputs)
986 {
987 /* Ensure buffer size. */
988 if (offState + pIt->cbInput + sizeof(uint32_t) > cbState)
989 {
990 uint8_t *pbStateNew = (uint8_t *)RTMemRealloc(pbState, cbState + pIt->cbInput + sizeof(uint32_t));
991 if (RT_LIKELY(pbStateNew))
992 {
993 pbState = pbStateNew;
994 cbState += pIt->cbInput + sizeof(uint32_t);
995 }
996 else
997 {
998 rc = VERR_NO_MEMORY;
999 break;
1000 }
1001 }
1002
1003 *(uint32_t *)&pbState[offState] = RT_H2LE_U32((uint32_t)pIt->cbInput);
1004 offState += sizeof(uint32_t);
1005 memcpy(&pbState[offState], &pIt->abInput[0], pIt->cbInput);
1006 offState += pIt->cbInput;
1007 }
1008
1009 if (RT_SUCCESS(rc))
1010 {
1011 *ppvState = pbState;
1012 *pcbState = offState;
1013 }
1014 else
1015 RTMemFree(pbState);
1016 }
1017 else
1018 rc = VERR_NO_MEMORY;
1019 }
1020
1021 return rc;
1022#else
1023 return VERR_NOT_IMPLEMENTED;
1024#endif
1025}
1026
1027
1028RTDECL(int) RTFuzzCtxStateExportToFile(RTFUZZCTX hFuzzCtx, const char *pszFilename)
1029{
1030 PRTFUZZCTXINT pThis = hFuzzCtx;
1031 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1032 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1033
1034 void *pvState = NULL;
1035 size_t cbState = 0;
1036 int rc = RTFuzzCtxStateExport(hFuzzCtx, &pvState, &cbState);
1037 if (RT_SUCCESS(rc))
1038 {
1039 RTFILE hFile;
1040
1041 rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
1042 if (RT_SUCCESS(rc))
1043 {
1044 rc = RTFileWrite(hFile, pvState, cbState, NULL);
1045 RTFileClose(hFile);
1046 if (RT_FAILURE(rc))
1047 RTFileDelete(pszFilename);
1048 }
1049
1050 RTMemFree(pvState);
1051 }
1052
1053 return rc;
1054}
1055
1056
1057RTDECL(int) RTFuzzCtxCorpusInputAdd(RTFUZZCTX hFuzzCtx, const void *pvInput, size_t cbInput)
1058{
1059 PRTFUZZCTXINT pThis = hFuzzCtx;
1060 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1061 AssertPtrReturn(pvInput, VERR_INVALID_POINTER);
1062 AssertReturn(cbInput, VERR_INVALID_POINTER);
1063
1064 int rc = VINF_SUCCESS;
1065 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, 0, NULL, cbInput);
1066 if (RT_LIKELY(pMutation))
1067 {
1068 pMutation->pMutator = &g_MutatorCorpus;
1069 pMutation->cbInput = cbInput;
1070 memcpy(&pMutation->u.abCorpus[0], pvInput, cbInput);
1071 rc = rtFuzzCtxMutationAdd(pThis, pMutation);
1072 if (RT_FAILURE(rc))
1073 rtFuzzMutationDestroy(pMutation);
1074 }
1075 else
1076 rc = VERR_NO_MEMORY;
1077
1078 return rc;
1079}
1080
1081
1082RTDECL(int) RTFuzzCtxCorpusInputAddFromFile(RTFUZZCTX hFuzzCtx, const char *pszFilename)
1083{
1084 PRTFUZZCTXINT pThis = hFuzzCtx;
1085 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1086 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1087
1088 void *pv = NULL;
1089 size_t cb = 0;
1090 int rc = RTFileReadAll(pszFilename, &pv, &cb);
1091 if (RT_SUCCESS(rc))
1092 {
1093 rc = RTFuzzCtxCorpusInputAdd(hFuzzCtx, pv, cb);
1094 RTFileReadAllFree(pv, cb);
1095 }
1096
1097 return rc;
1098}
1099
1100
1101RTDECL(int) RTFuzzCtxCorpusInputAddFromVfsFile(RTFUZZCTX hFuzzCtx, RTVFSFILE hVfsFile)
1102{
1103 PRTFUZZCTXINT pThis = hFuzzCtx;
1104 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1105 AssertReturn(hVfsFile != NIL_RTVFSFILE, VERR_INVALID_HANDLE);
1106
1107 uint64_t cbFile = 0;
1108 int rc = RTVfsFileGetSize(hVfsFile, &cbFile);
1109 if (RT_SUCCESS(rc))
1110 {
1111 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, 0, NULL, cbFile);
1112 if (RT_LIKELY(pMutation))
1113 {
1114 pMutation->pMutator = &g_MutatorCorpus;
1115 pMutation->cbInput = cbFile;
1116 rc = RTVfsFileRead(hVfsFile, &pMutation->u.abCorpus[0], cbFile, NULL);
1117 if (RT_SUCCESS(rc))
1118 rc = rtFuzzCtxMutationAdd(pThis, pMutation);
1119
1120 if (RT_FAILURE(rc))
1121 rtFuzzMutationDestroy(pMutation);
1122 }
1123 }
1124
1125 return rc;
1126}
1127
1128
1129RTDECL(int) RTFuzzCtxCorpusInputAddFromDirPath(RTFUZZCTX hFuzzCtx, const char *pszDirPath)
1130{
1131 PRTFUZZCTXINT pThis = hFuzzCtx;
1132 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1133 AssertPtrReturn(pszDirPath, VERR_INVALID_POINTER);
1134
1135 RTDIR hDir;
1136 int rc = RTDirOpen(&hDir, pszDirPath);
1137 if (RT_SUCCESS(rc))
1138 {
1139 for (;;)
1140 {
1141 RTDIRENTRY DirEntry;
1142 rc = RTDirRead(hDir, &DirEntry, NULL);
1143 if (RT_FAILURE(rc))
1144 break;
1145
1146 /* Skip '.', '..' and other non-files. */
1147 if ( DirEntry.enmType != RTDIRENTRYTYPE_UNKNOWN
1148 && DirEntry.enmType != RTDIRENTRYTYPE_FILE)
1149 continue;
1150 if (RTDirEntryIsStdDotLink(&DirEntry))
1151 continue;
1152
1153 /* Compose the full path, result 'unknown' entries and skip non-files. */
1154 char szFile[RTPATH_MAX];
1155 RT_ZERO(szFile);
1156 rc = RTPathJoin(szFile, sizeof(szFile), pszDirPath, DirEntry.szName);
1157 if (RT_FAILURE(rc))
1158 break;
1159
1160 if (DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN)
1161 {
1162 RTDirQueryUnknownType(szFile, false, &DirEntry.enmType);
1163 if (DirEntry.enmType != RTDIRENTRYTYPE_FILE)
1164 continue;
1165 }
1166
1167 /* Okay, it's a file we can add. */
1168 rc = RTFuzzCtxCorpusInputAddFromFile(hFuzzCtx, szFile);
1169 if (RT_FAILURE(rc))
1170 break;
1171 }
1172 if (rc == VERR_NO_MORE_FILES)
1173 rc = VINF_SUCCESS;
1174 RTDirClose(hDir);
1175 }
1176
1177 return rc;
1178}
1179
1180
1181RTDECL(int) RTFuzzCtxCfgSetInputSeedMaximum(RTFUZZCTX hFuzzCtx, size_t cbMax)
1182{
1183 PRTFUZZCTXINT pThis = hFuzzCtx;
1184 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1185
1186 pThis->cbInputMax = cbMax;
1187 return VINF_SUCCESS;
1188}
1189
1190
1191RTDECL(size_t) RTFuzzCtxCfgGetInputSeedMaximum(RTFUZZCTX hFuzzCtx)
1192{
1193 PRTFUZZCTXINT pThis = hFuzzCtx;
1194 AssertPtrReturn(pThis, 0);
1195
1196 return pThis->cbInputMax;
1197}
1198
1199
1200RTDECL(int) RTFuzzCtxCfgSetBehavioralFlags(RTFUZZCTX hFuzzCtx, uint32_t fFlags)
1201{
1202 PRTFUZZCTXINT pThis = hFuzzCtx;
1203 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1204 AssertReturn(!(fFlags & ~RTFUZZCTX_F_BEHAVIORAL_VALID), VERR_INVALID_PARAMETER);
1205
1206 pThis->fFlagsBehavioral = fFlags;
1207 return VINF_SUCCESS;
1208}
1209
1210
1211RTDECL(uint32_t) RTFuzzCfgGetBehavioralFlags(RTFUZZCTX hFuzzCtx)
1212{
1213 PRTFUZZCTXINT pThis = hFuzzCtx;
1214 AssertPtrReturn(pThis, 0);
1215
1216 return pThis->fFlagsBehavioral;
1217}
1218
1219
1220RTDECL(int) RTFuzzCtxCfgSetTmpDirectory(RTFUZZCTX hFuzzCtx, const char *pszPathTmp)
1221{
1222 PRTFUZZCTXINT pThis = hFuzzCtx;
1223 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1224 AssertPtrReturn(pszPathTmp, VERR_INVALID_POINTER);
1225
1226 return VERR_NOT_IMPLEMENTED;
1227}
1228
1229
1230RTDECL(const char *) RTFuzzCtxCfgGetTmpDirectory(RTFUZZCTX hFuzzCtx)
1231{
1232 PRTFUZZCTXINT pThis = hFuzzCtx;
1233 AssertPtrReturn(pThis, NULL);
1234
1235 return NULL;
1236}
1237
1238
1239RTDECL(int) RTFuzzCtxReseed(RTFUZZCTX hFuzzCtx, uint64_t uSeed)
1240{
1241 PRTFUZZCTXINT pThis = hFuzzCtx;
1242 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1243
1244 RTRandAdvSeed(pThis->hRand, uSeed);
1245 return VINF_SUCCESS;
1246}
1247
1248
1249RTDECL(int) RTFuzzCtxInputGenerate(RTFUZZCTX hFuzzCtx, PRTFUZZINPUT phFuzzInput)
1250{
1251 int rc = VINF_SUCCESS;
1252 PRTFUZZCTXINT pThis = hFuzzCtx;
1253 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1254 AssertPtrReturn(phFuzzInput, VERR_INVALID_POINTER);
1255
1256 uint32_t cTries = 0;
1257 PRTFUZZMUTATION pMutationParent = rtFuzzCtxMutationPickRnd(pThis);
1258 do
1259 {
1260 uint32_t idxMutator = RTRandAdvU32Ex(pThis->hRand, 0, pThis->cMutators - 1);
1261 PCRTFUZZMUTATOR pMutator = &pThis->paMutators[idxMutator];
1262 PRTFUZZMUTATION pMutation = NULL;
1263
1264 uint64_t offStart = 0;
1265 if (!(pMutator->fFlags & RTFUZZMUTATOR_F_END_OF_BUF))
1266 offStart = RTRandAdvU64Ex(pThis->hRand, 0, pMutationParent->cbInput);
1267 else
1268 offStart = pMutationParent->cbInput;
1269
1270 rc = pMutator->pfnPrep(pThis, offStart, pMutationParent, &pMutation);
1271 if ( RT_SUCCESS(rc)
1272 && VALID_PTR(pMutation))
1273 {
1274 pMutation->pMutator = pMutator;
1275
1276 if (pThis->fFlagsBehavioral & RTFUZZCTX_F_BEHAVIORAL_ADD_INPUT_AUTOMATICALLY_TO_CORPUS)
1277 rtFuzzCtxMutationAdd(pThis, pMutation);
1278
1279 /* Create a new input. */
1280 PRTFUZZINPUTINT pInput = (PRTFUZZINPUTINT)rtFuzzCtxMemoryAlloc(pThis, RT_UOFFSETOF_DYN(RTFUZZINPUTINT, apMutations[pMutation->iLvl + 1]));
1281 if (RT_LIKELY(pInput))
1282 {
1283 pInput->u32Magic = 0; /** @todo */
1284 pInput->cRefs = 1;
1285 pInput->pFuzzer = pThis;
1286 pInput->pMutationTop = pMutation;
1287 RTFuzzCtxRetain(pThis);
1288
1289 /* Traverse the mutations top to bottom and insert into the array. */
1290 uint32_t idx = pMutation->iLvl + 1;
1291 PCRTFUZZMUTATION pMutationCur = pMutation;
1292 size_t cbAlloc = 0;
1293 while (idx > 0)
1294 {
1295 pInput->apMutations[idx - 1] = pMutationCur;
1296 cbAlloc = RT_MAX(cbAlloc, pMutationCur->cbInput);
1297 pMutationCur = pMutationCur->pMutationParent;
1298 idx--;
1299 }
1300
1301 pInput->u.Blob.cbAlloc = cbAlloc;
1302 *phFuzzInput = pInput;
1303 return rc;
1304 }
1305 else
1306 rc = VERR_NO_MEMORY;
1307 }
1308 } while (++cTries <= 50);
1309
1310 if (RT_SUCCESS(rc))
1311 rc = VERR_INVALID_STATE;
1312
1313 return rc;
1314}
1315
1316
1317RTDECL(int) RTFuzzInputQueryBlobData(RTFUZZINPUT hFuzzInput, void **ppv, size_t *pcb)
1318{
1319 PRTFUZZINPUTINT pThis = hFuzzInput;
1320 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1321 AssertReturn(pThis->pFuzzer->enmType == RTFUZZCTXTYPE_BLOB, VERR_INVALID_STATE);
1322
1323 int rc = VINF_SUCCESS;
1324 if (!pThis->u.Blob.pvInput)
1325 rc = rtFuzzInputDataFinalize(pThis);
1326
1327 if (RT_SUCCESS(rc))
1328 {
1329 AssertPtr(pThis->u.Blob.pvInput);
1330 Assert(pThis->u.Blob.cbInput > 0);
1331
1332 *ppv = pThis->u.Blob.pvInput;
1333 *pcb = pThis->u.Blob.cbInput;
1334 }
1335
1336 return rc;
1337}
1338
1339
1340RTDECL(int) RTFuzzInputMutateStreamData(RTFUZZINPUT hFuzzInput, void *pvBuf, size_t cbBuf)
1341{
1342 PRTFUZZINPUTINT pThis = hFuzzInput;
1343 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1344 AssertReturn(pThis->pFuzzer->enmType == RTFUZZCTXTYPE_STREAM, VERR_INVALID_STATE);
1345
1346 RT_NOREF(pvBuf, cbBuf);
1347 return VERR_NOT_IMPLEMENTED;
1348}
1349
1350
1351RTDECL(uint32_t) RTFuzzInputRetain(RTFUZZINPUT hFuzzInput)
1352{
1353 PRTFUZZINPUTINT pThis = hFuzzInput;
1354
1355 AssertPtrReturn(pThis, UINT32_MAX);
1356
1357 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1358 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1359 return cRefs;
1360}
1361
1362
1363RTDECL(uint32_t) RTFuzzInputRelease(RTFUZZINPUT hFuzzInput)
1364{
1365 PRTFUZZINPUTINT pThis = hFuzzInput;
1366 if (pThis == NIL_RTFUZZINPUT)
1367 return 0;
1368 AssertPtrReturn(pThis, UINT32_MAX);
1369
1370 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1371 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1372 if (cRefs == 0)
1373 rtFuzzInputDestroy(pThis);
1374 return cRefs;
1375}
1376
1377
1378RTDECL(int) RTFuzzInputQueryDigestString(RTFUZZINPUT hFuzzInput, char *pszDigest, size_t cchDigest)
1379{
1380 PRTFUZZINPUTINT pThis = hFuzzInput;
1381 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1382 AssertReturn(pThis->pFuzzer->enmType == RTFUZZCTXTYPE_BLOB, VERR_INVALID_STATE);
1383 AssertPtrReturn(pszDigest, VERR_INVALID_POINTER);
1384 AssertReturn(cchDigest >= RTMD5_STRING_LEN + 1, VERR_INVALID_PARAMETER);
1385
1386 int rc = VINF_SUCCESS;
1387 if (!pThis->u.Blob.pvInput)
1388 rc = rtFuzzInputDataFinalize(pThis);
1389
1390 if (RT_SUCCESS(rc))
1391 {
1392 uint8_t abHash[RTMD5_HASH_SIZE];
1393 RTMd5(pThis->u.Blob.pvInput, pThis->u.Blob.cbInput, &abHash[0]);
1394 rc = RTMd5ToString(&abHash[0], pszDigest, cchDigest);
1395 }
1396
1397 return rc;
1398}
1399
1400
1401RTDECL(int) RTFuzzInputWriteToFile(RTFUZZINPUT hFuzzInput, const char *pszFilename)
1402{
1403 PRTFUZZINPUTINT pThis = hFuzzInput;
1404 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1405 AssertReturn(pThis->pFuzzer->enmType == RTFUZZCTXTYPE_BLOB, VERR_INVALID_STATE);
1406 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1407
1408 int rc = VINF_SUCCESS;
1409 if (!pThis->u.Blob.pvInput)
1410 rc = rtFuzzInputDataFinalize(pThis);
1411
1412 if (RT_SUCCESS(rc))
1413 {
1414 RTFILE hFile;
1415 rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
1416 if (RT_SUCCESS(rc))
1417 {
1418 rc = RTFileWrite(hFile, pThis->u.Blob.pvInput, pThis->u.Blob.cbInput, NULL);
1419 AssertRC(rc);
1420 RTFileClose(hFile);
1421
1422 if (RT_FAILURE(rc))
1423 RTFileDelete(pszFilename);
1424 }
1425 }
1426
1427 return rc;
1428}
1429
1430
1431RTDECL(int) RTFuzzInputAddToCtxCorpus(RTFUZZINPUT hFuzzInput)
1432{
1433 PRTFUZZINPUTINT pThis = hFuzzInput;
1434 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1435
1436 return rtFuzzCtxMutationAdd(pThis->pFuzzer, pThis->pMutationTop);
1437}
1438
1439
1440RTDECL(int) RTFuzzInputRemoveFromCtxCorpus(RTFUZZINPUT hFuzzInput)
1441{
1442 PRTFUZZINPUTINT pThis = hFuzzInput;
1443 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1444
1445#if 0
1446 int rc = VINF_SUCCESS;
1447 PRTFUZZINTERMEDIATE pIntermediate = NULL;
1448 PRTFUZZINPUTINT pInputLoc = rtFuzzCtxInputLocate(pThis->pFuzzer, &pThis->abMd5Hash[0], true /*fExact*/,
1449 &pIntermediate);
1450 if (pInputLoc)
1451 {
1452 AssertPtr(pIntermediate);
1453 Assert(pInputLoc == pThis);
1454
1455 uint64_t u64Md5Low = *(uint64_t *)&pThis->abMd5Hash[0];
1456 RTAvlU64Remove(&pIntermediate->TreeSeedsLow, u64Md5Low);
1457 RTFuzzInputRelease(hFuzzInput);
1458 }
1459 else
1460 rc = VERR_NOT_FOUND;
1461#endif
1462
1463 return VERR_NOT_IMPLEMENTED;
1464}
1465
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