fuzz.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*
  2. * fuzzing driver
  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. #include <wordexp.h>
  15. #include "qemu/datadir.h"
  16. #include "sysemu/sysemu.h"
  17. #include "sysemu/qtest.h"
  18. #include "sysemu/runstate.h"
  19. #include "qemu/main-loop.h"
  20. #include "qemu/rcu.h"
  21. #include "tests/qtest/libqtest.h"
  22. #include "tests/qtest/libqos/qgraph.h"
  23. #include "fuzz.h"
  24. #define MAX_EVENT_LOOPS 10
  25. typedef struct FuzzTargetState {
  26. FuzzTarget *target;
  27. QSLIST_ENTRY(FuzzTargetState) target_list;
  28. } FuzzTargetState;
  29. typedef QSLIST_HEAD(, FuzzTargetState) FuzzTargetList;
  30. static const char *fuzz_arch = TARGET_NAME;
  31. static FuzzTargetList *fuzz_target_list;
  32. static FuzzTarget *fuzz_target;
  33. static QTestState *fuzz_qts;
  34. void flush_events(QTestState *s)
  35. {
  36. int i = MAX_EVENT_LOOPS;
  37. while (g_main_context_pending(NULL) && i-- > 0) {
  38. main_loop_wait(false);
  39. }
  40. }
  41. static QTestState *qtest_setup(void)
  42. {
  43. qtest_server_set_send_handler(&qtest_client_inproc_recv, &fuzz_qts);
  44. return qtest_inproc_init(&fuzz_qts, false, fuzz_arch,
  45. &qtest_server_inproc_recv);
  46. }
  47. void fuzz_add_target(const FuzzTarget *target)
  48. {
  49. FuzzTargetState *tmp;
  50. FuzzTargetState *target_state;
  51. if (!fuzz_target_list) {
  52. fuzz_target_list = g_new0(FuzzTargetList, 1);
  53. }
  54. QSLIST_FOREACH(tmp, fuzz_target_list, target_list) {
  55. if (g_strcmp0(tmp->target->name, target->name) == 0) {
  56. fprintf(stderr, "Error: Fuzz target name %s already in use\n",
  57. target->name);
  58. abort();
  59. }
  60. }
  61. target_state = g_new0(FuzzTargetState, 1);
  62. target_state->target = g_new0(FuzzTarget, 1);
  63. *(target_state->target) = *target;
  64. QSLIST_INSERT_HEAD(fuzz_target_list, target_state, target_list);
  65. }
  66. static void usage(char *path)
  67. {
  68. printf("Usage: %s --fuzz-target=FUZZ_TARGET [LIBFUZZER ARGUMENTS]\n", path);
  69. printf("where FUZZ_TARGET is one of:\n");
  70. FuzzTargetState *tmp;
  71. if (!fuzz_target_list) {
  72. fprintf(stderr, "Fuzz target list not initialized\n");
  73. abort();
  74. }
  75. QSLIST_FOREACH(tmp, fuzz_target_list, target_list) {
  76. printf(" * %s : %s\n", tmp->target->name,
  77. tmp->target->description);
  78. }
  79. printf("Alternatively, add -target-FUZZ_TARGET to the executable name\n\n"
  80. "Set the environment variable FUZZ_SERIALIZE_QTEST=1 to serialize\n"
  81. "QTest commands into an ASCII protocol. Useful for building crash\n"
  82. "reproducers, but slows down execution.\n\n"
  83. "Set the environment variable QTEST_LOG=1 to log all qtest commands"
  84. "\n");
  85. exit(0);
  86. }
  87. static FuzzTarget *fuzz_get_target(char* name)
  88. {
  89. FuzzTargetState *tmp;
  90. if (!fuzz_target_list) {
  91. fprintf(stderr, "Fuzz target list not initialized\n");
  92. abort();
  93. }
  94. QSLIST_FOREACH(tmp, fuzz_target_list, target_list) {
  95. if (strcmp(tmp->target->name, name) == 0) {
  96. return tmp->target;
  97. }
  98. }
  99. return NULL;
  100. }
  101. /* Sometimes called by libfuzzer to mutate two inputs into one */
  102. size_t LLVMFuzzerCustomCrossOver(const uint8_t *data1, size_t size1,
  103. const uint8_t *data2, size_t size2,
  104. uint8_t *out, size_t max_out_size,
  105. unsigned int seed)
  106. {
  107. if (fuzz_target->crossover) {
  108. return fuzz_target->crossover(data1, size1, data2, size2, out,
  109. max_out_size, seed);
  110. }
  111. return 0;
  112. }
  113. /* Executed for each fuzzing-input */
  114. int LLVMFuzzerTestOneInput(const unsigned char *Data, size_t Size)
  115. {
  116. /*
  117. * Do the pre-fuzz-initialization before the first fuzzing iteration,
  118. * instead of before the actual fuzz loop. This is needed since libfuzzer
  119. * may fork off additional workers, prior to the fuzzing loop, and if
  120. * pre_fuzz() sets up e.g. shared memory, this should be done for the
  121. * individual worker processes
  122. */
  123. static int pre_fuzz_done;
  124. if (!pre_fuzz_done && fuzz_target->pre_fuzz) {
  125. fuzz_target->pre_fuzz(fuzz_qts);
  126. pre_fuzz_done = true;
  127. }
  128. fuzz_target->fuzz(fuzz_qts, Data, Size);
  129. return 0;
  130. }
  131. /* Executed once, prior to fuzzing */
  132. int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp)
  133. {
  134. char *target_name;
  135. const char *bindir;
  136. char *datadir;
  137. GString *cmd_line;
  138. gchar *pretty_cmd_line;
  139. bool serialize = false;
  140. /* Initialize qgraph and modules */
  141. qos_graph_init();
  142. module_call_init(MODULE_INIT_FUZZ_TARGET);
  143. module_call_init(MODULE_INIT_QOM);
  144. module_call_init(MODULE_INIT_LIBQOS);
  145. qemu_init_exec_dir(**argv);
  146. target_name = strstr(**argv, "-target-");
  147. if (target_name) { /* The binary name specifies the target */
  148. target_name += strlen("-target-");
  149. /*
  150. * With oss-fuzz, the executable is kept in the root of a directory (we
  151. * cannot assume the path). All data (including bios binaries) must be
  152. * in the same dir, or a subdir. Thus, we cannot place the pc-bios so
  153. * that it would be in exec_dir/../pc-bios.
  154. * As a workaround, oss-fuzz allows us to use argv[0] to get the
  155. * location of the executable. Using this we add exec_dir/pc-bios to
  156. * the datadirs.
  157. */
  158. bindir = qemu_get_exec_dir();
  159. datadir = g_build_filename(bindir, "pc-bios", NULL);
  160. if (g_file_test(datadir, G_FILE_TEST_IS_DIR)) {
  161. qemu_add_data_dir(datadir);
  162. } else {
  163. g_free(datadir);
  164. }
  165. } else if (*argc > 1) { /* The target is specified as an argument */
  166. target_name = (*argv)[1];
  167. if (!strstr(target_name, "--fuzz-target=")) {
  168. usage(**argv);
  169. }
  170. target_name += strlen("--fuzz-target=");
  171. } else {
  172. usage(**argv);
  173. }
  174. /* Should we always serialize qtest commands? */
  175. if (getenv("FUZZ_SERIALIZE_QTEST")) {
  176. serialize = true;
  177. }
  178. fuzz_qtest_set_serialize(serialize);
  179. /* Identify the fuzz target */
  180. fuzz_target = fuzz_get_target(target_name);
  181. if (!fuzz_target) {
  182. usage(**argv);
  183. }
  184. fuzz_qts = qtest_setup();
  185. if (fuzz_target->pre_vm_init) {
  186. fuzz_target->pre_vm_init();
  187. }
  188. /* Run QEMU's softmmu main with the fuzz-target dependent arguments */
  189. cmd_line = fuzz_target->get_init_cmdline(fuzz_target);
  190. g_string_append_printf(cmd_line, " %s -qtest /dev/null ",
  191. getenv("QTEST_LOG") ? "" : "-qtest-log none");
  192. /* Split the runcmd into an argv and argc */
  193. wordexp_t result;
  194. wordexp(cmd_line->str, &result, 0);
  195. g_string_free(cmd_line, true);
  196. if (getenv("QTEST_LOG")) {
  197. pretty_cmd_line = g_strjoinv(" ", result.we_wordv + 1);
  198. printf("Starting %s with Arguments: %s\n",
  199. result.we_wordv[0], pretty_cmd_line);
  200. g_free(pretty_cmd_line);
  201. }
  202. qemu_init(result.we_wordc, result.we_wordv, NULL);
  203. /* re-enable the rcu atfork, which was previously disabled in qemu_init */
  204. rcu_enable_atfork();
  205. /*
  206. * Disable QEMU's signal handlers, since we manually control the main_loop,
  207. * and don't check for main_loop_should_exit
  208. */
  209. signal(SIGINT, SIG_DFL);
  210. signal(SIGHUP, SIG_DFL);
  211. signal(SIGTERM, SIG_DFL);
  212. return 0;
  213. }