/src/wasm3/platforms/app_fuzz/fuzzer.c
Line | Count | Source |
1 | | // |
2 | | // Wasm3 - high performance WebAssembly interpreter written in C. |
3 | | // |
4 | | // Copyright © 2019 Steven Massey, Volodymyr Shymanskyy. |
5 | | // All rights reserved. |
6 | | // |
7 | | |
8 | | #include <stdint.h> |
9 | | #include <stddef.h> |
10 | | |
11 | | #include "wasm3.h" |
12 | | #include "m3_env.h" // for IM3Runtime::memoryLimit |
13 | | |
14 | | #define FATAL(...) __builtin_trap() |
15 | | |
16 | | // A module may declare up to 4 GiB of linear memory, and wasm3 allocates the |
17 | | // initial pages eagerly at load, so a handful of bytes can ask for more than |
18 | | // the fuzzing engine allows and get killed as an OOM rather than exercising |
19 | | // anything. Cap what is actually allocated: memory accesses and data segment |
20 | | // loads are bounded by the allocated length, not the declared page count. |
21 | 33.5k | #define d_m3FuzzMemoryLimit (4*1024*1024) |
22 | | |
23 | | // A table element is a pointer, so 1M of them are 8 MiB on a 64-bit host: the same |
24 | | // order as the memory budget, and far below what d_m3MaxSaneTableSize allows. |
25 | 33.5k | #define d_m3FuzzTableLimit (1024*1024) |
26 | | |
27 | | // Nothing stops a few fuzzed bytes from describing a loop that never ends. |
28 | | // Fuzzer timeout is an error => let's use gas metering to limit the number |
29 | | // of instructions that can run. |
30 | 33.5k | #define d_m3FuzzGasLimit (1000 * M3_GAS_UNITS_PER_GAS) |
31 | | |
32 | | // Each active continuation holds a value stack of 8 KiB, so 256 of them are 2 MiB. |
33 | 33.5k | #define d_m3FuzzContinuationLimit 256 |
34 | | |
35 | | int LLVMFuzzerTestOneInput (const uint8_t* data, size_t size) |
36 | 33.5k | { |
37 | 33.5k | M3Result result = m3Err_none; |
38 | | |
39 | 33.5k | if (size < 8 || size > 256 * 1024) { |
40 | 4 | return 0; |
41 | 4 | } |
42 | | |
43 | 33.5k | IM3Environment env = m3_NewEnvironment(); |
44 | 33.5k | if (env) { |
45 | 33.5k | IM3Runtime runtime = m3_NewRuntime(env, 4096, NULL); |
46 | 33.5k | if (runtime) { |
47 | 33.5k | IM3Module module = NULL; |
48 | | |
49 | 33.5k | runtime->memoryLimit = d_m3FuzzMemoryLimit; |
50 | | |
51 | 33.5k | const struct { |
52 | 33.5k | M3ResourceLimit limit; |
53 | 33.5k | uint64_t value; |
54 | 33.5k | } limits[] = { |
55 | 33.5k | { c_m3Limit_TableElements, d_m3FuzzTableLimit }, |
56 | 33.5k | { c_m3Limit_GasUnits, d_m3FuzzGasLimit }, |
57 | 33.5k | { c_m3Limit_Continuations, d_m3FuzzContinuationLimit }, |
58 | 33.5k | }; |
59 | 134k | for (unsigned i = 0; i < sizeof(limits) / sizeof(limits[0]); ++i) { |
60 | 100k | result = m3_SetResourceLimit(runtime, limits[i].limit, limits[i].value); |
61 | 100k | if (result && result != m3Err_resourceLimitNotSupported) { |
62 | 0 | m3_FreeRuntime(runtime); |
63 | 0 | m3_FreeEnvironment(env); |
64 | 0 | return 0; |
65 | 0 | } |
66 | 100k | } |
67 | | |
68 | 33.5k | result = m3_ParseModule(env, &module, data, size); |
69 | 33.5k | if (module) { |
70 | 28.8k | result = m3_LoadModule(runtime, module); |
71 | 28.8k | if (result == 0) { |
72 | 28.2k | IM3Function f = NULL; |
73 | | |
74 | 28.2k | result = m3_FindFunction(&f, runtime, "fib"); |
75 | 28.2k | if (f) { |
76 | 23.8k | if (m3_GetArgCount(f) == 1 && m3_GetArgType(f, 0) == c_m3Type_i32) { |
77 | 22 | m3_CallV(f, 10); |
78 | 23.7k | } else if (m3_GetArgCount(f) == 0) { |
79 | 23.5k | m3_CallV(f); |
80 | 23.5k | } |
81 | 23.8k | } |
82 | 28.2k | } |
83 | | // on failure too, the runtime owns the module now |
84 | 28.8k | } |
85 | | |
86 | 33.5k | m3_FreeRuntime(runtime); |
87 | 33.5k | } |
88 | 33.5k | m3_FreeEnvironment(env); |
89 | 33.5k | } |
90 | | |
91 | 33.5k | return 0; |
92 | 33.5k | } |