cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

i440fx_fuzz.c (5894B)


      1/*
      2 * I440FX Fuzzing Target
      3 *
      4 * Copyright Red Hat Inc., 2019
      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 "qemu/main-loop.h"
     16#include "tests/qtest/libqos/libqtest.h"
     17#include "tests/qtest/libqos/pci.h"
     18#include "tests/qtest/libqos/pci-pc.h"
     19#include "fuzz.h"
     20#include "qos_fuzz.h"
     21#include "fork_fuzz.h"
     22
     23
     24#define I440FX_PCI_HOST_BRIDGE_CFG 0xcf8
     25#define I440FX_PCI_HOST_BRIDGE_DATA 0xcfc
     26
     27/*
     28 * the input to the fuzzing functions below is a buffer of random bytes. we
     29 * want to convert these bytes into a sequence of qtest or qos calls. to do
     30 * this we define some opcodes:
     31 */
     32enum action_id {
     33    WRITEB,
     34    WRITEW,
     35    WRITEL,
     36    READB,
     37    READW,
     38    READL,
     39    ACTION_MAX
     40};
     41
     42static void ioport_fuzz_qtest(QTestState *s,
     43        const unsigned char *Data, size_t Size) {
     44    /*
     45     * loop over the Data, breaking it up into actions. each action has an
     46     * opcode, address offset and value
     47     */
     48    struct {
     49        uint8_t opcode;
     50        uint8_t addr;
     51        uint32_t value;
     52    } a;
     53
     54    while (Size >= sizeof(a)) {
     55        /* make a copy of the action so we can normalize the values in-place */
     56        memcpy(&a, Data, sizeof(a));
     57        /* select between two i440fx Port IO addresses */
     58        uint16_t addr = a.addr % 2 ? I440FX_PCI_HOST_BRIDGE_CFG :
     59                                      I440FX_PCI_HOST_BRIDGE_DATA;
     60        switch (a.opcode % ACTION_MAX) {
     61        case WRITEB:
     62            qtest_outb(s, addr, (uint8_t)a.value);
     63            break;
     64        case WRITEW:
     65            qtest_outw(s, addr, (uint16_t)a.value);
     66            break;
     67        case WRITEL:
     68            qtest_outl(s, addr, (uint32_t)a.value);
     69            break;
     70        case READB:
     71            qtest_inb(s, addr);
     72            break;
     73        case READW:
     74            qtest_inw(s, addr);
     75            break;
     76        case READL:
     77            qtest_inl(s, addr);
     78            break;
     79        }
     80        /* Move to the next operation */
     81        Size -= sizeof(a);
     82        Data += sizeof(a);
     83    }
     84    flush_events(s);
     85}
     86
     87static void i440fx_fuzz_qtest(QTestState *s,
     88                              const unsigned char *Data,
     89                              size_t Size)
     90{
     91    ioport_fuzz_qtest(s, Data, Size);
     92}
     93
     94static void pciconfig_fuzz_qos(QTestState *s, QPCIBus *bus,
     95        const unsigned char *Data, size_t Size) {
     96    /*
     97     * Same as ioport_fuzz_qtest, but using QOS. devfn is incorporated into the
     98     * value written over Port IO
     99     */
    100    struct {
    101        uint8_t opcode;
    102        uint8_t offset;
    103        int devfn;
    104        uint32_t value;
    105    } a;
    106
    107    while (Size >= sizeof(a)) {
    108        memcpy(&a, Data, sizeof(a));
    109        switch (a.opcode % ACTION_MAX) {
    110        case WRITEB:
    111            bus->config_writeb(bus, a.devfn, a.offset, (uint8_t)a.value);
    112            break;
    113        case WRITEW:
    114            bus->config_writew(bus, a.devfn, a.offset, (uint16_t)a.value);
    115            break;
    116        case WRITEL:
    117            bus->config_writel(bus, a.devfn, a.offset, (uint32_t)a.value);
    118            break;
    119        case READB:
    120            bus->config_readb(bus, a.devfn, a.offset);
    121            break;
    122        case READW:
    123            bus->config_readw(bus, a.devfn, a.offset);
    124            break;
    125        case READL:
    126            bus->config_readl(bus, a.devfn, a.offset);
    127            break;
    128        }
    129        Size -= sizeof(a);
    130        Data += sizeof(a);
    131    }
    132    flush_events(s);
    133}
    134
    135static void i440fx_fuzz_qos(QTestState *s,
    136                            const unsigned char *Data,
    137                            size_t Size)
    138{
    139    static QPCIBus *bus;
    140
    141    if (!bus) {
    142        bus = qpci_new_pc(s, fuzz_qos_alloc);
    143    }
    144
    145    pciconfig_fuzz_qos(s, bus, Data, Size);
    146}
    147
    148static void i440fx_fuzz_qos_fork(QTestState *s,
    149        const unsigned char *Data, size_t Size) {
    150    if (fork() == 0) {
    151        i440fx_fuzz_qos(s, Data, Size);
    152        _Exit(0);
    153    } else {
    154        flush_events(s);
    155        wait(NULL);
    156    }
    157}
    158
    159static const char *i440fx_qtest_argv = TARGET_NAME " -machine accel=qtest"
    160                                       " -m 0 -display none";
    161static GString *i440fx_argv(FuzzTarget *t)
    162{
    163    return g_string_new(i440fx_qtest_argv);
    164}
    165
    166static void fork_init(void)
    167{
    168    counter_shm_init();
    169}
    170
    171static void register_pci_fuzz_targets(void)
    172{
    173    /* Uses simple qtest commands and reboots to reset state */
    174    fuzz_add_target(&(FuzzTarget){
    175                .name = "i440fx-qtest-reboot-fuzz",
    176                .description = "Fuzz the i440fx using raw qtest commands and "
    177                               "rebooting after each run",
    178                .get_init_cmdline = i440fx_argv,
    179                .fuzz = i440fx_fuzz_qtest});
    180
    181    /* Uses libqos and forks to prevent state leakage */
    182    fuzz_add_qos_target(&(FuzzTarget){
    183                .name = "i440fx-qos-fork-fuzz",
    184                .description = "Fuzz the i440fx using raw qtest commands and "
    185                               "rebooting after each run",
    186                .pre_vm_init = &fork_init,
    187                .fuzz = i440fx_fuzz_qos_fork,},
    188                "i440FX-pcihost",
    189                &(QOSGraphTestOptions){}
    190                );
    191
    192    /*
    193     * Uses libqos. Doesn't do anything to reset state. Note that if we were to
    194     * reboot after each run, we would also have to redo the qos-related
    195     * initialization (qos_init_path)
    196     */
    197    fuzz_add_qos_target(&(FuzzTarget){
    198                .name = "i440fx-qos-noreset-fuzz",
    199                .description = "Fuzz the i440fx using raw qtest commands and "
    200                               "rebooting after each run",
    201                .fuzz = i440fx_fuzz_qos,},
    202                "i440FX-pcihost",
    203                &(QOSGraphTestOptions){}
    204                );
    205}
    206
    207fuzz_target_init(register_pci_fuzz_targets);