Coverage Report

Created: 2026-08-13 06:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensc/src/tests/fuzzing/fuzzer_tool.c
Line
Count
Source
1
/*
2
 * fuzzer_tool.c: Implementation of general tool-fuzzing functions
3
 *
4
 * Copyright (C) 2022 Red Hat, Inc.
5
 *
6
 * Author: Veronika Hanulikova <vhanulik@redhat.com>
7
 *
8
 * This library is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public
10
 * License as published by the Free Software Foundation; either
11
 * version 2.1 of the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 */
21
22
#include "fuzzer_tool.h"
23
14.4k
#define MAX_ARGC 10000
24
25
const uint8_t *get_word(const uint8_t *data, size_t size)
26
1.88M
{
27
  /* Words are separated by one zero byte,
28
     return pointer to the next word if there is one */
29
1.88M
  const uint8_t *ptr = data;
30
1.88M
  if (!data || size == 0 || *data == 0)
31
12
    return NULL;
32
  
33
1.88M
  ptr = memchr(data, 0, size - 1);
34
1.88M
  return ptr ? ++ptr : NULL;
35
1.88M
}
36
37
char *extract_word(const uint8_t **data, size_t *size)
38
469k
{
39
  /* Find word and return its copy (needs to be freed) */
40
469k
  char *result = NULL;
41
469k
  const uint8_t *ptr = NULL;
42
43
469k
  if (*size < 2)
44
5
    return NULL;
45
46
469k
  ptr = get_word(*data, *size);
47
469k
  if (!ptr)
48
33
    return NULL;
49
469k
  result = strdup((const char *)*data);
50
469k
  *size -=(ptr - *data);
51
469k
  *data = ptr;
52
53
469k
  return result;
54
469k
}
55
56
int get_fuzzed_argv(const char *app_name, const uint8_t *data, size_t size,
57
                    char ***argv_out, int *argc_out, const uint8_t **reader_data, size_t *reader_data_size)
58
14.4k
{
59
14.4k
  const uint8_t *ptr = data, *help_ptr = data;
60
14.4k
  size_t ptr_size = size;
61
14.4k
  char **argv = NULL;
62
14.4k
  int argc = 1;
63
64
  /* Count arguments until double zero bytes occurs*/
65
1.43M
  while(*ptr != 0) {
66
1.41M
    ptr = get_word(help_ptr, ptr_size);
67
1.41M
    if (!ptr)
68
13
      return -1;
69
1.41M
    argc++;
70
1.41M
    ptr_size -= (ptr - help_ptr);
71
1.41M
    help_ptr = ptr;
72
1.41M
  }
73
74
14.4k
  if (argc > MAX_ARGC)
75
12
    return -1;
76
77
14.4k
  argv = malloc((argc + 1) * sizeof(char*));
78
14.4k
  if (!argv)
79
0
    return -1;
80
81
  /* Copy arguments into argv */
82
14.4k
  ptr = data;
83
14.4k
  ptr_size = size;
84
14.4k
  argv[0] = strdup(app_name);
85
462k
  for (int i = 1; i < argc; i++) {
86
447k
    argv[i] = extract_word(&ptr, &ptr_size);
87
447k
  }
88
14.4k
  argv[argc] = NULL;
89
90
14.4k
  *argc_out = argc;
91
14.4k
  *argv_out = argv;
92
14.4k
  *reader_data = ptr + 1; /* there are two zero bytes at the end of argv */
93
14.4k
  *reader_data_size = ptr_size - 1;
94
14.4k
  return 0;
95
14.4k
}
96
97
uint16_t get_buffer(const uint8_t **buf, size_t buf_len, const uint8_t **out, size_t *out_len, size_t max_size)
98
12.6k
{
99
  /* Split buf into two parts according to length stored in first two bytes */
100
12.6k
  uint16_t len = 0;
101
102
12.6k
  if (!buf || !(*buf) || buf_len < sizeof(uint16_t))
103
22
    return 0;
104
105
  /* Get length of the result buffer*/
106
12.5k
  len = *((uint16_t *) *buf) % max_size;
107
12.5k
  (*buf) += 2;
108
12.5k
  buf_len -= 2;
109
12.5k
  if (buf_len <= len) {
110
79
    *out = *buf;
111
79
    *out_len = buf_len;
112
79
    return 0;
113
79
  }
114
115
  /* Set out buffer to new reader data*/
116
12.5k
  *out = *buf + len;
117
12.5k
  *out_len = buf_len - len;
118
12.5k
  return len;
119
12.5k
}
120
121
int create_input_file(char **filename_out, const uint8_t **data, size_t *size)
122
8.08k
{
123
8.08k
  const uint8_t *ptr = *data;
124
8.08k
  size_t file_size = 0, backup_size = *size;
125
8.08k
  int fd = 0;
126
8.08k
  size_t r = 0;
127
8.08k
  char *filename = NULL;
128
  
129
  /* Split data into file content and rest*/
130
8.08k
  file_size = get_buffer(&ptr, *size, data, size, 6000);
131
8.08k
  if (file_size == 0)
132
42
    return 1;
133
134
8.04k
  filename = strdup("/tmp/input.XXXXXX");
135
8.04k
  fd = mkstemp(filename);
136
8.04k
  if (fd < 0) {
137
0
    *data = ptr - 2;
138
0
    *size = backup_size;
139
0
    free(filename);
140
0
    return 1;
141
0
  }
142
143
8.04k
  r = write(fd, ptr, file_size);
144
8.04k
  close(fd);
145
146
8.04k
  if (r != file_size) {
147
0
    *data = ptr - 2;
148
0
    *size = backup_size;
149
0
    remove_file(filename);
150
0
    return 1;
151
0
  }
152
153
8.04k
  *filename_out = filename;
154
8.04k
  return 0;
155
8.04k
}
156
157
void remove_file(char *filename)
158
8.06k
{
159
8.06k
  if (filename) {
160
8.04k
    unlink(filename);
161
8.04k
    free(filename);
162
8.04k
  }
163
8.06k
}
164
165
void free_arguments(int argc, char **argv)
166
14.4k
{
167
476k
  for (int i = 0; i < argc; i++) {
168
462k
    free(argv[i]);
169
462k
  }
170
14.4k
  free(argv);
171
14.4k
}