xref: /qemu/tests/qtest/fuzz/i440fx_fuzz.c (revision 79e18a60ab456764eaa974b67b9c54281a5156db)
104f71324SAlexander Bulekov /*
204f71324SAlexander Bulekov  * I440FX Fuzzing Target
304f71324SAlexander Bulekov  *
404f71324SAlexander Bulekov  * Copyright Red Hat Inc., 2019
504f71324SAlexander Bulekov  *
604f71324SAlexander Bulekov  * Authors:
704f71324SAlexander Bulekov  *  Alexander Bulekov   <alxndr@bu.edu>
804f71324SAlexander Bulekov  *
904f71324SAlexander Bulekov  * This work is licensed under the terms of the GNU GPL, version 2 or later.
1004f71324SAlexander Bulekov  * See the COPYING file in the top-level directory.
1104f71324SAlexander Bulekov  */
1204f71324SAlexander Bulekov 
1304f71324SAlexander Bulekov #include "qemu/osdep.h"
1404f71324SAlexander Bulekov 
1504f71324SAlexander Bulekov #include "qemu/main-loop.h"
1604f71324SAlexander Bulekov #include "tests/qtest/libqtest.h"
1704f71324SAlexander Bulekov #include "tests/qtest/libqos/pci.h"
1804f71324SAlexander Bulekov #include "tests/qtest/libqos/pci-pc.h"
1904f71324SAlexander Bulekov #include "fuzz.h"
2004f71324SAlexander Bulekov #include "fuzz/qos_fuzz.h"
2104f71324SAlexander Bulekov #include "fuzz/fork_fuzz.h"
2204f71324SAlexander Bulekov 
2304f71324SAlexander Bulekov 
2404f71324SAlexander Bulekov #define I440FX_PCI_HOST_BRIDGE_CFG 0xcf8
2504f71324SAlexander Bulekov #define I440FX_PCI_HOST_BRIDGE_DATA 0xcfc
2604f71324SAlexander Bulekov 
2704f71324SAlexander Bulekov /*
2804f71324SAlexander Bulekov  * the input to the fuzzing functions below is a buffer of random bytes. we
2904f71324SAlexander Bulekov  * want to convert these bytes into a sequence of qtest or qos calls. to do
3004f71324SAlexander Bulekov  * this we define some opcodes:
3104f71324SAlexander Bulekov  */
3204f71324SAlexander Bulekov enum action_id {
3304f71324SAlexander Bulekov     WRITEB,
3404f71324SAlexander Bulekov     WRITEW,
3504f71324SAlexander Bulekov     WRITEL,
3604f71324SAlexander Bulekov     READB,
3704f71324SAlexander Bulekov     READW,
3804f71324SAlexander Bulekov     READL,
3904f71324SAlexander Bulekov     ACTION_MAX
4004f71324SAlexander Bulekov };
4104f71324SAlexander Bulekov 
4204f71324SAlexander Bulekov static void i440fx_fuzz_qtest(QTestState *s,
4304f71324SAlexander Bulekov         const unsigned char *Data, size_t Size) {
4404f71324SAlexander Bulekov     /*
4504f71324SAlexander Bulekov      * loop over the Data, breaking it up into actions. each action has an
4604f71324SAlexander Bulekov      * opcode, address offset and value
4704f71324SAlexander Bulekov      */
48*79e18a60SPhilippe Mathieu-Daudé     struct {
4904f71324SAlexander Bulekov         uint8_t opcode;
5004f71324SAlexander Bulekov         uint8_t addr;
5104f71324SAlexander Bulekov         uint32_t value;
52*79e18a60SPhilippe Mathieu-Daudé     } a;
5304f71324SAlexander Bulekov 
5404f71324SAlexander Bulekov     while (Size >= sizeof(a)) {
5504f71324SAlexander Bulekov         /* make a copy of the action so we can normalize the values in-place */
5604f71324SAlexander Bulekov         memcpy(&a, Data, sizeof(a));
5704f71324SAlexander Bulekov         /* select between two i440fx Port IO addresses */
5804f71324SAlexander Bulekov         uint16_t addr = a.addr % 2 ? I440FX_PCI_HOST_BRIDGE_CFG :
5904f71324SAlexander Bulekov                                       I440FX_PCI_HOST_BRIDGE_DATA;
6004f71324SAlexander Bulekov         switch (a.opcode % ACTION_MAX) {
6104f71324SAlexander Bulekov         case WRITEB:
6204f71324SAlexander Bulekov             qtest_outb(s, addr, (uint8_t)a.value);
6304f71324SAlexander Bulekov             break;
6404f71324SAlexander Bulekov         case WRITEW:
6504f71324SAlexander Bulekov             qtest_outw(s, addr, (uint16_t)a.value);
6604f71324SAlexander Bulekov             break;
6704f71324SAlexander Bulekov         case WRITEL:
6804f71324SAlexander Bulekov             qtest_outl(s, addr, (uint32_t)a.value);
6904f71324SAlexander Bulekov             break;
7004f71324SAlexander Bulekov         case READB:
7104f71324SAlexander Bulekov             qtest_inb(s, addr);
7204f71324SAlexander Bulekov             break;
7304f71324SAlexander Bulekov         case READW:
7404f71324SAlexander Bulekov             qtest_inw(s, addr);
7504f71324SAlexander Bulekov             break;
7604f71324SAlexander Bulekov         case READL:
7704f71324SAlexander Bulekov             qtest_inl(s, addr);
7804f71324SAlexander Bulekov             break;
7904f71324SAlexander Bulekov         }
8004f71324SAlexander Bulekov         /* Move to the next operation */
8104f71324SAlexander Bulekov         Size -= sizeof(a);
8204f71324SAlexander Bulekov         Data += sizeof(a);
8304f71324SAlexander Bulekov     }
8404f71324SAlexander Bulekov     flush_events(s);
8504f71324SAlexander Bulekov }
8604f71324SAlexander Bulekov 
8704f71324SAlexander Bulekov static void i440fx_fuzz_qos(QTestState *s,
8804f71324SAlexander Bulekov         const unsigned char *Data, size_t Size) {
8904f71324SAlexander Bulekov     /*
9004f71324SAlexander Bulekov      * Same as i440fx_fuzz_qtest, but using QOS. devfn is incorporated into the
9104f71324SAlexander Bulekov      * value written over Port IO
9204f71324SAlexander Bulekov      */
93*79e18a60SPhilippe Mathieu-Daudé     struct {
9404f71324SAlexander Bulekov         uint8_t opcode;
9504f71324SAlexander Bulekov         uint8_t offset;
9604f71324SAlexander Bulekov         int devfn;
9704f71324SAlexander Bulekov         uint32_t value;
98*79e18a60SPhilippe Mathieu-Daudé     } a;
9904f71324SAlexander Bulekov 
10004f71324SAlexander Bulekov     static QPCIBus *bus;
10104f71324SAlexander Bulekov     if (!bus) {
10204f71324SAlexander Bulekov         bus = qpci_new_pc(s, fuzz_qos_alloc);
10304f71324SAlexander Bulekov     }
10404f71324SAlexander Bulekov 
10504f71324SAlexander Bulekov     while (Size >= sizeof(a)) {
10604f71324SAlexander Bulekov         memcpy(&a, Data, sizeof(a));
10704f71324SAlexander Bulekov         switch (a.opcode % ACTION_MAX) {
10804f71324SAlexander Bulekov         case WRITEB:
10904f71324SAlexander Bulekov             bus->config_writeb(bus, a.devfn, a.offset, (uint8_t)a.value);
11004f71324SAlexander Bulekov             break;
11104f71324SAlexander Bulekov         case WRITEW:
11204f71324SAlexander Bulekov             bus->config_writew(bus, a.devfn, a.offset, (uint16_t)a.value);
11304f71324SAlexander Bulekov             break;
11404f71324SAlexander Bulekov         case WRITEL:
11504f71324SAlexander Bulekov             bus->config_writel(bus, a.devfn, a.offset, (uint32_t)a.value);
11604f71324SAlexander Bulekov             break;
11704f71324SAlexander Bulekov         case READB:
11804f71324SAlexander Bulekov             bus->config_readb(bus, a.devfn, a.offset);
11904f71324SAlexander Bulekov             break;
12004f71324SAlexander Bulekov         case READW:
12104f71324SAlexander Bulekov             bus->config_readw(bus, a.devfn, a.offset);
12204f71324SAlexander Bulekov             break;
12304f71324SAlexander Bulekov         case READL:
12404f71324SAlexander Bulekov             bus->config_readl(bus, a.devfn, a.offset);
12504f71324SAlexander Bulekov             break;
12604f71324SAlexander Bulekov         }
12704f71324SAlexander Bulekov         Size -= sizeof(a);
12804f71324SAlexander Bulekov         Data += sizeof(a);
12904f71324SAlexander Bulekov     }
13004f71324SAlexander Bulekov     flush_events(s);
13104f71324SAlexander Bulekov }
13204f71324SAlexander Bulekov 
13304f71324SAlexander Bulekov static void i440fx_fuzz_qos_fork(QTestState *s,
13404f71324SAlexander Bulekov         const unsigned char *Data, size_t Size) {
13504f71324SAlexander Bulekov     if (fork() == 0) {
13604f71324SAlexander Bulekov         i440fx_fuzz_qos(s, Data, Size);
13704f71324SAlexander Bulekov         _Exit(0);
13804f71324SAlexander Bulekov     } else {
13904f71324SAlexander Bulekov         wait(NULL);
14004f71324SAlexander Bulekov     }
14104f71324SAlexander Bulekov }
14204f71324SAlexander Bulekov 
14304f71324SAlexander Bulekov static const char *i440fx_qtest_argv = TARGET_NAME " -machine accel=qtest"
14404f71324SAlexander Bulekov                                        "-m 0 -display none";
14504f71324SAlexander Bulekov static const char *i440fx_argv(FuzzTarget *t)
14604f71324SAlexander Bulekov {
14704f71324SAlexander Bulekov     return i440fx_qtest_argv;
14804f71324SAlexander Bulekov }
14904f71324SAlexander Bulekov 
15004f71324SAlexander Bulekov static void fork_init(void)
15104f71324SAlexander Bulekov {
15204f71324SAlexander Bulekov     counter_shm_init();
15304f71324SAlexander Bulekov }
15404f71324SAlexander Bulekov 
15504f71324SAlexander Bulekov static void register_pci_fuzz_targets(void)
15604f71324SAlexander Bulekov {
15704f71324SAlexander Bulekov     /* Uses simple qtest commands and reboots to reset state */
15804f71324SAlexander Bulekov     fuzz_add_target(&(FuzzTarget){
15904f71324SAlexander Bulekov                 .name = "i440fx-qtest-reboot-fuzz",
16004f71324SAlexander Bulekov                 .description = "Fuzz the i440fx using raw qtest commands and "
16104f71324SAlexander Bulekov                                "rebooting after each run",
16204f71324SAlexander Bulekov                 .get_init_cmdline = i440fx_argv,
16304f71324SAlexander Bulekov                 .fuzz = i440fx_fuzz_qtest});
16404f71324SAlexander Bulekov 
16504f71324SAlexander Bulekov     /* Uses libqos and forks to prevent state leakage */
16604f71324SAlexander Bulekov     fuzz_add_qos_target(&(FuzzTarget){
16704f71324SAlexander Bulekov                 .name = "i440fx-qos-fork-fuzz",
16804f71324SAlexander Bulekov                 .description = "Fuzz the i440fx using raw qtest commands and "
16904f71324SAlexander Bulekov                                "rebooting after each run",
17004f71324SAlexander Bulekov                 .pre_vm_init = &fork_init,
17104f71324SAlexander Bulekov                 .fuzz = i440fx_fuzz_qos_fork,},
17204f71324SAlexander Bulekov                 "i440FX-pcihost",
17304f71324SAlexander Bulekov                 &(QOSGraphTestOptions){}
17404f71324SAlexander Bulekov                 );
17504f71324SAlexander Bulekov 
17604f71324SAlexander Bulekov     /*
17704f71324SAlexander Bulekov      * Uses libqos. Doesn't do anything to reset state. Note that if we were to
17804f71324SAlexander Bulekov      * reboot after each run, we would also have to redo the qos-related
17904f71324SAlexander Bulekov      * initialization (qos_init_path)
18004f71324SAlexander Bulekov      */
18104f71324SAlexander Bulekov     fuzz_add_qos_target(&(FuzzTarget){
18204f71324SAlexander Bulekov                 .name = "i440fx-qos-noreset-fuzz",
18304f71324SAlexander Bulekov                 .description = "Fuzz the i440fx using raw qtest commands and "
18404f71324SAlexander Bulekov                                "rebooting after each run",
18504f71324SAlexander Bulekov                 .fuzz = i440fx_fuzz_qos,},
18604f71324SAlexander Bulekov                 "i440FX-pcihost",
18704f71324SAlexander Bulekov                 &(QOSGraphTestOptions){}
18804f71324SAlexander Bulekov                 );
18904f71324SAlexander Bulekov }
19004f71324SAlexander Bulekov 
19104f71324SAlexander Bulekov fuzz_target_init(register_pci_fuzz_targets);
192