VirtualBox

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

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