/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.28M | #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 | 26.5M | { |
42 | 26.5M | return 0; |
43 | 26.5M | } |
44 | | |
45 | | |
46 | | static int objdump_sprintf (void *vf, const char *format, ...) |
47 | 644k | { |
48 | 644k | SFILE *f = (SFILE *) vf; |
49 | 644k | size_t n; |
50 | 644k | va_list args; |
51 | | |
52 | 644k | va_start (args, format); |
53 | 644k | 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 | 644k | n = vsnprintf (f->buffer + f->pos, MAX_TEXT_SIZE - f->pos, format, args); |
60 | | //vfprintf(stdout, format, args); |
61 | 644k | va_end (args); |
62 | 644k | f->pos += n; |
63 | 644k | return n; |
64 | 644k | } |
65 | | |
66 | | char options[100]; // Enable the disassemblers to have random options. |
67 | | char private_data[100]; // This is used for some targets. Watch out when |
68 | | // using it as some disassemblers have pointers |
69 | | // within their private_data. |
70 | | |
71 | | void |
72 | 38.2k | disassemble_architecture(int arch, const uint8_t *Data, size_t Size, int big) { |
73 | 38.2k | char AssemblyText[MAX_TEXT_SIZE]; |
74 | 38.2k | struct disassemble_info disasm_info; |
75 | 38.2k | SFILE s; |
76 | | |
77 | 38.2k | init_disassemble_info (&disasm_info, stdout, (fprintf_ftype) fprintf, fuzz_disasm_null_styled_printf); |
78 | 38.2k | disasm_info.fprintf_func = objdump_sprintf; |
79 | 38.2k | disasm_info.print_address_func = generic_print_address; |
80 | 38.2k | disasm_info.display_endian = disasm_info.endian = BFD_ENDIAN_LITTLE; |
81 | 38.2k | disasm_info.buffer = (bfd_byte *) Data+10; |
82 | 38.2k | disasm_info.buffer_vma = 0x1000; |
83 | 38.2k | disasm_info.buffer_length = Size-10; |
84 | 38.2k | disasm_info.insn_info_valid = 0; |
85 | 38.2k | disasm_info.disassembler_options = options; |
86 | 38.2k | disasm_info.created_styled_output = false; |
87 | | |
88 | 38.2k | if (arch == bfd_arch_arm) { |
89 | 17.9k | disasm_info.private_data = private_data; |
90 | 17.9k | } |
91 | | |
92 | 38.2k | s.buffer = AssemblyText; |
93 | 38.2k | s.pos = 0; |
94 | 38.2k | disasm_info.stream = &s; |
95 | 38.2k | disasm_info.bytes_per_line = 0; |
96 | | |
97 | 38.2k | disasm_info.arch = arch; |
98 | 38.2k | disasm_info.mach = bfd_getl64(&Data[Size-9]); |
99 | 38.2k | disasm_info.flavour = Data[Size-10]; |
100 | 38.2k | disasm_info.bytes_per_chunk = Data[Size-9]; |
101 | | |
102 | 38.2k | if (bfd_lookup_arch (disasm_info.arch, disasm_info.mach) != NULL) { |
103 | 37.1k | disassembler_ftype disasfunc = disassembler(disasm_info.arch, big, disasm_info.mach, NULL); |
104 | 37.1k | if (disasfunc != NULL) { |
105 | 37.1k | disassemble_init_for_target(&disasm_info); |
106 | 2.53M | while (1) { |
107 | 2.53M | s.pos = 0; |
108 | 2.53M | int octets = disasfunc(disasm_info.buffer_vma, &disasm_info); |
109 | 2.53M | if (octets < (int) disasm_info.octets_per_byte) |
110 | 16.8k | break; |
111 | 2.51M | if (disasm_info.buffer_length <= (size_t) octets) |
112 | 20.2k | break; |
113 | 2.49M | disasm_info.buffer += octets; |
114 | 2.49M | disasm_info.buffer_vma += octets / disasm_info.octets_per_byte; |
115 | 2.49M | disasm_info.buffer_length -= octets; |
116 | 2.49M | } |
117 | 37.1k | disassemble_free_target(&disasm_info); |
118 | 37.1k | } |
119 | 37.1k | } |
120 | 38.2k | } |
121 | | |
122 | 19.2k | int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { |
123 | 19.2k | if (Size < 210 || Size > 16394) { |
124 | | // 10 bytes for options |
125 | | // 16394 limit code to prevent timeouts |
126 | 159 | return 0; |
127 | 159 | } |
128 | 19.1k | char arch = *Data; |
129 | | |
130 | | // Create a random options string |
131 | 19.1k | memcpy(options, Data, 100); |
132 | 19.1k | options[99] = '\0'; |
133 | 19.1k | Data += 100; |
134 | 19.1k | Size -= 100; |
135 | | |
136 | | // The private data may or may not be used in the disassemble_architecture |
137 | | // depending on the the target. |
138 | 19.1k | memcpy(private_data, Data, 100); |
139 | 19.1k | options[99] = '\0'; |
140 | 19.1k | Data += 100; |
141 | 19.1k | Size -= 100; |
142 | | |
143 | | // FUZZ_TARGET_ARCH must be defined and should be the architecture |
144 | | // you target. |
145 | 19.1k | disassemble_architecture(FUZZ_TARGET_ARCH, Data, Size, 1); |
146 | 19.1k | disassemble_architecture(FUZZ_TARGET_ARCH, Data, Size, 0); |
147 | | |
148 | 19.1k | return 0; |
149 | 19.2k | } |