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 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 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 * 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 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 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 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 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 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