1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (C) 2018 Intel Corporation.
3 * All rights reserved.
4 */
5
6 #include "spdk/stdinc.h"
7 #include "spdk/env.h"
8 #include "spdk/file.h"
9 #include "spdk/base64.h"
10 #include "spdk/json.h"
11
12 #define DEFAULT_RUNTIME 30 /* seconds */
13 #define MAX_RUNTIME_S 86400 /* 24 hours */
14 #define IO_TIMEOUT_S 5
15
16 #define UNSIGNED_2BIT_MAX ((1 << 2) - 1)
17 #define UNSIGNED_4BIT_MAX ((1 << 4) - 1)
18 #define UNSIGNED_8BIT_MAX ((1 << 8) - 1)
19
20 typedef bool (*json_parse_fn)(void *ele, struct spdk_json_val *val, size_t num_vals);
21
22 static void
fuzz_fill_random_bytes(char * character_repr,size_t len,unsigned int * rand_seed)23 fuzz_fill_random_bytes(char *character_repr, size_t len, unsigned int *rand_seed)
24 {
25 size_t i;
26
27 for (i = 0; i < len; i++) {
28 character_repr[i] = rand_r(rand_seed) % UINT8_MAX;
29 }
30 }
31
32 static uint64_t
fuzz_refresh_timeout(void)33 fuzz_refresh_timeout(void)
34 {
35 uint64_t current_ticks;
36 uint64_t new_timeout_ticks;
37
38 current_ticks = spdk_get_ticks();
39
40 new_timeout_ticks = current_ticks + IO_TIMEOUT_S * spdk_get_ticks_hz();
41 assert(new_timeout_ticks > current_ticks);
42
43 return new_timeout_ticks;
44 }
45
46 static char *
fuzz_get_value_base_64_buffer(void * item,size_t len)47 fuzz_get_value_base_64_buffer(void *item, size_t len)
48 {
49 char *value_string;
50 size_t total_size;
51 int rc;
52
53 /* Null pointer */
54 total_size = spdk_base64_get_encoded_strlen(len) + 1;
55
56 value_string = calloc(1, total_size);
57 if (value_string == NULL) {
58 return NULL;
59 }
60
61 rc = spdk_base64_encode(value_string, item, len);
62 if (rc < 0) {
63 free(value_string);
64 return NULL;
65 }
66
67 return value_string;
68 }
69
70 static int
fuzz_get_base_64_buffer_value(void * item,size_t len,char * buf,size_t buf_len)71 fuzz_get_base_64_buffer_value(void *item, size_t len, char *buf, size_t buf_len)
72 {
73 size_t size_of_data;
74 char *new_buf;
75 int rc;
76
77 new_buf = malloc(buf_len + 1);
78 if (new_buf == NULL) {
79 return -ENOMEM;
80 }
81
82 snprintf(new_buf, buf_len + 1, "%s", buf);
83
84 size_of_data = spdk_base64_get_decoded_len(buf_len);
85
86 if (size_of_data < len) {
87 free(new_buf);
88 return -EINVAL;
89 }
90
91 rc = spdk_base64_decode(item, &size_of_data, new_buf);
92
93 if (rc || size_of_data != len) {
94 free(new_buf);
95 return -EINVAL;
96 }
97
98 free(new_buf);
99 return 0;
100 }
101
102 static ssize_t
read_json_into_buffer(const char * filename,struct spdk_json_val ** values,void ** file_data)103 read_json_into_buffer(const char *filename, struct spdk_json_val **values, void **file_data)
104 {
105 size_t file_data_size;
106 ssize_t num_json_values = 0, rc;
107
108 *file_data = spdk_posix_file_load_from_name(filename, &file_data_size);
109 if (*file_data == NULL) {
110 return 0;
111 }
112
113 num_json_values = spdk_json_parse(*file_data, file_data_size, NULL, 0, NULL,
114 SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS);
115
116 *values = calloc(num_json_values, sizeof(**values));
117 if (values == NULL) {
118 free(*file_data);
119 *file_data = NULL;
120 return 0;
121 }
122
123 rc = spdk_json_parse(*file_data, file_data_size, *values, num_json_values, NULL,
124 SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS);
125 if (num_json_values != rc) {
126 free(*values);
127 *values = NULL;
128 free(*file_data);
129 *file_data = NULL;
130 return 0;
131 }
132
133 return num_json_values;
134 }
135
136 static size_t
double_arr_size(void ** buffer,size_t num_ele,size_t ele_size)137 double_arr_size(void **buffer, size_t num_ele, size_t ele_size)
138 {
139 void *tmp;
140 size_t new_num_ele, allocation_size;
141
142 if (num_ele > SIZE_MAX / 2) {
143 return 0;
144 }
145
146 new_num_ele = num_ele * 2;
147
148 if (new_num_ele > SIZE_MAX / ele_size) {
149 return 0;
150 }
151
152 allocation_size = new_num_ele * ele_size;
153
154 tmp = realloc(*buffer, allocation_size);
155 if (tmp != NULL) {
156 *buffer = tmp;
157 return new_num_ele;
158 }
159
160 return 0;
161 }
162
163 static uint64_t
fuzz_parse_args_into_array(const char * file,void ** arr,size_t ele_size,const char * obj_name,json_parse_fn cb_fn)164 fuzz_parse_args_into_array(const char *file, void **arr, size_t ele_size, const char *obj_name,
165 json_parse_fn cb_fn)
166 {
167 ssize_t i, num_json_values;
168 struct spdk_json_val *values = NULL, *values_head = NULL, *obj_start;
169 void *file_data = NULL;;
170 char *arr_idx_pointer;
171 size_t num_arr_elements, arr_elements_used, values_in_obj;
172 bool rc;
173
174 num_json_values = read_json_into_buffer(file, &values_head, &file_data);
175 values = values_head;
176 if (num_json_values == 0 || values == NULL) {
177 if (file_data != NULL) {
178 free(file_data);
179 }
180 fprintf(stderr, "The file provided does not exist or we were unable to parse it.\n");
181 return 0;
182 }
183
184 num_arr_elements = 10;
185 arr_elements_used = 0;
186 *arr = calloc(num_arr_elements, ele_size);
187 arr_idx_pointer = (char *)*arr;
188 if (arr_idx_pointer == NULL) {
189 free(values);
190 free(file_data);
191 return 0;
192 }
193
194 i = 0;
195 while (i < num_json_values) {
196 if (values->type != SPDK_JSON_VAL_NAME) {
197 i++;
198 values++;
199 continue;
200 }
201
202 if (!strncmp(values->start, obj_name, values->len)) {
203 i++;
204 values++;
205 assert(values->type == SPDK_JSON_VAL_OBJECT_BEGIN);
206 obj_start = values;
207 values_in_obj = spdk_json_val_len(obj_start);
208 values += values_in_obj;
209 i += values_in_obj;
210
211 rc = cb_fn((void *)arr_idx_pointer, obj_start, values_in_obj);
212 if (rc == false) {
213 fprintf(stderr, "failed to parse file after %zu elements.\n", arr_elements_used);
214 goto fail;
215 }
216
217 arr_idx_pointer += ele_size;
218 arr_elements_used++;
219 if (arr_elements_used == num_arr_elements) {
220 num_arr_elements = double_arr_size(arr, num_arr_elements, ele_size);
221 if (num_arr_elements == 0) {
222 fprintf(stderr, "failed to allocate enough space for all json elements in your file.\n");
223 goto fail;
224 } else {
225 /* reset the array element position in case the pointer changed. */
226 arr_idx_pointer = ((char *)*arr) + arr_elements_used * ele_size;
227 }
228 }
229
230 continue;
231 } else {
232 i++;
233 values++;
234 continue;
235 }
236 }
237
238 if (arr_elements_used == 0) {
239 goto fail;
240 }
241
242 free(values_head);
243 free(file_data);
244 return arr_elements_used;
245 fail:
246 free(values_head);
247 free(file_data);
248 free(*arr);
249 *arr = NULL;
250 return 0;
251 }
252
253 static int
fuzz_parse_json_num(struct spdk_json_val * val,uint64_t max_val,uint64_t * val_ptr)254 fuzz_parse_json_num(struct spdk_json_val *val, uint64_t max_val, uint64_t *val_ptr)
255 {
256 uint64_t tmp_val;
257 int rc;
258
259 rc = spdk_json_number_to_uint64(val, &tmp_val);
260 if (rc || tmp_val > max_val) {
261 return -EINVAL;
262 } else {
263 *val_ptr = tmp_val;
264 return 0;
265 }
266 }
267