15f6fd09aSAlexander Bulekov /* 25f6fd09aSAlexander Bulekov * fuzzing driver 35f6fd09aSAlexander Bulekov * 45f6fd09aSAlexander Bulekov * Copyright Red Hat Inc., 2019 55f6fd09aSAlexander Bulekov * 65f6fd09aSAlexander Bulekov * Authors: 75f6fd09aSAlexander Bulekov * Alexander Bulekov <alxndr@bu.edu> 85f6fd09aSAlexander Bulekov * 95f6fd09aSAlexander Bulekov * This work is licensed under the terms of the GNU GPL, version 2 or later. 105f6fd09aSAlexander Bulekov * See the COPYING file in the top-level directory. 115f6fd09aSAlexander Bulekov * 125f6fd09aSAlexander Bulekov */ 135f6fd09aSAlexander Bulekov 145f6fd09aSAlexander Bulekov #include "qemu/osdep.h" 155f6fd09aSAlexander Bulekov 165f6fd09aSAlexander Bulekov #include <wordexp.h> 175f6fd09aSAlexander Bulekov 182c65db5eSPaolo Bonzini #include "qemu/datadir.h" 195f6fd09aSAlexander Bulekov #include "sysemu/qtest.h" 205f6fd09aSAlexander Bulekov #include "sysemu/runstate.h" 215f6fd09aSAlexander Bulekov #include "sysemu/sysemu.h" 225f6fd09aSAlexander Bulekov #include "qemu/main-loop.h" 23230225eaSAlexander Bulekov #include "qemu/rcu.h" 24a2ce7dbdSPaolo Bonzini #include "tests/qtest/libqos/libqtest.h" 255f6fd09aSAlexander Bulekov #include "tests/qtest/libqos/qgraph.h" 265f6fd09aSAlexander Bulekov #include "fuzz.h" 275f6fd09aSAlexander Bulekov 285f6fd09aSAlexander Bulekov #define MAX_EVENT_LOOPS 10 295f6fd09aSAlexander Bulekov 305f6fd09aSAlexander Bulekov typedef struct FuzzTargetState { 315f6fd09aSAlexander Bulekov FuzzTarget *target; 325f6fd09aSAlexander Bulekov QSLIST_ENTRY(FuzzTargetState) target_list; 335f6fd09aSAlexander Bulekov } FuzzTargetState; 345f6fd09aSAlexander Bulekov 355f6fd09aSAlexander Bulekov typedef QSLIST_HEAD(, FuzzTargetState) FuzzTargetList; 365f6fd09aSAlexander Bulekov 375f6fd09aSAlexander Bulekov static const char *fuzz_arch = TARGET_NAME; 385f6fd09aSAlexander Bulekov 395f6fd09aSAlexander Bulekov static FuzzTargetList *fuzz_target_list; 405f6fd09aSAlexander Bulekov static FuzzTarget *fuzz_target; 415f6fd09aSAlexander Bulekov static QTestState *fuzz_qts; 425f6fd09aSAlexander Bulekov 435f6fd09aSAlexander Bulekov 445f6fd09aSAlexander Bulekov 455f6fd09aSAlexander Bulekov void flush_events(QTestState *s) 465f6fd09aSAlexander Bulekov { 475f6fd09aSAlexander Bulekov int i = MAX_EVENT_LOOPS; 485f6fd09aSAlexander Bulekov while (g_main_context_pending(NULL) && i-- > 0) { 495f6fd09aSAlexander Bulekov main_loop_wait(false); 505f6fd09aSAlexander Bulekov } 515f6fd09aSAlexander Bulekov } 525f6fd09aSAlexander Bulekov 535f6fd09aSAlexander Bulekov static QTestState *qtest_setup(void) 545f6fd09aSAlexander Bulekov { 555f6fd09aSAlexander Bulekov qtest_server_set_send_handler(&qtest_client_inproc_recv, &fuzz_qts); 565f6fd09aSAlexander Bulekov return qtest_inproc_init(&fuzz_qts, false, fuzz_arch, 575f6fd09aSAlexander Bulekov &qtest_server_inproc_recv); 585f6fd09aSAlexander Bulekov } 595f6fd09aSAlexander Bulekov 605f6fd09aSAlexander Bulekov void fuzz_add_target(const FuzzTarget *target) 615f6fd09aSAlexander Bulekov { 625f6fd09aSAlexander Bulekov FuzzTargetState *tmp; 635f6fd09aSAlexander Bulekov FuzzTargetState *target_state; 645f6fd09aSAlexander Bulekov if (!fuzz_target_list) { 655f6fd09aSAlexander Bulekov fuzz_target_list = g_new0(FuzzTargetList, 1); 665f6fd09aSAlexander Bulekov } 675f6fd09aSAlexander Bulekov 685f6fd09aSAlexander Bulekov QSLIST_FOREACH(tmp, fuzz_target_list, target_list) { 695f6fd09aSAlexander Bulekov if (g_strcmp0(tmp->target->name, target->name) == 0) { 705f6fd09aSAlexander Bulekov fprintf(stderr, "Error: Fuzz target name %s already in use\n", 715f6fd09aSAlexander Bulekov target->name); 725f6fd09aSAlexander Bulekov abort(); 735f6fd09aSAlexander Bulekov } 745f6fd09aSAlexander Bulekov } 755f6fd09aSAlexander Bulekov target_state = g_new0(FuzzTargetState, 1); 765f6fd09aSAlexander Bulekov target_state->target = g_new0(FuzzTarget, 1); 775f6fd09aSAlexander Bulekov *(target_state->target) = *target; 785f6fd09aSAlexander Bulekov QSLIST_INSERT_HEAD(fuzz_target_list, target_state, target_list); 795f6fd09aSAlexander Bulekov } 805f6fd09aSAlexander Bulekov 815f6fd09aSAlexander Bulekov 825f6fd09aSAlexander Bulekov 835f6fd09aSAlexander Bulekov static void usage(char *path) 845f6fd09aSAlexander Bulekov { 855f6fd09aSAlexander Bulekov printf("Usage: %s --fuzz-target=FUZZ_TARGET [LIBFUZZER ARGUMENTS]\n", path); 865f6fd09aSAlexander Bulekov printf("where FUZZ_TARGET is one of:\n"); 875f6fd09aSAlexander Bulekov FuzzTargetState *tmp; 885f6fd09aSAlexander Bulekov if (!fuzz_target_list) { 895f6fd09aSAlexander Bulekov fprintf(stderr, "Fuzz target list not initialized\n"); 905f6fd09aSAlexander Bulekov abort(); 915f6fd09aSAlexander Bulekov } 925f6fd09aSAlexander Bulekov QSLIST_FOREACH(tmp, fuzz_target_list, target_list) { 935f6fd09aSAlexander Bulekov printf(" * %s : %s\n", tmp->target->name, 945f6fd09aSAlexander Bulekov tmp->target->description); 955f6fd09aSAlexander Bulekov } 96d92e1b6dSAlexander Bulekov printf("Alternatively, add -target-FUZZ_TARGET to the executable name\n\n" 97d92e1b6dSAlexander Bulekov "Set the environment variable FUZZ_SERIALIZE_QTEST=1 to serialize\n" 98d92e1b6dSAlexander Bulekov "QTest commands into an ASCII protocol. Useful for building crash\n" 998efebd4eSAlexander Bulekov "reproducers, but slows down execution.\n\n" 1008efebd4eSAlexander Bulekov "Set the environment variable QTEST_LOG=1 to log all qtest commands" 1018efebd4eSAlexander Bulekov "\n"); 1025f6fd09aSAlexander Bulekov exit(0); 1035f6fd09aSAlexander Bulekov } 1045f6fd09aSAlexander Bulekov 1055f6fd09aSAlexander Bulekov static FuzzTarget *fuzz_get_target(char* name) 1065f6fd09aSAlexander Bulekov { 1075f6fd09aSAlexander Bulekov FuzzTargetState *tmp; 1085f6fd09aSAlexander Bulekov if (!fuzz_target_list) { 1095f6fd09aSAlexander Bulekov fprintf(stderr, "Fuzz target list not initialized\n"); 1105f6fd09aSAlexander Bulekov abort(); 1115f6fd09aSAlexander Bulekov } 1125f6fd09aSAlexander Bulekov 1135f6fd09aSAlexander Bulekov QSLIST_FOREACH(tmp, fuzz_target_list, target_list) { 1145f6fd09aSAlexander Bulekov if (strcmp(tmp->target->name, name) == 0) { 1155f6fd09aSAlexander Bulekov return tmp->target; 1165f6fd09aSAlexander Bulekov } 1175f6fd09aSAlexander Bulekov } 1185f6fd09aSAlexander Bulekov return NULL; 1195f6fd09aSAlexander Bulekov } 1205f6fd09aSAlexander Bulekov 1215f6fd09aSAlexander Bulekov 122f81cb729SAlexander Bulekov /* Sometimes called by libfuzzer to mutate two inputs into one */ 123f81cb729SAlexander Bulekov size_t LLVMFuzzerCustomCrossOver(const uint8_t *data1, size_t size1, 124f81cb729SAlexander Bulekov const uint8_t *data2, size_t size2, 125f81cb729SAlexander Bulekov uint8_t *out, size_t max_out_size, 126f81cb729SAlexander Bulekov unsigned int seed) 127f81cb729SAlexander Bulekov { 128f81cb729SAlexander Bulekov if (fuzz_target->crossover) { 129f81cb729SAlexander Bulekov return fuzz_target->crossover(data1, size1, data2, size2, out, 130f81cb729SAlexander Bulekov max_out_size, seed); 131f81cb729SAlexander Bulekov } 132f81cb729SAlexander Bulekov return 0; 133f81cb729SAlexander Bulekov } 134f81cb729SAlexander Bulekov 1355f6fd09aSAlexander Bulekov /* Executed for each fuzzing-input */ 1365f6fd09aSAlexander Bulekov int LLVMFuzzerTestOneInput(const unsigned char *Data, size_t Size) 1375f6fd09aSAlexander Bulekov { 1385f6fd09aSAlexander Bulekov /* 1395f6fd09aSAlexander Bulekov * Do the pre-fuzz-initialization before the first fuzzing iteration, 1405f6fd09aSAlexander Bulekov * instead of before the actual fuzz loop. This is needed since libfuzzer 1415f6fd09aSAlexander Bulekov * may fork off additional workers, prior to the fuzzing loop, and if 1425f6fd09aSAlexander Bulekov * pre_fuzz() sets up e.g. shared memory, this should be done for the 1435f6fd09aSAlexander Bulekov * individual worker processes 1445f6fd09aSAlexander Bulekov */ 1455f6fd09aSAlexander Bulekov static int pre_fuzz_done; 1465f6fd09aSAlexander Bulekov if (!pre_fuzz_done && fuzz_target->pre_fuzz) { 1475f6fd09aSAlexander Bulekov fuzz_target->pre_fuzz(fuzz_qts); 1485f6fd09aSAlexander Bulekov pre_fuzz_done = true; 1495f6fd09aSAlexander Bulekov } 1505f6fd09aSAlexander Bulekov 1515f6fd09aSAlexander Bulekov fuzz_target->fuzz(fuzz_qts, Data, Size); 1525f6fd09aSAlexander Bulekov return 0; 1535f6fd09aSAlexander Bulekov } 1545f6fd09aSAlexander Bulekov 1555f6fd09aSAlexander Bulekov /* Executed once, prior to fuzzing */ 1565f6fd09aSAlexander Bulekov int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp) 1575f6fd09aSAlexander Bulekov { 1585f6fd09aSAlexander Bulekov 1595f6fd09aSAlexander Bulekov char *target_name; 160a4c13869SPaolo Bonzini const char *bindir; 161a4c13869SPaolo Bonzini char *datadir; 162*61f90e04SAlexander Bulekov GString *cmd_line; 163*61f90e04SAlexander Bulekov gchar *pretty_cmd_line; 164d92e1b6dSAlexander Bulekov bool serialize = false; 1655f6fd09aSAlexander Bulekov 1665f6fd09aSAlexander Bulekov /* Initialize qgraph and modules */ 1675f6fd09aSAlexander Bulekov qos_graph_init(); 1685f6fd09aSAlexander Bulekov module_call_init(MODULE_INIT_FUZZ_TARGET); 1695f6fd09aSAlexander Bulekov module_call_init(MODULE_INIT_QOM); 1705f6fd09aSAlexander Bulekov module_call_init(MODULE_INIT_LIBQOS); 1715f6fd09aSAlexander Bulekov 172ec986777SPaolo Bonzini qemu_init_exec_dir(**argv); 17305509c8eSAlexander Bulekov target_name = strstr(**argv, "-target-"); 17405509c8eSAlexander Bulekov if (target_name) { /* The binary name specifies the target */ 17505509c8eSAlexander Bulekov target_name += strlen("-target-"); 1767a071a96SAlexander Bulekov /* 1777a071a96SAlexander Bulekov * With oss-fuzz, the executable is kept in the root of a directory (we 1787a071a96SAlexander Bulekov * cannot assume the path). All data (including bios binaries) must be 1797a071a96SAlexander Bulekov * in the same dir, or a subdir. Thus, we cannot place the pc-bios so 1807a071a96SAlexander Bulekov * that it would be in exec_dir/../pc-bios. 1817a071a96SAlexander Bulekov * As a workaround, oss-fuzz allows us to use argv[0] to get the 1827a071a96SAlexander Bulekov * location of the executable. Using this we add exec_dir/pc-bios to 1837a071a96SAlexander Bulekov * the datadirs. 1847a071a96SAlexander Bulekov */ 185ec986777SPaolo Bonzini bindir = qemu_get_exec_dir(); 186bcbad8b0SAlexander Bulekov datadir = g_build_filename(bindir, "pc-bios", NULL); 187bcbad8b0SAlexander Bulekov if (g_file_test(datadir, G_FILE_TEST_IS_DIR)) { 188bcbad8b0SAlexander Bulekov qemu_add_data_dir(datadir); 189ea1edcd7SPaolo Bonzini } else { 190bcbad8b0SAlexander Bulekov g_free(datadir); 191ea1edcd7SPaolo Bonzini } 19205509c8eSAlexander Bulekov } else if (*argc > 1) { /* The target is specified as an argument */ 1935f6fd09aSAlexander Bulekov target_name = (*argv)[1]; 1945f6fd09aSAlexander Bulekov if (!strstr(target_name, "--fuzz-target=")) { 1955f6fd09aSAlexander Bulekov usage(**argv); 1965f6fd09aSAlexander Bulekov } 1975f6fd09aSAlexander Bulekov target_name += strlen("--fuzz-target="); 19805509c8eSAlexander Bulekov } else { 19905509c8eSAlexander Bulekov usage(**argv); 20005509c8eSAlexander Bulekov } 2015f6fd09aSAlexander Bulekov 202d92e1b6dSAlexander Bulekov /* Should we always serialize qtest commands? */ 203d92e1b6dSAlexander Bulekov if (getenv("FUZZ_SERIALIZE_QTEST")) { 204d92e1b6dSAlexander Bulekov serialize = true; 205d92e1b6dSAlexander Bulekov } 206d92e1b6dSAlexander Bulekov 207d92e1b6dSAlexander Bulekov fuzz_qtest_set_serialize(serialize); 208d92e1b6dSAlexander Bulekov 20905509c8eSAlexander Bulekov /* Identify the fuzz target */ 2105f6fd09aSAlexander Bulekov fuzz_target = fuzz_get_target(target_name); 2115f6fd09aSAlexander Bulekov if (!fuzz_target) { 2125f6fd09aSAlexander Bulekov usage(**argv); 2135f6fd09aSAlexander Bulekov } 2145f6fd09aSAlexander Bulekov 2155f6fd09aSAlexander Bulekov fuzz_qts = qtest_setup(); 2165f6fd09aSAlexander Bulekov 2175f6fd09aSAlexander Bulekov if (fuzz_target->pre_vm_init) { 2185f6fd09aSAlexander Bulekov fuzz_target->pre_vm_init(); 2195f6fd09aSAlexander Bulekov } 2205f6fd09aSAlexander Bulekov 2215f6fd09aSAlexander Bulekov /* Run QEMU's softmmu main with the fuzz-target dependent arguments */ 222*61f90e04SAlexander Bulekov cmd_line = fuzz_target->get_init_cmdline(fuzz_target); 223d287961fSAlexander Bulekov g_string_append_printf(cmd_line, " %s -qtest /dev/null ", 224d287961fSAlexander Bulekov getenv("QTEST_LOG") ? "" : "-qtest-log none"); 2255f6fd09aSAlexander Bulekov 2265f6fd09aSAlexander Bulekov /* Split the runcmd into an argv and argc */ 2275f6fd09aSAlexander Bulekov wordexp_t result; 228f5ec79f5SAlexander Bulekov wordexp(cmd_line->str, &result, 0); 229f5ec79f5SAlexander Bulekov g_string_free(cmd_line, true); 2305f6fd09aSAlexander Bulekov 231*61f90e04SAlexander Bulekov if (getenv("QTEST_LOG")) { 232*61f90e04SAlexander Bulekov pretty_cmd_line = g_strjoinv(" ", result.we_wordv + 1); 233*61f90e04SAlexander Bulekov printf("Starting %s with Arguments: %s\n", 234*61f90e04SAlexander Bulekov result.we_wordv[0], pretty_cmd_line); 235*61f90e04SAlexander Bulekov g_free(pretty_cmd_line); 236*61f90e04SAlexander Bulekov } 237*61f90e04SAlexander Bulekov 2385f6fd09aSAlexander Bulekov qemu_init(result.we_wordc, result.we_wordv, NULL); 2395f6fd09aSAlexander Bulekov 24045222b9aSAlexander Bulekov /* re-enable the rcu atfork, which was previously disabled in qemu_init */ 24145222b9aSAlexander Bulekov rcu_enable_atfork(); 24245222b9aSAlexander Bulekov 243fc69fa21SAlexander Bulekov /* 244fc69fa21SAlexander Bulekov * Disable QEMU's signal handlers, since we manually control the main_loop, 245fc69fa21SAlexander Bulekov * and don't check for main_loop_should_exit 246fc69fa21SAlexander Bulekov */ 247fc69fa21SAlexander Bulekov signal(SIGINT, SIG_DFL); 248fc69fa21SAlexander Bulekov signal(SIGHUP, SIG_DFL); 249fc69fa21SAlexander Bulekov signal(SIGTERM, SIG_DFL); 250fc69fa21SAlexander Bulekov 2515f6fd09aSAlexander Bulekov return 0; 2525f6fd09aSAlexander Bulekov } 253