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