/src/binutils-gdb/fuzz/fuzz_disas_ext.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright 2021 Google LLC |
2 | | Licensed under the Apache License, Version 2.0 (the "License"); |
3 | | you may not use this file except in compliance with the License. |
4 | | You may obtain a copy of the License at |
5 | | http://www.apache.org/licenses/LICENSE-2.0 |
6 | | Unless required by applicable law or agreed to in writing, software |
7 | | distributed under the License is distributed on an "AS IS" BASIS, |
8 | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
9 | | See the License for the specific language governing permissions and |
10 | | limitations under the License. |
11 | | */ |
12 | | |
13 | | /* |
14 | | * This disassemble fuzzer can be used for targetting specific architectures |
15 | | * and also initilises the target architecture with a random options string. |
16 | | * This is useful, for example, to hit architectures the general disassembly |
17 | | * fuzzer may not be hitting, and also to fuzz disassemblers in different |
18 | | * settings. This fuzzer also targets both big and small endianness. Down |
19 | | * the line this fuzzer can be expanded on, e.g. to include symobls and data |
20 | | * in the memory that is to be disassembled. |
21 | | */ |
22 | | #include "sysdep.h" |
23 | | #include "bfd.h" |
24 | | #include "dis-asm.h" |
25 | | #include "disassemble.h" |
26 | | |
27 | | #include <stdint.h> |
28 | | |
29 | 1.43M | #define MAX_TEXT_SIZE 256 |
30 | | |
31 | | typedef struct |
32 | | { |
33 | | char *buffer; |
34 | | size_t pos; |
35 | | } SFILE; |
36 | | |
37 | | static int |
38 | | fuzz_disasm_null_styled_printf (void *stream, |
39 | | enum disassembler_style style, |
40 | | const char *format, ...) |
41 | 16.2M | { |
42 | 16.2M | return 0; |
43 | 16.2M | } |
44 | | |
45 | | |
46 | | static int objdump_sprintf (void *vf, const char *format, ...) |
47 | 718k | { |
48 | 718k | SFILE *f = (SFILE *) vf; |
49 | 718k | size_t n; |
50 | 718k | va_list args; |
51 | | |
52 | 718k | va_start (args, format); |
53 | 718k | if (f->pos >= MAX_TEXT_SIZE){ |
54 | 0 | printf("buffer needs more space\n"); |
55 | | //reset |
56 | 0 | f->pos=0; |
57 | 0 | return 0; |
58 | 0 | } |
59 | 718k | n = vsnprintf (f->buffer + f->pos, MAX_TEXT_SIZE - f->pos, format, args); |
60 | | //vfprintf(stdout, format, args); |
61 | 718k | va_end (args); |
62 | 718k | f->pos += n; |
63 | 718k | return n; |
64 | 718k | } |
65 | | |
66 | | char options[100]; // Enable the disassemblers to have random options. |
67 | | |
68 | | void |
69 | 35.5k | disassemble_architecture(int arch, const uint8_t *Data, size_t Size, int big) { |
70 | 35.5k | char AssemblyText[MAX_TEXT_SIZE]; |
71 | 35.5k | struct disassemble_info disasm_info; |
72 | 35.5k | SFILE s; |
73 | | |
74 | 35.5k | init_disassemble_info (&disasm_info, stdout, (fprintf_ftype) fprintf, fuzz_disasm_null_styled_printf); |
75 | 35.5k | disasm_info.fprintf_func = objdump_sprintf; |
76 | 35.5k | disasm_info.print_address_func = generic_print_address; |
77 | 35.5k | disasm_info.display_endian = disasm_info.endian = BFD_ENDIAN_LITTLE; |
78 | 35.5k | disasm_info.buffer = (bfd_byte *) Data; |
79 | 35.5k | disasm_info.buffer_vma = 0x1000; |
80 | 35.5k | disasm_info.buffer_length = Size-10; |
81 | 35.5k | disasm_info.insn_info_valid = 0; |
82 | 35.5k | disasm_info.disassembler_options = options; |
83 | 35.5k | disasm_info.created_styled_output = false; |
84 | | |
85 | 35.5k | s.buffer = AssemblyText; |
86 | 35.5k | s.pos = 0; |
87 | 35.5k | disasm_info.stream = &s; |
88 | 35.5k | disasm_info.bytes_per_line = 0; |
89 | | |
90 | 35.5k | disasm_info.flags |= USER_SPECIFIED_MACHINE_TYPE; |
91 | 35.5k | disasm_info.arch = arch; |
92 | 35.5k | disasm_info.mach = bfd_getl64(&Data[Size-9]); |
93 | 35.5k | disasm_info.flavour = Data[Size-10]; |
94 | | |
95 | 35.5k | if (bfd_lookup_arch (disasm_info.arch, disasm_info.mach) != NULL) { |
96 | 34.3k | disassembler_ftype disasfunc = disassembler(disasm_info.arch, big, disasm_info.mach, NULL); |
97 | 34.3k | if (disasfunc != NULL) { |
98 | 34.3k | disassemble_init_for_target(&disasm_info); |
99 | 2.07M | while (1) { |
100 | 2.07M | s.pos = 0; |
101 | 2.07M | int octets = disasfunc(disasm_info.buffer_vma, &disasm_info); |
102 | 2.07M | if (octets < (int) disasm_info.octets_per_byte) |
103 | 5.75k | break; |
104 | 2.07M | if (disasm_info.buffer_length <= (size_t) octets) |
105 | 28.6k | break; |
106 | 2.04M | disasm_info.buffer += octets; |
107 | 2.04M | disasm_info.buffer_vma += octets / disasm_info.octets_per_byte; |
108 | 2.04M | disasm_info.buffer_length -= octets; |
109 | 2.04M | } |
110 | 34.3k | disassemble_free_target(&disasm_info); |
111 | 34.3k | } |
112 | 34.3k | } |
113 | 35.5k | } |
114 | | |
115 | 17.9k | int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { |
116 | 17.9k | if (Size < 110 || Size > 16394) { |
117 | | // 110 bytes for options |
118 | | // 16394 limit code to prevent timeouts |
119 | 160 | return 0; |
120 | 160 | } |
121 | 17.7k | char arch = *Data; |
122 | | |
123 | | // Create a random options string |
124 | 17.7k | memcpy(options, Data, 100); |
125 | 17.7k | options[99] = '\0'; |
126 | 17.7k | Data += 100; |
127 | 17.7k | Size -= 100; |
128 | | |
129 | | // FUZZ_TARGET_ARCH must be defined and should be the architecture |
130 | | // you target. |
131 | 17.7k | disassemble_architecture(FUZZ_TARGET_ARCH, Data, Size, 1); |
132 | 17.7k | disassemble_architecture(FUZZ_TARGET_ARCH, Data, Size, 0); |
133 | | |
134 | 17.7k | return 0; |
135 | 17.9k | } |