xref: /qemu/tests/qtest/fuzz/generic_fuzz.c (revision da9bf5319838c193f92a3444bd3258b32c606980)
1*da9bf531SAlexander Bulekov /*
2*da9bf531SAlexander Bulekov  * Generic Virtual-Device Fuzzing Target
3*da9bf531SAlexander Bulekov  *
4*da9bf531SAlexander Bulekov  * Copyright Red Hat Inc., 2020
5*da9bf531SAlexander Bulekov  *
6*da9bf531SAlexander Bulekov  * Authors:
7*da9bf531SAlexander Bulekov  *  Alexander Bulekov   <alxndr@bu.edu>
8*da9bf531SAlexander Bulekov  *
9*da9bf531SAlexander Bulekov  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10*da9bf531SAlexander Bulekov  * See the COPYING file in the top-level directory.
11*da9bf531SAlexander Bulekov  */
12*da9bf531SAlexander Bulekov 
13*da9bf531SAlexander Bulekov #include "qemu/osdep.h"
14*da9bf531SAlexander Bulekov 
15*da9bf531SAlexander Bulekov #include <wordexp.h>
16*da9bf531SAlexander Bulekov 
17*da9bf531SAlexander Bulekov #include "hw/core/cpu.h"
18*da9bf531SAlexander Bulekov #include "tests/qtest/libqos/libqtest.h"
19*da9bf531SAlexander Bulekov #include "fuzz.h"
20*da9bf531SAlexander Bulekov #include "fork_fuzz.h"
21*da9bf531SAlexander Bulekov #include "exec/address-spaces.h"
22*da9bf531SAlexander Bulekov #include "string.h"
23*da9bf531SAlexander Bulekov #include "exec/memory.h"
24*da9bf531SAlexander Bulekov #include "exec/ramblock.h"
25*da9bf531SAlexander Bulekov #include "exec/address-spaces.h"
26*da9bf531SAlexander Bulekov #include "hw/qdev-core.h"
27*da9bf531SAlexander Bulekov 
28*da9bf531SAlexander Bulekov /*
29*da9bf531SAlexander Bulekov  * SEPARATOR is used to separate "operations" in the fuzz input
30*da9bf531SAlexander Bulekov  */
31*da9bf531SAlexander Bulekov #define SEPARATOR "FUZZ"
32*da9bf531SAlexander Bulekov 
33*da9bf531SAlexander Bulekov enum cmds {
34*da9bf531SAlexander Bulekov     OP_IN,
35*da9bf531SAlexander Bulekov     OP_OUT,
36*da9bf531SAlexander Bulekov     OP_READ,
37*da9bf531SAlexander Bulekov     OP_WRITE,
38*da9bf531SAlexander Bulekov     OP_CLOCK_STEP,
39*da9bf531SAlexander Bulekov };
40*da9bf531SAlexander Bulekov 
41*da9bf531SAlexander Bulekov #define DEFAULT_TIMEOUT_US 100000
42*da9bf531SAlexander Bulekov #define USEC_IN_SEC 1000000000
43*da9bf531SAlexander Bulekov 
44*da9bf531SAlexander Bulekov typedef struct {
45*da9bf531SAlexander Bulekov     ram_addr_t addr;
46*da9bf531SAlexander Bulekov     ram_addr_t size; /* The number of bytes until the end of the I/O region */
47*da9bf531SAlexander Bulekov } address_range;
48*da9bf531SAlexander Bulekov 
49*da9bf531SAlexander Bulekov static useconds_t timeout = DEFAULT_TIMEOUT_US;
50*da9bf531SAlexander Bulekov 
51*da9bf531SAlexander Bulekov static bool qtest_log_enabled;
52*da9bf531SAlexander Bulekov 
53*da9bf531SAlexander Bulekov /*
54*da9bf531SAlexander Bulekov  * List of memory regions that are children of QOM objects specified by the
55*da9bf531SAlexander Bulekov  * user for fuzzing.
56*da9bf531SAlexander Bulekov  */
57*da9bf531SAlexander Bulekov static GHashTable *fuzzable_memoryregions;
58*da9bf531SAlexander Bulekov 
59*da9bf531SAlexander Bulekov struct get_io_cb_info {
60*da9bf531SAlexander Bulekov     int index;
61*da9bf531SAlexander Bulekov     int found;
62*da9bf531SAlexander Bulekov     address_range result;
63*da9bf531SAlexander Bulekov };
64*da9bf531SAlexander Bulekov 
65*da9bf531SAlexander Bulekov static int get_io_address_cb(Int128 start, Int128 size,
66*da9bf531SAlexander Bulekov                           const MemoryRegion *mr, void *opaque) {
67*da9bf531SAlexander Bulekov     struct get_io_cb_info *info = opaque;
68*da9bf531SAlexander Bulekov     if (g_hash_table_lookup(fuzzable_memoryregions, mr)) {
69*da9bf531SAlexander Bulekov         if (info->index == 0) {
70*da9bf531SAlexander Bulekov             info->result.addr = (ram_addr_t)start;
71*da9bf531SAlexander Bulekov             info->result.size = (ram_addr_t)size;
72*da9bf531SAlexander Bulekov             info->found = 1;
73*da9bf531SAlexander Bulekov             return 1;
74*da9bf531SAlexander Bulekov         }
75*da9bf531SAlexander Bulekov         info->index--;
76*da9bf531SAlexander Bulekov     }
77*da9bf531SAlexander Bulekov     return 0;
78*da9bf531SAlexander Bulekov }
79*da9bf531SAlexander Bulekov 
80*da9bf531SAlexander Bulekov /*
81*da9bf531SAlexander Bulekov  * Here we want to convert a fuzzer-provided [io-region-index, offset] to
82*da9bf531SAlexander Bulekov  * a physical address. To do this, we iterate over all of the matched
83*da9bf531SAlexander Bulekov  * MemoryRegions. Check whether each region exists within the particular io
84*da9bf531SAlexander Bulekov  * space. Return the absolute address of the offset within the index'th region
85*da9bf531SAlexander Bulekov  * that is a subregion of the io_space and the distance until the end of the
86*da9bf531SAlexander Bulekov  * memory region.
87*da9bf531SAlexander Bulekov  */
88*da9bf531SAlexander Bulekov static bool get_io_address(address_range *result, AddressSpace *as,
89*da9bf531SAlexander Bulekov                             uint8_t index,
90*da9bf531SAlexander Bulekov                             uint32_t offset) {
91*da9bf531SAlexander Bulekov     FlatView *view;
92*da9bf531SAlexander Bulekov     view = as->current_map;
93*da9bf531SAlexander Bulekov     g_assert(view);
94*da9bf531SAlexander Bulekov     struct get_io_cb_info cb_info = {};
95*da9bf531SAlexander Bulekov 
96*da9bf531SAlexander Bulekov     cb_info.index = index;
97*da9bf531SAlexander Bulekov 
98*da9bf531SAlexander Bulekov     /*
99*da9bf531SAlexander Bulekov      * Loop around the FlatView until we match "index" number of
100*da9bf531SAlexander Bulekov      * fuzzable_memoryregions, or until we know that there are no matching
101*da9bf531SAlexander Bulekov      * memory_regions.
102*da9bf531SAlexander Bulekov      */
103*da9bf531SAlexander Bulekov     do {
104*da9bf531SAlexander Bulekov         flatview_for_each_range(view, get_io_address_cb , &cb_info);
105*da9bf531SAlexander Bulekov     } while (cb_info.index != index && !cb_info.found);
106*da9bf531SAlexander Bulekov 
107*da9bf531SAlexander Bulekov     *result = cb_info.result;
108*da9bf531SAlexander Bulekov     return cb_info.found;
109*da9bf531SAlexander Bulekov }
110*da9bf531SAlexander Bulekov 
111*da9bf531SAlexander Bulekov static bool get_pio_address(address_range *result,
112*da9bf531SAlexander Bulekov                             uint8_t index, uint16_t offset)
113*da9bf531SAlexander Bulekov {
114*da9bf531SAlexander Bulekov     /*
115*da9bf531SAlexander Bulekov      * PIO BARs can be set past the maximum port address (0xFFFF). Thus, result
116*da9bf531SAlexander Bulekov      * can contain an addr that extends past the PIO space. When we pass this
117*da9bf531SAlexander Bulekov      * address to qtest_in/qtest_out, it is cast to a uint16_t, so we might end
118*da9bf531SAlexander Bulekov      * up fuzzing a completely different MemoryRegion/Device. Therefore, check
119*da9bf531SAlexander Bulekov      * that the address here is within the PIO space limits.
120*da9bf531SAlexander Bulekov      */
121*da9bf531SAlexander Bulekov     bool found = get_io_address(result, &address_space_io, index, offset);
122*da9bf531SAlexander Bulekov     return result->addr <= 0xFFFF ? found : false;
123*da9bf531SAlexander Bulekov }
124*da9bf531SAlexander Bulekov 
125*da9bf531SAlexander Bulekov static bool get_mmio_address(address_range *result,
126*da9bf531SAlexander Bulekov                              uint8_t index, uint32_t offset)
127*da9bf531SAlexander Bulekov {
128*da9bf531SAlexander Bulekov     return get_io_address(result, &address_space_memory, index, offset);
129*da9bf531SAlexander Bulekov }
130*da9bf531SAlexander Bulekov 
131*da9bf531SAlexander Bulekov static void op_in(QTestState *s, const unsigned char * data, size_t len)
132*da9bf531SAlexander Bulekov {
133*da9bf531SAlexander Bulekov     enum Sizes {Byte, Word, Long, end_sizes};
134*da9bf531SAlexander Bulekov     struct {
135*da9bf531SAlexander Bulekov         uint8_t size;
136*da9bf531SAlexander Bulekov         uint8_t base;
137*da9bf531SAlexander Bulekov         uint16_t offset;
138*da9bf531SAlexander Bulekov     } a;
139*da9bf531SAlexander Bulekov     address_range abs;
140*da9bf531SAlexander Bulekov 
141*da9bf531SAlexander Bulekov     if (len < sizeof(a)) {
142*da9bf531SAlexander Bulekov         return;
143*da9bf531SAlexander Bulekov     }
144*da9bf531SAlexander Bulekov     memcpy(&a, data, sizeof(a));
145*da9bf531SAlexander Bulekov     if (get_pio_address(&abs, a.base, a.offset) == 0) {
146*da9bf531SAlexander Bulekov         return;
147*da9bf531SAlexander Bulekov     }
148*da9bf531SAlexander Bulekov 
149*da9bf531SAlexander Bulekov     switch (a.size %= end_sizes) {
150*da9bf531SAlexander Bulekov     case Byte:
151*da9bf531SAlexander Bulekov         qtest_inb(s, abs.addr);
152*da9bf531SAlexander Bulekov         break;
153*da9bf531SAlexander Bulekov     case Word:
154*da9bf531SAlexander Bulekov         if (abs.size >= 2) {
155*da9bf531SAlexander Bulekov             qtest_inw(s, abs.addr);
156*da9bf531SAlexander Bulekov         }
157*da9bf531SAlexander Bulekov         break;
158*da9bf531SAlexander Bulekov     case Long:
159*da9bf531SAlexander Bulekov         if (abs.size >= 4) {
160*da9bf531SAlexander Bulekov             qtest_inl(s, abs.addr);
161*da9bf531SAlexander Bulekov         }
162*da9bf531SAlexander Bulekov         break;
163*da9bf531SAlexander Bulekov     }
164*da9bf531SAlexander Bulekov }
165*da9bf531SAlexander Bulekov 
166*da9bf531SAlexander Bulekov static void op_out(QTestState *s, const unsigned char * data, size_t len)
167*da9bf531SAlexander Bulekov {
168*da9bf531SAlexander Bulekov     enum Sizes {Byte, Word, Long, end_sizes};
169*da9bf531SAlexander Bulekov     struct {
170*da9bf531SAlexander Bulekov         uint8_t size;
171*da9bf531SAlexander Bulekov         uint8_t base;
172*da9bf531SAlexander Bulekov         uint16_t offset;
173*da9bf531SAlexander Bulekov         uint32_t value;
174*da9bf531SAlexander Bulekov     } a;
175*da9bf531SAlexander Bulekov     address_range abs;
176*da9bf531SAlexander Bulekov 
177*da9bf531SAlexander Bulekov     if (len < sizeof(a)) {
178*da9bf531SAlexander Bulekov         return;
179*da9bf531SAlexander Bulekov     }
180*da9bf531SAlexander Bulekov     memcpy(&a, data, sizeof(a));
181*da9bf531SAlexander Bulekov 
182*da9bf531SAlexander Bulekov     if (get_pio_address(&abs, a.base, a.offset) == 0) {
183*da9bf531SAlexander Bulekov         return;
184*da9bf531SAlexander Bulekov     }
185*da9bf531SAlexander Bulekov 
186*da9bf531SAlexander Bulekov     switch (a.size %= end_sizes) {
187*da9bf531SAlexander Bulekov     case Byte:
188*da9bf531SAlexander Bulekov         qtest_outb(s, abs.addr, a.value & 0xFF);
189*da9bf531SAlexander Bulekov         break;
190*da9bf531SAlexander Bulekov     case Word:
191*da9bf531SAlexander Bulekov         if (abs.size >= 2) {
192*da9bf531SAlexander Bulekov             qtest_outw(s, abs.addr, a.value & 0xFFFF);
193*da9bf531SAlexander Bulekov         }
194*da9bf531SAlexander Bulekov         break;
195*da9bf531SAlexander Bulekov     case Long:
196*da9bf531SAlexander Bulekov         if (abs.size >= 4) {
197*da9bf531SAlexander Bulekov             qtest_outl(s, abs.addr, a.value);
198*da9bf531SAlexander Bulekov         }
199*da9bf531SAlexander Bulekov         break;
200*da9bf531SAlexander Bulekov     }
201*da9bf531SAlexander Bulekov }
202*da9bf531SAlexander Bulekov 
203*da9bf531SAlexander Bulekov static void op_read(QTestState *s, const unsigned char * data, size_t len)
204*da9bf531SAlexander Bulekov {
205*da9bf531SAlexander Bulekov     enum Sizes {Byte, Word, Long, Quad, end_sizes};
206*da9bf531SAlexander Bulekov     struct {
207*da9bf531SAlexander Bulekov         uint8_t size;
208*da9bf531SAlexander Bulekov         uint8_t base;
209*da9bf531SAlexander Bulekov         uint32_t offset;
210*da9bf531SAlexander Bulekov     } a;
211*da9bf531SAlexander Bulekov     address_range abs;
212*da9bf531SAlexander Bulekov 
213*da9bf531SAlexander Bulekov     if (len < sizeof(a)) {
214*da9bf531SAlexander Bulekov         return;
215*da9bf531SAlexander Bulekov     }
216*da9bf531SAlexander Bulekov     memcpy(&a, data, sizeof(a));
217*da9bf531SAlexander Bulekov 
218*da9bf531SAlexander Bulekov     if (get_mmio_address(&abs, a.base, a.offset) == 0) {
219*da9bf531SAlexander Bulekov         return;
220*da9bf531SAlexander Bulekov     }
221*da9bf531SAlexander Bulekov 
222*da9bf531SAlexander Bulekov     switch (a.size %= end_sizes) {
223*da9bf531SAlexander Bulekov     case Byte:
224*da9bf531SAlexander Bulekov         qtest_readb(s, abs.addr);
225*da9bf531SAlexander Bulekov         break;
226*da9bf531SAlexander Bulekov     case Word:
227*da9bf531SAlexander Bulekov         if (abs.size >= 2) {
228*da9bf531SAlexander Bulekov             qtest_readw(s, abs.addr);
229*da9bf531SAlexander Bulekov         }
230*da9bf531SAlexander Bulekov         break;
231*da9bf531SAlexander Bulekov     case Long:
232*da9bf531SAlexander Bulekov         if (abs.size >= 4) {
233*da9bf531SAlexander Bulekov             qtest_readl(s, abs.addr);
234*da9bf531SAlexander Bulekov         }
235*da9bf531SAlexander Bulekov         break;
236*da9bf531SAlexander Bulekov     case Quad:
237*da9bf531SAlexander Bulekov         if (abs.size >= 8) {
238*da9bf531SAlexander Bulekov             qtest_readq(s, abs.addr);
239*da9bf531SAlexander Bulekov         }
240*da9bf531SAlexander Bulekov         break;
241*da9bf531SAlexander Bulekov     }
242*da9bf531SAlexander Bulekov }
243*da9bf531SAlexander Bulekov 
244*da9bf531SAlexander Bulekov static void op_write(QTestState *s, const unsigned char * data, size_t len)
245*da9bf531SAlexander Bulekov {
246*da9bf531SAlexander Bulekov     enum Sizes {Byte, Word, Long, Quad, end_sizes};
247*da9bf531SAlexander Bulekov     struct {
248*da9bf531SAlexander Bulekov         uint8_t size;
249*da9bf531SAlexander Bulekov         uint8_t base;
250*da9bf531SAlexander Bulekov         uint32_t offset;
251*da9bf531SAlexander Bulekov         uint64_t value;
252*da9bf531SAlexander Bulekov     } a;
253*da9bf531SAlexander Bulekov     address_range abs;
254*da9bf531SAlexander Bulekov 
255*da9bf531SAlexander Bulekov     if (len < sizeof(a)) {
256*da9bf531SAlexander Bulekov         return;
257*da9bf531SAlexander Bulekov     }
258*da9bf531SAlexander Bulekov     memcpy(&a, data, sizeof(a));
259*da9bf531SAlexander Bulekov 
260*da9bf531SAlexander Bulekov     if (get_mmio_address(&abs, a.base, a.offset) == 0) {
261*da9bf531SAlexander Bulekov         return;
262*da9bf531SAlexander Bulekov     }
263*da9bf531SAlexander Bulekov 
264*da9bf531SAlexander Bulekov     switch (a.size %= end_sizes) {
265*da9bf531SAlexander Bulekov     case Byte:
266*da9bf531SAlexander Bulekov             qtest_writeb(s, abs.addr, a.value & 0xFF);
267*da9bf531SAlexander Bulekov         break;
268*da9bf531SAlexander Bulekov     case Word:
269*da9bf531SAlexander Bulekov         if (abs.size >= 2) {
270*da9bf531SAlexander Bulekov             qtest_writew(s, abs.addr, a.value & 0xFFFF);
271*da9bf531SAlexander Bulekov         }
272*da9bf531SAlexander Bulekov         break;
273*da9bf531SAlexander Bulekov     case Long:
274*da9bf531SAlexander Bulekov         if (abs.size >= 4) {
275*da9bf531SAlexander Bulekov             qtest_writel(s, abs.addr, a.value & 0xFFFFFFFF);
276*da9bf531SAlexander Bulekov         }
277*da9bf531SAlexander Bulekov         break;
278*da9bf531SAlexander Bulekov     case Quad:
279*da9bf531SAlexander Bulekov         if (abs.size >= 8) {
280*da9bf531SAlexander Bulekov             qtest_writeq(s, abs.addr, a.value);
281*da9bf531SAlexander Bulekov         }
282*da9bf531SAlexander Bulekov         break;
283*da9bf531SAlexander Bulekov     }
284*da9bf531SAlexander Bulekov }
285*da9bf531SAlexander Bulekov 
286*da9bf531SAlexander Bulekov static void op_clock_step(QTestState *s, const unsigned char *data, size_t len)
287*da9bf531SAlexander Bulekov {
288*da9bf531SAlexander Bulekov     qtest_clock_step_next(s);
289*da9bf531SAlexander Bulekov }
290*da9bf531SAlexander Bulekov 
291*da9bf531SAlexander Bulekov static void handle_timeout(int sig)
292*da9bf531SAlexander Bulekov {
293*da9bf531SAlexander Bulekov     if (qtest_log_enabled) {
294*da9bf531SAlexander Bulekov         fprintf(stderr, "[Timeout]\n");
295*da9bf531SAlexander Bulekov         fflush(stderr);
296*da9bf531SAlexander Bulekov     }
297*da9bf531SAlexander Bulekov     _Exit(0);
298*da9bf531SAlexander Bulekov }
299*da9bf531SAlexander Bulekov 
300*da9bf531SAlexander Bulekov /*
301*da9bf531SAlexander Bulekov  * Here, we interpret random bytes from the fuzzer, as a sequence of commands.
302*da9bf531SAlexander Bulekov  * Some commands can be variable-width, so we use a separator, SEPARATOR, to
303*da9bf531SAlexander Bulekov  * specify the boundaries between commands. SEPARATOR is used to separate
304*da9bf531SAlexander Bulekov  * "operations" in the fuzz input. Why use a separator, instead of just using
305*da9bf531SAlexander Bulekov  * the operations' length to identify operation boundaries?
306*da9bf531SAlexander Bulekov  *   1. This is a simple way to support variable-length operations
307*da9bf531SAlexander Bulekov  *   2. This adds "stability" to the input.
308*da9bf531SAlexander Bulekov  *      For example take the input "AbBcgDefg", where there is no separator and
309*da9bf531SAlexander Bulekov  *      Opcodes are capitalized.
310*da9bf531SAlexander Bulekov  *      Simply, by removing the first byte, we end up with a very different
311*da9bf531SAlexander Bulekov  *      sequence:
312*da9bf531SAlexander Bulekov  *      BbcGdefg...
313*da9bf531SAlexander Bulekov  *      By adding a separator, we avoid this problem:
314*da9bf531SAlexander Bulekov  *      Ab SEP Bcg SEP Defg -> B SEP Bcg SEP Defg
315*da9bf531SAlexander Bulekov  *      Since B uses two additional bytes as operands, the first "B" will be
316*da9bf531SAlexander Bulekov  *      ignored. The fuzzer actively tries to reduce inputs, so such unused
317*da9bf531SAlexander Bulekov  *      bytes are likely to be pruned, eventually.
318*da9bf531SAlexander Bulekov  *
319*da9bf531SAlexander Bulekov  *  SEPARATOR is trivial for the fuzzer to discover when using ASan. Optionally,
320*da9bf531SAlexander Bulekov  *  SEPARATOR can be manually specified as a dictionary value (see libfuzzer's
321*da9bf531SAlexander Bulekov  *  -dict), though this should not be necessary.
322*da9bf531SAlexander Bulekov  *
323*da9bf531SAlexander Bulekov  * As a result, the stream of bytes is converted into a sequence of commands.
324*da9bf531SAlexander Bulekov  * In a simplified example where SEPARATOR is 0xFF:
325*da9bf531SAlexander Bulekov  * 00 01 02 FF 03 04 05 06 FF 01 FF ...
326*da9bf531SAlexander Bulekov  * becomes this sequence of commands:
327*da9bf531SAlexander Bulekov  * 00 01 02    -> op00 (0102)   -> in (0102, 2)
328*da9bf531SAlexander Bulekov  * 03 04 05 06 -> op03 (040506) -> write (040506, 3)
329*da9bf531SAlexander Bulekov  * 01          -> op01 (-,0)    -> out (-,0)
330*da9bf531SAlexander Bulekov  * ...
331*da9bf531SAlexander Bulekov  *
332*da9bf531SAlexander Bulekov  * Note here that it is the job of the individual opcode functions to check
333*da9bf531SAlexander Bulekov  * that enough data was provided. I.e. in the last command out (,0), out needs
334*da9bf531SAlexander Bulekov  * to check that there is not enough data provided to select an address/value
335*da9bf531SAlexander Bulekov  * for the operation.
336*da9bf531SAlexander Bulekov  */
337*da9bf531SAlexander Bulekov static void generic_fuzz(QTestState *s, const unsigned char *Data, size_t Size)
338*da9bf531SAlexander Bulekov {
339*da9bf531SAlexander Bulekov     void (*ops[]) (QTestState *s, const unsigned char* , size_t) = {
340*da9bf531SAlexander Bulekov         [OP_IN]                 = op_in,
341*da9bf531SAlexander Bulekov         [OP_OUT]                = op_out,
342*da9bf531SAlexander Bulekov         [OP_READ]               = op_read,
343*da9bf531SAlexander Bulekov         [OP_WRITE]              = op_write,
344*da9bf531SAlexander Bulekov         [OP_CLOCK_STEP]         = op_clock_step,
345*da9bf531SAlexander Bulekov     };
346*da9bf531SAlexander Bulekov     const unsigned char *cmd = Data;
347*da9bf531SAlexander Bulekov     const unsigned char *nextcmd;
348*da9bf531SAlexander Bulekov     size_t cmd_len;
349*da9bf531SAlexander Bulekov     uint8_t op;
350*da9bf531SAlexander Bulekov 
351*da9bf531SAlexander Bulekov     if (fork() == 0) {
352*da9bf531SAlexander Bulekov         /*
353*da9bf531SAlexander Bulekov          * Sometimes the fuzzer will find inputs that take quite a long time to
354*da9bf531SAlexander Bulekov          * process. Often times, these inputs do not result in new coverage.
355*da9bf531SAlexander Bulekov          * Even if these inputs might be interesting, they can slow down the
356*da9bf531SAlexander Bulekov          * fuzzer, overall. Set a timeout to avoid hurting performance, too much
357*da9bf531SAlexander Bulekov          */
358*da9bf531SAlexander Bulekov         if (timeout) {
359*da9bf531SAlexander Bulekov             struct sigaction sact;
360*da9bf531SAlexander Bulekov             struct itimerval timer;
361*da9bf531SAlexander Bulekov 
362*da9bf531SAlexander Bulekov             sigemptyset(&sact.sa_mask);
363*da9bf531SAlexander Bulekov             sact.sa_flags   = SA_NODEFER;
364*da9bf531SAlexander Bulekov             sact.sa_handler = handle_timeout;
365*da9bf531SAlexander Bulekov             sigaction(SIGALRM, &sact, NULL);
366*da9bf531SAlexander Bulekov 
367*da9bf531SAlexander Bulekov             memset(&timer, 0, sizeof(timer));
368*da9bf531SAlexander Bulekov             timer.it_value.tv_sec = timeout / USEC_IN_SEC;
369*da9bf531SAlexander Bulekov             timer.it_value.tv_usec = timeout % USEC_IN_SEC;
370*da9bf531SAlexander Bulekov             setitimer(ITIMER_VIRTUAL, &timer, NULL);
371*da9bf531SAlexander Bulekov         }
372*da9bf531SAlexander Bulekov 
373*da9bf531SAlexander Bulekov         while (cmd && Size) {
374*da9bf531SAlexander Bulekov             /* Get the length until the next command or end of input */
375*da9bf531SAlexander Bulekov             nextcmd = memmem(cmd, Size, SEPARATOR, strlen(SEPARATOR));
376*da9bf531SAlexander Bulekov             cmd_len = nextcmd ? nextcmd - cmd : Size;
377*da9bf531SAlexander Bulekov 
378*da9bf531SAlexander Bulekov             if (cmd_len > 0) {
379*da9bf531SAlexander Bulekov                 /* Interpret the first byte of the command as an opcode */
380*da9bf531SAlexander Bulekov                 op = *cmd % (sizeof(ops) / sizeof((ops)[0]));
381*da9bf531SAlexander Bulekov                 ops[op](s, cmd + 1, cmd_len - 1);
382*da9bf531SAlexander Bulekov 
383*da9bf531SAlexander Bulekov                 /* Run the main loop */
384*da9bf531SAlexander Bulekov                 flush_events(s);
385*da9bf531SAlexander Bulekov             }
386*da9bf531SAlexander Bulekov             /* Advance to the next command */
387*da9bf531SAlexander Bulekov             cmd = nextcmd ? nextcmd + sizeof(SEPARATOR) - 1 : nextcmd;
388*da9bf531SAlexander Bulekov             Size = Size - (cmd_len + sizeof(SEPARATOR) - 1);
389*da9bf531SAlexander Bulekov         }
390*da9bf531SAlexander Bulekov         _Exit(0);
391*da9bf531SAlexander Bulekov     } else {
392*da9bf531SAlexander Bulekov         flush_events(s);
393*da9bf531SAlexander Bulekov         wait(0);
394*da9bf531SAlexander Bulekov     }
395*da9bf531SAlexander Bulekov }
396*da9bf531SAlexander Bulekov 
397*da9bf531SAlexander Bulekov static void usage(void)
398*da9bf531SAlexander Bulekov {
399*da9bf531SAlexander Bulekov     printf("Please specify the following environment variables:\n");
400*da9bf531SAlexander Bulekov     printf("QEMU_FUZZ_ARGS= the command line arguments passed to qemu\n");
401*da9bf531SAlexander Bulekov     printf("QEMU_FUZZ_OBJECTS= "
402*da9bf531SAlexander Bulekov             "a space separated list of QOM type names for objects to fuzz\n");
403*da9bf531SAlexander Bulekov     printf("Optionally: QEMU_FUZZ_TIMEOUT= Specify a custom timeout (us). "
404*da9bf531SAlexander Bulekov             "0 to disable. %d by default\n", timeout);
405*da9bf531SAlexander Bulekov     exit(0);
406*da9bf531SAlexander Bulekov }
407*da9bf531SAlexander Bulekov 
408*da9bf531SAlexander Bulekov static int locate_fuzz_memory_regions(Object *child, void *opaque)
409*da9bf531SAlexander Bulekov {
410*da9bf531SAlexander Bulekov     const char *name;
411*da9bf531SAlexander Bulekov     MemoryRegion *mr;
412*da9bf531SAlexander Bulekov     if (object_dynamic_cast(child, TYPE_MEMORY_REGION)) {
413*da9bf531SAlexander Bulekov         mr = MEMORY_REGION(child);
414*da9bf531SAlexander Bulekov         if ((memory_region_is_ram(mr) ||
415*da9bf531SAlexander Bulekov             memory_region_is_ram_device(mr) ||
416*da9bf531SAlexander Bulekov             memory_region_is_rom(mr)) == false) {
417*da9bf531SAlexander Bulekov             name = object_get_canonical_path_component(child);
418*da9bf531SAlexander Bulekov             /*
419*da9bf531SAlexander Bulekov              * We don't want duplicate pointers to the same MemoryRegion, so
420*da9bf531SAlexander Bulekov              * try to remove copies of the pointer, before adding it.
421*da9bf531SAlexander Bulekov              */
422*da9bf531SAlexander Bulekov             g_hash_table_insert(fuzzable_memoryregions, mr, (gpointer)true);
423*da9bf531SAlexander Bulekov         }
424*da9bf531SAlexander Bulekov     }
425*da9bf531SAlexander Bulekov     return 0;
426*da9bf531SAlexander Bulekov }
427*da9bf531SAlexander Bulekov 
428*da9bf531SAlexander Bulekov static int locate_fuzz_objects(Object *child, void *opaque)
429*da9bf531SAlexander Bulekov {
430*da9bf531SAlexander Bulekov     char *pattern = opaque;
431*da9bf531SAlexander Bulekov     if (g_pattern_match_simple(pattern, object_get_typename(child))) {
432*da9bf531SAlexander Bulekov         /* Find and save ptrs to any child MemoryRegions */
433*da9bf531SAlexander Bulekov         object_child_foreach_recursive(child, locate_fuzz_memory_regions, NULL);
434*da9bf531SAlexander Bulekov 
435*da9bf531SAlexander Bulekov     } else if (object_dynamic_cast(OBJECT(child), TYPE_MEMORY_REGION)) {
436*da9bf531SAlexander Bulekov         if (g_pattern_match_simple(pattern,
437*da9bf531SAlexander Bulekov             object_get_canonical_path_component(child))) {
438*da9bf531SAlexander Bulekov             MemoryRegion *mr;
439*da9bf531SAlexander Bulekov             mr = MEMORY_REGION(child);
440*da9bf531SAlexander Bulekov             if ((memory_region_is_ram(mr) ||
441*da9bf531SAlexander Bulekov                  memory_region_is_ram_device(mr) ||
442*da9bf531SAlexander Bulekov                  memory_region_is_rom(mr)) == false) {
443*da9bf531SAlexander Bulekov                 g_hash_table_insert(fuzzable_memoryregions, mr, (gpointer)true);
444*da9bf531SAlexander Bulekov             }
445*da9bf531SAlexander Bulekov         }
446*da9bf531SAlexander Bulekov     }
447*da9bf531SAlexander Bulekov     return 0;
448*da9bf531SAlexander Bulekov }
449*da9bf531SAlexander Bulekov 
450*da9bf531SAlexander Bulekov static void generic_pre_fuzz(QTestState *s)
451*da9bf531SAlexander Bulekov {
452*da9bf531SAlexander Bulekov     GHashTableIter iter;
453*da9bf531SAlexander Bulekov     MemoryRegion *mr;
454*da9bf531SAlexander Bulekov     char **result;
455*da9bf531SAlexander Bulekov 
456*da9bf531SAlexander Bulekov     if (!getenv("QEMU_FUZZ_OBJECTS")) {
457*da9bf531SAlexander Bulekov         usage();
458*da9bf531SAlexander Bulekov     }
459*da9bf531SAlexander Bulekov     if (getenv("QTEST_LOG")) {
460*da9bf531SAlexander Bulekov         qtest_log_enabled = 1;
461*da9bf531SAlexander Bulekov     }
462*da9bf531SAlexander Bulekov     if (getenv("QEMU_FUZZ_TIMEOUT")) {
463*da9bf531SAlexander Bulekov         timeout = g_ascii_strtoll(getenv("QEMU_FUZZ_TIMEOUT"), NULL, 0);
464*da9bf531SAlexander Bulekov     }
465*da9bf531SAlexander Bulekov 
466*da9bf531SAlexander Bulekov     fuzzable_memoryregions = g_hash_table_new(NULL, NULL);
467*da9bf531SAlexander Bulekov 
468*da9bf531SAlexander Bulekov     result = g_strsplit(getenv("QEMU_FUZZ_OBJECTS"), " ", -1);
469*da9bf531SAlexander Bulekov     for (int i = 0; result[i] != NULL; i++) {
470*da9bf531SAlexander Bulekov         printf("Matching objects by name %s\n", result[i]);
471*da9bf531SAlexander Bulekov         object_child_foreach_recursive(qdev_get_machine(),
472*da9bf531SAlexander Bulekov                                     locate_fuzz_objects,
473*da9bf531SAlexander Bulekov                                     result[i]);
474*da9bf531SAlexander Bulekov     }
475*da9bf531SAlexander Bulekov     g_strfreev(result);
476*da9bf531SAlexander Bulekov     printf("This process will try to fuzz the following MemoryRegions:\n");
477*da9bf531SAlexander Bulekov 
478*da9bf531SAlexander Bulekov     g_hash_table_iter_init(&iter, fuzzable_memoryregions);
479*da9bf531SAlexander Bulekov     while (g_hash_table_iter_next(&iter, (gpointer)&mr, NULL)) {
480*da9bf531SAlexander Bulekov         printf("  * %s (size %lx)\n",
481*da9bf531SAlexander Bulekov                object_get_canonical_path_component(&(mr->parent_obj)),
482*da9bf531SAlexander Bulekov                (uint64_t)mr->size);
483*da9bf531SAlexander Bulekov     }
484*da9bf531SAlexander Bulekov 
485*da9bf531SAlexander Bulekov     if (!g_hash_table_size(fuzzable_memoryregions)) {
486*da9bf531SAlexander Bulekov         printf("No fuzzable memory regions found...\n");
487*da9bf531SAlexander Bulekov         exit(1);
488*da9bf531SAlexander Bulekov     }
489*da9bf531SAlexander Bulekov 
490*da9bf531SAlexander Bulekov     counter_shm_init();
491*da9bf531SAlexander Bulekov }
492*da9bf531SAlexander Bulekov 
493*da9bf531SAlexander Bulekov static GString *generic_fuzz_cmdline(FuzzTarget *t)
494*da9bf531SAlexander Bulekov {
495*da9bf531SAlexander Bulekov     GString *cmd_line = g_string_new(TARGET_NAME);
496*da9bf531SAlexander Bulekov     if (!getenv("QEMU_FUZZ_ARGS")) {
497*da9bf531SAlexander Bulekov         usage();
498*da9bf531SAlexander Bulekov     }
499*da9bf531SAlexander Bulekov     g_string_append_printf(cmd_line, " -display none \
500*da9bf531SAlexander Bulekov                                       -machine accel=qtest, \
501*da9bf531SAlexander Bulekov                                       -m 512M %s ", getenv("QEMU_FUZZ_ARGS"));
502*da9bf531SAlexander Bulekov     return cmd_line;
503*da9bf531SAlexander Bulekov }
504*da9bf531SAlexander Bulekov 
505*da9bf531SAlexander Bulekov static void register_generic_fuzz_targets(void)
506*da9bf531SAlexander Bulekov {
507*da9bf531SAlexander Bulekov     fuzz_add_target(&(FuzzTarget){
508*da9bf531SAlexander Bulekov             .name = "generic-fuzz",
509*da9bf531SAlexander Bulekov             .description = "Fuzz based on any qemu command-line args. ",
510*da9bf531SAlexander Bulekov             .get_init_cmdline = generic_fuzz_cmdline,
511*da9bf531SAlexander Bulekov             .pre_fuzz = generic_pre_fuzz,
512*da9bf531SAlexander Bulekov             .fuzz = generic_fuzz,
513*da9bf531SAlexander Bulekov     });
514*da9bf531SAlexander Bulekov }
515*da9bf531SAlexander Bulekov 
516*da9bf531SAlexander Bulekov fuzz_target_init(register_generic_fuzz_targets);
517