1
2
3
4
5
6
7
8
9
10
11
12
13#include "qemu/osdep.h"
14
15#include <wordexp.h>
16
17#include "hw/core/cpu.h"
18#include "tests/qtest/libqtest.h"
19#include "tests/qtest/libqos/pci-pc.h"
20#include "fuzz.h"
21#include "string.h"
22#include "exec/memory.h"
23#include "exec/ramblock.h"
24#include "hw/qdev-core.h"
25#include "hw/pci/pci.h"
26#include "hw/pci/pci_device.h"
27#include "hw/boards.h"
28#include "generic_fuzz_configs.h"
29#include "hw/mem/sparse-mem.h"
30
31static void pci_enum(gpointer pcidev, gpointer bus);
32
33
34
35
36#define SEPARATOR "FUZZ"
37
38enum cmds {
39 OP_IN,
40 OP_OUT,
41 OP_READ,
42 OP_WRITE,
43 OP_PCI_READ,
44 OP_PCI_WRITE,
45 OP_DISABLE_PCI,
46 OP_ADD_DMA_PATTERN,
47 OP_CLEAR_DMA_PATTERNS,
48 OP_CLOCK_STEP,
49};
50
51#define USEC_IN_SEC 1000000000
52
53#define MAX_DMA_FILL_SIZE 0x10000
54#define MAX_TOTAL_DMA_SIZE 0x10000000
55
56#define PCI_HOST_BRIDGE_CFG 0xcf8
57#define PCI_HOST_BRIDGE_DATA 0xcfc
58
59typedef struct {
60 ram_addr_t addr;
61 ram_addr_t size;
62} address_range;
63
64static bool qtest_log_enabled;
65size_t dma_bytes_written;
66
67MemoryRegion *sparse_mem_mr;
68
69
70
71
72
73
74
75typedef struct {
76 uint8_t index;
77 uint8_t stride;
78 size_t len;
79 const uint8_t *data;
80} pattern;
81
82
83static bool avoid_double_fetches;
84
85static QTestState *qts_global;
86
87
88
89
90
91static GHashTable *fuzzable_memoryregions;
92static GPtrArray *fuzzable_pci_devices;
93
94struct get_io_cb_info {
95 int index;
96 int found;
97 address_range result;
98};
99
100static bool get_io_address_cb(Int128 start, Int128 size,
101 const MemoryRegion *mr,
102 hwaddr offset_in_region,
103 void *opaque)
104{
105 struct get_io_cb_info *info = opaque;
106 if (g_hash_table_lookup(fuzzable_memoryregions, mr)) {
107 if (info->index == 0) {
108 info->result.addr = (ram_addr_t)start;
109 info->result.size = (ram_addr_t)size;
110 info->found = 1;
111 return true;
112 }
113 info->index--;
114 }
115 return false;
116}
117
118
119
120
121
122
123static GArray *dma_regions;
124
125static GArray *dma_patterns;
126static int dma_pattern_index;
127static bool pci_disabled;
128
129
130
131
132static void *pattern_alloc(pattern p, size_t len)
133{
134 int i;
135 uint8_t *buf = g_malloc(len);
136 uint8_t sum = 0;
137
138 for (i = 0; i < len; ++i) {
139 buf[i] = p.data[i % p.len];
140 if ((i % p.len) == p.index) {
141 buf[i] += sum;
142 sum += p.stride;
143 }
144 }
145 return buf;
146}
147
148static int fuzz_memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
149{
150 unsigned access_size_max = mr->ops->valid.max_access_size;
151
152
153
154
155
156 if (access_size_max == 0) {
157 access_size_max = 4;
158 }
159
160
161 if (!mr->ops->impl.unaligned) {
162 unsigned align_size_max = addr & -addr;
163 if (align_size_max != 0 && align_size_max < access_size_max) {
164 access_size_max = align_size_max;
165 }
166 }
167
168
169 if (l > access_size_max) {
170 l = access_size_max;
171 }
172 l = pow2floor(l);
173
174 return l;
175}
176
177
178
179
180
181
182
183void fuzz_dma_read_cb(size_t addr, size_t len, MemoryRegion *mr)
184{
185
186 if (!qts_global) {
187 return;
188 }
189
190
191
192
193
194
195
196
197 if (dma_patterns->len == 0
198 || len == 0
199 || dma_bytes_written + len > MAX_TOTAL_DMA_SIZE
200 || (mr != current_machine->ram && mr != sparse_mem_mr)) {
201 return;
202 }
203
204
205
206
207
208 address_range region;
209 bool double_fetch = false;
210 for (int i = 0;
211 i < dma_regions->len && (avoid_double_fetches || qtest_log_enabled);
212 ++i) {
213 region = g_array_index(dma_regions, address_range, i);
214 if (addr < region.addr + region.size && addr + len > region.addr) {
215 double_fetch = true;
216 if (addr < region.addr
217 && avoid_double_fetches) {
218 fuzz_dma_read_cb(addr, region.addr - addr, mr);
219 }
220 if (addr + len > region.addr + region.size
221 && avoid_double_fetches) {
222 fuzz_dma_read_cb(region.addr + region.size,
223 addr + len - (region.addr + region.size), mr);
224 }
225 return;
226 }
227 }
228
229
230 len = MIN(len, MAX_DMA_FILL_SIZE);
231
232 address_range ar = {addr, len};
233 g_array_append_val(dma_regions, ar);
234 pattern p = g_array_index(dma_patterns, pattern, dma_pattern_index);
235 void *buf_base = pattern_alloc(p, ar.size);
236 void *buf = buf_base;
237 hwaddr l, addr1;
238 MemoryRegion *mr1;
239 while (len > 0) {
240 l = len;
241 mr1 = address_space_translate(first_cpu->as,
242 addr, &addr1, &l, true,
243 MEMTXATTRS_UNSPECIFIED);
244
245
246
247
248
249
250
251 if (!memory_region_is_ram(mr1)) {
252 l = fuzz_memory_access_size(mr1, l, addr1);
253 }
254 if (memory_region_is_ram(mr1) ||
255 memory_region_is_romd(mr1) ||
256 mr1 == sparse_mem_mr) {
257
258 if (qtest_log_enabled) {
259
260
261
262
263
264
265 fprintf(stderr, "[DMA] ");
266 if (double_fetch) {
267 fprintf(stderr, "[DOUBLE-FETCH] ");
268 }
269 fflush(stderr);
270 }
271 qtest_memwrite(qts_global, addr, buf, l);
272 dma_bytes_written += l;
273 }
274 len -= l;
275 buf += l;
276 addr += l;
277
278 }
279 g_free(buf_base);
280
281
282 dma_pattern_index = (dma_pattern_index + 1) % dma_patterns->len;
283}
284
285
286
287
288
289
290
291
292
293static bool get_io_address(address_range *result, AddressSpace *as,
294 uint8_t index,
295 uint32_t offset) {
296 FlatView *view;
297 view = as->current_map;
298 g_assert(view);
299 struct get_io_cb_info cb_info = {};
300
301 cb_info.index = index;
302
303
304
305
306
307
308 do {
309 flatview_for_each_range(view, get_io_address_cb , &cb_info);
310 } while (cb_info.index != index && !cb_info.found);
311
312 *result = cb_info.result;
313 if (result->size) {
314 offset = offset % result->size;
315 result->addr += offset;
316 result->size -= offset;
317 }
318 return cb_info.found;
319}
320
321static bool get_pio_address(address_range *result,
322 uint8_t index, uint16_t offset)
323{
324
325
326
327
328
329
330
331 bool found = get_io_address(result, &address_space_io, index, offset);
332 return result->addr <= 0xFFFF ? found : false;
333}
334
335static bool get_mmio_address(address_range *result,
336 uint8_t index, uint32_t offset)
337{
338 return get_io_address(result, &address_space_memory, index, offset);
339}
340
341static void op_in(QTestState *s, const unsigned char * data, size_t len)
342{
343 enum Sizes {Byte, Word, Long, end_sizes};
344 struct {
345 uint8_t size;
346 uint8_t base;
347 uint16_t offset;
348 } a;
349 address_range abs;
350
351 if (len < sizeof(a)) {
352 return;
353 }
354 memcpy(&a, data, sizeof(a));
355 if (get_pio_address(&abs, a.base, a.offset) == 0) {
356 return;
357 }
358
359 switch (a.size %= end_sizes) {
360 case Byte:
361 qtest_inb(s, abs.addr);
362 break;
363 case Word:
364 if (abs.size >= 2) {
365 qtest_inw(s, abs.addr);
366 }
367 break;
368 case Long:
369 if (abs.size >= 4) {
370 qtest_inl(s, abs.addr);
371 }
372 break;
373 }
374}
375
376static void op_out(QTestState *s, const unsigned char * data, size_t len)
377{
378 enum Sizes {Byte, Word, Long, end_sizes};
379 struct {
380 uint8_t size;
381 uint8_t base;
382 uint16_t offset;
383 uint32_t value;
384 } a;
385 address_range abs;
386
387 if (len < sizeof(a)) {
388 return;
389 }
390 memcpy(&a, data, sizeof(a));
391
392 if (get_pio_address(&abs, a.base, a.offset) == 0) {
393 return;
394 }
395
396 switch (a.size %= end_sizes) {
397 case Byte:
398 qtest_outb(s, abs.addr, a.value & 0xFF);
399 break;
400 case Word:
401 if (abs.size >= 2) {
402 qtest_outw(s, abs.addr, a.value & 0xFFFF);
403 }
404 break;
405 case Long:
406 if (abs.size >= 4) {
407 qtest_outl(s, abs.addr, a.value);
408 }
409 break;
410 }
411}
412
413static void op_read(QTestState *s, const unsigned char * data, size_t len)
414{
415 enum Sizes {Byte, Word, Long, Quad, end_sizes};
416 struct {
417 uint8_t size;
418 uint8_t base;
419 uint32_t offset;
420 } a;
421 address_range abs;
422
423 if (len < sizeof(a)) {
424 return;
425 }
426 memcpy(&a, data, sizeof(a));
427
428 if (get_mmio_address(&abs, a.base, a.offset) == 0) {
429 return;
430 }
431
432 switch (a.size %= end_sizes) {
433 case Byte:
434 qtest_readb(s, abs.addr);
435 break;
436 case Word:
437 if (abs.size >= 2) {
438 qtest_readw(s, abs.addr);
439 }
440 break;
441 case Long:
442 if (abs.size >= 4) {
443 qtest_readl(s, abs.addr);
444 }
445 break;
446 case Quad:
447 if (abs.size >= 8) {
448 qtest_readq(s, abs.addr);
449 }
450 break;
451 }
452}
453
454static void op_write(QTestState *s, const unsigned char * data, size_t len)
455{
456 enum Sizes {Byte, Word, Long, Quad, end_sizes};
457 struct {
458 uint8_t size;
459 uint8_t base;
460 uint32_t offset;
461 uint64_t value;
462 } a;
463 address_range abs;
464
465 if (len < sizeof(a)) {
466 return;
467 }
468 memcpy(&a, data, sizeof(a));
469
470 if (get_mmio_address(&abs, a.base, a.offset) == 0) {
471 return;
472 }
473
474 switch (a.size %= end_sizes) {
475 case Byte:
476 qtest_writeb(s, abs.addr, a.value & 0xFF);
477 break;
478 case Word:
479 if (abs.size >= 2) {
480 qtest_writew(s, abs.addr, a.value & 0xFFFF);
481 }
482 break;
483 case Long:
484 if (abs.size >= 4) {
485 qtest_writel(s, abs.addr, a.value & 0xFFFFFFFF);
486 }
487 break;
488 case Quad:
489 if (abs.size >= 8) {
490 qtest_writeq(s, abs.addr, a.value);
491 }
492 break;
493 }
494}
495
496static void op_pci_read(QTestState *s, const unsigned char * data, size_t len)
497{
498 enum Sizes {Byte, Word, Long, end_sizes};
499 struct {
500 uint8_t size;
501 uint8_t base;
502 uint8_t offset;
503 } a;
504 if (len < sizeof(a) || fuzzable_pci_devices->len == 0 || pci_disabled) {
505 return;
506 }
507 memcpy(&a, data, sizeof(a));
508 PCIDevice *dev = g_ptr_array_index(fuzzable_pci_devices,
509 a.base % fuzzable_pci_devices->len);
510 int devfn = dev->devfn;
511 qtest_outl(s, PCI_HOST_BRIDGE_CFG, (1U << 31) | (devfn << 8) | a.offset);
512 switch (a.size %= end_sizes) {
513 case Byte:
514 qtest_inb(s, PCI_HOST_BRIDGE_DATA);
515 break;
516 case Word:
517 qtest_inw(s, PCI_HOST_BRIDGE_DATA);
518 break;
519 case Long:
520 qtest_inl(s, PCI_HOST_BRIDGE_DATA);
521 break;
522 }
523}
524
525static void op_pci_write(QTestState *s, const unsigned char * data, size_t len)
526{
527 enum Sizes {Byte, Word, Long, end_sizes};
528 struct {
529 uint8_t size;
530 uint8_t base;
531 uint8_t offset;
532 uint32_t value;
533 } a;
534 if (len < sizeof(a) || fuzzable_pci_devices->len == 0 || pci_disabled) {
535 return;
536 }
537 memcpy(&a, data, sizeof(a));
538 PCIDevice *dev = g_ptr_array_index(fuzzable_pci_devices,
539 a.base % fuzzable_pci_devices->len);
540 int devfn = dev->devfn;
541 qtest_outl(s, PCI_HOST_BRIDGE_CFG, (1U << 31) | (devfn << 8) | a.offset);
542 switch (a.size %= end_sizes) {
543 case Byte:
544 qtest_outb(s, PCI_HOST_BRIDGE_DATA, a.value & 0xFF);
545 break;
546 case Word:
547 qtest_outw(s, PCI_HOST_BRIDGE_DATA, a.value & 0xFFFF);
548 break;
549 case Long:
550 qtest_outl(s, PCI_HOST_BRIDGE_DATA, a.value & 0xFFFFFFFF);
551 break;
552 }
553}
554
555static void op_add_dma_pattern(QTestState *s,
556 const unsigned char *data, size_t len)
557{
558 struct {
559
560
561
562
563 uint8_t index;
564 uint8_t stride;
565 } a;
566
567 if (len < sizeof(a) + 1) {
568 return;
569 }
570 memcpy(&a, data, sizeof(a));
571 pattern p = {a.index, a.stride, len - sizeof(a), data + sizeof(a)};
572 p.index = a.index % p.len;
573 g_array_append_val(dma_patterns, p);
574 return;
575}
576
577static void op_clear_dma_patterns(QTestState *s,
578 const unsigned char *data, size_t len)
579{
580 g_array_set_size(dma_patterns, 0);
581 dma_pattern_index = 0;
582}
583
584static void op_clock_step(QTestState *s, const unsigned char *data, size_t len)
585{
586 qtest_clock_step_next(s);
587}
588
589static void op_disable_pci(QTestState *s, const unsigned char *data, size_t len)
590{
591 pci_disabled = true;
592}
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631static void generic_fuzz(QTestState *s, const unsigned char *Data, size_t Size)
632{
633 void (*ops[]) (QTestState *s, const unsigned char* , size_t) = {
634 [OP_IN] = op_in,
635 [OP_OUT] = op_out,
636 [OP_READ] = op_read,
637 [OP_WRITE] = op_write,
638 [OP_PCI_READ] = op_pci_read,
639 [OP_PCI_WRITE] = op_pci_write,
640 [OP_DISABLE_PCI] = op_disable_pci,
641 [OP_ADD_DMA_PATTERN] = op_add_dma_pattern,
642 [OP_CLEAR_DMA_PATTERNS] = op_clear_dma_patterns,
643 [OP_CLOCK_STEP] = op_clock_step,
644 };
645 const unsigned char *cmd = Data;
646 const unsigned char *nextcmd;
647 size_t cmd_len;
648 uint8_t op;
649
650 op_clear_dma_patterns(s, NULL, 0);
651 pci_disabled = false;
652 dma_bytes_written = 0;
653
654 QPCIBus *pcibus = qpci_new_pc(s, NULL);
655 g_ptr_array_foreach(fuzzable_pci_devices, pci_enum, pcibus);
656 qpci_free_pc(pcibus);
657
658 while (cmd && Size) {
659
660 nextcmd = memmem(cmd, Size, SEPARATOR, strlen(SEPARATOR));
661 cmd_len = nextcmd ? nextcmd - cmd : Size;
662
663 if (cmd_len > 0) {
664
665 op = *cmd % (sizeof(ops) / sizeof((ops)[0]));
666 ops[op](s, cmd + 1, cmd_len - 1);
667
668
669 flush_events(s);
670 }
671
672 cmd = nextcmd ? nextcmd + sizeof(SEPARATOR) - 1 : nextcmd;
673 Size = Size - (cmd_len + sizeof(SEPARATOR) - 1);
674 g_array_set_size(dma_regions, 0);
675 }
676 fuzz_reset(s);
677}
678
679static void usage(void)
680{
681 printf("Please specify the following environment variables:\n");
682 printf("QEMU_FUZZ_ARGS= the command line arguments passed to qemu\n");
683 printf("QEMU_FUZZ_OBJECTS= "
684 "a space separated list of QOM type names for objects to fuzz\n");
685 printf("Optionally: QEMU_AVOID_DOUBLE_FETCH= "
686 "Try to avoid racy DMA double fetch bugs? %d by default\n",
687 avoid_double_fetches);
688 exit(0);
689}
690
691static int locate_fuzz_memory_regions(Object *child, void *opaque)
692{
693 MemoryRegion *mr;
694 if (object_dynamic_cast(child, TYPE_MEMORY_REGION)) {
695 mr = MEMORY_REGION(child);
696 if ((memory_region_is_ram(mr) ||
697 memory_region_is_ram_device(mr) ||
698 memory_region_is_rom(mr)) == false) {
699
700
701
702
703 g_hash_table_insert(fuzzable_memoryregions, mr, (gpointer)true);
704 }
705 }
706 return 0;
707}
708
709static int locate_fuzz_objects(Object *child, void *opaque)
710{
711 GString *type_name;
712 GString *path_name;
713 char *pattern = opaque;
714
715 type_name = g_string_new(object_get_typename(child));
716 g_string_ascii_down(type_name);
717 if (g_pattern_match_simple(pattern, type_name->str)) {
718
719 object_child_foreach_recursive(child, locate_fuzz_memory_regions, NULL);
720
721
722
723
724
725 if (object_dynamic_cast(OBJECT(child), TYPE_PCI_DEVICE)) {
726
727
728
729
730 g_ptr_array_remove_fast(fuzzable_pci_devices, PCI_DEVICE(child));
731 g_ptr_array_add(fuzzable_pci_devices, PCI_DEVICE(child));
732 }
733 } else if (object_dynamic_cast(OBJECT(child), TYPE_MEMORY_REGION)) {
734 path_name = g_string_new(object_get_canonical_path_component(child));
735 g_string_ascii_down(path_name);
736 if (g_pattern_match_simple(pattern, path_name->str)) {
737 MemoryRegion *mr;
738 mr = MEMORY_REGION(child);
739 if ((memory_region_is_ram(mr) ||
740 memory_region_is_ram_device(mr) ||
741 memory_region_is_rom(mr)) == false) {
742 g_hash_table_insert(fuzzable_memoryregions, mr, (gpointer)true);
743 }
744 }
745 g_string_free(path_name, true);
746 }
747 g_string_free(type_name, true);
748 return 0;
749}
750
751
752static void pci_enum(gpointer pcidev, gpointer bus)
753{
754 PCIDevice *dev = pcidev;
755 QPCIDevice *qdev;
756 int i;
757
758 qdev = qpci_device_find(bus, dev->devfn);
759 g_assert(qdev != NULL);
760 for (i = 0; i < 6; i++) {
761 if (dev->io_regions[i].size) {
762 qpci_iomap(qdev, i, NULL);
763 }
764 }
765 qpci_device_enable(qdev);
766 g_free(qdev);
767}
768
769static void generic_pre_fuzz(QTestState *s)
770{
771 GHashTableIter iter;
772 MemoryRegion *mr;
773 char **result;
774 GString *name_pattern;
775
776 if (!getenv("QEMU_FUZZ_OBJECTS")) {
777 usage();
778 }
779 if (getenv("QTEST_LOG")) {
780 qtest_log_enabled = 1;
781 }
782 if (getenv("QEMU_AVOID_DOUBLE_FETCH")) {
783 avoid_double_fetches = 1;
784 }
785 qts_global = s;
786
787
788
789
790
791 sparse_mem_mr = sparse_mem_init(0, UINT64_MAX);
792
793 dma_regions = g_array_new(false, false, sizeof(address_range));
794 dma_patterns = g_array_new(false, false, sizeof(pattern));
795
796 fuzzable_memoryregions = g_hash_table_new(NULL, NULL);
797 fuzzable_pci_devices = g_ptr_array_new();
798
799 result = g_strsplit(getenv("QEMU_FUZZ_OBJECTS"), " ", -1);
800 for (int i = 0; result[i] != NULL; i++) {
801 name_pattern = g_string_new(result[i]);
802
803
804
805
806 g_string_ascii_down(name_pattern);
807 printf("Matching objects by name %s\n", result[i]);
808 object_child_foreach_recursive(qdev_get_machine(),
809 locate_fuzz_objects,
810 name_pattern->str);
811 g_string_free(name_pattern, true);
812 }
813 g_strfreev(result);
814 printf("This process will try to fuzz the following MemoryRegions:\n");
815
816 g_hash_table_iter_init(&iter, fuzzable_memoryregions);
817 while (g_hash_table_iter_next(&iter, (gpointer)&mr, NULL)) {
818 printf(" * %s (size 0x%" PRIx64 ")\n",
819 object_get_canonical_path_component(&(mr->parent_obj)),
820 memory_region_size(mr));
821 }
822
823 if (!g_hash_table_size(fuzzable_memoryregions)) {
824 printf("No fuzzable memory regions found...\n");
825 exit(1);
826 }
827}
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853static size_t generic_fuzz_crossover(const uint8_t *data1, size_t size1, const
854 uint8_t *data2, size_t size2, uint8_t *out,
855 size_t max_out_size, unsigned int seed)
856{
857 size_t copy_len = 0, size = 0;
858
859
860 if (max_out_size <= size1 + strlen(SEPARATOR) * 3 + 2) {
861 return 0;
862 }
863
864
865 copy_len = size1;
866 memcpy(out + size, data1, copy_len);
867 size += copy_len;
868 max_out_size -= copy_len;
869
870
871 copy_len = strlen(SEPARATOR);
872 memcpy(out + size, SEPARATOR, copy_len);
873 size += copy_len;
874 max_out_size -= copy_len;
875
876
877 copy_len = 1;
878 if (copy_len) {
879 out[size] = OP_CLEAR_DMA_PATTERNS;
880 }
881 size += copy_len;
882 max_out_size -= copy_len;
883
884
885 copy_len = strlen(SEPARATOR);
886 memcpy(out + size, SEPARATOR, copy_len);
887 size += copy_len;
888 max_out_size -= copy_len;
889
890
891 copy_len = 1;
892 if (copy_len) {
893 out[size] = OP_DISABLE_PCI;
894 }
895 size += copy_len;
896 max_out_size -= copy_len;
897
898
899 copy_len = strlen(SEPARATOR);
900 memcpy(out + size, SEPARATOR, copy_len);
901 size += copy_len;
902 max_out_size -= copy_len;
903
904
905 copy_len = MIN(size2, max_out_size);
906 memcpy(out + size, data2, copy_len);
907 size += copy_len;
908 max_out_size -= copy_len;
909
910 return size;
911}
912
913
914static GString *generic_fuzz_cmdline(FuzzTarget *t)
915{
916 GString *cmd_line = g_string_new(TARGET_NAME);
917 if (!getenv("QEMU_FUZZ_ARGS")) {
918 usage();
919 }
920 g_string_append_printf(cmd_line, " -display none \
921 -machine accel=qtest, \
922 -m 512M %s ", getenv("QEMU_FUZZ_ARGS"));
923 return cmd_line;
924}
925
926static GString *generic_fuzz_predefined_config_cmdline(FuzzTarget *t)
927{
928 gchar *args;
929 const generic_fuzz_config *config;
930 g_assert(t->opaque);
931
932 config = t->opaque;
933 g_setenv("QEMU_AVOID_DOUBLE_FETCH", "1", 1);
934 if (config->argfunc) {
935 args = config->argfunc();
936 g_setenv("QEMU_FUZZ_ARGS", args, 1);
937 g_free(args);
938 } else {
939 g_assert_nonnull(config->args);
940 g_setenv("QEMU_FUZZ_ARGS", config->args, 1);
941 }
942 g_setenv("QEMU_FUZZ_OBJECTS", config->objects, 1);
943 return generic_fuzz_cmdline(t);
944}
945
946static void register_generic_fuzz_targets(void)
947{
948 fuzz_add_target(&(FuzzTarget){
949 .name = "generic-fuzz",
950 .description = "Fuzz based on any qemu command-line args. ",
951 .get_init_cmdline = generic_fuzz_cmdline,
952 .pre_fuzz = generic_pre_fuzz,
953 .fuzz = generic_fuzz,
954 .crossover = generic_fuzz_crossover
955 });
956
957 for (int i = 0; i < ARRAY_SIZE(predefined_configs); i++) {
958 const generic_fuzz_config *config = predefined_configs + i;
959 fuzz_add_target(&(FuzzTarget){
960 .name = g_strconcat("generic-fuzz-", config->name, NULL),
961 .description = "Predefined generic-fuzz config.",
962 .get_init_cmdline = generic_fuzz_predefined_config_cmdline,
963 .pre_fuzz = generic_pre_fuzz,
964 .fuzz = generic_fuzz,
965 .crossover = generic_fuzz_crossover,
966 .opaque = (void *)config
967 });
968 }
969}
970
971fuzz_target_init(register_generic_fuzz_targets);
972