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