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