VirtualBox

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

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

Runtime/fuzz: Updates, add a target state recording mechanism to record changes in target behavior caused by mutated inputs. This allows to decide which mutated input gets added to the input corpus and which one gets discarded. Currently this is only able to record the stdout/stderr channels of the fuzzed process but other sources to detect changed behvior will get added in the future

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

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