qemu/tests/qtest/fuzz/generic_fuzz.c
<<
>>
Prefs
   1/*
   2 * Generic Virtual-Device Fuzzing Target
   3 *
   4 * Copyright Red Hat Inc., 2020
   5 *
   6 * Authors:
   7 *  Alexander Bulekov   <alxndr@bu.edu>
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10 * See the COPYING file in the top-level directory.
  11 */
  12
  13#include "qemu/osdep.h"
  14
  15#include <wordexp.h>
  16
  17#include "hw/core/cpu.h"
  18#include "tests/qtest/libqtest.h"
  19#include "tests/qtest/libqos/pci-pc.h"
  20#include "fuzz.h"
  21#include "string.h"
  22#include "exec/memory.h"
  23#include "exec/ramblock.h"
  24#include "hw/qdev-core.h"
  25#include "hw/pci/pci.h"
  26#include "hw/pci/pci_device.h"
  27#include "hw/boards.h"
  28#include "generic_fuzz_configs.h"
  29#include "hw/mem/sparse-mem.h"
  30
  31static void pci_enum(gpointer pcidev, gpointer bus);
  32
  33/*
  34 * SEPARATOR is used to separate "operations" in the fuzz input
  35 */
  36#define SEPARATOR "FUZZ"
  37
  38enum cmds {
  39    OP_IN,
  40    OP_OUT,
  41    OP_READ,
  42    OP_WRITE,
  43    OP_PCI_READ,
  44    OP_PCI_WRITE,
  45    OP_DISABLE_PCI,
  46    OP_ADD_DMA_PATTERN,
  47    OP_CLEAR_DMA_PATTERNS,
  48    OP_CLOCK_STEP,
  49};
  50
  51#define USEC_IN_SEC 1000000000
  52
  53#define MAX_DMA_FILL_SIZE 0x10000
  54#define MAX_TOTAL_DMA_SIZE 0x10000000
  55
  56#define PCI_HOST_BRIDGE_CFG 0xcf8
  57#define PCI_HOST_BRIDGE_DATA 0xcfc
  58
  59typedef struct {
  60    ram_addr_t addr;
  61    ram_addr_t size; /* The number of bytes until the end of the I/O region */
  62} address_range;
  63
  64static bool qtest_log_enabled;
  65size_t dma_bytes_written;
  66
  67MemoryRegion *sparse_mem_mr;
  68
  69/*
  70 * A pattern used to populate a DMA region or perform a memwrite. This is
  71 * useful for e.g. populating tables of unique addresses.
  72 * Example {.index = 1; .stride = 2; .len = 3; .data = "\x00\x01\x02"}
  73 * Renders as: 00 01 02   00 03 02   00 05 02   00 07 02 ...
  74 */
  75typedef struct {
  76    uint8_t index;      /* Index of a byte to increment by stride */
  77    uint8_t stride;     /* Increment each index'th byte by this amount */
  78    size_t len;
  79    const uint8_t *data;
  80} pattern;
  81
  82/* Avoid filling the same DMA region between MMIO/PIO commands ? */
  83static bool avoid_double_fetches;
  84
  85static QTestState *qts_global; /* Need a global for the DMA callback */
  86
  87/*
  88 * List of memory regions that are children of QOM objects specified by the
  89 * user for fuzzing.
  90 */
  91static GHashTable *fuzzable_memoryregions;
  92static GPtrArray *fuzzable_pci_devices;
  93
  94struct get_io_cb_info {
  95    int index;
  96    int found;
  97    address_range result;
  98};
  99
 100static bool get_io_address_cb(Int128 start, Int128 size,
 101                              const MemoryRegion *mr,
 102                              hwaddr offset_in_region,
 103                              void *opaque)
 104{
 105    struct get_io_cb_info *info = opaque;
 106    if (g_hash_table_lookup(fuzzable_memoryregions, mr)) {
 107        if (info->index == 0) {
 108            info->result.addr = (ram_addr_t)start;
 109            info->result.size = (ram_addr_t)size;
 110            info->found = 1;
 111            return true;
 112        }
 113        info->index--;
 114    }
 115    return false;
 116}
 117
 118/*
 119 * List of dma regions populated since the last fuzzing command. Used to ensure
 120 * that we only write to each DMA address once, to avoid race conditions when
 121 * building reproducers.
 122 */
 123static GArray *dma_regions;
 124
 125static GArray *dma_patterns;
 126static int dma_pattern_index;
 127static bool pci_disabled;
 128
 129/*
 130 * Allocate a block of memory and populate it with a pattern.
 131 */
 132static void *pattern_alloc(pattern p, size_t len)
 133{
 134    int i;
 135    uint8_t *buf = g_malloc(len);
 136    uint8_t sum = 0;
 137
 138    for (i = 0; i < len; ++i) {
 139        buf[i] = p.data[i % p.len];
 140        if ((i % p.len) == p.index) {
 141            buf[i] += sum;
 142            sum += p.stride;
 143        }
 144    }
 145    return buf;
 146}
 147
 148static int fuzz_memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
 149{
 150    unsigned access_size_max = mr->ops->valid.max_access_size;
 151
 152    /*
 153     * Regions are assumed to support 1-4 byte accesses unless
 154     * otherwise specified.
 155     */
 156    if (access_size_max == 0) {
 157        access_size_max = 4;
 158    }
 159
 160    /* Bound the maximum access by the alignment of the address.  */
 161    if (!mr->ops->impl.unaligned) {
 162        unsigned align_size_max = addr & -addr;
 163        if (align_size_max != 0 && align_size_max < access_size_max) {
 164            access_size_max = align_size_max;
 165        }
 166    }
 167
 168    /* Don't attempt accesses larger than the maximum.  */
 169    if (l > access_size_max) {
 170        l = access_size_max;
 171    }
 172    l = pow2floor(l);
 173
 174    return l;
 175}
 176
 177/*
 178 * Call-back for functions that perform DMA reads from guest memory. Confirm
 179 * that the region has not already been populated since the last loop in
 180 * generic_fuzz(), avoiding potential race-conditions, which we don't have
 181 * a good way for reproducing right now.
 182 */
 183void fuzz_dma_read_cb(size_t addr, size_t len, MemoryRegion *mr)
 184{
 185    /* Are we in the generic-fuzzer or are we using another fuzz-target? */
 186    if (!qts_global) {
 187        return;
 188    }
 189
 190    /*
 191     * Return immediately if:
 192     * - We have no DMA patterns defined
 193     * - The length of the DMA read request is zero
 194     * - The DMA read is hitting an MR other than the machine's main RAM
 195     * - The DMA request hits past the bounds of our RAM
 196     */
 197    if (dma_patterns->len == 0
 198        || len == 0
 199        || dma_bytes_written + len > MAX_TOTAL_DMA_SIZE
 200        || (mr != current_machine->ram && mr != sparse_mem_mr)) {
 201        return;
 202    }
 203
 204    /*
 205     * If we overlap with any existing dma_regions, split the range and only
 206     * populate the non-overlapping parts.
 207     */
 208    address_range region;
 209    bool double_fetch = false;
 210    for (int i = 0;
 211         i < dma_regions->len && (avoid_double_fetches || qtest_log_enabled);
 212         ++i) {
 213        region = g_array_index(dma_regions, address_range, i);
 214        if (addr < region.addr + region.size && addr + len > region.addr) {
 215            double_fetch = true;
 216            if (addr < region.addr
 217                && avoid_double_fetches) {
 218                fuzz_dma_read_cb(addr, region.addr - addr, mr);
 219            }
 220            if (addr + len > region.addr + region.size
 221                && avoid_double_fetches) {
 222                fuzz_dma_read_cb(region.addr + region.size,
 223                        addr + len - (region.addr + region.size), mr);
 224            }
 225            return;
 226        }
 227    }
 228
 229    /* Cap the length of the DMA access to something reasonable */
 230    len = MIN(len, MAX_DMA_FILL_SIZE);
 231
 232    address_range ar = {addr, len};
 233    g_array_append_val(dma_regions, ar);
 234    pattern p = g_array_index(dma_patterns, pattern, dma_pattern_index);
 235    void *buf_base = pattern_alloc(p, ar.size);
 236    void *buf = buf_base;
 237    hwaddr l, addr1;
 238    MemoryRegion *mr1;
 239    while (len > 0) {
 240        l = len;
 241        mr1 = address_space_translate(first_cpu->as,
 242                                      addr, &addr1, &l, true,
 243                                      MEMTXATTRS_UNSPECIFIED);
 244
 245        /*
 246         *  If mr1 isn't RAM, address_space_translate doesn't update l. Use
 247         *  fuzz_memory_access_size to identify the number of bytes that it
 248         *  is safe to write without accidentally writing to another
 249         *  MemoryRegion.
 250         */
 251        if (!memory_region_is_ram(mr1)) {
 252            l = fuzz_memory_access_size(mr1, l, addr1);
 253        }
 254        if (memory_region_is_ram(mr1) ||
 255            memory_region_is_romd(mr1) ||
 256            mr1 == sparse_mem_mr) {
 257            /* ROM/RAM case */
 258            if (qtest_log_enabled) {
 259                /*
 260                * With QTEST_LOG, use a normal, slow QTest memwrite. Prefix the log
 261                * that will be written by qtest.c with a DMA tag, so we can reorder
 262                * the resulting QTest trace so the DMA fills precede the last PIO/MMIO
 263                * command.
 264                */
 265                fprintf(stderr, "[DMA] ");
 266                if (double_fetch) {
 267                    fprintf(stderr, "[DOUBLE-FETCH] ");
 268                }
 269                fflush(stderr);
 270            }
 271            qtest_memwrite(qts_global, addr, buf, l);
 272            dma_bytes_written += l;
 273        }
 274        len -= l;
 275        buf += l;
 276        addr += l;
 277
 278    }
 279    g_free(buf_base);
 280
 281    /* Increment the index of the pattern for the next DMA access */
 282    dma_pattern_index = (dma_pattern_index + 1) % dma_patterns->len;
 283}
 284
 285/*
 286 * Here we want to convert a fuzzer-provided [io-region-index, offset] to
 287 * a physical address. To do this, we iterate over all of the matched
 288 * MemoryRegions. Check whether each region exists within the particular io
 289 * space. Return the absolute address of the offset within the index'th region
 290 * that is a subregion of the io_space and the distance until the end of the
 291 * memory region.
 292 */
 293static bool get_io_address(address_range *result, AddressSpace *as,
 294                            uint8_t index,
 295                            uint32_t offset) {
 296    FlatView *view;
 297    view = as->current_map;
 298    g_assert(view);
 299    struct get_io_cb_info cb_info = {};
 300
 301    cb_info.index = index;
 302
 303    /*
 304     * Loop around the FlatView until we match "index" number of
 305     * fuzzable_memoryregions, or until we know that there are no matching
 306     * memory_regions.
 307     */
 308    do {
 309        flatview_for_each_range(view, get_io_address_cb , &cb_info);
 310    } while (cb_info.index != index && !cb_info.found);
 311
 312    *result = cb_info.result;
 313    if (result->size) {
 314        offset = offset % result->size;
 315        result->addr += offset;
 316        result->size -= offset;
 317    }
 318    return cb_info.found;
 319}
 320
 321static bool get_pio_address(address_range *result,
 322                            uint8_t index, uint16_t offset)
 323{
 324    /*
 325     * PIO BARs can be set past the maximum port address (0xFFFF). Thus, result
 326     * can contain an addr that extends past the PIO space. When we pass this
 327     * address to qtest_in/qtest_out, it is cast to a uint16_t, so we might end
 328     * up fuzzing a completely different MemoryRegion/Device. Therefore, check
 329     * that the address here is within the PIO space limits.
 330     */
 331    bool found = get_io_address(result, &address_space_io, index, offset);
 332    return result->addr <= 0xFFFF ? found : false;
 333}
 334
 335static bool get_mmio_address(address_range *result,
 336                             uint8_t index, uint32_t offset)
 337{
 338    return get_io_address(result, &address_space_memory, index, offset);
 339}
 340
 341static void op_in(QTestState *s, const unsigned char * data, size_t len)
 342{
 343    enum Sizes {Byte, Word, Long, end_sizes};
 344    struct {
 345        uint8_t size;
 346        uint8_t base;
 347        uint16_t offset;
 348    } a;
 349    address_range abs;
 350
 351    if (len < sizeof(a)) {
 352        return;
 353    }
 354    memcpy(&a, data, sizeof(a));
 355    if (get_pio_address(&abs, a.base, a.offset) == 0) {
 356        return;
 357    }
 358
 359    switch (a.size %= end_sizes) {
 360    case Byte:
 361        qtest_inb(s, abs.addr);
 362        break;
 363    case Word:
 364        if (abs.size >= 2) {
 365            qtest_inw(s, abs.addr);
 366        }
 367        break;
 368    case Long:
 369        if (abs.size >= 4) {
 370            qtest_inl(s, abs.addr);
 371        }
 372        break;
 373    }
 374}
 375
 376static void op_out(QTestState *s, const unsigned char * data, size_t len)
 377{
 378    enum Sizes {Byte, Word, Long, end_sizes};
 379    struct {
 380        uint8_t size;
 381        uint8_t base;
 382        uint16_t offset;
 383        uint32_t value;
 384    } a;
 385    address_range abs;
 386
 387    if (len < sizeof(a)) {
 388        return;
 389    }
 390    memcpy(&a, data, sizeof(a));
 391
 392    if (get_pio_address(&abs, a.base, a.offset) == 0) {
 393        return;
 394    }
 395
 396    switch (a.size %= end_sizes) {
 397    case Byte:
 398        qtest_outb(s, abs.addr, a.value & 0xFF);
 399        break;
 400    case Word:
 401        if (abs.size >= 2) {
 402            qtest_outw(s, abs.addr, a.value & 0xFFFF);
 403        }
 404        break;
 405    case Long:
 406        if (abs.size >= 4) {
 407            qtest_outl(s, abs.addr, a.value);
 408        }
 409        break;
 410    }
 411}
 412
 413static void op_read(QTestState *s, const unsigned char * data, size_t len)
 414{
 415    enum Sizes {Byte, Word, Long, Quad, end_sizes};
 416    struct {
 417        uint8_t size;
 418        uint8_t base;
 419        uint32_t offset;
 420    } a;
 421    address_range abs;
 422
 423    if (len < sizeof(a)) {
 424        return;
 425    }
 426    memcpy(&a, data, sizeof(a));
 427
 428    if (get_mmio_address(&abs, a.base, a.offset) == 0) {
 429        return;
 430    }
 431
 432    switch (a.size %= end_sizes) {
 433    case Byte:
 434        qtest_readb(s, abs.addr);
 435        break;
 436    case Word:
 437        if (abs.size >= 2) {
 438            qtest_readw(s, abs.addr);
 439        }
 440        break;
 441    case Long:
 442        if (abs.size >= 4) {
 443            qtest_readl(s, abs.addr);
 444        }
 445        break;
 446    case Quad:
 447        if (abs.size >= 8) {
 448            qtest_readq(s, abs.addr);
 449        }
 450        break;
 451    }
 452}
 453
 454static void op_write(QTestState *s, const unsigned char * data, size_t len)
 455{
 456    enum Sizes {Byte, Word, Long, Quad, end_sizes};
 457    struct {
 458        uint8_t size;
 459        uint8_t base;
 460        uint32_t offset;
 461        uint64_t value;
 462    } a;
 463    address_range abs;
 464
 465    if (len < sizeof(a)) {
 466        return;
 467    }
 468    memcpy(&a, data, sizeof(a));
 469
 470    if (get_mmio_address(&abs, a.base, a.offset) == 0) {
 471        return;
 472    }
 473
 474    switch (a.size %= end_sizes) {
 475    case Byte:
 476            qtest_writeb(s, abs.addr, a.value & 0xFF);
 477        break;
 478    case Word:
 479        if (abs.size >= 2) {
 480            qtest_writew(s, abs.addr, a.value & 0xFFFF);
 481        }
 482        break;
 483    case Long:
 484        if (abs.size >= 4) {
 485            qtest_writel(s, abs.addr, a.value & 0xFFFFFFFF);
 486        }
 487        break;
 488    case Quad:
 489        if (abs.size >= 8) {
 490            qtest_writeq(s, abs.addr, a.value);
 491        }
 492        break;
 493    }
 494}
 495
 496static void op_pci_read(QTestState *s, const unsigned char * data, size_t len)
 497{
 498    enum Sizes {Byte, Word, Long, end_sizes};
 499    struct {
 500        uint8_t size;
 501        uint8_t base;
 502        uint8_t offset;
 503    } a;
 504    if (len < sizeof(a) || fuzzable_pci_devices->len == 0 || pci_disabled) {
 505        return;
 506    }
 507    memcpy(&a, data, sizeof(a));
 508    PCIDevice *dev = g_ptr_array_index(fuzzable_pci_devices,
 509                                  a.base % fuzzable_pci_devices->len);
 510    int devfn = dev->devfn;
 511    qtest_outl(s, PCI_HOST_BRIDGE_CFG, (1U << 31) | (devfn << 8) | a.offset);
 512    switch (a.size %= end_sizes) {
 513    case Byte:
 514        qtest_inb(s, PCI_HOST_BRIDGE_DATA);
 515        break;
 516    case Word:
 517        qtest_inw(s, PCI_HOST_BRIDGE_DATA);
 518        break;
 519    case Long:
 520        qtest_inl(s, PCI_HOST_BRIDGE_DATA);
 521        break;
 522    }
 523}
 524
 525static void op_pci_write(QTestState *s, const unsigned char * data, size_t len)
 526{
 527    enum Sizes {Byte, Word, Long, end_sizes};
 528    struct {
 529        uint8_t size;
 530        uint8_t base;
 531        uint8_t offset;
 532        uint32_t value;
 533    } a;
 534    if (len < sizeof(a) || fuzzable_pci_devices->len == 0 || pci_disabled) {
 535        return;
 536    }
 537    memcpy(&a, data, sizeof(a));
 538    PCIDevice *dev = g_ptr_array_index(fuzzable_pci_devices,
 539                                  a.base % fuzzable_pci_devices->len);
 540    int devfn = dev->devfn;
 541    qtest_outl(s, PCI_HOST_BRIDGE_CFG, (1U << 31) | (devfn << 8) | a.offset);
 542    switch (a.size %= end_sizes) {
 543    case Byte:
 544        qtest_outb(s, PCI_HOST_BRIDGE_DATA, a.value & 0xFF);
 545        break;
 546    case Word:
 547        qtest_outw(s, PCI_HOST_BRIDGE_DATA, a.value & 0xFFFF);
 548        break;
 549    case Long:
 550        qtest_outl(s, PCI_HOST_BRIDGE_DATA, a.value & 0xFFFFFFFF);
 551        break;
 552    }
 553}
 554
 555static void op_add_dma_pattern(QTestState *s,
 556                               const unsigned char *data, size_t len)
 557{
 558    struct {
 559        /*
 560         * index and stride can be used to increment the index-th byte of the
 561         * pattern by the value stride, for each loop of the pattern.
 562         */
 563        uint8_t index;
 564        uint8_t stride;
 565    } a;
 566
 567    if (len < sizeof(a) + 1) {
 568        return;
 569    }
 570    memcpy(&a, data, sizeof(a));
 571    pattern p = {a.index, a.stride, len - sizeof(a), data + sizeof(a)};
 572    p.index = a.index % p.len;
 573    g_array_append_val(dma_patterns, p);
 574    return;
 575}
 576
 577static void op_clear_dma_patterns(QTestState *s,
 578                                  const unsigned char *data, size_t len)
 579{
 580    g_array_set_size(dma_patterns, 0);
 581    dma_pattern_index = 0;
 582}
 583
 584static void op_clock_step(QTestState *s, const unsigned char *data, size_t len)
 585{
 586    qtest_clock_step_next(s);
 587}
 588
 589static void op_disable_pci(QTestState *s, const unsigned char *data, size_t len)
 590{
 591    pci_disabled = true;
 592}
 593
 594/*
 595 * Here, we interpret random bytes from the fuzzer, as a sequence of commands.
 596 * Some commands can be variable-width, so we use a separator, SEPARATOR, to
 597 * specify the boundaries between commands. SEPARATOR is used to separate
 598 * "operations" in the fuzz input. Why use a separator, instead of just using
 599 * the operations' length to identify operation boundaries?
 600 *   1. This is a simple way to support variable-length operations
 601 *   2. This adds "stability" to the input.
 602 *      For example take the input "AbBcgDefg", where there is no separator and
 603 *      Opcodes are capitalized.
 604 *      Simply, by removing the first byte, we end up with a very different
 605 *      sequence:
 606 *      BbcGdefg...
 607 *      By adding a separator, we avoid this problem:
 608 *      Ab SEP Bcg SEP Defg -> B SEP Bcg SEP Defg
 609 *      Since B uses two additional bytes as operands, the first "B" will be
 610 *      ignored. The fuzzer actively tries to reduce inputs, so such unused
 611 *      bytes are likely to be pruned, eventually.
 612 *
 613 *  SEPARATOR is trivial for the fuzzer to discover when using ASan. Optionally,
 614 *  SEPARATOR can be manually specified as a dictionary value (see libfuzzer's
 615 *  -dict), though this should not be necessary.
 616 *
 617 * As a result, the stream of bytes is converted into a sequence of commands.
 618 * In a simplified example where SEPARATOR is 0xFF:
 619 * 00 01 02 FF 03 04 05 06 FF 01 FF ...
 620 * becomes this sequence of commands:
 621 * 00 01 02    -> op00 (0102)   -> in (0102, 2)
 622 * 03 04 05 06 -> op03 (040506) -> write (040506, 3)
 623 * 01          -> op01 (-,0)    -> out (-,0)
 624 * ...
 625 *
 626 * Note here that it is the job of the individual opcode functions to check
 627 * that enough data was provided. I.e. in the last command out (,0), out needs
 628 * to check that there is not enough data provided to select an address/value
 629 * for the operation.
 630 */
 631static void generic_fuzz(QTestState *s, const unsigned char *Data, size_t Size)
 632{
 633    void (*ops[]) (QTestState *s, const unsigned char* , size_t) = {
 634        [OP_IN]                 = op_in,
 635        [OP_OUT]                = op_out,
 636        [OP_READ]               = op_read,
 637        [OP_WRITE]              = op_write,
 638        [OP_PCI_READ]           = op_pci_read,
 639        [OP_PCI_WRITE]          = op_pci_write,
 640        [OP_DISABLE_PCI]        = op_disable_pci,
 641        [OP_ADD_DMA_PATTERN]    = op_add_dma_pattern,
 642        [OP_CLEAR_DMA_PATTERNS] = op_clear_dma_patterns,
 643        [OP_CLOCK_STEP]         = op_clock_step,
 644    };
 645    const unsigned char *cmd = Data;
 646    const unsigned char *nextcmd;
 647    size_t cmd_len;
 648    uint8_t op;
 649
 650    op_clear_dma_patterns(s, NULL, 0);
 651    pci_disabled = false;
 652    dma_bytes_written = 0;
 653
 654    QPCIBus *pcibus = qpci_new_pc(s, NULL);
 655    g_ptr_array_foreach(fuzzable_pci_devices, pci_enum, pcibus);
 656    qpci_free_pc(pcibus);
 657
 658    while (cmd && Size) {
 659        /* Get the length until the next command or end of input */
 660        nextcmd = memmem(cmd, Size, SEPARATOR, strlen(SEPARATOR));
 661        cmd_len = nextcmd ? nextcmd - cmd : Size;
 662
 663        if (cmd_len > 0) {
 664            /* Interpret the first byte of the command as an opcode */
 665            op = *cmd % (sizeof(ops) / sizeof((ops)[0]));
 666            ops[op](s, cmd + 1, cmd_len - 1);
 667
 668            /* Run the main loop */
 669            flush_events(s);
 670        }
 671        /* Advance to the next command */
 672        cmd = nextcmd ? nextcmd + sizeof(SEPARATOR) - 1 : nextcmd;
 673        Size = Size - (cmd_len + sizeof(SEPARATOR) - 1);
 674        g_array_set_size(dma_regions, 0);
 675    }
 676    fuzz_reset(s);
 677}
 678
 679static void usage(void)
 680{
 681    printf("Please specify the following environment variables:\n");
 682    printf("QEMU_FUZZ_ARGS= the command line arguments passed to qemu\n");
 683    printf("QEMU_FUZZ_OBJECTS= "
 684            "a space separated list of QOM type names for objects to fuzz\n");
 685    printf("Optionally: QEMU_AVOID_DOUBLE_FETCH= "
 686            "Try to avoid racy DMA double fetch bugs? %d by default\n",
 687            avoid_double_fetches);
 688    exit(0);
 689}
 690
 691static int locate_fuzz_memory_regions(Object *child, void *opaque)
 692{
 693    MemoryRegion *mr;
 694    if (object_dynamic_cast(child, TYPE_MEMORY_REGION)) {
 695        mr = MEMORY_REGION(child);
 696        if ((memory_region_is_ram(mr) ||
 697            memory_region_is_ram_device(mr) ||
 698            memory_region_is_rom(mr)) == false) {
 699            /*
 700             * We don't want duplicate pointers to the same MemoryRegion, so
 701             * try to remove copies of the pointer, before adding it.
 702             */
 703            g_hash_table_insert(fuzzable_memoryregions, mr, (gpointer)true);
 704        }
 705    }
 706    return 0;
 707}
 708
 709static int locate_fuzz_objects(Object *child, void *opaque)
 710{
 711    GString *type_name;
 712    GString *path_name;
 713    char *pattern = opaque;
 714
 715    type_name = g_string_new(object_get_typename(child));
 716    g_string_ascii_down(type_name);
 717    if (g_pattern_match_simple(pattern, type_name->str)) {
 718        /* Find and save ptrs to any child MemoryRegions */
 719        object_child_foreach_recursive(child, locate_fuzz_memory_regions, NULL);
 720
 721        /*
 722         * We matched an object. If its a PCI device, store a pointer to it so
 723         * we can map BARs and fuzz its config space.
 724         */
 725        if (object_dynamic_cast(OBJECT(child), TYPE_PCI_DEVICE)) {
 726            /*
 727             * Don't want duplicate pointers to the same PCIDevice, so remove
 728             * copies of the pointer, before adding it.
 729             */
 730            g_ptr_array_remove_fast(fuzzable_pci_devices, PCI_DEVICE(child));
 731            g_ptr_array_add(fuzzable_pci_devices, PCI_DEVICE(child));
 732        }
 733    } else if (object_dynamic_cast(OBJECT(child), TYPE_MEMORY_REGION)) {
 734        path_name = g_string_new(object_get_canonical_path_component(child));
 735        g_string_ascii_down(path_name);
 736        if (g_pattern_match_simple(pattern, path_name->str)) {
 737            MemoryRegion *mr;
 738            mr = MEMORY_REGION(child);
 739            if ((memory_region_is_ram(mr) ||
 740                 memory_region_is_ram_device(mr) ||
 741                 memory_region_is_rom(mr)) == false) {
 742                g_hash_table_insert(fuzzable_memoryregions, mr, (gpointer)true);
 743            }
 744        }
 745        g_string_free(path_name, true);
 746    }
 747    g_string_free(type_name, true);
 748    return 0;
 749}
 750
 751
 752static void pci_enum(gpointer pcidev, gpointer bus)
 753{
 754    PCIDevice *dev = pcidev;
 755    QPCIDevice *qdev;
 756    int i;
 757
 758    qdev = qpci_device_find(bus, dev->devfn);
 759    g_assert(qdev != NULL);
 760    for (i = 0; i < 6; i++) {
 761        if (dev->io_regions[i].size) {
 762            qpci_iomap(qdev, i, NULL);
 763        }
 764    }
 765    qpci_device_enable(qdev);
 766    g_free(qdev);
 767}
 768
 769static void generic_pre_fuzz(QTestState *s)
 770{
 771    GHashTableIter iter;
 772    MemoryRegion *mr;
 773    char **result;
 774    GString *name_pattern;
 775
 776    if (!getenv("QEMU_FUZZ_OBJECTS")) {
 777        usage();
 778    }
 779    if (getenv("QTEST_LOG")) {
 780        qtest_log_enabled = 1;
 781    }
 782    if (getenv("QEMU_AVOID_DOUBLE_FETCH")) {
 783        avoid_double_fetches = 1;
 784    }
 785    qts_global = s;
 786
 787    /*
 788     * Create a special device that we can use to back DMA buffers at very
 789     * high memory addresses
 790     */
 791    sparse_mem_mr = sparse_mem_init(0, UINT64_MAX);
 792
 793    dma_regions = g_array_new(false, false, sizeof(address_range));
 794    dma_patterns = g_array_new(false, false, sizeof(pattern));
 795
 796    fuzzable_memoryregions = g_hash_table_new(NULL, NULL);
 797    fuzzable_pci_devices   = g_ptr_array_new();
 798
 799    result = g_strsplit(getenv("QEMU_FUZZ_OBJECTS"), " ", -1);
 800    for (int i = 0; result[i] != NULL; i++) {
 801        name_pattern = g_string_new(result[i]);
 802        /*
 803         * Make the pattern lowercase. We do the same for all the MemoryRegion
 804         * and Type names so the configs are case-insensitive.
 805         */
 806        g_string_ascii_down(name_pattern);
 807        printf("Matching objects by name %s\n", result[i]);
 808        object_child_foreach_recursive(qdev_get_machine(),
 809                                    locate_fuzz_objects,
 810                                    name_pattern->str);
 811        g_string_free(name_pattern, true);
 812    }
 813    g_strfreev(result);
 814    printf("This process will try to fuzz the following MemoryRegions:\n");
 815
 816    g_hash_table_iter_init(&iter, fuzzable_memoryregions);
 817    while (g_hash_table_iter_next(&iter, (gpointer)&mr, NULL)) {
 818        printf("  * %s (size 0x%" PRIx64 ")\n",
 819               object_get_canonical_path_component(&(mr->parent_obj)),
 820               memory_region_size(mr));
 821    }
 822
 823    if (!g_hash_table_size(fuzzable_memoryregions)) {
 824        printf("No fuzzable memory regions found...\n");
 825        exit(1);
 826    }
 827}
 828
 829/*
 830 * When libfuzzer gives us two inputs to combine, return a new input with the
 831 * following structure:
 832 *
 833 * Input 1 (data1)
 834 * SEPARATOR
 835 * Clear out the DMA Patterns
 836 * SEPARATOR
 837 * Disable the pci_read/write instructions
 838 * SEPARATOR
 839 * Input 2 (data2)
 840 *
 841 * The idea is to collate the core behaviors of the two inputs.
 842 * For example:
 843 * Input 1: maps a device's BARs, sets up three DMA patterns, and triggers
 844 *          device functionality A
 845 * Input 2: maps a device's BARs, sets up one DMA pattern, and triggers device
 846 *          functionality B
 847 *
 848 * This function attempts to produce an input that:
 849 * Ouptut: maps a device's BARs, set up three DMA patterns, triggers
 850 *          functionality A device, replaces the DMA patterns with a single
 851 *          patten, and triggers device functionality B.
 852 */
 853static size_t generic_fuzz_crossover(const uint8_t *data1, size_t size1, const
 854                                     uint8_t *data2, size_t size2, uint8_t *out,
 855                                     size_t max_out_size, unsigned int seed)
 856{
 857    size_t copy_len = 0, size = 0;
 858
 859    /* Check that we have enough space for data1 and at least part of data2 */
 860    if (max_out_size <= size1 + strlen(SEPARATOR) * 3 + 2) {
 861        return 0;
 862    }
 863
 864    /* Copy_Len in the first input */
 865    copy_len = size1;
 866    memcpy(out + size, data1, copy_len);
 867    size += copy_len;
 868    max_out_size -= copy_len;
 869
 870    /* Append a separator */
 871    copy_len = strlen(SEPARATOR);
 872    memcpy(out + size, SEPARATOR, copy_len);
 873    size += copy_len;
 874    max_out_size -= copy_len;
 875
 876    /* Clear out the DMA Patterns */
 877    copy_len = 1;
 878    if (copy_len) {
 879        out[size] = OP_CLEAR_DMA_PATTERNS;
 880    }
 881    size += copy_len;
 882    max_out_size -= copy_len;
 883
 884    /* Append a separator */
 885    copy_len = strlen(SEPARATOR);
 886    memcpy(out + size, SEPARATOR, copy_len);
 887    size += copy_len;
 888    max_out_size -= copy_len;
 889
 890    /* Disable PCI ops. Assume data1 took care of setting up PCI */
 891    copy_len = 1;
 892    if (copy_len) {
 893        out[size] = OP_DISABLE_PCI;
 894    }
 895    size += copy_len;
 896    max_out_size -= copy_len;
 897
 898    /* Append a separator */
 899    copy_len = strlen(SEPARATOR);
 900    memcpy(out + size, SEPARATOR, copy_len);
 901    size += copy_len;
 902    max_out_size -= copy_len;
 903
 904    /* Copy_Len over the second input */
 905    copy_len = MIN(size2, max_out_size);
 906    memcpy(out + size, data2, copy_len);
 907    size += copy_len;
 908    max_out_size -= copy_len;
 909
 910    return  size;
 911}
 912
 913
 914static GString *generic_fuzz_cmdline(FuzzTarget *t)
 915{
 916    GString *cmd_line = g_string_new(TARGET_NAME);
 917    if (!getenv("QEMU_FUZZ_ARGS")) {
 918        usage();
 919    }
 920    g_string_append_printf(cmd_line, " -display none \
 921                                      -machine accel=qtest, \
 922                                      -m 512M %s ", getenv("QEMU_FUZZ_ARGS"));
 923    return cmd_line;
 924}
 925
 926static GString *generic_fuzz_predefined_config_cmdline(FuzzTarget *t)
 927{
 928    gchar *args;
 929    const generic_fuzz_config *config;
 930    g_assert(t->opaque);
 931
 932    config = t->opaque;
 933    g_setenv("QEMU_AVOID_DOUBLE_FETCH", "1", 1);
 934    if (config->argfunc) {
 935        args = config->argfunc();
 936        g_setenv("QEMU_FUZZ_ARGS", args, 1);
 937        g_free(args);
 938    } else {
 939        g_assert_nonnull(config->args);
 940        g_setenv("QEMU_FUZZ_ARGS", config->args, 1);
 941    }
 942    g_setenv("QEMU_FUZZ_OBJECTS", config->objects, 1);
 943    return generic_fuzz_cmdline(t);
 944}
 945
 946static void register_generic_fuzz_targets(void)
 947{
 948    fuzz_add_target(&(FuzzTarget){
 949            .name = "generic-fuzz",
 950            .description = "Fuzz based on any qemu command-line args. ",
 951            .get_init_cmdline = generic_fuzz_cmdline,
 952            .pre_fuzz = generic_pre_fuzz,
 953            .fuzz = generic_fuzz,
 954            .crossover = generic_fuzz_crossover
 955    });
 956
 957    for (int i = 0; i < ARRAY_SIZE(predefined_configs); i++) {
 958        const generic_fuzz_config *config = predefined_configs + i;
 959        fuzz_add_target(&(FuzzTarget){
 960                .name = g_strconcat("generic-fuzz-", config->name, NULL),
 961                .description = "Predefined generic-fuzz config.",
 962                .get_init_cmdline = generic_fuzz_predefined_config_cmdline,
 963                .pre_fuzz = generic_pre_fuzz,
 964                .fuzz = generic_fuzz,
 965                .crossover = generic_fuzz_crossover,
 966                .opaque = (void *)config
 967        });
 968    }
 969}
 970
 971fuzz_target_init(register_generic_fuzz_targets);
 972