VirtualBox

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

最後變更 在這個檔案從84192是 83426,由 vboxsync 提交於 5 年 前

Runtime/RTFuzzCfg: Initial implementation of API for configuring a fuzzing context. The config and input corpus is stored in a single tarball to keep things easy to pass around

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 82.1 KB
 
1/* $Id: fuzz.cpp 83426 2020-03-25 19:40:09Z vboxsync $ */
2/** @file
3 * IPRT - Fuzzing framework API, core.
4 */
5
6/*
7 * Copyright (C) 2018-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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/critsect.h>
38#include <iprt/ctype.h>
39#include <iprt/dir.h>
40#include <iprt/err.h>
41#include <iprt/file.h>
42#include <iprt/list.h>
43#include <iprt/md5.h>
44#include <iprt/mem.h>
45#include <iprt/path.h>
46#include <iprt/rand.h>
47#include <iprt/semaphore.h>
48#include <iprt/string.h>
49#include <iprt/time.h>
50#include <iprt/vfs.h>
51
52
53#define RTFUZZCTX_MAGIC UINT32_C(0xdeadc0de) /** @todo */
54
55
56/*********************************************************************************************************************************
57* Structures and Typedefs *
58*********************************************************************************************************************************/
59/** Pointer to the internal fuzzer state. */
60typedef struct RTFUZZCTXINT *PRTFUZZCTXINT;
61/** Pointer to a fuzzed mutation. */
62typedef struct RTFUZZMUTATION *PRTFUZZMUTATION;
63/** Pointer to a fuzzed mutation pointer. */
64typedef PRTFUZZMUTATION *PPRTFUZZMUTATION;
65/** Pointer to a const mutation. */
66typedef const struct RTFUZZMUTATION *PCRTFUZZMUTATION;
67
68
69/**
70 * Mutator class.
71 */
72typedef enum RTFUZZMUTATORCLASS
73{
74 /** Invalid class, do not use. */
75 RTFUZZMUTATORCLASS_INVALID = 0,
76 /** Mutator operates on single bits. */
77 RTFUZZMUTATORCLASS_BITS,
78 /** Mutator operates on bytes (single or multiple). */
79 RTFUZZMUTATORCLASS_BYTES,
80 /** Mutator interpretes data as integers and operates on them. */
81 RTFUZZMUTATORCLASS_INTEGERS,
82 /** Mutator uses multiple mutations to create new mutations. */
83 RTFUZZMUTATORCLASS_MUTATORS,
84 /** 32bit hack. */
85 RTFUZZMUTATORCLASS_32BIT_HACK = 0x7fffffff
86} RTFUZZMUTATORCLASS;
87
88
89/**
90 * Mutator preparation callback.
91 *
92 * @returns IPRT status code.
93 * @param pThis The fuzzer context instance.
94 * @param offStart Where the mutation should start.
95 * @param pMutationParent The parent mutation to start working from.
96 * @param ppMutation Where to store the created mutation on success.
97 */
98typedef DECLCALLBACK(int) FNRTFUZZCTXMUTATORPREP(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
99 PPRTFUZZMUTATION ppMutation);
100/** Pointer to a mutator preparation callback. */
101typedef FNRTFUZZCTXMUTATORPREP *PFNRTFUZZCTXMUTATORPREP;
102
103
104/**
105 * Mutator execution callback.
106 *
107 * @returns IPRT status code.
108 * @param pThis The fuzzer context instance.
109 * @param pMutation The mutation to work on.
110 * @param pvMutation Mutation dependent data.
111 * @param pbBuf The buffer to work on.
112 * @param cbBuf Size of the remaining buffer.
113 */
114typedef DECLCALLBACK(int) FNRTFUZZCTXMUTATOREXEC(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
115 uint8_t *pbBuf, size_t cbBuf);
116/** Pointer to a mutator execution callback. */
117typedef FNRTFUZZCTXMUTATOREXEC *PFNRTFUZZCTXMUTATOREXEC;
118
119
120/**
121 * Mutator export callback.
122 *
123 * @returns IPRT status code.
124 * @param pThis The fuzzer context instance.
125 * @param pMutation The mutation to work on.
126 * @param pvMutation Mutation dependent data.
127 * @param pfnExport The export callback.
128 * @param pvUser Opaque user data to pass to the export callback.
129 */
130typedef DECLCALLBACK(int) FNRTFUZZCTXMUTATOREXPORT(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
131 PFNRTFUZZCTXEXPORT pfnExport, void *pvUser);
132/** Pointer to a mutator export callback. */
133typedef FNRTFUZZCTXMUTATOREXPORT *PFNRTFUZZCTXMUTATOREXPORT;
134
135
136/**
137 * Mutator import callback.
138 *
139 * @returns IPRT status code.
140 * @param pThis The fuzzer context instance.
141 * @param pMutation The mutation to work on.
142 * @param pvMutation Mutation dependent data.
143 * @param pfnExport The import callback.
144 * @param pvUser Opaque user data to pass to the import callback.
145 */
146typedef DECLCALLBACK(int) FNRTFUZZCTXMUTATORIMPORT(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, void *pvMutation,
147 PFNRTFUZZCTXIMPORT pfnImport, void *pvUser);
148/** Pointer to a mutator import callback. */
149typedef FNRTFUZZCTXMUTATORIMPORT *PFNRTFUZZCTXMUTATORIMPORT;
150
151
152/**
153 * A fuzzing mutator descriptor.
154 */
155typedef struct RTFUZZMUTATOR
156{
157 /** Id of the mutator. */
158 const char *pszId;
159 /** Mutator description. */
160 const char *pszDesc;
161 /** Mutator index. */
162 uint32_t uMutator;
163 /** Mutator class. */
164 RTFUZZMUTATORCLASS enmClass;
165 /** Additional flags for the mutator, controlling the behavior. */
166 uint64_t fFlags;
167 /** The preparation callback. */
168 PFNRTFUZZCTXMUTATORPREP pfnPrep;
169 /** The execution callback. */
170 PFNRTFUZZCTXMUTATOREXEC pfnExec;
171 /** The export callback. */
172 PFNRTFUZZCTXMUTATOREXPORT pfnExport;
173 /** The import callback. */
174 PFNRTFUZZCTXMUTATORIMPORT pfnImport;
175} RTFUZZMUTATOR;
176/** Pointer to a fuzzing mutator descriptor. */
177typedef RTFUZZMUTATOR *PRTFUZZMUTATOR;
178/** Pointer to a const fuzzing mutator descriptor. */
179typedef const RTFUZZMUTATOR *PCRTFUZZMUTATOR;
180
181/** The special corpus mutator. */
182#define RTFUZZMUTATOR_ID_CORPUS UINT32_C(0xffffffff)
183
184/** Mutator always works from the end of the buffer (no starting offset generation). */
185#define RTFUZZMUTATOR_F_END_OF_BUF RT_BIT_64(0)
186/** Default flags. */
187#define RTFUZZMUTATOR_F_DEFAULT (0)
188
189
190/**
191 * A fuzzed mutation.
192 */
193typedef struct RTFUZZMUTATION
194{
195 /** The AVL tree core. */
196 AVLU64NODECORE Core;
197 /** The list node if the mutation has the mutated
198 * data allocated. */
199 RTLISTNODE NdAlloc;
200 /** Magic identifying this structure. */
201 uint32_t u32Magic;
202 /** Reference counter. */
203 volatile uint32_t cRefs;
204 /** The fuzzer this mutation belongs to. */
205 PRTFUZZCTXINT pFuzzer;
206 /** Parent mutation (no reference is held), NULL means root or original data. */
207 PRTFUZZMUTATION pMutationParent;
208 /** Start offset where new mutations are allowed to start. */
209 uint64_t offMutStartNew;
210 /** Size of the range in bytes where mutations are allowed to happen. */
211 uint64_t cbMutNew;
212 /** Mutation level. */
213 uint32_t iLvl;
214 /** The mutator causing this mutation, NULL if original input data. */
215 PCRTFUZZMUTATOR pMutator;
216 /** Byte offset where the mutation starts. */
217 uint64_t offMutation;
218 /** Size of the generated input data in bytes after the mutation was applied. */
219 size_t cbInput;
220 /** Size of the mutation dependent data. */
221 size_t cbMutation;
222 /** Size allocated for the input. */
223 size_t cbAlloc;
224 /** Pointer to the input data if created. */
225 void *pvInput;
226 /** Flag whether the mutation is contained in the tree of the context. */
227 bool fInTree;
228 /** Flag whether the mutation input data is cached. */
229 bool fCached;
230 /** Mutation dependent data, variable in size. */
231 uint8_t abMutation[1];
232} RTFUZZMUTATION;
233
234
235/**
236 * A fuzzing input seed.
237 */
238typedef struct RTFUZZINPUTINT
239{
240 /** Magic identifying this structure. */
241 uint32_t u32Magic;
242 /** Reference counter. */
243 volatile uint32_t cRefs;
244 /** The fuzzer this input belongs to. */
245 PRTFUZZCTXINT pFuzzer;
246 /** The top mutation to work from (reference held). */
247 PRTFUZZMUTATION pMutationTop;
248 /** Fuzzer context type dependent data. */
249 union
250 {
251 /** Blob data. */
252 struct
253 {
254 /** Pointer to the input data if created. */
255 void *pvInput;
256 } Blob;
257 /** Stream state. */
258 struct
259 {
260 /** Number of bytes seen so far. */
261 size_t cbSeen;
262 } Stream;
263 } u;
264} RTFUZZINPUTINT;
265/** Pointer to the internal input state. */
266typedef RTFUZZINPUTINT *PRTFUZZINPUTINT;
267/** Pointer to an internal input state pointer. */
268typedef PRTFUZZINPUTINT *PPRTFUZZINPUTINT;
269
270
271/**
272 * The fuzzer state.
273 */
274typedef struct RTFUZZCTXINT
275{
276 /** Magic value for identification. */
277 uint32_t u32Magic;
278 /** Reference counter. */
279 volatile uint32_t cRefs;
280 /** The random number generator. */
281 RTRAND hRand;
282 /** Fuzzing context type. */
283 RTFUZZCTXTYPE enmType;
284 /** Semaphore protecting the mutations tree. */
285 RTSEMRW hSemRwMutations;
286 /** The AVL tree for indexing the mutations (keyed by counter). */
287 AVLU64TREE TreeMutations;
288 /** Number of inputs currently in the tree. */
289 volatile uint64_t cMutations;
290 /** The maximum size of one input seed to generate. */
291 size_t cbInputMax;
292 /** Behavioral flags. */
293 uint32_t fFlagsBehavioral;
294 /** Number of enabled mutators. */
295 uint32_t cMutators;
296 /** Pointer to the mutator descriptors. */
297 PRTFUZZMUTATOR paMutators;
298 /** Maximum amount of bytes of mutated inputs to cache. */
299 size_t cbMutationsAllocMax;
300 /** Current amount of bytes of cached mutated inputs. */
301 size_t cbMutationsAlloc;
302 /** List of mutators having data allocated currently. */
303 RTLISTANCHOR LstMutationsAlloc;
304 /** Critical section protecting the allocation list. */
305 RTCRITSECT CritSectAlloc;
306 /** Total number of bytes of memory currently allocated in total for this context. */
307 volatile size_t cbMemTotal;
308 /** Start offset in the input where a mutation is allowed to happen. */
309 uint64_t offMutStart;
310 /** size of the range where a mutation can happen. */
311 uint64_t cbMutRange;
312} RTFUZZCTXINT;
313
314
315/**
316 * The fuzzer state to be exported - all members are stored in little endian form.
317 */
318typedef struct RTFUZZCTXSTATE
319{
320 /** Magic value for identification. */
321 uint32_t u32Magic;
322 /** Context type. */
323 uint32_t uCtxType;
324 /** Size of the PRNG state following in bytes. */
325 uint32_t cbPrng;
326 /** Number of mutator descriptors following. */
327 uint32_t cMutators;
328 /** Number of mutation descriptors following. */
329 uint32_t cMutations;
330 /** Behavioral flags. */
331 uint32_t fFlagsBehavioral;
332 /** Maximum input size to generate. */
333 uint64_t cbInputMax;
334} RTFUZZCTXSTATE;
335/** Pointer to a fuzzing context state. */
336typedef RTFUZZCTXSTATE *PRTFUZZCTXSTATE;
337
338/** BLOB context type. */
339#define RTFUZZCTX_STATE_TYPE_BLOB UINT32_C(0)
340/** Stream context type. */
341#define RTFUZZCTX_STATE_TYPE_STREAM UINT32_C(1)
342
343
344/**
345 * The fuzzer mutation state to be exported - all members are stored in little endian form.
346 */
347typedef struct RTFUZZMUTATIONSTATE
348{
349 /** The mutation identifier. */
350 uint64_t u64Id;
351 /** The mutation identifier of the parent, 0 for no parent. */
352 uint64_t u64IdParent;
353 /** The byte offset where the mutation starts. */
354 uint64_t u64OffMutation;
355 /** Size of input data after mutation was applied. */
356 uint64_t cbInput;
357 /** Size of mutation dependent data following. */
358 uint64_t cbMutation;
359 /** The mutator ID. */
360 uint32_t u32IdMutator;
361 /** The mutation level. */
362 uint32_t iLvl;
363 /** Magic value for identification. */
364 uint32_t u32Magic;
365} RTFUZZMUTATIONSTATE;
366
367
368/**
369 * Fuzzing context memory header.
370 */
371typedef struct RTFUZZMEMHDR
372{
373 /** Size of the memory area following. */
374 size_t cb;
375#if HC_ARCH_BITS == 32
376 /** Some padding. */
377 uint32_t uPadding0;
378#elif HC_ARCH_BITS == 64
379 /** Some padding. */
380 uint64_t uPadding0;
381#else
382# error "Port me"
383#endif
384} RTFUZZMEMHDR;
385/** Pointer to a memory header. */
386typedef RTFUZZMEMHDR *PRTFUZZMEMHDR;
387
388
389/**
390 * Fuzzing context export AVL arguments.
391 */
392typedef struct RTFUZZEXPORTARGS
393{
394 /** Pointer to the export callback. */
395 PFNRTFUZZCTXEXPORT pfnExport;
396 /** Opaque user data to pass to the callback. */
397 void *pvUser;
398} RTFUZZEXPORTARGS;
399/** Pointer to the export arguments. */
400typedef RTFUZZEXPORTARGS *PRTFUZZEXPORTARGS;
401/** Pointer to the constant export arguments. */
402typedef const RTFUZZEXPORTARGS *PCRTFUZZEXPORTARGS;
403
404
405/**
406 * Integer replacing mutator additional data.
407 */
408typedef struct RTFUZZMUTATORINTEGER
409{
410 /** The integer class. */
411 uint8_t uIntClass;
412 /** Flag whether to do a byte swap. */
413 bool fByteSwap;
414 /** The index into the class specific array. */
415 uint16_t idxInt;
416} RTFUZZMUTATORINTEGER;
417/** Pointer to additional integer replacing mutator data. */
418typedef RTFUZZMUTATORINTEGER *PRTFUZZMUTATORINTEGER;
419/** Pointer to constant additional integer replacing mutator data. */
420typedef const RTFUZZMUTATORINTEGER *PCRTFUZZMUTATORINTEGER;
421
422
423/*********************************************************************************************************************************
424* Internal Functions *
425*********************************************************************************************************************************/
426static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlipPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
427 PPRTFUZZMUTATION ppMutation);
428static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplacePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
429 PPRTFUZZMUTATION ppMutation);
430static DECLCALLBACK(int) rtFuzzCtxMutatorByteInsertPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
431 PPRTFUZZMUTATION ppMutation);
432static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsertAppendPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
433 PPRTFUZZMUTATION ppMutation);
434static DECLCALLBACK(int) rtFuzzCtxMutatorByteDeletePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
435 PPRTFUZZMUTATION ppMutation);
436static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDeletePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
437 PPRTFUZZMUTATION ppMutation);
438static DECLCALLBACK(int) rtFuzzCtxMutatorIntegerReplacePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
439 PPRTFUZZMUTATION ppMutation);
440static DECLCALLBACK(int) rtFuzzCtxMutatorCrossoverPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
441 PPRTFUZZMUTATION ppMutation);
442
443static DECLCALLBACK(int) rtFuzzCtxMutatorCorpusExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
444 uint8_t *pbBuf, size_t cbBuf);
445static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlipExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
446 uint8_t *pbBuf, size_t cbBuf);
447static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplaceExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
448 uint8_t *pbBuf, size_t cbBuf);
449static DECLCALLBACK(int) rtFuzzCtxMutatorByteInsertExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
450 uint8_t *pbBuf, size_t cbBuf);
451static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsertAppendExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
452 uint8_t *pbBuf, size_t cbBuf);
453static DECLCALLBACK(int) rtFuzzCtxMutatorByteDeleteExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
454 uint8_t *pbBuf, size_t cbBuf);
455static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDeleteExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
456 uint8_t *pbBuf, size_t cbBuf);
457static DECLCALLBACK(int) rtFuzzCtxMutatorIntegerReplaceExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
458 uint8_t *pbBuf, size_t cbBuf);
459static DECLCALLBACK(int) rtFuzzCtxMutatorCrossoverExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
460 uint8_t *pbBuf, size_t cbBuf);
461
462static DECLCALLBACK(int) rtFuzzCtxMutatorExportDefault(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
463 PFNRTFUZZCTXEXPORT pfnExport, void *pvUser);
464static DECLCALLBACK(int) rtFuzzCtxMutatorImportDefault(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, void *pvMutation,
465 PFNRTFUZZCTXIMPORT pfnImport, void *pvUser);
466
467static DECLCALLBACK(int) rtFuzzCtxMutatorCrossoverExport(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
468 PFNRTFUZZCTXEXPORT pfnExport, void *pvUser);
469static DECLCALLBACK(int) rtFuzzCtxMutatorCrossoverImport(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, void *pvMutation,
470 PFNRTFUZZCTXIMPORT pfnImport, void *pvUser);
471
472
473/*********************************************************************************************************************************
474* Global Variables *
475*********************************************************************************************************************************/
476
477/** Signed 8bit interesting values. */
478static int8_t s_ai8Interesting[] = { INT8_MIN, INT8_MIN + 1, -1, 0, 1, INT8_MAX - 1, INT8_MAX };
479/** Unsigned 8bit interesting values. */
480static uint8_t s_au8Interesting[] = { 0, 1, UINT8_MAX - 1, UINT8_MAX };
481/** Signed 16bit interesting values. */
482static int16_t s_ai16Interesting[] = { INT16_MIN, INT16_MIN + 1, -1, 0, 1, INT16_MAX - 1, INT16_MAX };
483/** Unsigned 16bit interesting values. */
484static uint16_t s_au16Interesting[] = { 0, 1, UINT16_MAX - 1, UINT16_MAX };
485/** Signed 32bit interesting values. */
486static int32_t s_ai32Interesting[] = { INT32_MIN, INT32_MIN + 1, -1, 0, 1, INT32_MAX - 1, INT32_MAX };
487/** Unsigned 32bit interesting values. */
488static uint32_t s_au32Interesting[] = { 0, 1, UINT32_MAX - 1, UINT32_MAX };
489/** Signed 64bit interesting values. */
490static int64_t s_ai64Interesting[] = { INT64_MIN, INT64_MIN + 1, -1, 0, 1, INT64_MAX - 1, INT64_MAX };
491/** Unsigned 64bit interesting values. */
492static uint64_t s_au64Interesting[] = { 0, 1, UINT64_MAX - 1, UINT64_MAX };
493
494
495/**
496 * The special corpus mutator for the original data.
497 */
498static RTFUZZMUTATOR const g_MutatorCorpus =
499{
500 /** pszId */
501 "Corpus",
502 /** pszDesc */
503 "Special mutator, which is assigned to the initial corpus",
504 /** uMutator. */
505 RTFUZZMUTATOR_ID_CORPUS,
506 /** enmClass. */
507 RTFUZZMUTATORCLASS_BYTES,
508 /** fFlags */
509 RTFUZZMUTATOR_F_DEFAULT,
510 /** pfnPrep */
511 NULL,
512 /** pfnExec */
513 rtFuzzCtxMutatorCorpusExec,
514 /** pfnExport */
515 rtFuzzCtxMutatorExportDefault,
516 /** pfnImport */
517 rtFuzzCtxMutatorImportDefault
518};
519
520/**
521 * Array of all available mutators.
522 */
523static RTFUZZMUTATOR const g_aMutators[] =
524{
525 /* pszId pszDesc uMutator enmClass fFlags pfnPrep pfnExec pfnExport pfnImport */
526 { "BitFlip", "Flips a single bit in the input", 0, RTFUZZMUTATORCLASS_BITS, RTFUZZMUTATOR_F_DEFAULT, rtFuzzCtxMutatorBitFlipPrep, rtFuzzCtxMutatorBitFlipExec, rtFuzzCtxMutatorExportDefault, rtFuzzCtxMutatorImportDefault },
527 { "ByteReplace", "Replaces a single byte in the input", 1, RTFUZZMUTATORCLASS_BYTES, RTFUZZMUTATOR_F_DEFAULT, rtFuzzCtxMutatorByteReplacePrep, rtFuzzCtxMutatorByteReplaceExec, rtFuzzCtxMutatorExportDefault, rtFuzzCtxMutatorImportDefault },
528 { "ByteInsert", "Inserts a single byte sequence into the input", 2, RTFUZZMUTATORCLASS_BYTES, RTFUZZMUTATOR_F_DEFAULT, rtFuzzCtxMutatorByteInsertPrep, rtFuzzCtxMutatorByteInsertExec, rtFuzzCtxMutatorExportDefault, rtFuzzCtxMutatorImportDefault },
529 { "ByteSeqIns", "Inserts a byte sequence in the input", 3, RTFUZZMUTATORCLASS_BYTES, RTFUZZMUTATOR_F_DEFAULT, rtFuzzCtxMutatorByteSequenceInsertAppendPrep, rtFuzzCtxMutatorByteSequenceInsertAppendExec, rtFuzzCtxMutatorExportDefault, rtFuzzCtxMutatorImportDefault },
530 { "ByteSeqApp", "Appends a byte sequence to the input", 4, RTFUZZMUTATORCLASS_BYTES, RTFUZZMUTATOR_F_END_OF_BUF, rtFuzzCtxMutatorByteSequenceInsertAppendPrep, rtFuzzCtxMutatorByteSequenceInsertAppendExec, rtFuzzCtxMutatorExportDefault, rtFuzzCtxMutatorImportDefault },
531 { "ByteDelete", "Deletes a single byte sequence from the input", 5, RTFUZZMUTATORCLASS_BYTES, RTFUZZMUTATOR_F_DEFAULT, rtFuzzCtxMutatorByteDeletePrep, rtFuzzCtxMutatorByteDeleteExec, NULL, NULL },
532 { "ByteSeqDel", "Deletes a byte sequence from the input", 6, RTFUZZMUTATORCLASS_BYTES, RTFUZZMUTATOR_F_DEFAULT, rtFuzzCtxMutatorByteSequenceDeletePrep, rtFuzzCtxMutatorByteSequenceDeleteExec, NULL, NULL },
533 { "IntReplace", "Replaces a possible integer with an interesting one", 7, RTFUZZMUTATORCLASS_INTEGERS, RTFUZZMUTATOR_F_DEFAULT, rtFuzzCtxMutatorIntegerReplacePrep, rtFuzzCtxMutatorIntegerReplaceExec, rtFuzzCtxMutatorExportDefault, rtFuzzCtxMutatorImportDefault },
534 { "MutCrossover", "Creates a crossover of two other mutations", 8, RTFUZZMUTATORCLASS_MUTATORS, RTFUZZMUTATOR_F_DEFAULT, rtFuzzCtxMutatorCrossoverPrep, rtFuzzCtxMutatorCrossoverExec, rtFuzzCtxMutatorCrossoverExport, rtFuzzCtxMutatorCrossoverImport }
535};
536
537
538/**
539 * Allocates the given number of bytes.
540 *
541 * @returns Pointer to the allocated memory
542 * @param pThis The fuzzer context instance.
543 * @param cb How much to allocate.
544 */
545static void *rtFuzzCtxMemoryAlloc(PRTFUZZCTXINT pThis, size_t cb)
546{
547 AssertReturn(cb > 0, NULL);
548
549 PRTFUZZMEMHDR pMemHdr = (PRTFUZZMEMHDR)RTMemAllocZ(cb + sizeof(RTFUZZMEMHDR));
550 if (RT_LIKELY(pMemHdr))
551 {
552 pMemHdr->cb = cb;
553 size_t cbIgn = ASMAtomicAddZ(&pThis->cbMemTotal, cb + sizeof(RTFUZZMEMHDR)); RT_NOREF(cbIgn);
554 return pMemHdr + 1;
555 }
556
557 return NULL;
558}
559
560
561/**
562 * Frees the given memory.
563 *
564 * @returns nothing.
565 * @param pThis The fuzzer context instance.
566 * @param pv Pointer to the memory area to free.
567 */
568static void rtFuzzCtxMemoryFree(PRTFUZZCTXINT pThis, void *pv)
569{
570 AssertReturnVoid(pv != NULL);
571 PRTFUZZMEMHDR pMemHdr = ((PRTFUZZMEMHDR)pv) - 1;
572
573 size_t cbIgn = ASMAtomicSubZ(&pThis->cbMemTotal, pMemHdr->cb + sizeof(RTFUZZMEMHDR)); RT_NOREF(cbIgn);
574 RTMemFree(pMemHdr);
575}
576
577
578/**
579 * Frees the cached inputs until the given amount is free.
580 *
581 * @returns Whether the amount of memory is free.
582 * @param pThis The fuzzer context instance.
583 * @param cb How many bytes to reclaim
584 */
585static bool rtFuzzCtxMutationAllocReclaim(PRTFUZZCTXINT pThis, size_t cb)
586{
587 while ( !RTListIsEmpty(&pThis->LstMutationsAlloc)
588 && pThis->cbMutationsAlloc + cb > pThis->cbMutationsAllocMax)
589 {
590 PRTFUZZMUTATION pMutation = RTListGetLast(&pThis->LstMutationsAlloc, RTFUZZMUTATION, NdAlloc);
591 AssertPtr(pMutation);
592 AssertPtr(pMutation->pvInput);
593
594 rtFuzzCtxMemoryFree(pThis, pMutation->pvInput);
595 pThis->cbMutationsAlloc -= pMutation->cbAlloc;
596 pMutation->pvInput = NULL;
597 pMutation->cbAlloc = 0;
598 pMutation->fCached = false;
599 RTListNodeRemove(&pMutation->NdAlloc);
600 }
601
602 return pThis->cbMutationsAlloc + cb <= pThis->cbMutationsAllocMax;
603}
604
605
606/**
607 * Updates the cache status of the given mutation.
608 *
609 * @returns nothing.
610 * @param pThis The fuzzer context instance.
611 * @param pMutation The mutation to update.
612 */
613static void rtFuzzCtxMutationMaybeEnterCache(PRTFUZZCTXINT pThis, PRTFUZZMUTATION pMutation)
614{
615 RTCritSectEnter(&pThis->CritSectAlloc);
616
617 /* Initial corpus mutations are not freed. */
618 if ( pMutation->pvInput
619 && pMutation->pMutator != &g_MutatorCorpus)
620 {
621 Assert(!pMutation->fCached);
622
623 if (rtFuzzCtxMutationAllocReclaim(pThis, pMutation->cbAlloc))
624 {
625 RTListPrepend(&pThis->LstMutationsAlloc, &pMutation->NdAlloc);
626 pThis->cbMutationsAlloc += pMutation->cbAlloc;
627 pMutation->fCached = true;
628 }
629 else
630 {
631 rtFuzzCtxMemoryFree(pThis, pMutation->pvInput);
632 pMutation->pvInput = NULL;
633 pMutation->cbAlloc = 0;
634 pMutation->fCached = false;
635 }
636 }
637 RTCritSectLeave(&pThis->CritSectAlloc);
638}
639
640
641/**
642 * Removes a cached mutation from the cache.
643 *
644 * @returns nothing.
645 * @param pThis The fuzzer context instance.
646 * @param pMutation The mutation to remove.
647 */
648static void rtFuzzCtxMutationCacheRemove(PRTFUZZCTXINT pThis, PRTFUZZMUTATION pMutation)
649{
650 RTCritSectEnter(&pThis->CritSectAlloc);
651 if (pMutation->fCached)
652 {
653 RTListNodeRemove(&pMutation->NdAlloc);
654 pThis->cbMutationsAlloc -= pMutation->cbAlloc;
655 pMutation->fCached = false;
656 }
657 RTCritSectLeave(&pThis->CritSectAlloc);
658}
659
660
661/**
662 * Destroys the given mutation.
663 *
664 * @returns nothing.
665 * @param pMutation The mutation to destroy.
666 */
667static void rtFuzzMutationDestroy(PRTFUZZMUTATION pMutation)
668{
669 if (pMutation->pvInput)
670 {
671 rtFuzzCtxMemoryFree(pMutation->pFuzzer, pMutation->pvInput);
672 if (pMutation->fCached)
673 {
674 RTCritSectEnter(&pMutation->pFuzzer->CritSectAlloc);
675 RTListNodeRemove(&pMutation->NdAlloc);
676 pMutation->pFuzzer->cbMutationsAlloc -= pMutation->cbAlloc;
677 RTCritSectLeave(&pMutation->pFuzzer->CritSectAlloc);
678 }
679 pMutation->pvInput = NULL;
680 pMutation->cbAlloc = 0;
681 pMutation->fCached = false;
682 }
683 rtFuzzCtxMemoryFree(pMutation->pFuzzer, pMutation);
684}
685
686
687/**
688 * Retains an external reference to the given mutation.
689 *
690 * @returns New reference count on success.
691 * @param pMutation The mutation to retain.
692 */
693static uint32_t rtFuzzMutationRetain(PRTFUZZMUTATION pMutation)
694{
695 uint32_t cRefs = ASMAtomicIncU32(&pMutation->cRefs);
696 AssertMsg( ( cRefs > 1
697 || pMutation->fInTree)
698 && cRefs < _1M, ("%#x %p\n", cRefs, pMutation));
699
700 if (cRefs == 1)
701 rtFuzzCtxMutationCacheRemove(pMutation->pFuzzer, pMutation);
702 return cRefs;
703}
704
705
706/**
707 * Releases an external reference from the given mutation.
708 *
709 * @returns New reference count on success.
710 * @param pMutation The mutation to retain.
711 */
712static uint32_t rtFuzzMutationRelease(PRTFUZZMUTATION pMutation)
713{
714 uint32_t cRefs = ASMAtomicDecU32(&pMutation->cRefs);
715 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pMutation));
716
717 if (cRefs == 0)
718 {
719 if (!pMutation->fInTree)
720 rtFuzzMutationDestroy(pMutation);
721 else
722 rtFuzzCtxMutationMaybeEnterCache(pMutation->pFuzzer, pMutation);
723 }
724
725 return cRefs;
726}
727
728
729/**
730 * Adds the given mutation to the corpus of the given fuzzer context.
731 *
732 * @returns IPRT status code.
733 * @param pThis The fuzzer context instance.
734 * @param pMutation The mutation to add.
735 */
736static int rtFuzzCtxMutationAdd(PRTFUZZCTXINT pThis, PRTFUZZMUTATION pMutation)
737{
738 int rc = VINF_SUCCESS;
739
740 pMutation->Core.Key = ASMAtomicIncU64(&pThis->cMutations);
741 rc = RTSemRWRequestWrite(pThis->hSemRwMutations, RT_INDEFINITE_WAIT);
742 AssertRC(rc); RT_NOREF(rc);
743 bool fIns = RTAvlU64Insert(&pThis->TreeMutations, &pMutation->Core);
744 Assert(fIns); RT_NOREF(fIns);
745 rc = RTSemRWReleaseWrite(pThis->hSemRwMutations);
746 AssertRC(rc); RT_NOREF(rc);
747
748 pMutation->fInTree = true;
749 return rc;
750}
751
752
753/**
754 * Locates the mutation with the given key.
755 *
756 * @returns Pointer to the mutation if found or NULL otherwise.
757 * @param pThis The fuzzer context instance.
758 * @param uKey The key to locate.
759 */
760static PRTFUZZMUTATION rtFuzzCtxMutationLocate(PRTFUZZCTXINT pThis, uint64_t uKey)
761{
762 int rc = RTSemRWRequestRead(pThis->hSemRwMutations, RT_INDEFINITE_WAIT);
763 AssertRC(rc); RT_NOREF(rc);
764
765 /*
766 * Using best fit getter here as there might be a racing mutation insertion and the mutation counter has increased
767 * already but the mutation is not yet in the tree.
768 */
769 PRTFUZZMUTATION pMutation = (PRTFUZZMUTATION)RTAvlU64GetBestFit(&pThis->TreeMutations, uKey, false /*fAbove*/);
770 if (RT_LIKELY(pMutation))
771 rtFuzzMutationRetain(pMutation);
772
773 rc = RTSemRWReleaseRead(pThis->hSemRwMutations);
774 AssertRC(rc); RT_NOREF(rc);
775
776 return pMutation;
777}
778
779
780/**
781 * Returns a random mutation from the corpus of the given fuzzer context.
782 *
783 * @returns Pointer to a randomly picked mutation (reference count is increased).
784 * @param pThis The fuzzer context instance.
785 */
786static PRTFUZZMUTATION rtFuzzCtxMutationPickRnd(PRTFUZZCTXINT pThis)
787{
788 uint64_t idxMutation = RTRandAdvU64Ex(pThis->hRand, 1, ASMAtomicReadU64(&pThis->cMutations));
789 return rtFuzzCtxMutationLocate(pThis, idxMutation);
790}
791
792
793/**
794 * Creates a new mutation capable of holding the additional number of bytes - extended version.
795 *
796 * @returns Pointer to the newly created mutation or NULL if out of memory.
797 * @param pThis The fuzzer context instance.
798 * @param offMutation The starting offset for the mutation.
799 * @param pMutationParent The parent mutation, can be NULL.
800 * @param offMuStartNew Offset where descendants of the created mutation can start to mutate.
801 * @param cbMutNew Range in bytes where descendants of the created mutation can mutate.c
802 * @param cbAdditional Additional number of bytes to allocate after the core structure.
803 * @param ppvMutation Where to store the pointer to the mutation dependent data on success.
804 */
805static PRTFUZZMUTATION rtFuzzMutationCreateEx(PRTFUZZCTXINT pThis, uint64_t offMutation, PRTFUZZMUTATION pMutationParent,
806 uint64_t offMutStartNew, uint64_t cbMutNew, size_t cbAdditional, void **ppvMutation)
807{
808 PRTFUZZMUTATION pMutation = (PRTFUZZMUTATION)rtFuzzCtxMemoryAlloc(pThis, sizeof(RTFUZZMUTATION) + cbAdditional);
809 if (RT_LIKELY(pMutation))
810 {
811 pMutation->u32Magic = 0; /** @todo */
812 pMutation->pFuzzer = pThis;
813 pMutation->cRefs = 1;
814 pMutation->iLvl = 0;
815 pMutation->offMutation = offMutation;
816 pMutation->pMutationParent = pMutationParent;
817 pMutation->offMutStartNew = offMutStartNew;
818 pMutation->cbMutNew = cbMutNew;
819 pMutation->cbMutation = cbAdditional;
820 pMutation->fInTree = false;
821 pMutation->fCached = false;
822 pMutation->pvInput = NULL;
823 pMutation->cbInput = 0;
824 pMutation->cbAlloc = 0;
825
826 if (pMutationParent)
827 pMutation->iLvl = pMutationParent->iLvl + 1;
828 if (ppvMutation)
829 *ppvMutation = &pMutation->abMutation[0];
830 }
831
832 return pMutation;
833}
834
835
836/**
837 * Creates a new mutation capable of holding the additional number of bytes.
838 *
839 * @returns Pointer to the newly created mutation or NULL if out of memory.
840 * @param pThis The fuzzer context instance.
841 * @param offMutation The starting offset for the mutation.
842 * @param pMutationParent The parent mutation, can be NULL.
843 * @param cbAdditional Additional number of bytes to allocate after the core structure.
844 * @param ppvMutation Where to store the pointer to the mutation dependent data on success.
845 */
846DECLINLINE(PRTFUZZMUTATION) rtFuzzMutationCreate(PRTFUZZCTXINT pThis, uint64_t offMutation, PRTFUZZMUTATION pMutationParent,
847 size_t cbAdditional, void **ppvMutation)
848{
849 uint64_t offMutNew = pMutationParent ? pMutationParent->offMutStartNew : pThis->offMutStart;
850 uint64_t cbMutNew = pMutationParent ? pMutationParent->cbMutNew : pThis->cbMutRange;
851
852 return rtFuzzMutationCreateEx(pThis, offMutation, pMutationParent, offMutNew, cbMutNew, cbAdditional, ppvMutation);
853}
854
855
856/**
857 * Destroys the given fuzzer context freeing all allocated resources.
858 *
859 * @returns nothing.
860 * @param pThis The fuzzer context instance.
861 */
862static void rtFuzzCtxDestroy(PRTFUZZCTXINT pThis)
863{
864 RT_NOREF(pThis);
865}
866
867
868/**
869 * Creates the final input data applying all accumulated mutations.
870 *
871 * @returns IPRT status code.
872 * @param pMutation The mutation to finalize.
873 */
874static int rtFuzzMutationDataFinalize(PRTFUZZMUTATION pMutation)
875{
876 if (pMutation->pvInput)
877 return VINF_SUCCESS;
878
879 /* Traverse the mutations top to bottom and insert into the array. */
880 int rc = VINF_SUCCESS;
881 uint32_t idx = pMutation->iLvl + 1;
882 PRTFUZZMUTATION *papMutations = (PRTFUZZMUTATION *)RTMemTmpAlloc(idx * sizeof(PCRTFUZZMUTATION));
883 if (RT_LIKELY(papMutations))
884 {
885 PRTFUZZMUTATION pMutationCur = pMutation;
886 size_t cbAlloc = 0;
887
888 /*
889 * As soon as a mutation with allocated input data is encountered the insertion is
890 * stopped as it contains all necessary mutated inputs we can start from.
891 */
892 while (idx > 0)
893 {
894 rtFuzzMutationRetain(pMutationCur);
895 papMutations[idx - 1] = pMutationCur;
896 cbAlloc = RT_MAX(cbAlloc, pMutationCur->cbInput);
897 if (pMutationCur->pvInput)
898 {
899 idx--;
900 break;
901 }
902 pMutationCur = pMutationCur->pMutationParent;
903 idx--;
904 }
905
906 pMutation->cbAlloc = cbAlloc;
907 uint8_t *pbBuf = (uint8_t *)rtFuzzCtxMemoryAlloc(pMutation->pFuzzer, cbAlloc);
908 if (RT_LIKELY(pbBuf))
909 {
910 pMutation->pvInput = pbBuf;
911
912 /* Copy the initial input data. */
913 size_t cbInputNow = papMutations[idx]->cbInput;
914 memcpy(pbBuf, papMutations[idx]->pvInput, cbInputNow);
915 rtFuzzMutationRelease(papMutations[idx]);
916
917 for (uint32_t i = idx + 1; i < pMutation->iLvl + 1; i++)
918 {
919 PRTFUZZMUTATION pCur = papMutations[i];
920 pCur->pMutator->pfnExec(pCur->pFuzzer, pCur, (void *)&pCur->abMutation[0],
921 pbBuf + pCur->offMutation,
922 cbInputNow - pCur->offMutation);
923
924 cbInputNow = pCur->cbInput;
925 rtFuzzMutationRelease(pCur);
926 }
927
928 Assert(cbInputNow == pMutation->cbInput);
929 }
930 else
931 rc = VERR_NO_MEMORY;
932
933 RTMemTmpFree(papMutations);
934 }
935 else
936 rc = VERR_NO_MEMORY;
937
938 return rc;
939}
940
941
942/**
943 * Default mutator export callback (just writing the raw data).
944 */
945static DECLCALLBACK(int) rtFuzzCtxMutatorExportDefault(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
946 PFNRTFUZZCTXEXPORT pfnExport, void *pvUser)
947{
948 return pfnExport(pThis, pvMutation, pMutation->cbMutation, pvUser);
949}
950
951
952/**
953 * Default mutator import callback (just reading the raw data).
954 */
955static DECLCALLBACK(int) rtFuzzCtxMutatorImportDefault(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, void *pvMutation,
956 PFNRTFUZZCTXIMPORT pfnImport, void *pvUser)
957{
958 return pfnImport(pThis, pvMutation, pMutation->cbMutation, NULL, pvUser);
959}
960
961
962static DECLCALLBACK(int) rtFuzzCtxMutatorCorpusExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
963 uint8_t *pbBuf, size_t cbBuf)
964{
965 RT_NOREF(pThis, cbBuf, pvMutation);
966 memcpy(pbBuf, pvMutation, pMutation->cbInput);
967 return VINF_SUCCESS;
968}
969
970
971/**
972 * Mutator callback - flips a single bit in the input.
973 */
974static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlipPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
975 PPRTFUZZMUTATION ppMutation)
976{
977 int rc = VINF_SUCCESS;
978 uint8_t *pidxBitFlip = 0;
979 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, sizeof(*pidxBitFlip), (void **)&pidxBitFlip);
980 if (RT_LIKELY(pMutation))
981 {
982 pMutation->cbInput = pMutationParent->cbInput; /* Bit flips don't change the input size. */
983 *pidxBitFlip = (uint8_t)RTRandAdvU32Ex(pThis->hRand, 0, sizeof(uint8_t) * 8 - 1);
984 *ppMutation = pMutation;
985 }
986 else
987 rc = VERR_NO_MEMORY;
988
989 return rc;
990}
991
992
993static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlipExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
994 uint8_t *pbBuf, size_t cbBuf)
995{
996 RT_NOREF(pThis, cbBuf, pMutation);
997 uint8_t idxBitFlip = *(uint8_t *)pvMutation;
998 ASMBitToggle(pbBuf, idxBitFlip);
999 return VINF_SUCCESS;
1000}
1001
1002
1003/**
1004 * Mutator callback - replaces a single byte in the input.
1005 */
1006static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplacePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
1007 PPRTFUZZMUTATION ppMutation)
1008{
1009 int rc = VINF_SUCCESS;
1010 uint8_t *pbReplace = 0;
1011 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, sizeof(*pbReplace), (void **)&pbReplace);
1012 if (RT_LIKELY(pMutation))
1013 {
1014 pMutation->cbInput = pMutationParent->cbInput; /* Byte replacements don't change the input size. */
1015 RTRandAdvBytes(pThis->hRand, pbReplace, 1); /** @todo Filter out same values. */
1016 *ppMutation = pMutation;
1017 }
1018 else
1019 rc = VERR_NO_MEMORY;
1020
1021 return rc;
1022}
1023
1024
1025static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplaceExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
1026 uint8_t *pbBuf, size_t cbBuf)
1027{
1028 RT_NOREF(pThis, cbBuf, pMutation);
1029 uint8_t bReplace = *(uint8_t *)pvMutation;
1030 *pbBuf = bReplace;
1031 return VINF_SUCCESS;
1032}
1033
1034
1035/**
1036 * Mutator callback - inserts a single byte into the input.
1037 */
1038static DECLCALLBACK(int) rtFuzzCtxMutatorByteInsertPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
1039 PPRTFUZZMUTATION ppMutation)
1040{
1041 int rc = VINF_SUCCESS;
1042 uint8_t *pbInsert = 0;
1043 if (pMutationParent->cbInput < pThis->cbInputMax)
1044 {
1045 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, 1 /*cbAdditional*/, (void **)&pbInsert);
1046 if (RT_LIKELY(pMutation))
1047 {
1048 pMutation->cbInput = pMutationParent->cbInput + 1;
1049 RTRandAdvBytes(pThis->hRand, pbInsert, 1);
1050 *ppMutation = pMutation;
1051 }
1052 else
1053 rc = VERR_NO_MEMORY;
1054 }
1055
1056 return rc;
1057}
1058
1059
1060static DECLCALLBACK(int) rtFuzzCtxMutatorByteInsertExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
1061 uint8_t *pbBuf, size_t cbBuf)
1062{
1063 RT_NOREF(pThis, pMutation, pvMutation);
1064
1065 /* Just move the residual data one byte to the back. */
1066 memmove(pbBuf + 1, pbBuf, cbBuf);
1067 *pbBuf = *(uint8_t *)pvMutation;
1068 return VINF_SUCCESS;
1069}
1070
1071
1072/**
1073 * Mutator callback - inserts a byte sequence into the input.
1074 */
1075static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsertAppendPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
1076 PPRTFUZZMUTATION ppMutation)
1077{
1078 int rc = VINF_SUCCESS;
1079 if (pMutationParent->cbInput < pThis->cbInputMax)
1080 {
1081 size_t cbInputMutated = (size_t)RTRandAdvU64Ex(pThis->hRand, pMutationParent->cbInput + 1, pThis->cbInputMax);
1082 size_t cbInsert = cbInputMutated - pMutationParent->cbInput;
1083 uint8_t *pbAdd = NULL;
1084
1085 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, cbInsert, (void **)&pbAdd);
1086 if (RT_LIKELY(pMutation))
1087 {
1088 pMutation->cbInput = cbInputMutated;
1089 RTRandAdvBytes(pThis->hRand, pbAdd, cbInsert);
1090 *ppMutation = pMutation;
1091 }
1092 else
1093 rc = VERR_NO_MEMORY;
1094 }
1095
1096 return rc;
1097}
1098
1099
1100static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsertAppendExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
1101 uint8_t *pbBuf, size_t cbBuf)
1102{
1103 RT_NOREF(pThis);
1104 size_t cbInsert = pMutation->cbInput - pMutation->pMutationParent->cbInput;
1105
1106 /* Move any remaining data to the end. */
1107 if (cbBuf)
1108 memmove(pbBuf + cbInsert, pbBuf, cbBuf);
1109
1110 memcpy(pbBuf, pvMutation, cbInsert);
1111 return VINF_SUCCESS;
1112}
1113
1114
1115/**
1116 * Mutator callback - deletes a single byte in the input.
1117 */
1118static DECLCALLBACK(int) rtFuzzCtxMutatorByteDeletePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
1119 PPRTFUZZMUTATION ppMutation)
1120{
1121 int rc = VINF_SUCCESS;
1122 if (pMutationParent->cbInput - offStart >= 1)
1123 {
1124 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, 0 /*cbAdditional*/, NULL);
1125 if (RT_LIKELY(pMutation))
1126 {
1127 pMutation->cbInput = pMutationParent->cbInput - 1;
1128 *ppMutation = pMutation;
1129 }
1130 else
1131 rc = VERR_NO_MEMORY;
1132 }
1133
1134 return rc;
1135}
1136
1137
1138static DECLCALLBACK(int) rtFuzzCtxMutatorByteDeleteExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
1139 uint8_t *pbBuf, size_t cbBuf)
1140{
1141 RT_NOREF(pThis, pMutation, pvMutation);
1142
1143 /* Just move the residual data to the front. */
1144 memmove(pbBuf, pbBuf + 1, cbBuf - 1);
1145 return VINF_SUCCESS;
1146}
1147
1148
1149/**
1150 * Mutator callback - deletes a byte sequence in the input.
1151 */
1152static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDeletePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
1153 PPRTFUZZMUTATION ppMutation)
1154{
1155 int rc = VINF_SUCCESS;
1156 if ( pMutationParent->cbInput > offStart
1157 && pMutationParent->cbInput > 1)
1158 {
1159 size_t cbInputMutated = (size_t)RTRandAdvU64Ex(pThis->hRand, offStart, pMutationParent->cbInput - 1);
1160
1161 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, 0 /*cbAdditional*/, NULL);
1162 if (RT_LIKELY(pMutation))
1163 {
1164 pMutation->cbInput = cbInputMutated;
1165 *ppMutation = pMutation;
1166 }
1167 else
1168 rc = VERR_NO_MEMORY;
1169 }
1170
1171 return rc;
1172}
1173
1174
1175static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDeleteExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
1176 uint8_t *pbBuf, size_t cbBuf)
1177{
1178 RT_NOREF(pThis, pvMutation);
1179 Assert(pMutation->pMutationParent->cbInput > pMutation->cbInput);
1180 size_t cbDel = pMutation->pMutationParent->cbInput - pMutation->cbInput;
1181
1182 /* Just move the residual data to the front. */
1183 memmove(pbBuf, pbBuf + cbDel, cbBuf - cbDel);
1184 return VINF_SUCCESS;
1185}
1186
1187
1188/**
1189 * Mutator callback - replaces a possible integer with something interesting.
1190 */
1191static DECLCALLBACK(int) rtFuzzCtxMutatorIntegerReplacePrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
1192 PPRTFUZZMUTATION ppMutation)
1193{
1194 int rc = VINF_SUCCESS;
1195 PRTFUZZMUTATORINTEGER pMutInt = NULL;
1196 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, sizeof(*pMutInt), (void **)&pMutInt);
1197 if (RT_LIKELY(pMutation))
1198 {
1199 size_t cbLeft = pMutationParent->cbInput - offStart;
1200 uint32_t uClassMax = 0;
1201
1202 switch (cbLeft)
1203 {
1204 case 1:
1205 uClassMax = 1;
1206 break;
1207 case 2:
1208 case 3:
1209 uClassMax = 3;
1210 break;
1211 case 4:
1212 case 5:
1213 case 6:
1214 case 7:
1215 uClassMax = 5;
1216 break;
1217 default:
1218 uClassMax = 7;
1219 break;
1220 }
1221
1222 pMutInt->uIntClass = (uint8_t)RTRandAdvU32Ex(pThis->hRand, 0, uClassMax);
1223 pMutInt->fByteSwap = RT_BOOL(RTRandAdvU32Ex(pThis->hRand, 0, 1));
1224
1225 switch (pMutInt->uIntClass)
1226 {
1227 case 0:
1228 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_ai8Interesting) - 1);
1229 break;
1230 case 1:
1231 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_au8Interesting) - 1);
1232 break;
1233 case 2:
1234 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_ai16Interesting) - 1);
1235 break;
1236 case 3:
1237 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_au16Interesting) - 1);
1238 break;
1239 case 4:
1240 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_ai32Interesting) - 1);
1241 break;
1242 case 5:
1243 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_au32Interesting) - 1);
1244 break;
1245 case 6:
1246 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_ai64Interesting) - 1);
1247 break;
1248 case 7:
1249 pMutInt->idxInt = (uint16_t)RTRandAdvU32Ex(pThis->hRand, 0, RT_ELEMENTS(s_au64Interesting) - 1);
1250 break;
1251 default:
1252 AssertReleaseFailed();
1253 }
1254
1255 pMutation->cbInput = pMutationParent->cbInput;
1256 *ppMutation = pMutation;
1257 }
1258 else
1259 rc = VERR_NO_MEMORY;
1260
1261 return rc;
1262}
1263
1264
1265static DECLCALLBACK(int) rtFuzzCtxMutatorIntegerReplaceExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
1266 uint8_t *pbBuf, size_t cbBuf)
1267{
1268 RT_NOREF(pThis, pMutation, cbBuf);
1269 union
1270 {
1271 int8_t i8;
1272 uint8_t u8;
1273 int16_t i16;
1274 uint16_t u16;
1275 int32_t i32;
1276 uint32_t u32;
1277 int64_t i64;
1278 uint64_t u64;
1279 } Int;
1280 PCRTFUZZMUTATORINTEGER pMutInt = (PCRTFUZZMUTATORINTEGER)pvMutation;
1281 size_t cb = 0;
1282
1283 switch (pMutInt->uIntClass)
1284 {
1285 case 0:
1286 Int.i8 = s_ai8Interesting[pMutInt->idxInt];
1287 cb = 1;
1288 break;
1289 case 1:
1290 Int.u8 = s_au8Interesting[pMutInt->idxInt];
1291 cb = 1;
1292 break;
1293 case 2:
1294 Int.i16 = s_ai16Interesting[pMutInt->idxInt];
1295 cb = 2;
1296 if (pMutInt->fByteSwap)
1297 Int.u16 = RT_BSWAP_U16(Int.u16);
1298 break;
1299 case 3:
1300 Int.u16 = s_au16Interesting[pMutInt->idxInt];
1301 cb = 2;
1302 if (pMutInt->fByteSwap)
1303 Int.u16 = RT_BSWAP_U16(Int.u16);
1304 break;
1305 case 4:
1306 Int.i32 = s_ai32Interesting[pMutInt->idxInt];
1307 cb = 4;
1308 if (pMutInt->fByteSwap)
1309 Int.u32 = RT_BSWAP_U32(Int.u32);
1310 break;
1311 case 5:
1312 Int.u32 = s_au32Interesting[pMutInt->idxInt];
1313 cb = 4;
1314 if (pMutInt->fByteSwap)
1315 Int.u32 = RT_BSWAP_U32(Int.u32);
1316 break;
1317 case 6:
1318 Int.i64 = s_ai64Interesting[pMutInt->idxInt];
1319 cb = 8;
1320 if (pMutInt->fByteSwap)
1321 Int.u64 = RT_BSWAP_U64(Int.u64);
1322 break;
1323 case 7:
1324 Int.u64 = s_au64Interesting[pMutInt->idxInt];
1325 cb = 8;
1326 if (pMutInt->fByteSwap)
1327 Int.u64 = RT_BSWAP_U64(Int.u64);
1328 break;
1329 default:
1330 AssertReleaseFailed();
1331 }
1332
1333 memcpy(pbBuf, &Int, cb);
1334 return VINF_SUCCESS;
1335}
1336
1337
1338/**
1339 * Mutator callback - crosses over two mutations at the given point.
1340 */
1341static DECLCALLBACK(int) rtFuzzCtxMutatorCrossoverPrep(PRTFUZZCTXINT pThis, uint64_t offStart, PRTFUZZMUTATION pMutationParent,
1342 PPRTFUZZMUTATION ppMutation)
1343{
1344 int rc = VINF_SUCCESS;
1345
1346 if (pThis->cMutations > 1)
1347 {
1348 uint64_t *pidxMutCrossover = NULL;
1349 PRTFUZZMUTATION pMutation = rtFuzzMutationCreate(pThis, offStart, pMutationParent, sizeof(*pidxMutCrossover), (void **)&pidxMutCrossover);
1350 if (RT_LIKELY(pMutation))
1351 {
1352 uint32_t cTries = 10;
1353 PRTFUZZMUTATION pMutCrossover = NULL;
1354 /*
1355 * Pick a random mutation to crossover with (making sure it is not the current one
1356 * or the crossover point is beyond the end of input).
1357 */
1358 do
1359 {
1360 if (pMutCrossover)
1361 rtFuzzMutationRelease(pMutCrossover);
1362 pMutCrossover = rtFuzzCtxMutationPickRnd(pThis);
1363 cTries--;
1364 } while ( ( pMutCrossover == pMutationParent
1365 || offStart >= pMutCrossover->cbInput)
1366 && cTries > 0);
1367
1368 if (cTries)
1369 {
1370 pMutation->cbInput = pMutCrossover->cbInput;
1371 *pidxMutCrossover = pMutCrossover->Core.Key;
1372 *ppMutation = pMutation;
1373 }
1374 else
1375 rtFuzzMutationDestroy(pMutation);
1376
1377 rtFuzzMutationRelease(pMutCrossover);
1378 }
1379 else
1380 rc = VERR_NO_MEMORY;
1381 }
1382
1383 return rc;
1384}
1385
1386
1387static DECLCALLBACK(int) rtFuzzCtxMutatorCrossoverExec(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
1388 uint8_t *pbBuf, size_t cbBuf)
1389{
1390 RT_NOREF(cbBuf);
1391 uint64_t idxMutCrossover = *(uint64_t *)pvMutation;
1392
1393 PRTFUZZMUTATION pMutCrossover = rtFuzzCtxMutationLocate(pThis, idxMutCrossover);
1394 int rc = rtFuzzMutationDataFinalize(pMutCrossover);
1395 if (RT_SUCCESS(rc))
1396 {
1397 memcpy(pbBuf, (uint8_t *)pMutCrossover->pvInput + pMutation->offMutation,
1398 pMutCrossover->cbInput - pMutation->offMutation);
1399 rtFuzzMutationRelease(pMutCrossover);
1400 }
1401
1402 return rc;
1403}
1404
1405
1406static DECLCALLBACK(int) rtFuzzCtxMutatorCrossoverExport(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, const void *pvMutation,
1407 PFNRTFUZZCTXEXPORT pfnExport, void *pvUser)
1408{
1409 RT_NOREF(pMutation);
1410
1411 uint64_t idxMutCrossover = *(uint64_t *)pvMutation;
1412 idxMutCrossover = RT_H2LE_U64(idxMutCrossover);
1413 return pfnExport(pThis, &idxMutCrossover, sizeof(idxMutCrossover), pvUser);
1414}
1415
1416
1417static DECLCALLBACK(int) rtFuzzCtxMutatorCrossoverImport(PRTFUZZCTXINT pThis, PCRTFUZZMUTATION pMutation, void *pvMutation,
1418 PFNRTFUZZCTXIMPORT pfnImport, void *pvUser)
1419{
1420 RT_NOREF(pMutation);
1421
1422 uint64_t uKey = 0;
1423 int rc = pfnImport(pThis, &uKey, sizeof(uKey), NULL, pvUser);
1424 if (RT_SUCCESS(rc))
1425 {
1426 uKey = RT_LE2H_U64(uKey);
1427 *(uint64_t *)pvMutation = uKey;
1428 }
1429
1430 return rc;
1431}
1432
1433
1434/**
1435 * Creates an empty fuzzing context.
1436 *
1437 * @returns IPRT status code.
1438 * @param ppThis Where to store the pointer to the internal fuzzing context instance on success.
1439 * @param enmType Fuzzing context type.
1440 */
1441static int rtFuzzCtxCreateEmpty(PRTFUZZCTXINT *ppThis, RTFUZZCTXTYPE enmType)
1442{
1443 int rc;
1444 PRTFUZZCTXINT pThis = (PRTFUZZCTXINT)RTMemAllocZ(sizeof(*pThis));
1445 if (RT_LIKELY(pThis))
1446 {
1447 pThis->u32Magic = RTFUZZCTX_MAGIC;
1448 pThis->cRefs = 1;
1449 pThis->enmType = enmType;
1450 pThis->TreeMutations = NULL;
1451 pThis->cbInputMax = UINT32_MAX;
1452 pThis->cMutations = 0;
1453 pThis->fFlagsBehavioral = 0;
1454 pThis->cbMutationsAllocMax = _1G;
1455 pThis->cbMemTotal = 0;
1456 pThis->offMutStart = 0;
1457 pThis->cbMutRange = UINT64_MAX;
1458 RTListInit(&pThis->LstMutationsAlloc);
1459
1460 /* Copy the default mutator descriptors over. */
1461 pThis->paMutators = (PRTFUZZMUTATOR)RTMemAllocZ(RT_ELEMENTS(g_aMutators) * sizeof(RTFUZZMUTATOR));
1462 if (RT_LIKELY(pThis->paMutators))
1463 {
1464 pThis->cMutators = RT_ELEMENTS(g_aMutators);
1465 memcpy(&pThis->paMutators[0], &g_aMutators[0], RT_ELEMENTS(g_aMutators) * sizeof(RTFUZZMUTATOR));
1466
1467 rc = RTSemRWCreate(&pThis->hSemRwMutations);
1468 if (RT_SUCCESS(rc))
1469 {
1470 rc = RTCritSectInit(&pThis->CritSectAlloc);
1471 if (RT_SUCCESS(rc))
1472 {
1473 rc = RTRandAdvCreateParkMiller(&pThis->hRand);
1474 if (RT_SUCCESS(rc))
1475 {
1476 RTRandAdvSeed(pThis->hRand, RTTimeSystemNanoTS());
1477 *ppThis = pThis;
1478 return VINF_SUCCESS;
1479 }
1480
1481 RTCritSectDelete(&pThis->CritSectAlloc);
1482 }
1483
1484 RTSemRWDestroy(pThis->hSemRwMutations);
1485 }
1486 }
1487 else
1488 rc = VERR_NO_MEMORY;
1489
1490 RTMemFree(pThis);
1491 }
1492 else
1493 rc = VERR_NO_MEMORY;
1494
1495 return rc;
1496}
1497
1498
1499/**
1500 * Destroys the given fuzzing input.
1501 *
1502 * @returns nothing.
1503 * @param pThis The fuzzing input to destroy.
1504 */
1505static void rtFuzzInputDestroy(PRTFUZZINPUTINT pThis)
1506{
1507 PRTFUZZCTXINT pFuzzer = pThis->pFuzzer;
1508
1509 rtFuzzMutationRelease(pThis->pMutationTop);
1510 rtFuzzCtxMemoryFree(pFuzzer, pThis);
1511 RTFuzzCtxRelease(pFuzzer);
1512}
1513
1514
1515RTDECL(int) RTFuzzCtxCreate(PRTFUZZCTX phFuzzCtx, RTFUZZCTXTYPE enmType)
1516{
1517 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
1518
1519 return rtFuzzCtxCreateEmpty(phFuzzCtx, enmType);
1520}
1521
1522
1523RTDECL(int) RTFuzzCtxCreateFromState(PRTFUZZCTX phFuzzCtx, PFNRTFUZZCTXIMPORT pfnImport, void *pvUser)
1524{
1525 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
1526 AssertPtrReturn(pfnImport, VERR_INVALID_POINTER);
1527
1528#if 0
1529 int rc = VINF_SUCCESS;
1530 if (cbState >= sizeof(RTFUZZCTXSTATE))
1531 {
1532 RTFUZZCTXSTATE StateImport;
1533
1534 memcpy(&StateImport, pvState, sizeof(RTFUZZCTXSTATE));
1535 if ( RT_LE2H_U32(StateImport.u32Magic) == RTFUZZCTX_MAGIC
1536 && RT_LE2H_U32(StateImport.cbPrng) <= cbState - sizeof(RTFUZZCTXSTATE))
1537 {
1538 PRTFUZZCTXINT pThis = rtFuzzCtxCreateEmpty();
1539 if (RT_LIKELY(pThis))
1540 {
1541 pThis->cbInputMax = (size_t)RT_LE2H_U64(StateImport.cbInputMax);
1542 pThis->fFlagsBehavioral = RT_LE2H_U32(StateImport.fFlagsBehavioral);
1543
1544 uint8_t *pbState = (uint8_t *)pvState;
1545 uint32_t cInputs = RT_LE2H_U32(StateImport.cInputs);
1546 rc = RTRandAdvRestoreState(pThis->hRand, (const char *)&pbState[sizeof(RTFUZZCTXSTATE)]);
1547 if (RT_SUCCESS(rc))
1548 {
1549 /* Go through the inputs and add them. */
1550 pbState += sizeof(RTFUZZCTXSTATE) + RT_LE2H_U32(StateImport.cbPrng);
1551 cbState -= sizeof(RTFUZZCTXSTATE) + RT_LE2H_U32(StateImport.cbPrng);
1552
1553 uint32_t idx = 0;
1554 while ( idx < cInputs
1555 && RT_SUCCESS(rc))
1556 {
1557 size_t cbInput = 0;
1558 if (cbState >= sizeof(uint32_t))
1559 {
1560 memcpy(&cbInput, pbState, sizeof(uint32_t));
1561 cbInput = RT_LE2H_U32(cbInput);
1562 pbState += sizeof(uint32_t);
1563 }
1564
1565 if ( cbInput
1566 && cbInput <= cbState)
1567 {
1568 PRTFUZZINPUTINT pInput = rtFuzzCtxInputCreate(pThis, cbInput);
1569 if (RT_LIKELY(pInput))
1570 {
1571 memcpy(&pInput->abInput[0], pbState, cbInput);
1572 RTMd5(&pInput->abInput[0], pInput->cbInput, &pInput->abMd5Hash[0]);
1573 rc = rtFuzzCtxInputAdd(pThis, pInput);
1574 if (RT_FAILURE(rc))
1575 RTMemFree(pInput);
1576 pbState += cbInput;
1577 }
1578 }
1579 else
1580 rc = VERR_INVALID_STATE;
1581
1582 idx++;
1583 }
1584
1585 if (RT_SUCCESS(rc))
1586 {
1587 *phFuzzCtx = pThis;
1588 return VINF_SUCCESS;
1589 }
1590 }
1591
1592 rtFuzzCtxDestroy(pThis);
1593 }
1594 else
1595 rc = VERR_NO_MEMORY;
1596 }
1597 else
1598 rc = VERR_INVALID_MAGIC;
1599 }
1600 else
1601 rc = VERR_INVALID_MAGIC;
1602
1603 return rc;
1604#else
1605 RT_NOREF(pvUser);
1606 return VERR_NOT_IMPLEMENTED;
1607#endif
1608}
1609
1610
1611RTDECL(int) RTFuzzCtxCreateFromStateMem(PRTFUZZCTX phFuzzCtx, const void *pvState, size_t cbState)
1612{
1613 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
1614 AssertPtrReturn(pvState, VERR_INVALID_POINTER);
1615 AssertPtrReturn(cbState, VERR_INVALID_POINTER);
1616
1617 return VERR_NOT_IMPLEMENTED;
1618}
1619
1620
1621RTDECL(int) RTFuzzCtxCreateFromStateFile(PRTFUZZCTX phFuzzCtx, const char *pszFilename)
1622{
1623 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
1624 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1625
1626 void *pv = NULL;
1627 size_t cb = 0;
1628 int rc = RTFileReadAll(pszFilename, &pv, &cb);
1629 if (RT_SUCCESS(rc))
1630 {
1631 rc = RTFuzzCtxCreateFromStateMem(phFuzzCtx, pv, cb);
1632 RTFileReadAllFree(pv, cb);
1633 }
1634
1635 return rc;
1636}
1637
1638
1639RTDECL(uint32_t) RTFuzzCtxRetain(RTFUZZCTX hFuzzCtx)
1640{
1641 PRTFUZZCTXINT pThis = hFuzzCtx;
1642
1643 AssertPtrReturn(pThis, UINT32_MAX);
1644
1645 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1646 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1647 return cRefs;
1648}
1649
1650
1651RTDECL(uint32_t) RTFuzzCtxRelease(RTFUZZCTX hFuzzCtx)
1652{
1653 PRTFUZZCTXINT pThis = hFuzzCtx;
1654 if (pThis == NIL_RTFUZZCTX)
1655 return 0;
1656 AssertPtrReturn(pThis, UINT32_MAX);
1657
1658 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1659 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1660 if (cRefs == 0)
1661 rtFuzzCtxDestroy(pThis);
1662 return cRefs;
1663}
1664
1665
1666RTDECL(int) RTFuzzCtxQueryStats(RTFUZZCTX hFuzzCtx, PRTFUZZCTXSTATS pStats)
1667{
1668 PRTFUZZCTXINT pThis = hFuzzCtx;
1669 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1670 AssertPtrReturn(pStats, VERR_INVALID_POINTER);
1671
1672 pStats->cbMemory = ASMAtomicReadZ(&pThis->cbMemTotal);
1673 pStats->cMutations = ASMAtomicReadU64(&pThis->cMutations);
1674 return VINF_SUCCESS;
1675}
1676
1677
1678/**
1679 * Fuzzing context export callback for a single mutation.
1680 */
1681static DECLCALLBACK(int) rtFuzzCtxStateExportMutations(PAVLU64NODECORE pCore, void *pvParam)
1682{
1683 PRTFUZZMUTATION pMutation = (PRTFUZZMUTATION)pCore;
1684 PCRTFUZZMUTATOR pMutator = pMutation->pMutator;
1685 PCRTFUZZEXPORTARGS pArgs = (PCRTFUZZEXPORTARGS)pvParam;
1686 RTFUZZMUTATIONSTATE MutationState;
1687
1688 MutationState.u64Id = RT_H2LE_U64(pMutation->Core.Key);
1689 if (pMutation->pMutationParent)
1690 MutationState.u64IdParent = RT_H2LE_U64(pMutation->pMutationParent->Core.Key);
1691 else
1692 MutationState.u64IdParent = RT_H2LE_U64(0);
1693 MutationState.u64OffMutation = RT_H2LE_U64(pMutation->offMutation);
1694 MutationState.cbInput = RT_H2LE_U64((uint64_t)pMutation->cbInput);
1695 MutationState.cbMutation = RT_H2LE_U64((uint64_t)pMutation->cbMutation);
1696 MutationState.u32IdMutator = RT_H2LE_U32(pMutator->uMutator);
1697 MutationState.iLvl = RT_H2LE_U32(pMutation->iLvl);
1698 MutationState.u32Magic = RT_H2LE_U32(pMutation->u32Magic);
1699
1700 int rc = pArgs->pfnExport(pMutation->pFuzzer, &MutationState, sizeof(MutationState), pArgs->pvUser);
1701 if ( RT_SUCCESS(rc)
1702 && pMutator->pfnExport)
1703 rc = pMutator->pfnExport(pMutation->pFuzzer, pMutation, &pMutation->abMutation[0], pArgs->pfnExport, pArgs->pvUser);
1704 return rc;
1705}
1706
1707
1708RTDECL(int) RTFuzzCtxStateExport(RTFUZZCTX hFuzzCtx, PFNRTFUZZCTXEXPORT pfnExport, void *pvUser)
1709{
1710 PRTFUZZCTXINT pThis = hFuzzCtx;
1711 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1712 AssertPtrReturn(pfnExport, VERR_INVALID_POINTER);
1713
1714 char aszPrngExport[_4K]; /* Should be plenty of room here. */
1715 size_t cbPrng = sizeof(aszPrngExport);
1716 int rc = RTRandAdvSaveState(pThis->hRand, &aszPrngExport[0], &cbPrng);
1717 if (RT_SUCCESS(rc))
1718 {
1719 RTFUZZCTXSTATE StateExport;
1720
1721 StateExport.u32Magic = RT_H2LE_U32(RTFUZZCTX_MAGIC);
1722 switch (pThis->enmType)
1723 {
1724 case RTFUZZCTXTYPE_BLOB:
1725 StateExport.uCtxType = RT_H2LE_U32(RTFUZZCTX_STATE_TYPE_BLOB);
1726 break;
1727 case RTFUZZCTXTYPE_STREAM:
1728 StateExport.uCtxType = RT_H2LE_U32(RTFUZZCTX_STATE_TYPE_STREAM);
1729 break;
1730 default:
1731 AssertFailed();
1732 break;
1733 }
1734 StateExport.cbPrng = RT_H2LE_U32((uint32_t)cbPrng);
1735 StateExport.cMutations = RT_H2LE_U32(pThis->cMutations);
1736 StateExport.cMutators = RT_H2LE_U32(pThis->cMutators);
1737 StateExport.fFlagsBehavioral = RT_H2LE_U32(pThis->fFlagsBehavioral);
1738 StateExport.cbInputMax = RT_H2LE_U64(pThis->cbInputMax);
1739
1740 /* Write the context state and PRNG state first. */
1741 rc = pfnExport(pThis, &StateExport, sizeof(StateExport), pvUser);
1742 if (RT_SUCCESS(rc))
1743 rc = pfnExport(pThis, &aszPrngExport[0], cbPrng, pvUser);
1744 if (RT_SUCCESS(rc))
1745 {
1746 /* Write the mutator descriptors next. */
1747 for (uint32_t i = 0; i < pThis->cMutators && RT_SUCCESS(rc); i++)
1748 {
1749 PRTFUZZMUTATOR pMutator = &pThis->paMutators[i];
1750 uint32_t cchId = (uint32_t)strlen(pMutator->pszId) + 1;
1751 uint32_t cchIdW = RT_H2LE_U32(cchId);
1752
1753 rc = pfnExport(pThis, &cchIdW, sizeof(cchIdW), pvUser);
1754 if (RT_SUCCESS(rc))
1755 rc = pfnExport(pThis, &pMutator->pszId[0], cchId, pvUser);
1756 }
1757 }
1758
1759 /* Write the mutations last. */
1760 if (RT_SUCCESS(rc))
1761 {
1762 RTFUZZEXPORTARGS Args;
1763
1764 Args.pfnExport = pfnExport;
1765 Args.pvUser = pvUser;
1766 rc = RTAvlU64DoWithAll(&pThis->TreeMutations, true /*fFromLeft*/, rtFuzzCtxStateExportMutations, &Args);
1767 }
1768 }
1769
1770 return rc;
1771}
1772
1773
1774RTDECL(int) RTFuzzCtxStateExportToMem(RTFUZZCTX hFuzzCtx, void **ppvState, size_t *pcbState)
1775{
1776 PRTFUZZCTXINT pThis = hFuzzCtx;
1777 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1778 AssertPtrReturn(ppvState, VERR_INVALID_POINTER);
1779 AssertPtrReturn(pcbState, VERR_INVALID_POINTER);
1780
1781 return VERR_NOT_IMPLEMENTED;
1782}
1783
1784
1785/**
1786 * Export to file callback.
1787 */
1788static DECLCALLBACK(int) rtFuzzCtxStateExportFile(RTFUZZCTX hFuzzCtx, const void *pvBuf, size_t cbWrite, void *pvUser)
1789{
1790 RT_NOREF(hFuzzCtx);
1791
1792 RTFILE hFile = (RTFILE)pvUser;
1793 return RTFileWrite(hFile, pvBuf, cbWrite, NULL);
1794}
1795
1796
1797RTDECL(int) RTFuzzCtxStateExportToFile(RTFUZZCTX hFuzzCtx, const char *pszFilename)
1798{
1799 PRTFUZZCTXINT pThis = hFuzzCtx;
1800 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1801 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1802
1803 RTFILE hFile;
1804 int rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
1805 if (RT_SUCCESS(rc))
1806 {
1807 rc = RTFuzzCtxStateExport(hFuzzCtx, rtFuzzCtxStateExportFile, hFile);
1808 RTFileClose(hFile);
1809 if (RT_FAILURE(rc))
1810 RTFileDelete(pszFilename);
1811 }
1812
1813 return rc;
1814}
1815
1816
1817RTDECL(int) RTFuzzCtxCorpusInputAdd(RTFUZZCTX hFuzzCtx, const void *pvInput, size_t cbInput)
1818{
1819 PRTFUZZCTXINT pThis = hFuzzCtx;
1820 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1821 AssertPtrReturn(pvInput, VERR_INVALID_POINTER);
1822 AssertReturn(cbInput, VERR_INVALID_POINTER);
1823
1824 return RTFuzzCtxCorpusInputAddEx(hFuzzCtx, pvInput, cbInput, pThis->offMutStart, pThis->cbMutRange);
1825}
1826
1827
1828RTDECL(int) RTFuzzCtxCorpusInputAddEx(RTFUZZCTX hFuzzCtx, const void *pvInput, size_t cbInput,
1829 uint64_t offMutStart, uint64_t cbMutRange)
1830{
1831 PRTFUZZCTXINT pThis = hFuzzCtx;
1832 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1833 AssertPtrReturn(pvInput, VERR_INVALID_POINTER);
1834 AssertReturn(cbInput, VERR_INVALID_POINTER);
1835
1836 int rc = VINF_SUCCESS;
1837 void *pvCorpus = NULL;
1838 PRTFUZZMUTATION pMutation = rtFuzzMutationCreateEx(pThis, 0, NULL, offMutStart, cbMutRange,
1839 cbInput, &pvCorpus);
1840 if (RT_LIKELY(pMutation))
1841 {
1842 pMutation->pMutator = &g_MutatorCorpus;
1843 pMutation->cbInput = cbInput;
1844 pMutation->pvInput = pvCorpus;
1845 memcpy(pvCorpus, pvInput, cbInput);
1846 rc = rtFuzzCtxMutationAdd(pThis, pMutation);
1847 if (RT_FAILURE(rc))
1848 rtFuzzMutationDestroy(pMutation);
1849 }
1850 else
1851 rc = VERR_NO_MEMORY;
1852
1853 return rc;
1854}
1855
1856
1857RTDECL(int) RTFuzzCtxCorpusInputAddFromFile(RTFUZZCTX hFuzzCtx, const char *pszFilename)
1858{
1859 PRTFUZZCTXINT pThis = hFuzzCtx;
1860 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1861 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1862
1863 return RTFuzzCtxCorpusInputAddFromFileEx(hFuzzCtx, pszFilename, pThis->offMutStart, pThis->cbMutRange);
1864}
1865
1866
1867RTDECL(int) RTFuzzCtxCorpusInputAddFromFileEx(RTFUZZCTX hFuzzCtx, const char *pszFilename,
1868 uint64_t offMutStart, uint64_t cbMutRange)
1869{
1870 PRTFUZZCTXINT pThis = hFuzzCtx;
1871 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1872 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1873
1874 void *pv = NULL;
1875 size_t cb = 0;
1876 int rc = RTFileReadAll(pszFilename, &pv, &cb);
1877 if (RT_SUCCESS(rc))
1878 {
1879 rc = RTFuzzCtxCorpusInputAddEx(hFuzzCtx, pv, cb, offMutStart, cbMutRange);
1880 RTFileReadAllFree(pv, cb);
1881 }
1882
1883 return rc;
1884}
1885
1886
1887RTDECL(int) RTFuzzCtxCorpusInputAddFromVfsFile(RTFUZZCTX hFuzzCtx, RTVFSFILE hVfsFile)
1888{
1889 PRTFUZZCTXINT pThis = hFuzzCtx;
1890 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1891 AssertReturn(hVfsFile != NIL_RTVFSFILE, VERR_INVALID_HANDLE);
1892
1893 return RTFuzzCtxCorpusInputAddFromVfsFileEx(hFuzzCtx, hVfsFile, pThis->offMutStart, pThis->cbMutRange);
1894}
1895
1896
1897RTDECL(int) RTFuzzCtxCorpusInputAddFromVfsFileEx(RTFUZZCTX hFuzzCtx, RTVFSFILE hVfsFile,
1898 uint64_t offMutStart, uint64_t cbMutRange)
1899{
1900 PRTFUZZCTXINT pThis = hFuzzCtx;
1901 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1902 AssertReturn(hVfsFile != NIL_RTVFSFILE, VERR_INVALID_HANDLE);
1903
1904 uint64_t cbFile = 0;
1905 void *pvCorpus = NULL;
1906 int rc = RTVfsFileQuerySize(hVfsFile, &cbFile);
1907 if (RT_SUCCESS(rc))
1908 {
1909 PRTFUZZMUTATION pMutation = rtFuzzMutationCreateEx(pThis, 0, NULL, offMutStart, cbMutRange,
1910 cbFile, &pvCorpus);
1911 if (RT_LIKELY(pMutation))
1912 {
1913 pMutation->pMutator = &g_MutatorCorpus;
1914 pMutation->cbInput = cbFile;
1915 pMutation->pvInput = pvCorpus;
1916 rc = RTVfsFileRead(hVfsFile, pvCorpus, cbFile, NULL);
1917 if (RT_SUCCESS(rc))
1918 rc = rtFuzzCtxMutationAdd(pThis, pMutation);
1919
1920 if (RT_FAILURE(rc))
1921 rtFuzzMutationDestroy(pMutation);
1922 }
1923 else
1924 rc = VERR_NO_MEMORY;
1925 }
1926
1927 return rc;
1928}
1929
1930
1931RTDECL(int) RTFuzzCtxCorpusInputAddFromVfsIoStrm(RTFUZZCTX hFuzzCtx, RTVFSIOSTREAM hVfsIos)
1932{
1933 PRTFUZZCTXINT pThis = hFuzzCtx;
1934 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1935 AssertReturn(hVfsIos != NIL_RTVFSIOSTREAM, VERR_INVALID_HANDLE);
1936
1937 return RTFuzzCtxCorpusInputAddFromVfsIoStrmEx(hFuzzCtx, hVfsIos, pThis->offMutStart, pThis->cbMutRange);
1938}
1939
1940RTDECL(int) RTFuzzCtxCorpusInputAddFromVfsIoStrmEx(RTFUZZCTX hFuzzCtx, RTVFSIOSTREAM hVfsIos,
1941 uint64_t offMutStart, uint64_t cbMutRange)
1942{
1943 PRTFUZZCTXINT pThis = hFuzzCtx;
1944 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1945 AssertReturn(hVfsIos != NIL_RTVFSIOSTREAM, VERR_INVALID_HANDLE);
1946
1947 void *pvCorpus = NULL;
1948 RTFSOBJINFO ObjInfo;
1949 int rc = RTVfsIoStrmQueryInfo(hVfsIos, &ObjInfo, RTFSOBJATTRADD_UNIX);
1950 if (RT_SUCCESS(rc))
1951 {
1952 PRTFUZZMUTATION pMutation = rtFuzzMutationCreateEx(pThis, 0, NULL, offMutStart, cbMutRange,
1953 ObjInfo.cbObject, &pvCorpus);
1954 if (RT_LIKELY(pMutation))
1955 {
1956 pMutation->pMutator = &g_MutatorCorpus;
1957 pMutation->cbInput = ObjInfo.cbObject;
1958 pMutation->pvInput = pvCorpus;
1959 rc = RTVfsIoStrmRead(hVfsIos, pvCorpus, ObjInfo.cbObject, true /*fBlocking*/, NULL);
1960 if (RT_SUCCESS(rc))
1961 rc = rtFuzzCtxMutationAdd(pThis, pMutation);
1962
1963 if (RT_FAILURE(rc))
1964 rtFuzzMutationDestroy(pMutation);
1965 }
1966 else
1967 rc = VERR_NO_MEMORY;
1968 }
1969
1970 return rc;
1971}
1972
1973
1974RTDECL(int) RTFuzzCtxCorpusInputAddFromDirPath(RTFUZZCTX hFuzzCtx, const char *pszDirPath)
1975{
1976 PRTFUZZCTXINT pThis = hFuzzCtx;
1977 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1978 AssertPtrReturn(pszDirPath, VERR_INVALID_POINTER);
1979
1980 RTDIR hDir;
1981 int rc = RTDirOpen(&hDir, pszDirPath);
1982 if (RT_SUCCESS(rc))
1983 {
1984 for (;;)
1985 {
1986 RTDIRENTRY DirEntry;
1987 rc = RTDirRead(hDir, &DirEntry, NULL);
1988 if (RT_FAILURE(rc))
1989 break;
1990
1991 /* Skip '.', '..' and other non-files. */
1992 if ( DirEntry.enmType != RTDIRENTRYTYPE_UNKNOWN
1993 && DirEntry.enmType != RTDIRENTRYTYPE_FILE)
1994 continue;
1995 if (RTDirEntryIsStdDotLink(&DirEntry))
1996 continue;
1997
1998 /* Compose the full path, result 'unknown' entries and skip non-files. */
1999 char szFile[RTPATH_MAX];
2000 RT_ZERO(szFile);
2001 rc = RTPathJoin(szFile, sizeof(szFile), pszDirPath, DirEntry.szName);
2002 if (RT_FAILURE(rc))
2003 break;
2004
2005 if (DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN)
2006 {
2007 RTDirQueryUnknownType(szFile, false, &DirEntry.enmType);
2008 if (DirEntry.enmType != RTDIRENTRYTYPE_FILE)
2009 continue;
2010 }
2011
2012 /* Okay, it's a file we can add. */
2013 rc = RTFuzzCtxCorpusInputAddFromFile(hFuzzCtx, szFile);
2014 if (RT_FAILURE(rc))
2015 break;
2016 }
2017 if (rc == VERR_NO_MORE_FILES)
2018 rc = VINF_SUCCESS;
2019 RTDirClose(hDir);
2020 }
2021
2022 return rc;
2023}
2024
2025
2026RTDECL(int) RTFuzzCtxCfgSetInputSeedMaximum(RTFUZZCTX hFuzzCtx, size_t cbMax)
2027{
2028 PRTFUZZCTXINT pThis = hFuzzCtx;
2029 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2030
2031 pThis->cbInputMax = cbMax;
2032 return VINF_SUCCESS;
2033}
2034
2035
2036RTDECL(size_t) RTFuzzCtxCfgGetInputSeedMaximum(RTFUZZCTX hFuzzCtx)
2037{
2038 PRTFUZZCTXINT pThis = hFuzzCtx;
2039 AssertPtrReturn(pThis, 0);
2040
2041 return pThis->cbInputMax;
2042}
2043
2044
2045RTDECL(int) RTFuzzCtxCfgSetBehavioralFlags(RTFUZZCTX hFuzzCtx, uint32_t fFlags)
2046{
2047 PRTFUZZCTXINT pThis = hFuzzCtx;
2048 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2049 AssertReturn(!(fFlags & ~RTFUZZCTX_F_BEHAVIORAL_VALID), VERR_INVALID_PARAMETER);
2050
2051 pThis->fFlagsBehavioral = fFlags;
2052 return VINF_SUCCESS;
2053}
2054
2055
2056RTDECL(uint32_t) RTFuzzCfgGetBehavioralFlags(RTFUZZCTX hFuzzCtx)
2057{
2058 PRTFUZZCTXINT pThis = hFuzzCtx;
2059 AssertPtrReturn(pThis, 0);
2060
2061 return pThis->fFlagsBehavioral;
2062}
2063
2064
2065RTDECL(int) RTFuzzCtxCfgSetTmpDirectory(RTFUZZCTX hFuzzCtx, const char *pszPathTmp)
2066{
2067 PRTFUZZCTXINT pThis = hFuzzCtx;
2068 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2069 AssertPtrReturn(pszPathTmp, VERR_INVALID_POINTER);
2070
2071 return VERR_NOT_IMPLEMENTED;
2072}
2073
2074
2075RTDECL(const char *) RTFuzzCtxCfgGetTmpDirectory(RTFUZZCTX hFuzzCtx)
2076{
2077 PRTFUZZCTXINT pThis = hFuzzCtx;
2078 AssertPtrReturn(pThis, NULL);
2079
2080 return NULL;
2081}
2082
2083
2084RTDECL(int) RTFuzzCtxCfgSetMutationRange(RTFUZZCTX hFuzzCtx, uint64_t offStart, uint64_t cbRange)
2085{
2086 PRTFUZZCTXINT pThis = hFuzzCtx;
2087 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2088
2089 pThis->offMutStart = offStart;
2090 pThis->cbMutRange = cbRange;
2091 return VINF_SUCCESS;
2092}
2093
2094
2095RTDECL(int) RTFuzzCtxReseed(RTFUZZCTX hFuzzCtx, uint64_t uSeed)
2096{
2097 PRTFUZZCTXINT pThis = hFuzzCtx;
2098 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2099
2100 RTRandAdvSeed(pThis->hRand, uSeed);
2101 return VINF_SUCCESS;
2102}
2103
2104
2105RTDECL(int) RTFuzzCtxInputGenerate(RTFUZZCTX hFuzzCtx, PRTFUZZINPUT phFuzzInput)
2106{
2107 int rc = VINF_SUCCESS;
2108 PRTFUZZCTXINT pThis = hFuzzCtx;
2109 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2110 AssertPtrReturn(phFuzzInput, VERR_INVALID_POINTER);
2111
2112 uint32_t cTries = 0;
2113 PRTFUZZMUTATION pMutationParent = rtFuzzCtxMutationPickRnd(pThis);
2114 do
2115 {
2116 uint32_t idxMutator = RTRandAdvU32Ex(pThis->hRand, 0, pThis->cMutators - 1);
2117 PCRTFUZZMUTATOR pMutator = &pThis->paMutators[idxMutator];
2118 PRTFUZZMUTATION pMutation = NULL;
2119
2120 uint64_t offStart = 0;
2121 if (!(pMutator->fFlags & RTFUZZMUTATOR_F_END_OF_BUF))
2122 {
2123 uint64_t offMax = pMutationParent->cbInput - 1;
2124 if ( pMutationParent->cbMutNew != UINT64_MAX
2125 && pMutationParent->offMutStartNew + pMutationParent->cbMutNew < offMax)
2126 offMax = pMutationParent->offMutStartNew + pMutationParent->cbMutNew - 1;
2127
2128 offMax = RT_MAX(pMutationParent->offMutStartNew, offMax);
2129 offStart = RTRandAdvU64Ex(pThis->hRand, pMutationParent->offMutStartNew, offMax);
2130 }
2131 else
2132 offStart = pMutationParent->cbInput;
2133
2134 rc = pMutator->pfnPrep(pThis, offStart, pMutationParent, &pMutation);
2135 if ( RT_SUCCESS(rc)
2136 && VALID_PTR(pMutation))
2137 {
2138 pMutation->pMutator = pMutator;
2139
2140 if (pThis->fFlagsBehavioral & RTFUZZCTX_F_BEHAVIORAL_ADD_INPUT_AUTOMATICALLY_TO_CORPUS)
2141 rtFuzzCtxMutationAdd(pThis, pMutation);
2142
2143 /* Create a new input. */
2144 PRTFUZZINPUTINT pInput = (PRTFUZZINPUTINT)rtFuzzCtxMemoryAlloc(pThis, sizeof(RTFUZZINPUTINT));
2145 if (RT_LIKELY(pInput))
2146 {
2147 pInput->u32Magic = 0; /** @todo */
2148 pInput->cRefs = 1;
2149 pInput->pFuzzer = pThis;
2150 pInput->pMutationTop = pMutation;
2151 RTFuzzCtxRetain(pThis);
2152
2153 rtFuzzMutationRelease(pMutationParent);
2154 *phFuzzInput = pInput;
2155 return rc;
2156 }
2157 else
2158 rc = VERR_NO_MEMORY;
2159 }
2160 } while (++cTries <= 50);
2161
2162 rtFuzzMutationRelease(pMutationParent);
2163 if (RT_SUCCESS(rc))
2164 rc = VERR_INVALID_STATE;
2165
2166 return rc;
2167}
2168
2169
2170RTDECL(int) RTFuzzInputQueryBlobData(RTFUZZINPUT hFuzzInput, void **ppv, size_t *pcb)
2171{
2172 PRTFUZZINPUTINT pThis = hFuzzInput;
2173 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2174 AssertReturn(pThis->pFuzzer->enmType == RTFUZZCTXTYPE_BLOB, VERR_INVALID_STATE);
2175
2176 int rc = VINF_SUCCESS;
2177 if (!pThis->pMutationTop->pvInput)
2178 rc = rtFuzzMutationDataFinalize(pThis->pMutationTop);
2179
2180 if (RT_SUCCESS(rc))
2181 {
2182 *ppv = pThis->pMutationTop->pvInput;
2183 *pcb = pThis->pMutationTop->cbInput;
2184 }
2185
2186 return rc;
2187}
2188
2189
2190RTDECL(int) RTFuzzInputMutateStreamData(RTFUZZINPUT hFuzzInput, void *pvBuf, size_t cbBuf)
2191{
2192 PRTFUZZINPUTINT pThis = hFuzzInput;
2193 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2194 AssertReturn(pThis->pFuzzer->enmType == RTFUZZCTXTYPE_STREAM, VERR_INVALID_STATE);
2195
2196 RT_NOREF(pvBuf, cbBuf);
2197 return VERR_NOT_IMPLEMENTED;
2198}
2199
2200
2201RTDECL(uint32_t) RTFuzzInputRetain(RTFUZZINPUT hFuzzInput)
2202{
2203 PRTFUZZINPUTINT pThis = hFuzzInput;
2204
2205 AssertPtrReturn(pThis, UINT32_MAX);
2206
2207 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
2208 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
2209 return cRefs;
2210}
2211
2212
2213RTDECL(uint32_t) RTFuzzInputRelease(RTFUZZINPUT hFuzzInput)
2214{
2215 PRTFUZZINPUTINT pThis = hFuzzInput;
2216 if (pThis == NIL_RTFUZZINPUT)
2217 return 0;
2218 AssertPtrReturn(pThis, UINT32_MAX);
2219
2220 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
2221 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
2222 if (cRefs == 0)
2223 rtFuzzInputDestroy(pThis);
2224 return cRefs;
2225}
2226
2227
2228RTDECL(int) RTFuzzInputQueryDigestString(RTFUZZINPUT hFuzzInput, char *pszDigest, size_t cchDigest)
2229{
2230 PRTFUZZINPUTINT pThis = hFuzzInput;
2231 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2232 AssertReturn(pThis->pFuzzer->enmType == RTFUZZCTXTYPE_BLOB, VERR_INVALID_STATE);
2233 AssertPtrReturn(pszDigest, VERR_INVALID_POINTER);
2234 AssertReturn(cchDigest >= RTMD5_STRING_LEN + 1, VERR_INVALID_PARAMETER);
2235
2236 int rc = VINF_SUCCESS;
2237 if (!pThis->pMutationTop->pvInput)
2238 rc = rtFuzzMutationDataFinalize(pThis->pMutationTop);
2239
2240 if (RT_SUCCESS(rc))
2241 {
2242 uint8_t abHash[RTMD5_HASH_SIZE];
2243 RTMd5(pThis->pMutationTop->pvInput, pThis->pMutationTop->cbInput, &abHash[0]);
2244 rc = RTMd5ToString(&abHash[0], pszDigest, cchDigest);
2245 }
2246
2247 return rc;
2248}
2249
2250
2251RTDECL(int) RTFuzzInputWriteToFile(RTFUZZINPUT hFuzzInput, const char *pszFilename)
2252{
2253 PRTFUZZINPUTINT pThis = hFuzzInput;
2254 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2255 AssertReturn(pThis->pFuzzer->enmType == RTFUZZCTXTYPE_BLOB, VERR_INVALID_STATE);
2256 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
2257
2258 int rc = VINF_SUCCESS;
2259 if (!pThis->pMutationTop->pvInput)
2260 rc = rtFuzzMutationDataFinalize(pThis->pMutationTop);
2261
2262 if (RT_SUCCESS(rc))
2263 {
2264 RTFILE hFile;
2265 rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
2266 if (RT_SUCCESS(rc))
2267 {
2268 rc = RTFileWrite(hFile, pThis->pMutationTop->pvInput, pThis->pMutationTop->cbInput, NULL);
2269 AssertRC(rc);
2270 RTFileClose(hFile);
2271
2272 if (RT_FAILURE(rc))
2273 RTFileDelete(pszFilename);
2274 }
2275 }
2276
2277 return rc;
2278}
2279
2280
2281RTDECL(int) RTFuzzInputAddToCtxCorpus(RTFUZZINPUT hFuzzInput)
2282{
2283 PRTFUZZINPUTINT pThis = hFuzzInput;
2284 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2285
2286 return rtFuzzCtxMutationAdd(pThis->pFuzzer, pThis->pMutationTop);
2287}
2288
2289
2290RTDECL(int) RTFuzzInputRemoveFromCtxCorpus(RTFUZZINPUT hFuzzInput)
2291{
2292 PRTFUZZINPUTINT pThis = hFuzzInput;
2293 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2294
2295#if 0
2296 int rc = VINF_SUCCESS;
2297 PRTFUZZINTERMEDIATE pIntermediate = NULL;
2298 PRTFUZZINPUTINT pInputLoc = rtFuzzCtxInputLocate(pThis->pFuzzer, &pThis->abMd5Hash[0], true /*fExact*/,
2299 &pIntermediate);
2300 if (pInputLoc)
2301 {
2302 AssertPtr(pIntermediate);
2303 Assert(pInputLoc == pThis);
2304
2305 uint64_t u64Md5Low = *(uint64_t *)&pThis->abMd5Hash[0];
2306 RTAvlU64Remove(&pIntermediate->TreeSeedsLow, u64Md5Low);
2307 RTFuzzInputRelease(hFuzzInput);
2308 }
2309 else
2310 rc = VERR_NOT_FOUND;
2311#endif
2312
2313 return VERR_NOT_IMPLEMENTED;
2314}
2315
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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