Coverage Report

Created: 2023-08-28 06:31

/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
}