VirtualBox

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

Last change on this file since 72940 was 72940, checked in by vboxsync, 7 years ago

Runtime/RTFuzz: Some updates, add a mode where the client is aware of being fuzzed for improved efficiency. The input data is fuzzed in the client and fed to the consumer until the program crashes upon the master can reconstruct the input causing the crash because we work with deterministic random number generators. This eliminates the overhead of constantly spawning new client processes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.4 KB
Line 
1/* $Id: fuzz.cpp 72940 2018-07-07 13:37:19Z vboxsync $ */
2/** @file
3 * IPRT - Fuzzing framework API, core.
4 */
5
6/*
7 * Copyright (C) 2018 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/fuzz.h>
32#include "internal/iprt.h"
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/avl.h>
37#include <iprt/ctype.h>
38#include <iprt/dir.h>
39#include <iprt/err.h>
40#include <iprt/file.h>
41#include <iprt/list.h>
42#include <iprt/md5.h>
43#include <iprt/mem.h>
44#include <iprt/path.h>
45#include <iprt/rand.h>
46#include <iprt/string.h>
47#include <iprt/time.h>
48#include <iprt/vfs.h>
49
50
51#define RTFUZZCTX_MAGIC UINT32_C(0xdeadc0de) /** @todo */
52
53/*********************************************************************************************************************************
54* Structures and Typedefs *
55*********************************************************************************************************************************/
56/** Pointer to the internal fuzzer state. */
57typedef struct RTFUZZCTXINT *PRTFUZZCTXINT;
58
59/**
60 * A fuzzing input seed.
61 */
62typedef struct RTFUZZINPUTINT
63{
64 /** The AVL tree core. */
65 AVLU64NODECORE Core;
66 /** Node for the global list. */
67 RTLISTNODE NdInputs;
68 /** Reference counter. */
69 volatile uint32_t cRefs;
70/** @todo add magic here (unused padding space on 64-bit hosts). */
71 /** The fuzzer this input belongs to. */
72 PRTFUZZCTXINT pFuzzer;
73 /** Complete MD5 hash of the input data. */
74 uint8_t abMd5Hash[RTMD5_HASH_SIZE];
75 /** Size of the input data. */
76 size_t cbInput;
77 /** Input data - variable in size. */
78 uint8_t abInput[1];
79} RTFUZZINPUTINT;
80/** Pointer to the internal input state. */
81typedef RTFUZZINPUTINT *PRTFUZZINPUTINT;
82/** Pointer to an internal input state pointer. */
83typedef PRTFUZZINPUTINT *PPRTFUZZINPUTINT;
84
85
86/**
87 * Intermediate indexing structure.
88 */
89typedef struct RTFUZZINTERMEDIATE
90{
91 /** The AVL tree core. */
92 AVLU64NODECORE Core;
93 /** The AVL tree for indexing the input seeds (keyed by the lower half of the MD5). */
94 AVLU64TREE TreeSeedsLow;
95} RTFUZZINTERMEDIATE;
96/** Pointer to an intermediate indexing state. */
97typedef RTFUZZINTERMEDIATE *PRTFUZZINTERMEDIATE;
98/** Pointer to an intermediate indexing state pointer. */
99typedef PRTFUZZINTERMEDIATE *PPRTFUZZINTERMEDIATE;
100
101/**
102 * The fuzzer state.
103 */
104typedef struct RTFUZZCTXINT
105{
106 /** Magic value for identification. */
107 uint32_t u32Magic;
108 /** Reference counter. */
109 volatile uint32_t cRefs;
110 /** The random number generator. */
111 RTRAND hRand;
112 /** The AVL tree for indexing the input seeds (keyed by the upper half of the MD5). */
113 AVLU64TREE TreeSeedsHigh;
114 /** Sequential list of all inputs. */
115 RTLISTANCHOR LstInputs;
116 /** Number of inputs currently in the tree. */
117 uint32_t cInputs;
118 /** The maximum size of one input seed to generate. */
119 size_t cbInputMax;
120 /** Behavioral flags. */
121 uint32_t fFlagsBehavioral;
122} RTFUZZCTXINT;
123
124
125/**
126 * Available mutators enum.
127 */
128typedef enum RTFUZZCTXMUTATOR
129{
130 /** Invalid mutator, not used. */
131 RTFUZZCTXMUTATOR_INVALID = 0,
132 /** Flips a single bit in the input. */
133 RTFUZZCTXMUTATOR_BIT_FLIP,
134 /** Replaces a single byte in the input. */
135 RTFUZZCTXMUTATOR_BYTE_REPLACE,
136 /** Inserts a byte sequence into the input. */
137 RTFUZZCTXMUTATOR_BYTE_SEQUENCE_INSERT,
138 /** Appends a byte sequence to the input. */
139 RTFUZZCTXMUTATOR_BYTE_SEQUENCE_APPEND,
140 /** Deletes a single byte from the input. */
141 RTFUZZCTXMUTATOR_BYTE_DELETE,
142 /** Deletes a sequence of bytes from the input. */
143 RTFUZZCTXMUTATOR_BYTE_SEQUENCE_DELETE,
144 /** Last valid mutator. */
145 RTFUZZCTXMUTATOR_LAST = RTFUZZCTXMUTATOR_BYTE_SEQUENCE_DELETE,
146 /** 32bit hack. */
147 RTFUZZCTXMUTATOR_32BIT_HACK = 0x7fffffff
148} RTFUZZCTXMUTATOR;
149/** Pointer to a mutator enum. */
150typedef RTFUZZCTXMUTATOR *PRTFUZZCTXMUTATOR;
151
152
153/**
154 * The fuzzer state to be exported - all members are stored in little endian form.
155 */
156typedef struct RTFUZZCTXSTATE
157{
158 /** Magic value for identification. */
159 uint32_t u32Magic;
160 /** Size of the PRNG state following in bytes. */
161 uint32_t cbPrng;
162 /** Number of input descriptors following. */
163 uint32_t cInputs;
164 /** Behavioral flags. */
165 uint32_t fFlagsBehavioral;
166 /** Maximum input size to generate. */
167 uint64_t cbInputMax;
168} RTFUZZCTXSTATE;
169/** Pointer to a fuzzing context state. */
170typedef RTFUZZCTXSTATE *PRTFUZZCTXSTATE;
171
172
173/**
174 * Mutator callback.
175 *
176 * @returns IPRT status code.
177 * @param pThis The fuzzer context instance.
178 * @param pvBuf The input buffer to mutate.
179 * @param cbBuf Size of the buffer in bytes.
180 * @param ppInputMutated Where to store the pointer to the mutated input success.
181 */
182typedef DECLCALLBACK(int) FNRTFUZZCTXMUTATOR(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf, PPRTFUZZINPUTINT ppInputMutated);
183/** Pointer to a mutator callback. */
184typedef FNRTFUZZCTXMUTATOR *PFNRTFUZZCTXMUTATOR;
185
186
187
188/*********************************************************************************************************************************
189* Internal Functions *
190*********************************************************************************************************************************/
191static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlip(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf,
192 PPRTFUZZINPUTINT ppInputMutated);
193static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplace(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf,
194 PPRTFUZZINPUTINT ppInputMutated);
195static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsert(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf,
196 PPRTFUZZINPUTINT ppInputMutated);
197static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceAppend(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf,
198 PPRTFUZZINPUTINT ppInputMutated);
199static DECLCALLBACK(int) rtFuzzCtxMutatorByteDelete(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf,
200 PPRTFUZZINPUTINT ppInputMutated);
201static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDelete(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf,
202 PPRTFUZZINPUTINT ppInputMutated);
203
204
205/*********************************************************************************************************************************
206* Global Variables *
207*********************************************************************************************************************************/
208/**
209 * Array of all available mutators.
210 */
211static PFNRTFUZZCTXMUTATOR const g_apfnMutators[] =
212{
213 NULL,
214 rtFuzzCtxMutatorBitFlip,
215 rtFuzzCtxMutatorByteReplace,
216 rtFuzzCtxMutatorByteSequenceInsert,
217 rtFuzzCtxMutatorByteSequenceAppend,
218 rtFuzzCtxMutatorByteDelete,
219 rtFuzzCtxMutatorByteSequenceDelete,
220 NULL
221};
222
223
224
225/**
226 * Tries to locate an input seed with the given input MD5 seed.
227 *
228 * @returns Pointer to the input seed on success or NULL if not found.
229 * @param pThis The fuzzer context instance.
230 * @param pbMd5Hash The MD5 hash to search for.
231 * @param fExact Flag whether to search for an exact match or return the next best fit if no match exists.
232 * @param ppIntermediate Where to store the pointer to the intermediate layer upon success, optional.
233 */
234static PRTFUZZINPUTINT rtFuzzCtxInputLocate(PRTFUZZCTXINT pThis, uint8_t *pbMd5Hash, bool fExact, PPRTFUZZINTERMEDIATE ppIntermediate)
235{
236 PRTFUZZINPUTINT pInput = NULL;
237 uint64_t u64Md5High = *(uint64_t *)&pbMd5Hash[RTMD5_HASH_SIZE / 2];
238 uint64_t u64Md5Low = *(uint64_t *)&pbMd5Hash[0];
239 PRTFUZZINTERMEDIATE pIntermediate = (PRTFUZZINTERMEDIATE)RTAvlU64Get(&pThis->TreeSeedsHigh, u64Md5High);
240 if (!fExact && !pIntermediate)
241 pIntermediate = (PRTFUZZINTERMEDIATE)RTAvlU64GetBestFit(&pThis->TreeSeedsHigh, u64Md5High, true /*fAbove*/);
242 if (!fExact && !pIntermediate)
243 pIntermediate = (PRTFUZZINTERMEDIATE)RTAvlU64GetBestFit(&pThis->TreeSeedsHigh, u64Md5High, false /*fAbove*/);
244
245 if (pIntermediate)
246 {
247 /* 2nd level lookup. */
248 pInput = (PRTFUZZINPUTINT)RTAvlU64Get(&pIntermediate->TreeSeedsLow, u64Md5Low);
249 if (!fExact && !pInput)
250 pInput = (PRTFUZZINPUTINT)RTAvlU64GetBestFit(&pIntermediate->TreeSeedsLow, u64Md5Low, true /*fAbove*/);
251 if (!fExact && !pInput)
252 pInput = (PRTFUZZINPUTINT)RTAvlU64GetBestFit(&pIntermediate->TreeSeedsLow, u64Md5Low, false /*fAbove*/);
253 }
254
255 if (ppIntermediate)
256 *ppIntermediate = pIntermediate;
257
258 return pInput;
259}
260
261
262/**
263 * Adds the given input to the corpus of the given fuzzer context.
264 *
265 * @returns IPRT status code.
266 * @param pThis The fuzzer context instance.
267 * @param pInput The input to add.
268 */
269static int rtFuzzCtxInputAdd(PRTFUZZCTXINT pThis, PRTFUZZINPUTINT pInput)
270{
271 int rc = VINF_SUCCESS;
272 uint64_t u64Md5High = *(uint64_t *)&pInput->abMd5Hash[RTMD5_HASH_SIZE / 2];
273 uint64_t u64Md5Low = *(uint64_t *)&pInput->abMd5Hash[0];
274
275 pInput->Core.Key = u64Md5Low;
276 PRTFUZZINTERMEDIATE pIntermediate = (PRTFUZZINTERMEDIATE)RTAvlU64Get(&pThis->TreeSeedsHigh, u64Md5High);
277 if (!pIntermediate)
278 {
279 pIntermediate = (PRTFUZZINTERMEDIATE)RTMemAllocZ(sizeof(*pIntermediate));
280 if (RT_LIKELY(pIntermediate))
281 {
282 pIntermediate->Core.Key = u64Md5High;
283 pIntermediate->TreeSeedsLow = NULL;
284 bool fIns = RTAvlU64Insert(&pThis->TreeSeedsHigh, &pIntermediate->Core);
285 Assert(fIns); RT_NOREF(fIns);
286 }
287 else
288 rc = VERR_NO_MEMORY;
289 }
290
291 if (RT_SUCCESS(rc))
292 {
293 AssertPtr(pIntermediate);
294 bool fIns = RTAvlU64Insert(&pIntermediate->TreeSeedsLow, &pInput->Core);
295 if (!fIns)
296 rc = VERR_ALREADY_EXISTS;
297 else
298 {
299 RTListAppend(&pThis->LstInputs, &pInput->NdInputs);
300 pThis->cInputs++;
301 RTFuzzInputRetain(pInput);
302 }
303 }
304
305 return rc;
306}
307
308
309/**
310 * Returns a random input from the corpus of the given fuzzer context.
311 *
312 * @returns Pointer to a randomly picked input.
313 * @param pThis The fuzzer context instance.
314 */
315static PRTFUZZINPUTINT rtFuzzCtxInputPickRnd(PRTFUZZCTXINT pThis)
316{
317 /* Generate a random MD5 hash and do a non exact localisation. */
318 uint8_t abDigestRnd[RTMD5_HASH_SIZE];
319 RTRandAdvBytes(pThis->hRand, &abDigestRnd[0], sizeof(abDigestRnd));
320
321 return rtFuzzCtxInputLocate(pThis, &abDigestRnd[0], false /*fExact*/, NULL /*ppIntermediate*/);
322}
323
324
325/**
326 * Clones a given input.
327 *
328 * @returns Pointer to the cloned input or NULL if out of memory.
329 * @param pThis The fuzzer context instance.
330 * @param pvBuf The buffer to clone.
331 * @param cbBuf Size of the buffer in bytes.
332 */
333static PRTFUZZINPUTINT rtFuzzCtxInputClone(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf)
334{
335 PRTFUZZINPUTINT pInpClone = (PRTFUZZINPUTINT)RTMemAllocZ(RT_OFFSETOF(RTFUZZINPUTINT, abInput[cbBuf]));
336 if (RT_LIKELY(pInpClone))
337 {
338 pInpClone->cRefs = 1;
339 pInpClone->pFuzzer = pThis,
340 pInpClone->cbInput = cbBuf;
341 memcpy(&pInpClone->abInput[0], pvBuf, cbBuf);
342 }
343
344 return pInpClone;
345}
346
347
348/**
349 * Creates an empty input seed capable of holding the given number of bytes.
350 *
351 * @returns Pointer to the newly created input seed.
352 * @param pThis The fuzzer context instance.
353 * @param cbInput Input seed size in bytes.
354 */
355static PRTFUZZINPUTINT rtFuzzCtxInputCreate(PRTFUZZCTXINT pThis, size_t cbInput)
356{
357 PRTFUZZINPUTINT pInput = (PRTFUZZINPUTINT)RTMemAllocZ(RT_OFFSETOF(RTFUZZINPUTINT, abInput[cbInput]));
358 if (RT_LIKELY(pInput))
359 {
360 pInput->pFuzzer = pThis;
361 pInput->cRefs = 1;
362 pInput->cbInput = cbInput;
363 }
364
365 return pInput;
366}
367
368
369/**
370 * Destroys the given input.
371 *
372 * @returns nothing.
373 * @param pInput The input to destroy.
374 */
375static void rtFuzzInputDestroy(PRTFUZZINPUTINT pInput)
376{
377 RTMemFree(pInput);
378}
379
380
381/**
382 * Destorys the given fuzzer context freeing all allocated resources.
383 *
384 * @returns nothing.
385 * @param pThis The fuzzer context instance.
386 */
387static void rtFuzzCtxDestroy(PRTFUZZCTXINT pThis)
388{
389 RT_NOREF(pThis);
390}
391
392
393/**
394 * Mutator callback - flips a single bit in the input.
395 */
396static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlip(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf, PPRTFUZZINPUTINT ppInputMutated)
397{
398 int rc = VINF_SUCCESS;
399 PRTFUZZINPUTINT pInputMutated = rtFuzzCtxInputClone(pThis, pvBuf, cbBuf);
400 if (RT_LIKELY(pInputMutated))
401 {
402 int32_t iBit = RTRandAdvS32Ex(pThis->hRand, 0, (uint32_t)cbBuf * 8 - 1);
403 ASMBitToggle(&pInputMutated->abInput[0], iBit);
404 RTMd5(&pInputMutated->abInput[0], pInputMutated->cbInput, &pInputMutated->abMd5Hash[0]);
405 *ppInputMutated = pInputMutated;
406 }
407 else
408 rc = VERR_NO_MEMORY;
409
410 return rc;
411}
412
413
414/**
415 * Mutator callback - replaces a single byte in the input.
416 */
417static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplace(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf, PPRTFUZZINPUTINT ppInputMutated)
418{
419 int rc = VINF_SUCCESS;
420 PRTFUZZINPUTINT pInputMutated = rtFuzzCtxInputClone(pThis, pvBuf, cbBuf);
421 if (RT_LIKELY(pInputMutated))
422 {
423 uint8_t *pbBuf = (uint8_t *)pvBuf;
424 uint32_t offByte = RTRandAdvU32Ex(pThis->hRand, 0, (uint32_t)cbBuf - 1);
425 RTRandAdvBytes(pThis->hRand, &pInputMutated->abInput[offByte], 1);
426 if (pbBuf[offByte] != pInputMutated->abInput[offByte])
427 {
428 RTMd5(&pInputMutated->abInput[0], pInputMutated->cbInput, &pInputMutated->abMd5Hash[0]);
429 *ppInputMutated = pInputMutated;
430 }
431 else
432 RTMemFree(pInputMutated);
433 }
434 else
435 rc = VERR_NO_MEMORY;
436
437 return rc;
438}
439
440
441/**
442 * Mutator callback - inserts a byte sequence into the input.
443 */
444static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsert(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf, PPRTFUZZINPUTINT ppInputMutated)
445{
446 int rc = VINF_SUCCESS;
447 if (cbBuf < pThis->cbInputMax)
448 {
449 size_t cbInputMutated = RTRandAdvU32Ex(pThis->hRand, (uint32_t)cbBuf + 1, (uint32_t)pThis->cbInputMax);
450 size_t cbInsert = cbInputMutated - cbBuf;
451 uint32_t offInsert = RTRandAdvU32Ex(pThis->hRand, 0, (uint32_t)cbBuf);
452 uint8_t *pbBuf = (uint8_t *)pvBuf;
453 PRTFUZZINPUTINT pInputMutated = rtFuzzCtxInputCreate(pThis, cbInputMutated);
454 if (RT_LIKELY(pInputMutated))
455 {
456 if (offInsert)
457 memcpy(&pInputMutated->abInput[0], pbBuf, offInsert);
458 RTRandAdvBytes(pThis->hRand, &pInputMutated->abInput[offInsert], cbInsert);
459 memcpy(&pInputMutated->abInput[offInsert + cbInsert], &pbBuf[offInsert], cbBuf - offInsert);
460 RTMd5(&pInputMutated->abInput[0], pInputMutated->cbInput, &pInputMutated->abMd5Hash[0]);
461 *ppInputMutated = pInputMutated;
462 }
463 else
464 rc = VERR_NO_MEMORY;
465 }
466
467 return rc;
468}
469
470
471/**
472 * Mutator callback - appends a byte sequence to the input.
473 */
474static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceAppend(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf, PPRTFUZZINPUTINT ppInputMutated)
475{
476 int rc = VINF_SUCCESS;
477 if (cbBuf < pThis->cbInputMax)
478 {
479 size_t cbInputMutated = RTRandAdvU32Ex(pThis->hRand, (uint32_t)cbBuf + 1, (uint32_t)pThis->cbInputMax);
480 size_t cbInsert = cbInputMutated - cbBuf;
481 PRTFUZZINPUTINT pInputMutated = rtFuzzCtxInputCreate(pThis, cbInputMutated);
482 if (RT_LIKELY(pInputMutated))
483 {
484 memcpy(&pInputMutated->abInput[0], pvBuf, cbBuf);
485 RTRandAdvBytes(pThis->hRand, &pInputMutated->abInput[cbBuf], cbInsert);
486 RTMd5(&pInputMutated->abInput[0], pInputMutated->cbInput, &pInputMutated->abMd5Hash[0]);
487 *ppInputMutated = pInputMutated;
488 }
489 else
490 rc = VERR_NO_MEMORY;
491 }
492
493 return rc;
494}
495
496
497/**
498 * Mutator callback - deletes a single byte in the input.
499 */
500static DECLCALLBACK(int) rtFuzzCtxMutatorByteDelete(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf, PPRTFUZZINPUTINT ppInputMutated)
501{
502 int rc = VINF_SUCCESS;
503 if (cbBuf > 1)
504 {
505 uint32_t offDelete = RTRandAdvU32Ex(pThis->hRand, 0, (uint32_t)cbBuf - 1);
506 uint8_t *pbBuf = (uint8_t *)pvBuf;
507 PRTFUZZINPUTINT pInputMutated = rtFuzzCtxInputCreate(pThis, cbBuf - 1);
508 if (RT_LIKELY(pInputMutated))
509 {
510 if (offDelete)
511 memcpy(&pInputMutated->abInput[0], pbBuf, offDelete);
512 if (offDelete < cbBuf - 1)
513 memcpy(&pInputMutated->abInput[offDelete], &pbBuf[offDelete + 1], cbBuf - offDelete - 1);
514 RTMd5(&pInputMutated->abInput[0], pInputMutated->cbInput, &pInputMutated->abMd5Hash[0]);
515 *ppInputMutated = pInputMutated;
516 }
517 else
518 rc = VERR_NO_MEMORY;
519 }
520
521 return rc;
522}
523
524
525/**
526 * Mutator callback - deletes a byte sequence in the input.
527 */
528static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDelete(PRTFUZZCTXINT pThis, const void *pvBuf, size_t cbBuf, PPRTFUZZINPUTINT ppInputMutated)
529{
530 int rc = VINF_SUCCESS;
531 if (cbBuf > 1)
532 {
533 size_t cbInputMutated = RTRandAdvU32Ex(pThis->hRand, 0, (uint32_t)cbBuf - 1);
534 size_t cbDel = cbBuf - cbInputMutated;
535 uint32_t offDel = RTRandAdvU32Ex(pThis->hRand, 0, (uint32_t)(cbBuf - cbDel));
536 uint8_t *pbBuf = (uint8_t *)pvBuf;
537
538 PRTFUZZINPUTINT pInputMutated = rtFuzzCtxInputCreate(pThis, cbInputMutated);
539 if (RT_LIKELY(pInputMutated))
540 {
541 if (offDel)
542 memcpy(&pInputMutated->abInput[0], pbBuf, offDel);
543 memcpy(&pInputMutated->abInput[offDel], &pbBuf[offDel + cbDel], cbBuf - offDel - cbDel);
544 RTMd5(&pInputMutated->abInput[0], pInputMutated->cbInput, &pInputMutated->abMd5Hash[0]);
545 *ppInputMutated = pInputMutated;
546 }
547 else
548 rc = VERR_NO_MEMORY;
549 }
550
551 return rc;
552}
553
554
555static PRTFUZZCTXINT rtFuzzCtxCreateEmpty(void)
556{
557 PRTFUZZCTXINT pThis = (PRTFUZZCTXINT)RTMemAllocZ(sizeof(*pThis));
558 if (RT_LIKELY(pThis))
559 {
560 pThis->u32Magic = RTFUZZCTX_MAGIC;
561 pThis->cRefs = 1;
562 pThis->TreeSeedsHigh = NULL;
563 pThis->cbInputMax = UINT32_MAX;
564 pThis->cInputs = 0;
565 pThis->fFlagsBehavioral = 0;
566 RTListInit(&pThis->LstInputs);
567
568 int rc = RTRandAdvCreateParkMiller(&pThis->hRand);
569 if (RT_SUCCESS(rc))
570 {
571 RTRandAdvSeed(pThis->hRand, RTTimeSystemNanoTS());
572 return pThis;
573 }
574
575 RTMemFree(pThis);
576 }
577
578 return NULL;
579}
580
581
582RTDECL(int) RTFuzzCtxCreate(PRTFUZZCTX phFuzzCtx)
583{
584 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
585
586 int rc = VINF_SUCCESS;
587 PRTFUZZCTXINT pThis = rtFuzzCtxCreateEmpty();
588 if (RT_LIKELY(pThis))
589 {
590 *phFuzzCtx = pThis;
591 return VINF_SUCCESS;
592 }
593 else
594 rc = VERR_NO_MEMORY;
595
596 return rc;
597}
598
599
600RTDECL(int) RTFuzzCtxCreateFromState(PRTFUZZCTX phFuzzCtx, const void *pvState, size_t cbState)
601{
602 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
603 AssertPtrReturn(pvState, VERR_INVALID_POINTER);
604 AssertReturn(cbState > 0, VERR_INVALID_PARAMETER);
605
606 int rc = VINF_SUCCESS;
607 if (cbState >= sizeof(RTFUZZCTXSTATE))
608 {
609 RTFUZZCTXSTATE StateImport;
610
611 memcpy(&StateImport, pvState, sizeof(RTFUZZCTXSTATE));
612 if ( RT_LE2H_U32(StateImport.u32Magic) == RTFUZZCTX_MAGIC
613 && RT_LE2H_U32(StateImport.cbPrng) <= cbState - sizeof(RTFUZZCTXSTATE))
614 {
615 PRTFUZZCTXINT pThis = rtFuzzCtxCreateEmpty();
616 if (RT_LIKELY(pThis))
617 {
618 pThis->cbInputMax = (size_t)RT_LE2H_U64(StateImport.cbInputMax);
619 pThis->fFlagsBehavioral = RT_LE2H_U32(StateImport.fFlagsBehavioral);
620
621 uint8_t *pbState = (uint8_t *)pvState;
622 uint32_t cInputs = RT_LE2H_U32(StateImport.cInputs);
623 rc = RTRandAdvRestoreState(pThis->hRand, (const char *)&pbState[sizeof(RTFUZZCTXSTATE)]);
624 if (RT_SUCCESS(rc))
625 {
626 /* Go through the inputs and add them. */
627 pbState += sizeof(RTFUZZCTXSTATE) + RT_LE2H_U32(StateImport.cbPrng);
628 cbState -= sizeof(RTFUZZCTXSTATE) + RT_LE2H_U32(StateImport.cbPrng);
629
630 uint32_t idx = 0;
631 while ( idx < cInputs
632 && RT_SUCCESS(rc))
633 {
634 size_t cbInput = 0;
635 if (cbState >= sizeof(uint32_t))
636 {
637 memcpy(&cbInput, pbState, sizeof(uint32_t));
638 cbInput = RT_LE2H_U32(cbInput);
639 pbState += sizeof(uint32_t);
640 }
641
642 if ( cbInput
643 && cbInput <= cbState)
644 {
645 PRTFUZZINPUTINT pInput = rtFuzzCtxInputCreate(pThis, cbInput);
646 if (RT_LIKELY(pInput))
647 {
648 memcpy(&pInput->abInput[0], pbState, cbInput);
649 RTMd5(&pInput->abInput[0], pInput->cbInput, &pInput->abMd5Hash[0]);
650 rc = rtFuzzCtxInputAdd(pThis, pInput);
651 if (RT_FAILURE(rc))
652 RTMemFree(pInput);
653 pbState += cbInput;
654 }
655 }
656 else
657 rc = VERR_INVALID_STATE;
658
659 idx++;
660 }
661
662 if (RT_SUCCESS(rc))
663 {
664 *phFuzzCtx = pThis;
665 return VINF_SUCCESS;
666 }
667 }
668
669 rtFuzzCtxDestroy(pThis);
670 }
671 else
672 rc = VERR_NO_MEMORY;
673 }
674 else
675 rc = VERR_INVALID_MAGIC;
676 }
677 else
678 rc = VERR_INVALID_MAGIC;
679
680 return rc;
681}
682
683
684RTDECL(int) RTFuzzCtxCreateFromStateFile(PRTFUZZCTX phFuzzCtx, const char *pszFilename)
685{
686 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
687 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
688
689 void *pv = NULL;
690 size_t cb = 0;
691 int rc = RTFileReadAll(pszFilename, &pv, &cb);
692 if (RT_SUCCESS(rc))
693 {
694 rc = RTFuzzCtxCreateFromState(phFuzzCtx, pv, cb);
695 RTFileReadAllFree(pv, cb);
696 }
697
698 return rc;
699}
700
701
702RTDECL(uint32_t) RTFuzzCtxRetain(RTFUZZCTX hFuzzCtx)
703{
704 PRTFUZZCTXINT pThis = hFuzzCtx;
705
706 AssertPtrReturn(pThis, UINT32_MAX);
707
708 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
709 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
710 return cRefs;
711}
712
713
714RTDECL(uint32_t) RTFuzzCtxRelease(RTFUZZCTX hFuzzCtx)
715{
716 PRTFUZZCTXINT pThis = hFuzzCtx;
717 if (pThis == NIL_RTFUZZCTX)
718 return 0;
719 AssertPtrReturn(pThis, UINT32_MAX);
720
721 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
722 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
723 if (cRefs == 0)
724 rtFuzzCtxDestroy(pThis);
725 return cRefs;
726}
727
728
729RTDECL(int) RTFuzzCtxStateExport(RTFUZZCTX hFuzzCtx, void **ppvState, size_t *pcbState)
730{
731 PRTFUZZCTXINT pThis = hFuzzCtx;
732 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
733 AssertPtrReturn(ppvState, VERR_INVALID_POINTER);
734 AssertPtrReturn(pcbState, VERR_INVALID_POINTER);
735
736 char aszPrngExport[_4K]; /* Should be plenty of room here. */
737 size_t cbPrng = sizeof(aszPrngExport);
738 int rc = RTRandAdvSaveState(pThis->hRand, &aszPrngExport[0], &cbPrng);
739 if (RT_SUCCESS(rc))
740 {
741 RTFUZZCTXSTATE StateExport;
742
743 StateExport.u32Magic = RT_H2LE_U32(RTFUZZCTX_MAGIC);
744 StateExport.cbPrng = RT_H2LE_U32((uint32_t)cbPrng);
745 StateExport.cInputs = RT_H2LE_U32(pThis->cInputs);
746 StateExport.fFlagsBehavioral = RT_H2LE_U32(pThis->fFlagsBehavioral);
747 StateExport.cbInputMax = RT_H2LE_U64(pThis->cbInputMax);
748
749 /* Estimate the size of the required state. */
750 size_t cbState = sizeof(StateExport)
751 + cbPrng
752 + pThis->cInputs * ((pThis->cbInputMax < _1M ? pThis->cbInputMax : _64K) + sizeof(uint32_t)); /* For the size indicator before each input. */
753 uint8_t *pbState = (uint8_t *)RTMemAllocZ(cbState);
754 if (RT_LIKELY(pbState))
755 {
756 size_t offState = 0;
757 memcpy(pbState, &StateExport, sizeof(StateExport));
758 offState += sizeof(StateExport);
759 memcpy(&pbState[offState], &aszPrngExport[0], cbPrng);
760 offState += cbPrng;
761
762 /* Export each input. */
763 PRTFUZZINPUTINT pIt;
764 RTListForEach(&pThis->LstInputs, pIt, RTFUZZINPUTINT, NdInputs)
765 {
766 /* Ensure buffer size. */
767 if (offState + pIt->cbInput + sizeof(uint32_t) > cbState)
768 {
769 uint8_t *pbStateNew = (uint8_t *)RTMemRealloc(pbState, cbState + pIt->cbInput + sizeof(uint32_t));
770 if (RT_LIKELY(pbStateNew))
771 {
772 pbState = pbStateNew;
773 cbState += pIt->cbInput + sizeof(uint32_t);
774 }
775 else
776 {
777 rc = VERR_NO_MEMORY;
778 break;
779 }
780 }
781
782 *(uint32_t *)&pbState[offState] = RT_H2LE_U32((uint32_t)pIt->cbInput);
783 offState += sizeof(uint32_t);
784 memcpy(&pbState[offState], &pIt->abInput[0], pIt->cbInput);
785 offState += pIt->cbInput;
786 }
787
788 if (RT_SUCCESS(rc))
789 {
790 *ppvState = pbState;
791 *pcbState = offState;
792 }
793 else
794 RTMemFree(pbState);
795 }
796 else
797 rc = VERR_NO_MEMORY;
798 }
799
800 return rc;
801}
802
803
804RTDECL(int) RTFuzzCtxStateExportToFile(RTFUZZCTX hFuzzCtx, const char *pszFilename)
805{
806 PRTFUZZCTXINT pThis = hFuzzCtx;
807 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
808 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
809
810 void *pvState = NULL;
811 size_t cbState = 0;
812 int rc = RTFuzzCtxStateExport(hFuzzCtx, &pvState, &cbState);
813 if (RT_SUCCESS(rc))
814 {
815 RTFILE hFile;
816
817 rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
818 if (RT_SUCCESS(rc))
819 {
820 rc = RTFileWrite(hFile, pvState, cbState, NULL);
821 RTFileClose(hFile);
822 if (RT_FAILURE(rc))
823 RTFileDelete(pszFilename);
824 }
825
826 RTMemFree(pvState);
827 }
828
829 return rc;
830}
831
832
833RTDECL(int) RTFuzzCtxCorpusInputAdd(RTFUZZCTX hFuzzCtx, const void *pvInput, size_t cbInput)
834{
835 PRTFUZZCTXINT pThis = hFuzzCtx;
836 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
837 AssertPtrReturn(pvInput, VERR_INVALID_POINTER);
838 AssertReturn(cbInput, VERR_INVALID_POINTER);
839
840 /* Generate MD5 checksum and try to locate input. */
841 int rc = VINF_SUCCESS;
842 uint8_t abDigest[RTMD5_HASH_SIZE];
843 RTMd5(pvInput, cbInput, &abDigest[0]);
844
845 PRTFUZZINPUTINT pInput = rtFuzzCtxInputLocate(pThis, &abDigest[0], true /*fExact*/, NULL /*ppIntermediate*/);
846 if (!pInput)
847 {
848 pInput = (PRTFUZZINPUTINT)RTMemAllocZ(RT_OFFSETOF(RTFUZZINPUTINT, abInput[cbInput]));
849 if (RT_LIKELY(pInput))
850 {
851 pInput->cRefs = 1;
852 pInput->pFuzzer = pThis;
853 pInput->cbInput = cbInput;
854 memcpy(&pInput->abInput[0], pvInput, cbInput);
855 memcpy(&pInput->abMd5Hash[0], &abDigest[0], sizeof(abDigest));
856 rc = rtFuzzCtxInputAdd(pThis, pInput);
857 if (RT_FAILURE(rc))
858 RTMemFree(pInput);
859 }
860 else
861 rc = VERR_NO_MEMORY;
862 }
863 else
864 rc = VERR_ALREADY_EXISTS;
865
866 return rc;
867}
868
869
870RTDECL(int) RTFuzzCtxCorpusInputAddFromFile(RTFUZZCTX hFuzzCtx, const char *pszFilename)
871{
872 PRTFUZZCTXINT pThis = hFuzzCtx;
873 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
874 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
875
876 void *pv = NULL;
877 size_t cb = 0;
878 int rc = RTFileReadAll(pszFilename, &pv, &cb);
879 if (RT_SUCCESS(rc))
880 {
881 rc = RTFuzzCtxCorpusInputAdd(hFuzzCtx, pv, cb);
882 RTFileReadAllFree(pv, cb);
883 }
884
885 return rc;
886}
887
888
889RTDECL(int) RTFuzzCtxCorpusInputAddFromVfsFile(RTFUZZCTX hFuzzCtx, RTVFSFILE hVfsFile)
890{
891 PRTFUZZCTXINT pThis = hFuzzCtx;
892 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
893 AssertReturn(hVfsFile != NIL_RTVFSFILE, VERR_INVALID_HANDLE);
894
895 uint64_t cbFile = 0;
896 int rc = RTVfsFileGetSize(hVfsFile, &cbFile);
897 if (RT_SUCCESS(rc))
898 {
899 PRTFUZZINPUTINT pInput = (PRTFUZZINPUTINT)RTMemAllocZ(RT_OFFSETOF(RTFUZZINPUTINT, abInput[cbFile]));
900 if (RT_LIKELY(pInput))
901 {
902 pInput->cRefs = 1;
903 pInput->pFuzzer = pThis;
904 pInput->cbInput = cbFile;
905
906 rc = RTVfsFileRead(hVfsFile, &pInput->abInput[0], cbFile, NULL);
907 if (RT_SUCCESS(rc))
908 {
909 /* Generate MD5 checksum and try to locate input. */
910 uint8_t abDigest[RTMD5_HASH_SIZE];
911 RTMd5(&pInput->abInput[0], cbFile, &abDigest[0]);
912
913 if (!rtFuzzCtxInputLocate(pThis, &abDigest[0], true /*fExact*/, NULL /*ppIntermediate*/))
914 {
915 memcpy(&pInput->abMd5Hash[0], &abDigest[0], sizeof(abDigest));
916 rc = rtFuzzCtxInputAdd(pThis, pInput);
917 }
918 else
919 rc = VERR_ALREADY_EXISTS;
920 }
921
922 if (RT_FAILURE(rc))
923 RTMemFree(pInput);
924 }
925 else
926 rc = VERR_NO_MEMORY;
927 }
928
929 return rc;
930}
931
932
933RTDECL(int) RTFuzzCtxCorpusInputAddFromDirPath(RTFUZZCTX hFuzzCtx, const char *pszDirPath)
934{
935 PRTFUZZCTXINT pThis = hFuzzCtx;
936 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
937 AssertPtrReturn(pszDirPath, VERR_INVALID_POINTER);
938
939 RTDIR hDir;
940 int rc = RTDirOpen(&hDir, pszDirPath);
941 if (RT_SUCCESS(rc))
942 {
943 for (;;)
944 {
945 RTDIRENTRY DirEntry;
946 rc = RTDirRead(hDir, &DirEntry, NULL);
947 if (RT_FAILURE(rc))
948 break;
949
950 /* Skip '.', '..' and other non-files. */
951 if ( DirEntry.enmType != RTDIRENTRYTYPE_UNKNOWN
952 && DirEntry.enmType != RTDIRENTRYTYPE_FILE)
953 continue;
954 if (RTDirEntryIsStdDotLink(&DirEntry))
955 continue;
956
957 /* Compose the full path, result 'unknown' entries and skip non-files. */
958 char szFile[RTPATH_MAX];
959 RT_ZERO(szFile);
960 rc = RTPathJoin(szFile, sizeof(szFile), pszDirPath, DirEntry.szName);
961 if (RT_FAILURE(rc))
962 break;
963
964 if (DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN)
965 {
966 RTDirQueryUnknownType(szFile, false, &DirEntry.enmType);
967 if (DirEntry.enmType != RTDIRENTRYTYPE_FILE)
968 continue;
969 }
970
971 /* Okay, it's a file we can add. */
972 rc = RTFuzzCtxCorpusInputAddFromFile(hFuzzCtx, szFile);
973 if (RT_FAILURE(rc))
974 break;
975 }
976 if (rc == VERR_NO_MORE_FILES)
977 rc = VINF_SUCCESS;
978 RTDirClose(hDir);
979 }
980
981 return rc;
982}
983
984
985RTDECL(int) RTFuzzCtxCfgSetInputSeedMaximum(RTFUZZCTX hFuzzCtx, size_t cbMax)
986{
987 PRTFUZZCTXINT pThis = hFuzzCtx;
988 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
989
990 pThis->cbInputMax = cbMax;
991 return VINF_SUCCESS;
992}
993
994
995RTDECL(size_t) RTFuzzCtxCfgGetInputSeedMaximum(RTFUZZCTX hFuzzCtx)
996{
997 PRTFUZZCTXINT pThis = hFuzzCtx;
998 AssertPtrReturn(pThis, 0);
999
1000 return pThis->cbInputMax;
1001}
1002
1003
1004RTDECL(int) RTFuzzCtxCfgSetBehavioralFlags(RTFUZZCTX hFuzzCtx, uint32_t fFlags)
1005{
1006 PRTFUZZCTXINT pThis = hFuzzCtx;
1007 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1008 AssertReturn(!(fFlags & ~RTFUZZCTX_F_BEHAVIORAL_VALID), VERR_INVALID_PARAMETER);
1009
1010 pThis->fFlagsBehavioral = fFlags;
1011 return VINF_SUCCESS;
1012}
1013
1014
1015RTDECL(uint32_t) RTFuzzCfgGetBehavioralFlags(RTFUZZCTX hFuzzCtx)
1016{
1017 PRTFUZZCTXINT pThis = hFuzzCtx;
1018 AssertPtrReturn(pThis, 0);
1019
1020 return pThis->fFlagsBehavioral;
1021}
1022
1023
1024RTDECL(int) RTFuzzCtxCfgSetTmpDirectory(RTFUZZCTX hFuzzCtx, const char *pszPathTmp)
1025{
1026 PRTFUZZCTXINT pThis = hFuzzCtx;
1027 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1028 AssertPtrReturn(pszPathTmp, VERR_INVALID_POINTER);
1029
1030 return VERR_NOT_IMPLEMENTED;
1031}
1032
1033
1034RTDECL(const char *) RTFuzzCtxCfgGetTmpDirectory(RTFUZZCTX hFuzzCtx)
1035{
1036 PRTFUZZCTXINT pThis = hFuzzCtx;
1037 AssertPtrReturn(pThis, NULL);
1038
1039 return NULL;
1040}
1041
1042
1043RTDECL(int) RTFuzzCtxReseed(RTFUZZCTX hFuzzCtx, uint64_t uSeed)
1044{
1045 PRTFUZZCTXINT pThis = hFuzzCtx;
1046 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1047
1048 RTRandAdvSeed(pThis->hRand, uSeed);
1049 return VINF_SUCCESS;
1050}
1051
1052
1053RTDECL(int) RTFuzzCtxInputGenerate(RTFUZZCTX hFuzzCtx, PRTFUZZINPUT phFuzzInput)
1054{
1055 int rc = VINF_SUCCESS;
1056 PRTFUZZCTXINT pThis = hFuzzCtx;
1057 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1058 AssertPtrReturn(phFuzzInput, VERR_INVALID_POINTER);
1059
1060 uint32_t cTries = 0;
1061 PRTFUZZINPUTINT pSrc = rtFuzzCtxInputPickRnd(pThis);
1062 do
1063 {
1064 RTFUZZCTXMUTATOR enmMutator = (RTFUZZCTXMUTATOR)RTRandAdvU32Ex(pThis->hRand, 1, RTFUZZCTXMUTATOR_LAST);
1065 PRTFUZZINPUTINT pInput = NULL;
1066 rc = g_apfnMutators[enmMutator](pThis, &pSrc->abInput[0], pSrc->cbInput, &pInput);
1067 if ( RT_SUCCESS(rc)
1068 && VALID_PTR(pInput))
1069 {
1070 if (pThis->fFlagsBehavioral & RTFUZZCTX_F_BEHAVIORAL_ADD_INPUT_AUTOMATICALLY_TO_CORPUS)
1071 rtFuzzCtxInputAdd(pThis, pInput);
1072 *phFuzzInput = pInput;
1073 return rc;
1074 }
1075 } while (++cTries <= 50);
1076
1077 if (RT_SUCCESS(rc))
1078 rc = VERR_INVALID_STATE;
1079
1080 return rc;
1081}
1082
1083
1084RTDECL(int) RTFuzzCtxMutateBuffer(RTFUZZCTX hFuzzCtx, void *pvBuf, size_t cbBuf, PRTFUZZINPUT phFuzzInput)
1085{
1086 int rc = VINF_SUCCESS;
1087 PRTFUZZCTXINT pThis = hFuzzCtx;
1088 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1089 AssertPtrReturn(phFuzzInput, VERR_INVALID_POINTER);
1090
1091 uint32_t cTries = 0;
1092 do
1093 {
1094 RTFUZZCTXMUTATOR enmMutator = (RTFUZZCTXMUTATOR)RTRandAdvU32Ex(pThis->hRand, 1, RTFUZZCTXMUTATOR_LAST);
1095 PRTFUZZINPUTINT pInput = NULL;
1096 rc = g_apfnMutators[enmMutator](pThis, pvBuf, cbBuf, &pInput);
1097 if ( RT_SUCCESS(rc)
1098 && VALID_PTR(pInput))
1099 {
1100 *phFuzzInput = pInput;
1101 return rc;
1102 }
1103 } while (++cTries <= 50);
1104
1105 if (RT_SUCCESS(rc))
1106 rc = VERR_INVALID_STATE;
1107
1108 return rc;
1109}
1110
1111
1112RTDECL(uint32_t) RTFuzzInputRetain(RTFUZZINPUT hFuzzInput)
1113{
1114 PRTFUZZINPUTINT pThis = hFuzzInput;
1115
1116 AssertPtrReturn(pThis, UINT32_MAX);
1117
1118 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
1119 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1120 return cRefs;
1121}
1122
1123
1124RTDECL(uint32_t) RTFuzzInputRelease(RTFUZZINPUT hFuzzInput)
1125{
1126 PRTFUZZINPUTINT pThis = hFuzzInput;
1127 if (pThis == NIL_RTFUZZINPUT)
1128 return 0;
1129 AssertPtrReturn(pThis, UINT32_MAX);
1130
1131 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1132 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
1133 if (cRefs == 0)
1134 rtFuzzInputDestroy(pThis);
1135 return cRefs;
1136}
1137
1138
1139RTDECL(int) RTFuzzInputQueryData(RTFUZZINPUT hFuzzInput, void **ppv, size_t *pcb)
1140{
1141 PRTFUZZINPUTINT pThis = hFuzzInput;
1142 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1143 AssertPtrReturn(ppv, VERR_INVALID_POINTER);
1144 AssertPtrReturn(pcb, VERR_INVALID_POINTER);
1145
1146 *ppv = &pThis->abInput[0];
1147 *pcb = pThis->cbInput;
1148 return VINF_SUCCESS;
1149}
1150
1151
1152RTDECL(int) RTFuzzInputQueryDigestString(RTFUZZINPUT hFuzzInput, char *pszDigest, size_t cchDigest)
1153{
1154 PRTFUZZINPUTINT pThis = hFuzzInput;
1155 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1156 AssertPtrReturn(pszDigest, VERR_INVALID_POINTER);
1157 AssertReturn(cchDigest >= RTMD5_STRING_LEN + 1, VERR_INVALID_PARAMETER);
1158
1159 return RTMd5ToString(&pThis->abMd5Hash[0], pszDigest, cchDigest);
1160}
1161
1162
1163RTDECL(int) RTFuzzInputWriteToFile(RTFUZZINPUT hFuzzInput, const char *pszFilename)
1164{
1165 PRTFUZZINPUTINT pThis = hFuzzInput;
1166 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1167 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1168
1169 RTFILE hFile;
1170 int rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
1171 if (RT_SUCCESS(rc))
1172 {
1173 rc = RTFileWrite(hFile, &pThis->abInput[0], pThis->cbInput, NULL);
1174 AssertRC(rc);
1175 RTFileClose(hFile);
1176
1177 if (RT_FAILURE(rc))
1178 RTFileDelete(pszFilename);
1179 }
1180
1181 return rc;
1182}
1183
1184
1185RTDECL(int) RTFuzzInputAddToCtxCorpus(RTFUZZINPUT hFuzzInput)
1186{
1187 PRTFUZZINPUTINT pThis = hFuzzInput;
1188 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1189
1190 return rtFuzzCtxInputAdd(pThis->pFuzzer, pThis);
1191}
1192
1193
1194RTDECL(int) RTFuzzInputRemoveFromCtxCorpus(RTFUZZINPUT hFuzzInput)
1195{
1196 PRTFUZZINPUTINT pThis = hFuzzInput;
1197 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1198
1199 int rc = VINF_SUCCESS;
1200 PRTFUZZINTERMEDIATE pIntermediate = NULL;
1201 PRTFUZZINPUTINT pInputLoc = rtFuzzCtxInputLocate(pThis->pFuzzer, &pThis->abMd5Hash[0], true /*fExact*/,
1202 &pIntermediate);
1203 if (pInputLoc)
1204 {
1205 AssertPtr(pIntermediate);
1206 Assert(pInputLoc == pThis);
1207
1208 uint64_t u64Md5Low = *(uint64_t *)&pThis->abMd5Hash[0];
1209 RTAvlU64Remove(&pIntermediate->TreeSeedsLow, u64Md5Low);
1210 RTFuzzInputRelease(hFuzzInput);
1211 }
1212 else
1213 rc = VERR_NOT_FOUND;
1214
1215 return rc;
1216}
1217
Note: See TracBrowser for help on using the repository browser.

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