2 * I440FX Fuzzing Target
4 * Copyright Red Hat Inc., 2019
7 * Alexander Bulekov <alxndr@bu.edu>
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.
13 #include "qemu/osdep.h"
15 #include "qemu/main-loop.h"
16 #include "tests/qtest/libqtest.h"
17 #include "tests/qtest/libqos/pci.h"
18 #include "tests/qtest/libqos/pci-pc.h"
20 #include "fuzz/qos_fuzz.h"
21 #include "fuzz/fork_fuzz.h"
24 #define I440FX_PCI_HOST_BRIDGE_CFG 0xcf8
25 #define I440FX_PCI_HOST_BRIDGE_DATA 0xcfc
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:
42 static void ioport_fuzz_qtest(QTestState
*s
,
43 const unsigned char *Data
, size_t Size
) {
45 * loop over the Data, breaking it up into actions. each action has an
46 * opcode, address offset and value
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
) {
62 qtest_outb(s
, addr
, (uint8_t)a
.value
);
65 qtest_outw(s
, addr
, (uint16_t)a
.value
);
68 qtest_outl(s
, addr
, (uint32_t)a
.value
);
80 /* Move to the next operation */
87 static void i440fx_fuzz_qtest(QTestState
*s
,
88 const unsigned char *Data
,
91 ioport_fuzz_qtest(s
, Data
, Size
);
94 static void pciconfig_fuzz_qos(QTestState
*s
, QPCIBus
*bus
,
95 const unsigned char *Data
, size_t Size
) {
97 * Same as ioport_fuzz_qtest, but using QOS. devfn is incorporated into the
98 * value written over Port IO
107 while (Size
>= sizeof(a
)) {
108 memcpy(&a
, Data
, sizeof(a
));
109 switch (a
.opcode
% ACTION_MAX
) {
111 bus
->config_writeb(bus
, a
.devfn
, a
.offset
, (uint8_t)a
.value
);
114 bus
->config_writew(bus
, a
.devfn
, a
.offset
, (uint16_t)a
.value
);
117 bus
->config_writel(bus
, a
.devfn
, a
.offset
, (uint32_t)a
.value
);
120 bus
->config_readb(bus
, a
.devfn
, a
.offset
);
123 bus
->config_readw(bus
, a
.devfn
, a
.offset
);
126 bus
->config_readl(bus
, a
.devfn
, a
.offset
);
135 static void i440fx_fuzz_qos(QTestState
*s
,
136 const unsigned char *Data
,
142 bus
= qpci_new_pc(s
, fuzz_qos_alloc
);
145 pciconfig_fuzz_qos(s
, bus
, Data
, Size
);
148 static void i440fx_fuzz_qos_fork(QTestState
*s
,
149 const unsigned char *Data
, size_t Size
) {
151 i440fx_fuzz_qos(s
, Data
, Size
);
159 static const char *i440fx_qtest_argv
= TARGET_NAME
" -machine accel=qtest"
160 " -m 0 -display none";
161 static GString
*i440fx_argv(FuzzTarget
*t
)
163 return g_string_new(i440fx_qtest_argv
);
166 static void fork_init(void)
171 static void register_pci_fuzz_targets(void)
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
});
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
,},
189 &(QOSGraphTestOptions
){}
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)
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
,},
203 &(QOSGraphTestOptions
){}
207 fuzz_target_init(register_pci_fuzz_targets
);