Coverage Report

Created: 2023-06-07 07:16

/src/gdbm/fuzz/gdbm_fuzzer.c
Line
Count
Source (jump to first uncovered line)
1
/* This file is part of GDBM, the GNU data base manager.
2
   Copyright (C) 2021-2023 Free Software Foundation, Inc.
3
4
   GDBM is free software; you can redistribute it and/or modify
5
   it under the terms of the GNU General Public License as published by
6
   the Free Software Foundation; either version 3, or (at your option)
7
   any later version.
8
9
   GDBM is distributed in the hope that it will be useful,
10
   but WITHOUT ANY WARRANTY; without even the implied warranty of
11
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
   GNU General Public License for more details.
13
14
   You should have received a copy of the GNU General Public License
15
   along with GDBM. If not, see <http://www.gnu.org/licenses/>.    */
16
17
#include <stdio.h>
18
#include <sys/types.h>
19
#include <sys/stat.h>
20
#include <sys/syscall.h>
21
#include <unistd.h>
22
#include <stdint.h>
23
#include <time.h>
24
#include <gdbmtool.h>
25
26
static char dbname[] = "a.db";
27
static char fuzz_rc_name[] = "gdbm_fuzzer.rc";
28
29

30
struct instream_string
31
{
32
  struct instream base;
33
  char *string;
34
  size_t length;
35
  size_t pos;
36
};
37
38
static ssize_t
39
instream_string_read (instream_t istr, char *buf, size_t size)
40
4.59k
{
41
4.59k
  struct instream_string *str = (struct instream_string *)istr;
42
4.59k
  size_t n = str->length - str->pos;
43
4.59k
  if (size > n)
44
4.59k
    size = n;
45
4.59k
  memcpy (buf, str->string + str->pos, n);
46
4.59k
  str->pos += n;
47
4.59k
  return n;
48
4.59k
}
49
50
static void
51
instream_string_close (instream_t istr)
52
4.59k
{
53
4.59k
  struct instream_string *str = (struct instream_string *)istr;
54
4.59k
  str->pos = 0;
55
4.59k
}
56
57
static int
58
instream_string_eq (instream_t a, instream_t b)
59
0
{
60
0
  return 0;
61
0
}
62
63
static instream_t
64
instream_string_create (char const *input, char const *name)
65
2
{
66
2
  struct instream_string *istr;
67
2
  size_t len;
68
2
  int nl;
69
  
70
2
  istr = emalloc (sizeof (*istr));
71
2
  istr->base.in_name = estrdup (name);
72
2
  istr->base.in_inter = 0;
73
2
  istr->base.in_read = instream_string_read;
74
2
  istr->base.in_close = instream_string_close;
75
2
  istr->base.in_eq = instream_string_eq;
76
2
  istr->base.in_history_size = NULL;
77
2
  istr->base.in_history_get = NULL;
78
2
  len = strlen (input);
79
2
  while (len > 0 && (input[len-1] == ' ' || input[len-1] == '\t'))
80
0
    --len;
81
82
2
  nl = len > 0 && input[len-1] != '\n';
83
2
  istr->string = emalloc (len + nl + 1);
84
2
  memcpy (istr->string, input, len);
85
2
  if (nl)
86
0
    istr->string[len++] = '\n';
87
2
  istr->string[len] = 0;
88
2
  istr->length = len;
89
2
  istr->pos = 0;
90
91
2
  return (instream_t) istr;
92
2
}
93

94
static instream_t input;
95
96
static void
97
fuzzer_exit (void)
98
2
{
99
2
  struct instream_string *istr = (struct instream_string *)input;
100
2
  free (istr->string);
101
2
  free (input->in_name);
102
2
  free (input);
103
2
}
104
105
int
106
LLVMFuzzerInitialize (int *argc, char ***argv)
107
2
{
108
2
  char *argv0 = (*argv)[0];
109
2
  char *p, *file_name;
110
2
  size_t len;
111
2
  struct stat st;
112
2
  char *input_buffer;
113
2
  FILE *fp;
114
115
  /* Initialize gdbmshell globals */
116
2
  set_progname ("gdbmfuzz");
117
118
  /* Build full rc file name */
119
2
  p = strrchr (argv0, '/');
120
2
  len = p - argv0;
121
2
  file_name = emalloc (len + 1 + strlen (fuzz_rc_name) + 1);
122
2
  memcpy (file_name, argv0, len);
123
2
  file_name[len++] = '/';
124
2
  strcpy (file_name + len, fuzz_rc_name);
125
126
  /* Read the file */
127
2
  if (stat (file_name, &st))
128
0
    {
129
0
      terror ("can't stat %s: %s", file_name, strerror (errno));
130
0
      exit (1);
131
0
    }
132
133
2
  input_buffer = emalloc (st.st_size + 1);
134
2
  fp = fopen (file_name, "r");
135
2
  if (!fp)
136
0
    {
137
0
      terror ("can't open %s: %s", file_name, strerror (errno));
138
0
      exit (1);
139
0
    }
140
2
  if (fread (input_buffer, st.st_size, 1, fp) != 1)
141
0
    {
142
0
      terror ("error reading from %s: %s", file_name, strerror (errno));
143
0
      exit (1);
144
0
    }
145
2
  input_buffer[st.st_size] = 0;
146
2
  fclose (fp);
147
148
  /* Set up the input stream */
149
2
  input = instream_string_create (input_buffer, file_name);
150
2
  free (file_name);
151
2
  free (input_buffer);
152
2
  if (!input)
153
0
    exit (1);
154
155
2
  atexit (fuzzer_exit);
156
157
  /* Disable usual gdbmshell output. */
158
2
  stdout = fopen ("/dev/null","w");
159
2
  if (!stdout)
160
0
    {
161
0
      terror ("can't open %s: %s", "/dev/null", strerror (errno));
162
0
      exit (1);
163
0
    }
164
  
165
2
  return 0;
166
2
}
167
168
169
int
170
LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
171
4.59k
{
172
4.59k
  int fd;
173
4.59k
  GDBM_FILE db;
174
  
175
4.59k
  fd = syscall (SYS_memfd_create, dbname, 0);
176
4.59k
  if (fd == -1)
177
0
    {
178
0
      perror ("memfd_create");
179
0
      exit (1);
180
0
    }
181
182
4.59k
  if (write (fd, data, size) < size)
183
0
    {
184
0
      close (fd);
185
0
      perror ("write");
186
0
      exit (1);
187
0
    }
188
189
4.59k
  if (lseek (fd, 0, SEEK_SET) != 0)
190
0
    {
191
0
      close (fd);
192
0
      perror ("write");
193
0
      exit (1);
194
0
    }
195
196
4.59k
  variable_set ("filename", VART_STRING, dbname);
197
4.59k
  variable_set ("fd", VART_INT, &fd);
198
199
4.59k
  return gdbmshell (input);
200
4.59k
}