VirtualBox

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

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

iprt/fuzz: Some delinting. bugref:9006

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.2 KB
Line 
1/* $Id: fuzz.cpp 72454 2018-06-05 19:32:45Z 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.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/fuzz.h>
32#include "internal/iprt.h"
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/avl.h>
37#include <iprt/ctype.h>
38#include <iprt/dir.h>
39#include <iprt/err.h>
40#include <iprt/file.h>
41#include <iprt/md5.h>
42#include <iprt/mem.h>
43#include <iprt/path.h>
44#include <iprt/rand.h>
45#include <iprt/string.h>
46#include <iprt/time.h>
47
48
49/*********************************************************************************************************************************
50* Structures and Typedefs *
51*********************************************************************************************************************************/
52/** Pointer to the internal fuzzer state. */
53typedef struct RTFUZZCTXINT *PRTFUZZCTXINT;
54
55/**
56 * A fuzzing input seed.
57 */
58typedef struct RTFUZZINPUTINT
59{
60 /** The AVL tree core. */
61 AVLU64NODECORE Core;
62 /** Reference counter. */
63 volatile uint32_t cRefs;
64/** @todo add magic here (unused padding space on 64-bit hosts). */
65 /** The fuzzer this input belongs to. */
66 PRTFUZZCTXINT pFuzzer;
67 /** Complete MD5 hash of the input data. */
68 uint8_t abMd5Hash[RTMD5_HASH_SIZE];
69 /** Size of the input data. */
70 size_t cbInput;
71 /** Input data - variable in size. */
72 uint8_t abInput[1];
73} RTFUZZINPUTINT;
74/** Pointer to the internal input state. */
75typedef RTFUZZINPUTINT *PRTFUZZINPUTINT;
76/** Pointer to an internal input state pointer. */
77typedef PRTFUZZINPUTINT *PPRTFUZZINPUTINT;
78
79
80/**
81 * Intermediate indexing structure.
82 */
83typedef struct RTFUZZINTERMEDIATE
84{
85 /** The AVL tree core. */
86 AVLU64NODECORE Core;
87 /** The AVL tree for indexing the input seeds (keyed by the lower half of the MD5). */
88 AVLU64TREE TreeSeedsLow;
89} RTFUZZINTERMEDIATE;
90/** Pointer to an intermediate indexing state. */
91typedef RTFUZZINTERMEDIATE *PRTFUZZINTERMEDIATE;
92/** Pointer to an intermediate indexing state pointer. */
93typedef PRTFUZZINTERMEDIATE *PPRTFUZZINTERMEDIATE;
94
95/**
96 * The fuzzer state.
97 */
98typedef struct RTFUZZCTXINT
99{
100 /** Magic value for identification. */
101 uint32_t u32Magic;
102 /** Reference counter. */
103 volatile uint32_t cRefs;
104 /** The random number generator. */
105 RTRAND hRand;
106 /** The AVL tree for indexing the input seeds (keyed by the upper half of the MD5). */
107 AVLU64TREE TreeSeedsHigh;
108 /** The maximum size of one input seed to generate. */
109 size_t cbInputMax;
110 /** Behavioral flags. */
111 uint32_t fFlagsBehavioral;
112} RTFUZZCTXINT;
113
114
115/**
116 * Available mutators enum.
117 */
118typedef enum RTFUZZCTXMUTATOR
119{
120 /** Invalid mutator, not used. */
121 RTFUZZCTXMUTATOR_INVALID = 0,
122 /** Flips a single bit in the input. */
123 RTFUZZCTXMUTATOR_BIT_FLIP,
124 /** Replaces a single byte in the input. */
125 RTFUZZCTXMUTATOR_BYTE_REPLACE,
126 /** Inserts a byte sequence into the input. */
127 RTFUZZCTXMUTATOR_BYTE_SEQUENCE_INSERT,
128 /** Appends a byte sequence to the input. */
129 RTFUZZCTXMUTATOR_BYTE_SEQUENCE_APPEND,
130 /** Deletes a single byte from the input. */
131 RTFUZZCTXMUTATOR_BYTE_DELETE,
132 /** Deletes a sequence of bytes from the input. */
133 RTFUZZCTXMUTATOR_BYTE_SEQUENCE_DELETE,
134 /** Last valid mutator. */
135 RTFUZZCTXMUTATOR_LAST = RTFUZZCTXMUTATOR_BYTE_SEQUENCE_DELETE,
136 /** 32bit hack. */
137 RTFUZZCTXMUTATOR_32BIT_HACK = 0x7fffffff
138} RTFUZZCTXMUTATOR;
139/** Pointer to a mutator enum. */
140typedef RTFUZZCTXMUTATOR *PRTFUZZCTXMUTATOR;
141
142
143/**
144 * Mutator callback.
145 *
146 * @returns IPRT status code.
147 * @param pThis The fuzzer context instance.
148 * @param ppInputMutated Where to store the pointer to the mutated input success.
149 */
150typedef DECLCALLBACK(int) FNRTFUZZCTXMUTATOR(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated);
151/** Pointer to a mutator callback. */
152typedef FNRTFUZZCTXMUTATOR *PFNRTFUZZCTXMUTATOR;
153
154
155
156/*********************************************************************************************************************************
157* Internal Functions *
158*********************************************************************************************************************************/
159static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlip(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated);
160static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplace(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated);
161static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsert(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated);
162static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceAppend(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated);
163static DECLCALLBACK(int) rtFuzzCtxMutatorByteDelete(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated);
164static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDelete(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated);
165
166
167/*********************************************************************************************************************************
168* Global Variables *
169*********************************************************************************************************************************/
170/**
171 * Array of all available mutators.
172 */
173static PFNRTFUZZCTXMUTATOR const g_apfnMutators[] =
174{
175 NULL,
176 rtFuzzCtxMutatorBitFlip,
177 rtFuzzCtxMutatorByteReplace,
178 rtFuzzCtxMutatorByteSequenceInsert,
179 rtFuzzCtxMutatorByteSequenceAppend,
180 rtFuzzCtxMutatorByteDelete,
181 rtFuzzCtxMutatorByteSequenceDelete,
182 NULL
183};
184
185
186
187/**
188 * Tries to locate an input seed with the given input MD5 seed.
189 *
190 * @returns Pointer to the input seed on success or NULL if not found.
191 * @param pThis The fuzzer context instance.
192 * @param pbMd5Hash The MD5 hash to search for.
193 * @param fExact Flag whether to search for an exact match or return the next best fit if no match exists.
194 * @param ppIntermediate Where to store the pointer to the intermediate layer upon success, optional.
195 */
196static PRTFUZZINPUTINT rtFuzzCtxInputLocate(PRTFUZZCTXINT pThis, uint8_t *pbMd5Hash, bool fExact, PPRTFUZZINTERMEDIATE ppIntermediate)
197{
198 PRTFUZZINPUTINT pInput = NULL;
199 uint64_t u64Md5High = *(uint64_t *)&pbMd5Hash[RTMD5_HASH_SIZE / 2];
200 uint64_t u64Md5Low = *(uint64_t *)&pbMd5Hash[0];
201 PRTFUZZINTERMEDIATE pIntermediate = (PRTFUZZINTERMEDIATE)RTAvlU64Get(&pThis->TreeSeedsHigh, u64Md5High);
202 if (!fExact && !pIntermediate)
203 pIntermediate = (PRTFUZZINTERMEDIATE)RTAvlU64GetBestFit(&pThis->TreeSeedsHigh, u64Md5High, true /*fAbove*/);
204 if (!fExact && !pIntermediate)
205 pIntermediate = (PRTFUZZINTERMEDIATE)RTAvlU64GetBestFit(&pThis->TreeSeedsHigh, u64Md5High, false /*fAbove*/);
206
207 if (pIntermediate)
208 {
209 /* 2nd level lookup. */
210 pInput = (PRTFUZZINPUTINT)RTAvlU64Get(&pIntermediate->TreeSeedsLow, u64Md5Low);
211 if (!fExact && !pInput)
212 pInput = (PRTFUZZINPUTINT)RTAvlU64GetBestFit(&pIntermediate->TreeSeedsLow, u64Md5Low, true /*fAbove*/);
213 if (!fExact && !pInput)
214 pInput = (PRTFUZZINPUTINT)RTAvlU64GetBestFit(&pIntermediate->TreeSeedsLow, u64Md5Low, false /*fAbove*/);
215 }
216
217 if (ppIntermediate)
218 *ppIntermediate = pIntermediate;
219
220 return pInput;
221}
222
223
224/**
225 * Adds the given input to the corpus of the given fuzzer context.
226 *
227 * @returns IPRT status code.
228 * @param pThis The fuzzer context instance.
229 * @param pInput The input to add.
230 */
231static int rtFuzzCtxInputAdd(PRTFUZZCTXINT pThis, PRTFUZZINPUTINT pInput)
232{
233 int rc = VINF_SUCCESS;
234 uint64_t u64Md5High = *(uint64_t *)&pInput->abMd5Hash[RTMD5_HASH_SIZE / 2];
235 uint64_t u64Md5Low = *(uint64_t *)&pInput->abMd5Hash[0];
236
237 pInput->Core.Key = u64Md5Low;
238 PRTFUZZINTERMEDIATE pIntermediate = (PRTFUZZINTERMEDIATE)RTAvlU64Get(&pThis->TreeSeedsHigh, u64Md5High);
239 if (!pIntermediate)
240 {
241 pIntermediate = (PRTFUZZINTERMEDIATE)RTMemAllocZ(sizeof(*pIntermediate));
242 if (RT_LIKELY(pIntermediate))
243 {
244 pIntermediate->Core.Key = u64Md5High;
245 pIntermediate->TreeSeedsLow = NULL;
246 bool fIns = RTAvlU64Insert(&pThis->TreeSeedsHigh, &pIntermediate->Core);
247 Assert(fIns); RT_NOREF(fIns);
248 }
249 else
250 rc = VERR_NO_MEMORY;
251 }
252
253 if (RT_SUCCESS(rc))
254 {
255 AssertPtr(pIntermediate);
256 bool fIns = RTAvlU64Insert(&pIntermediate->TreeSeedsLow, &pInput->Core);
257 if (!fIns)
258 rc = VERR_ALREADY_EXISTS;
259 else
260 RTFuzzInputRetain(pInput);
261 }
262
263 return rc;
264}
265
266
267/**
268 * Returns a random input from the corpus of the given fuzzer context.
269 *
270 * @returns Pointer to a randomly picked input.
271 * @param pThis The fuzzer context instance.
272 */
273static PRTFUZZINPUTINT rtFuzzCtxInputPickRnd(PRTFUZZCTXINT pThis)
274{
275 /* Generate a random MD5 hash and do a non exact localisation. */
276 uint8_t abDigestRnd[RTMD5_HASH_SIZE];
277 RTRandAdvBytes(pThis->hRand, &abDigestRnd[0], sizeof(abDigestRnd));
278
279 return rtFuzzCtxInputLocate(pThis, &abDigestRnd[0], false /*fExact*/, NULL /*ppIntermediate*/);
280}
281
282
283/**
284 * Clones a given input.
285 *
286 * @returns Pointer to the cloned input or NULL if out of memory.
287 * @param pInput The input to clone.
288 */
289static PRTFUZZINPUTINT rtFuzzCtxInputClone(PRTFUZZINPUTINT pInput)
290{
291 PRTFUZZINPUTINT pInpClone = (PRTFUZZINPUTINT)RTMemDup(pInput, RT_OFFSETOF(RTFUZZINPUTINT, abInput[pInput->cbInput]));
292 if (RT_LIKELY(pInpClone))
293 {
294 pInpClone->cRefs = 1;
295 pInpClone->Core.Key = 0;
296 }
297
298 return pInpClone;
299}
300
301
302/**
303 * Creates an empty input seed capable of holding the given number of bytes.
304 *
305 * @returns Pointer to the newly created input seed.
306 * @param pThis The fuzzer context instance.
307 * @param cbInput Input seed size in bytes.
308 */
309static PRTFUZZINPUTINT rtFuzzCtxInputCreate(PRTFUZZCTXINT pThis, size_t cbInput)
310{
311 PRTFUZZINPUTINT pInput = (PRTFUZZINPUTINT)RTMemAllocZ(RT_OFFSETOF(RTFUZZINPUTINT, abInput[cbInput]));
312 if (RT_LIKELY(pInput))
313 {
314 pInput->pFuzzer = pThis;
315 pInput->cRefs = 1;
316 pInput->cbInput = cbInput;
317 }
318
319 return pInput;
320}
321
322
323/**
324 * Destroys the given input.
325 *
326 * @returns nothing.
327 * @param pInput The input to destroy.
328 */
329static void rtFuzzInputDestroy(PRTFUZZINPUTINT pInput)
330{
331 RTMemFree(pInput);
332}
333
334
335/**
336 * Destorys the given fuzzer context freeing all allocated resources.
337 *
338 * @returns nothing.
339 * @param pThis The fuzzer context instance.
340 */
341static void rtFuzzCtxDestroy(PRTFUZZCTXINT pThis)
342{
343 RT_NOREF(pThis);
344}
345
346
347/**
348 * Mutator callback - flips a single bit in the input.
349 */
350static DECLCALLBACK(int) rtFuzzCtxMutatorBitFlip(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated)
351{
352 int rc = VINF_SUCCESS;
353 PRTFUZZINPUTINT pInput = rtFuzzCtxInputPickRnd(pThis);
354 PRTFUZZINPUTINT pInputMutated = rtFuzzCtxInputClone(pInput);
355 if (RT_LIKELY(pInputMutated))
356 {
357 int32_t iBit = RTRandAdvS32Ex(pThis->hRand, 0, (uint32_t)pInput->cbInput * 8 - 1);
358 ASMBitToggle(&pInputMutated->abInput[0], iBit);
359 RTMd5(&pInputMutated->abInput[0], pInputMutated->cbInput, &pInputMutated->abMd5Hash[0]);
360 *ppInputMutated = pInputMutated;
361 }
362 else
363 rc = VERR_NO_MEMORY;
364
365 return rc;
366}
367
368
369/**
370 * Mutator callback - replaces a single byte in the input.
371 */
372static DECLCALLBACK(int) rtFuzzCtxMutatorByteReplace(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated)
373{
374 int rc = VINF_SUCCESS;
375 PRTFUZZINPUTINT pInput = rtFuzzCtxInputPickRnd(pThis);
376 PRTFUZZINPUTINT pInputMutated = rtFuzzCtxInputClone(pInput);
377 if (RT_LIKELY(pInputMutated))
378 {
379 uint32_t offByte = RTRandAdvU32Ex(pThis->hRand, 0, (uint32_t)pInput->cbInput - 1);
380 RTRandAdvBytes(pThis->hRand, &pInputMutated->abInput[offByte], 1);
381 if (pInput->abInput[offByte] != pInputMutated->abInput[offByte])
382 {
383 RTMd5(&pInputMutated->abInput[0], pInputMutated->cbInput, &pInputMutated->abMd5Hash[0]);
384 *ppInputMutated = pInputMutated;
385 }
386 else
387 RTMemFree(pInputMutated);
388 }
389 else
390 rc = VERR_NO_MEMORY;
391
392 return rc;
393}
394
395
396/**
397 * Mutator callback - inserts a byte sequence into the input.
398 */
399static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceInsert(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated)
400{
401 int rc = VINF_SUCCESS;
402 PRTFUZZINPUTINT pInput = rtFuzzCtxInputPickRnd(pThis);
403 if (pInput->cbInput < pThis->cbInputMax)
404 {
405 size_t cbInputMutated = RTRandAdvU32Ex(pThis->hRand, (uint32_t)pInput->cbInput + 1, (uint32_t)pThis->cbInputMax);
406 size_t cbInsert = cbInputMutated - pInput->cbInput;
407 uint32_t offInsert = RTRandAdvU32Ex(pThis->hRand, 0, (uint32_t)pInput->cbInput);
408 PRTFUZZINPUTINT pInputMutated = rtFuzzCtxInputCreate(pThis, cbInputMutated);
409 if (RT_LIKELY(pInputMutated))
410 {
411 if (offInsert)
412 memcpy(&pInputMutated->abInput[0], &pInput->abInput[0], offInsert);
413 RTRandAdvBytes(pThis->hRand, &pInputMutated->abInput[offInsert], cbInsert);
414 memcpy(&pInputMutated->abInput[offInsert + cbInsert], &pInput->abInput[offInsert], pInput->cbInput - offInsert);
415 RTMd5(&pInputMutated->abInput[0], pInputMutated->cbInput, &pInputMutated->abMd5Hash[0]);
416 *ppInputMutated = pInputMutated;
417 }
418 else
419 rc = VERR_NO_MEMORY;
420 }
421
422 return rc;
423}
424
425
426/**
427 * Mutator callback - appends a byte sequence to the input.
428 */
429static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceAppend(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated)
430{
431 int rc = VINF_SUCCESS;
432 PRTFUZZINPUTINT pInput = rtFuzzCtxInputPickRnd(pThis);
433 if (pInput->cbInput < pThis->cbInputMax)
434 {
435 size_t cbInputMutated = RTRandAdvU32Ex(pThis->hRand, (uint32_t)pInput->cbInput + 1, (uint32_t)pThis->cbInputMax);
436 size_t cbInsert = cbInputMutated - pInput->cbInput;
437 PRTFUZZINPUTINT pInputMutated = rtFuzzCtxInputCreate(pThis, cbInputMutated);
438 if (RT_LIKELY(pInputMutated))
439 {
440 memcpy(&pInputMutated->abInput[0], &pInput->abInput[0], pInput->cbInput);
441 RTRandAdvBytes(pThis->hRand, &pInputMutated->abInput[pInput->cbInput], cbInsert);
442 RTMd5(&pInputMutated->abInput[0], pInputMutated->cbInput, &pInputMutated->abMd5Hash[0]);
443 *ppInputMutated = pInputMutated;
444 }
445 else
446 rc = VERR_NO_MEMORY;
447 }
448
449 return rc;
450}
451
452
453/**
454 * Mutator callback - deletes a single byte in the input.
455 */
456static DECLCALLBACK(int) rtFuzzCtxMutatorByteDelete(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated)
457{
458 int rc = VINF_SUCCESS;
459 PRTFUZZINPUTINT pInput = rtFuzzCtxInputPickRnd(pThis);
460 if (pInput->cbInput > 1)
461 {
462 uint32_t offDelete = RTRandAdvU32Ex(pThis->hRand, 0, (uint32_t)pInput->cbInput - 1);
463 PRTFUZZINPUTINT pInputMutated = rtFuzzCtxInputCreate(pThis, pInput->cbInput - 1);
464 if (RT_LIKELY(pInputMutated))
465 {
466 if (offDelete)
467 memcpy(&pInputMutated->abInput[0], &pInput->abInput[0], offDelete);
468 if (offDelete < pInput->cbInput - 1)
469 memcpy(&pInputMutated->abInput[offDelete], &pInput->abInput[offDelete + 1], pInput->cbInput - offDelete - 1);
470 RTMd5(&pInputMutated->abInput[0], pInputMutated->cbInput, &pInputMutated->abMd5Hash[0]);
471 *ppInputMutated = pInputMutated;
472 }
473 else
474 rc = VERR_NO_MEMORY;
475 }
476
477 return rc;
478}
479
480
481/**
482 * Mutator callback - deletes a byte sequence in the input.
483 */
484static DECLCALLBACK(int) rtFuzzCtxMutatorByteSequenceDelete(PRTFUZZCTXINT pThis, PPRTFUZZINPUTINT ppInputMutated)
485{
486 RT_NOREF(pThis, ppInputMutated);
487 return VERR_NOT_IMPLEMENTED;
488}
489
490
491RTDECL(int) RTFuzzCtxCreate(PRTFUZZCTX phFuzzCtx)
492{
493 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
494
495 int rc = VINF_SUCCESS;
496 PRTFUZZCTXINT pThis = (PRTFUZZCTXINT)RTMemAllocZ(sizeof(*pThis));
497 if (RT_LIKELY(pThis))
498 {
499 pThis->u32Magic = 0xdeadc0de; /** @todo */
500 pThis->cRefs = 1;
501 pThis->TreeSeedsHigh = NULL;
502 pThis->cbInputMax = UINT32_MAX;
503 pThis->fFlagsBehavioral = 0;
504 rc = RTRandAdvCreateParkMiller(&pThis->hRand);
505 if (RT_SUCCESS(rc))
506 {
507 RTRandAdvSeed(pThis->hRand, RTTimeSystemNanoTS()); /** @todo */
508 *phFuzzCtx = pThis;
509 return VINF_SUCCESS;
510 }
511
512 RTMemFree(pThis);
513 }
514 else
515 rc = VERR_NO_MEMORY;
516
517 return rc;
518}
519
520
521RTDECL(int) RTFuzzCtxCreateFromState(PRTFUZZCTX phFuzzCtx, const void *pvState, size_t cbState)
522{
523 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
524 AssertPtrReturn(pvState, VERR_INVALID_POINTER);
525 AssertReturn(cbState > 0, VERR_INVALID_PARAMETER);
526
527 return VERR_NOT_IMPLEMENTED;
528}
529
530
531RTDECL(int) RTFuzzCtxCreateFromStateFile(PRTFUZZCTX phFuzzCtx, const char *pszFilename)
532{
533 AssertPtrReturn(phFuzzCtx, VERR_INVALID_POINTER);
534 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
535
536 return VERR_NOT_IMPLEMENTED;
537}
538
539
540RTDECL(uint32_t) RTFuzzCtxRetain(RTFUZZCTX hFuzzCtx)
541{
542 PRTFUZZCTXINT pThis = hFuzzCtx;
543
544 AssertPtrReturn(pThis, UINT32_MAX);
545
546 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
547 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
548 return cRefs;
549}
550
551
552RTDECL(uint32_t) RTFuzzCtxRelease(RTFUZZCTX hFuzzCtx)
553{
554 PRTFUZZCTXINT pThis = hFuzzCtx;
555 if (pThis == NIL_RTFUZZCTX)
556 return 0;
557 AssertPtrReturn(pThis, UINT32_MAX);
558
559 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
560 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
561 if (cRefs == 0)
562 rtFuzzCtxDestroy(pThis);
563 return cRefs;
564}
565
566
567RTDECL(int) RTFuzzCtxStateExport(RTFUZZCTX hFuzzCtx, void **ppvState, size_t *pcbState)
568{
569 PRTFUZZCTXINT pThis = hFuzzCtx;
570 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
571 AssertPtrReturn(ppvState, VERR_INVALID_POINTER);
572 AssertPtrReturn(pcbState, VERR_INVALID_POINTER);
573
574 return VERR_NOT_IMPLEMENTED;
575}
576
577
578RTDECL(int) RTFuzzCtxStateExportToFile(RTFUZZCTX hFuzzCtx, const char *pszFilename)
579{
580 PRTFUZZCTXINT pThis = hFuzzCtx;
581 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
582 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
583
584 return VERR_NOT_IMPLEMENTED;
585}
586
587
588RTDECL(int) RTFuzzCtxCorpusInputAdd(RTFUZZCTX hFuzzCtx, const void *pvInput, size_t cbInput)
589{
590 PRTFUZZCTXINT pThis = hFuzzCtx;
591 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
592 AssertPtrReturn(pvInput, VERR_INVALID_POINTER);
593 AssertReturn(cbInput, VERR_INVALID_POINTER);
594
595 /* Generate MD5 checksum and try to locate input. */
596 int rc = VINF_SUCCESS;
597 uint8_t abDigest[RTMD5_HASH_SIZE];
598 RTMd5(pvInput, cbInput, &abDigest[0]);
599
600 PRTFUZZINPUTINT pInput = rtFuzzCtxInputLocate(pThis, &abDigest[0], true /*fExact*/, NULL /*ppIntermediate*/);
601 if (!pInput)
602 {
603 pInput = (PRTFUZZINPUTINT)RTMemAllocZ(RT_OFFSETOF(RTFUZZINPUTINT, abInput[cbInput]));
604 if (RT_LIKELY(pInput))
605 {
606 pInput->cRefs = 1;
607 pInput->pFuzzer = pThis;
608 pInput->cbInput = cbInput;
609 memcpy(&pInput->abInput[0], pvInput, cbInput);
610 memcpy(&pInput->abMd5Hash[0], &abDigest[0], sizeof(abDigest));
611 rc = rtFuzzCtxInputAdd(pThis, pInput);
612 if (RT_FAILURE(rc))
613 RTMemFree(pInput);
614 }
615 else
616 rc = VERR_NO_MEMORY;
617 }
618 else
619 rc = VERR_ALREADY_EXISTS;
620
621 return rc;
622}
623
624
625RTDECL(int) RTFuzzCtxCorpusInputAddFromFile(RTFUZZCTX hFuzzCtx, const char *pszFilename)
626{
627 PRTFUZZCTXINT pThis = hFuzzCtx;
628 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
629 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
630
631 void *pv = NULL;
632 size_t cb = 0;
633 int rc = RTFileReadAll(pszFilename, &pv, &cb);
634 if (RT_SUCCESS(rc))
635 {
636 rc = RTFuzzCtxCorpusInputAdd(hFuzzCtx, pv, cb);
637 RTFileReadAllFree(pv, cb);
638 }
639
640 return rc;
641}
642
643
644RTDECL(int) RTFuzzCtxCorpusInputAddFromDirPath(RTFUZZCTX hFuzzCtx, const char *pszDirPath)
645{
646 PRTFUZZCTXINT pThis = hFuzzCtx;
647 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
648 AssertPtrReturn(pszDirPath, VERR_INVALID_POINTER);
649
650 RTDIR hDir;
651 int rc = RTDirOpen(&hDir, pszDirPath);
652 if (RT_SUCCESS(rc))
653 {
654 for (;;)
655 {
656 RTDIRENTRY DirEntry;
657 rc = RTDirRead(hDir, &DirEntry, NULL);
658 if (RT_FAILURE(rc))
659 break;
660
661 /* Skip '.', '..' and other non-files. */
662 if ( DirEntry.enmType != RTDIRENTRYTYPE_UNKNOWN
663 && DirEntry.enmType != RTDIRENTRYTYPE_FILE)
664 continue;
665 if (RTDirEntryIsStdDotLink(&DirEntry))
666 continue;
667
668 /* Compose the full path, result 'unknown' entries and skip non-files. */
669 char szFile[RTPATH_MAX];
670 RT_ZERO(szFile);
671 rc = RTPathJoin(szFile, sizeof(szFile), pszDirPath, DirEntry.szName);
672 if (RT_FAILURE(rc))
673 break;
674
675 if (DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN)
676 {
677 RTDirQueryUnknownType(szFile, false, &DirEntry.enmType);
678 if (DirEntry.enmType != RTDIRENTRYTYPE_FILE)
679 continue;
680 }
681
682 /* Okay, it's a file we can add. */
683 rc = RTFuzzCtxCorpusInputAddFromFile(hFuzzCtx, szFile);
684 if (RT_FAILURE(rc))
685 break;
686 }
687 if (rc == VERR_NO_MORE_FILES)
688 rc = VINF_SUCCESS;
689 RTDirClose(hDir);
690 }
691
692 return rc;
693}
694
695
696RTDECL(int) RTFuzzCtxCfgSetInputSeedMaximum(RTFUZZCTX hFuzzCtx, size_t cbMax)
697{
698 PRTFUZZCTXINT pThis = hFuzzCtx;
699 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
700 AssertReturn(cbMax, VERR_INVALID_PARAMETER);
701
702 pThis->cbInputMax = cbMax;
703 return VINF_SUCCESS;
704}
705
706
707RTDECL(size_t) RTFuzzCtxCfgGetInputSeedMaximum(RTFUZZCTX hFuzzCtx)
708{
709 PRTFUZZCTXINT pThis = hFuzzCtx;
710 AssertPtrReturn(pThis, 0);
711
712 return pThis->cbInputMax;
713}
714
715
716RTDECL(int) RTFuzzCtxCfgSetBehavioralFlags(RTFUZZCTX hFuzzCtx, uint32_t fFlags)
717{
718 PRTFUZZCTXINT pThis = hFuzzCtx;
719 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
720 AssertReturn(!(fFlags & ~RTFUZZCTX_F_BEHAVIORAL_VALID), VERR_INVALID_PARAMETER);
721
722 pThis->fFlagsBehavioral = fFlags;
723 return VINF_SUCCESS;
724}
725
726
727RTDECL(uint32_t) RTFuzzCfgGetBehavioralFlags(RTFUZZCTX hFuzzCtx)
728{
729 PRTFUZZCTXINT pThis = hFuzzCtx;
730 AssertPtrReturn(pThis, 0);
731
732 return pThis->fFlagsBehavioral;
733}
734
735
736RTDECL(int) RTFuzzCtxCfgSetTmpDirectory(RTFUZZCTX hFuzzCtx, const char *pszPathTmp)
737{
738 PRTFUZZCTXINT pThis = hFuzzCtx;
739 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
740 AssertPtrReturn(pszPathTmp, VERR_INVALID_POINTER);
741
742 return VERR_NOT_IMPLEMENTED;
743}
744
745
746RTDECL(const char *) RTFuzzCtxCfgGetTmpDirectory(RTFUZZCTX hFuzzCtx)
747{
748 PRTFUZZCTXINT pThis = hFuzzCtx;
749 AssertPtrReturn(pThis, NULL);
750
751 return NULL;
752}
753
754
755RTDECL(int) RTFuzzCtxInputGenerate(RTFUZZCTX hFuzzCtx, PRTFUZZINPUT phFuzzInput)
756{
757 int rc = VINF_SUCCESS;
758 PRTFUZZCTXINT pThis = hFuzzCtx;
759 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
760 AssertPtrReturn(phFuzzInput, VERR_INVALID_POINTER);
761
762 uint32_t cTries = 0;
763 do
764 {
765 RTFUZZCTXMUTATOR enmMutator = (RTFUZZCTXMUTATOR)RTRandAdvU32Ex(pThis->hRand, 1, RTFUZZCTXMUTATOR_LAST);
766 PRTFUZZINPUTINT pInput = NULL;
767 rc = g_apfnMutators[enmMutator](pThis, &pInput);
768 if ( RT_SUCCESS(rc)
769 && VALID_PTR(pInput))
770 {
771 if (pThis->fFlagsBehavioral & RTFUZZCTX_F_BEHAVIORAL_ADD_INPUT_AUTOMATICALLY_TO_CORPUS)
772 rtFuzzCtxInputAdd(pThis, pInput);
773 *phFuzzInput = pInput;
774 return rc;
775 }
776 } while (++cTries <= 50);
777
778 if (RT_SUCCESS(rc))
779 rc = VERR_INVALID_STATE;
780
781 return rc;
782}
783
784
785RTDECL(uint32_t) RTFuzzInputRetain(RTFUZZINPUT hFuzzInput)
786{
787 PRTFUZZINPUTINT pThis = hFuzzInput;
788
789 AssertPtrReturn(pThis, UINT32_MAX);
790
791 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
792 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p\n", cRefs, pThis));
793 return cRefs;
794}
795
796
797RTDECL(uint32_t) RTFuzzInputRelease(RTFUZZINPUT hFuzzInput)
798{
799 PRTFUZZINPUTINT pThis = hFuzzInput;
800 if (pThis == NIL_RTFUZZINPUT)
801 return 0;
802 AssertPtrReturn(pThis, UINT32_MAX);
803
804 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
805 AssertMsg(cRefs < _1M, ("%#x %p\n", cRefs, pThis));
806 if (cRefs == 0)
807 rtFuzzInputDestroy(pThis);
808 return cRefs;
809}
810
811
812RTDECL(int) RTFuzzInputQueryData(RTFUZZINPUT hFuzzInput, void **ppv, size_t *pcb)
813{
814 PRTFUZZINPUTINT pThis = hFuzzInput;
815 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
816 AssertPtrReturn(ppv, VERR_INVALID_POINTER);
817 AssertPtrReturn(pcb, VERR_INVALID_POINTER);
818
819 *ppv = &pThis->abInput[0];
820 *pcb = pThis->cbInput;
821 return VINF_SUCCESS;
822}
823
824
825RTDECL(int) RTFuzzInputQueryDigestString(RTFUZZINPUT hFuzzInput, char *pszDigest, size_t cchDigest)
826{
827 PRTFUZZINPUTINT pThis = hFuzzInput;
828 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
829 AssertPtrReturn(pszDigest, VERR_INVALID_POINTER);
830 AssertReturn(cchDigest >= RTMD5_STRING_LEN + 1, VERR_INVALID_PARAMETER);
831
832 return RTMd5ToString(&pThis->abMd5Hash[0], pszDigest, cchDigest);
833}
834
835
836RTDECL(int) RTFuzzInputWriteToFile(RTFUZZINPUT hFuzzInput, const char *pszFilename)
837{
838 PRTFUZZINPUTINT pThis = hFuzzInput;
839 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
840 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
841
842 RTFILE hFile;
843 int rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
844 if (RT_SUCCESS(rc))
845 {
846 rc = RTFileWrite(hFile, &pThis->abInput[0], pThis->cbInput, NULL);
847 AssertRC(rc);
848 RTFileClose(hFile);
849
850 if (RT_FAILURE(rc))
851 RTFileDelete(pszFilename);
852 }
853
854 return rc;
855}
856
857
858RTDECL(int) RTFuzzInputAddToCtxCorpus(RTFUZZINPUT hFuzzInput)
859{
860 PRTFUZZINPUTINT pThis = hFuzzInput;
861 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
862
863 return rtFuzzCtxInputAdd(pThis->pFuzzer, pThis);
864}
865
866
867RTDECL(int) RTFuzzInputRemoveFromCtxCorpus(RTFUZZINPUT hFuzzInput)
868{
869 PRTFUZZINPUTINT pThis = hFuzzInput;
870 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
871
872 int rc = VINF_SUCCESS;
873 PRTFUZZINTERMEDIATE pIntermediate = NULL;
874 PRTFUZZINPUTINT pInputLoc = rtFuzzCtxInputLocate(pThis->pFuzzer, &pThis->abMd5Hash[0], true /*fExact*/,
875 &pIntermediate);
876 if (pInputLoc)
877 {
878 AssertPtr(pIntermediate);
879 Assert(pInputLoc == pThis);
880
881 uint64_t u64Md5Low = *(uint64_t *)&pThis->abMd5Hash[0];
882 RTAvlU64Remove(&pIntermediate->TreeSeedsLow, u64Md5Low);
883 RTFuzzInputRelease(hFuzzInput);
884 }
885 else
886 rc = VERR_NOT_FOUND;
887
888 return rc;
889}
890
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