1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 #include "spdk/env.h" 36 #include "spdk/file.h" 37 #include "spdk/base64.h" 38 #include "spdk/json.h" 39 40 #define DEFAULT_RUNTIME 30 /* seconds */ 41 #define MAX_RUNTIME_S 86400 /* 24 hours */ 42 #define IO_TIMEOUT_S 5 43 44 #define UNSIGNED_2BIT_MAX ((1 << 2) - 1) 45 #define UNSIGNED_4BIT_MAX ((1 << 4) - 1) 46 #define UNSIGNED_8BIT_MAX ((1 << 8) - 1) 47 48 typedef bool (*json_parse_fn)(void *ele, struct spdk_json_val *val, size_t num_vals); 49 50 static void 51 fuzz_fill_random_bytes(char *character_repr, size_t len, unsigned int *rand_seed) 52 { 53 size_t i; 54 55 for (i = 0; i < len; i++) { 56 character_repr[i] = rand_r(rand_seed) % UINT8_MAX; 57 } 58 } 59 60 static uint64_t 61 fuzz_refresh_timeout(void) 62 { 63 uint64_t current_ticks; 64 uint64_t new_timeout_ticks; 65 66 current_ticks = spdk_get_ticks(); 67 68 new_timeout_ticks = current_ticks + IO_TIMEOUT_S * spdk_get_ticks_hz(); 69 assert(new_timeout_ticks > current_ticks); 70 71 return new_timeout_ticks; 72 } 73 74 static char * 75 fuzz_get_value_base_64_buffer(void *item, size_t len) 76 { 77 char *value_string; 78 size_t total_size; 79 int rc; 80 81 /* Null pointer */ 82 total_size = spdk_base64_get_encoded_strlen(len) + 1; 83 84 value_string = calloc(1, total_size); 85 if (value_string == NULL) { 86 return NULL; 87 } 88 89 rc = spdk_base64_encode(value_string, item, len); 90 if (rc < 0) { 91 free(value_string); 92 return NULL; 93 } 94 95 return value_string; 96 } 97 98 static int 99 fuzz_get_base_64_buffer_value(void *item, size_t len, char *buf, size_t buf_len) 100 { 101 size_t size_of_data; 102 char *new_buf; 103 int rc; 104 105 new_buf = malloc(buf_len + 1); 106 if (new_buf == NULL) { 107 return -ENOMEM; 108 } 109 110 snprintf(new_buf, buf_len + 1, "%s", buf); 111 112 size_of_data = spdk_base64_get_decoded_len(buf_len); 113 114 if (size_of_data < len) { 115 free(new_buf); 116 return -EINVAL; 117 } 118 119 rc = spdk_base64_decode(item, &size_of_data, new_buf); 120 121 if (rc || size_of_data != len) { 122 free(new_buf); 123 return -EINVAL; 124 } 125 126 free(new_buf); 127 return 0; 128 } 129 130 static ssize_t 131 read_json_into_buffer(const char *filename, struct spdk_json_val **values, void **file_data) 132 { 133 FILE *file = fopen(filename, "r"); 134 size_t file_data_size; 135 ssize_t num_json_values = 0, rc; 136 137 if (file == NULL) { 138 /* errno is set by fopen */ 139 return 0; 140 } 141 142 *file_data = spdk_posix_file_load(file, &file_data_size); 143 if (*file_data == NULL) { 144 fclose(file); 145 return 0; 146 } 147 148 fclose(file); 149 150 num_json_values = spdk_json_parse(*file_data, file_data_size, NULL, 0, NULL, 151 SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS); 152 153 *values = calloc(num_json_values, sizeof(**values)); 154 if (values == NULL) { 155 free(*file_data); 156 *file_data = NULL; 157 return 0; 158 } 159 160 rc = spdk_json_parse(*file_data, file_data_size, *values, num_json_values, NULL, 161 SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS); 162 if (num_json_values != rc) { 163 free(*values); 164 *values = NULL; 165 free(*file_data); 166 *file_data = NULL; 167 return 0; 168 } 169 170 return num_json_values; 171 } 172 173 static size_t 174 double_arr_size(void **buffer, size_t num_ele, size_t ele_size) 175 { 176 void *tmp; 177 size_t new_num_ele, allocation_size; 178 179 if (num_ele > SIZE_MAX / 2) { 180 return 0; 181 } 182 183 new_num_ele = num_ele * 2; 184 185 if (new_num_ele > SIZE_MAX / ele_size) { 186 return 0; 187 } 188 189 allocation_size = new_num_ele * ele_size; 190 191 tmp = realloc(*buffer, allocation_size); 192 if (tmp != NULL) { 193 *buffer = tmp; 194 return new_num_ele; 195 } 196 197 return 0; 198 } 199 200 static uint64_t 201 fuzz_parse_args_into_array(const char *file, void **arr, size_t ele_size, const char *obj_name, 202 json_parse_fn cb_fn) 203 { 204 ssize_t i, num_json_values; 205 struct spdk_json_val *values = NULL, *values_head = NULL, *obj_start; 206 void *file_data = NULL;; 207 char *arr_idx_pointer; 208 size_t num_arr_elements, arr_elements_used, values_in_obj; 209 bool rc; 210 211 num_json_values = read_json_into_buffer(file, &values_head, &file_data); 212 values = values_head; 213 if (num_json_values == 0 || values == NULL) { 214 if (file_data != NULL) { 215 free(file_data); 216 } 217 fprintf(stderr, "The file provided does not exist or we were unable to parse it.\n"); 218 return 0; 219 } 220 221 num_arr_elements = 10; 222 arr_elements_used = 0; 223 *arr = calloc(num_arr_elements, ele_size); 224 arr_idx_pointer = (char *)*arr; 225 if (arr_idx_pointer == NULL) { 226 free(values); 227 free(file_data); 228 return 0; 229 } 230 231 i = 0; 232 while (i < num_json_values) { 233 if (values->type != SPDK_JSON_VAL_NAME) { 234 i++; 235 values++; 236 continue; 237 } 238 239 if (!strncmp(values->start, obj_name, values->len)) { 240 i++; 241 values++; 242 assert(values->type == SPDK_JSON_VAL_OBJECT_BEGIN); 243 obj_start = values; 244 values_in_obj = spdk_json_val_len(obj_start); 245 values += values_in_obj; 246 i += values_in_obj; 247 248 rc = cb_fn((void *)arr_idx_pointer, obj_start, values_in_obj); 249 if (rc == false) { 250 fprintf(stderr, "failed to parse file after %lu elements.\n", arr_elements_used); 251 goto fail; 252 } 253 254 arr_idx_pointer += ele_size; 255 arr_elements_used++; 256 if (arr_elements_used == num_arr_elements) { 257 num_arr_elements = double_arr_size(arr, num_arr_elements, ele_size); 258 if (num_arr_elements == 0) { 259 fprintf(stderr, "failed to allocate enough space for all json elements in your file.\n"); 260 goto fail; 261 } else { 262 /* reset the array element position in case the pointer changed. */ 263 arr_idx_pointer = ((char *)*arr) + arr_elements_used * ele_size; 264 } 265 } 266 267 continue; 268 } else { 269 i++; 270 values++; 271 continue; 272 } 273 } 274 275 if (arr_elements_used == 0) { 276 goto fail; 277 } 278 279 free(values_head); 280 free(file_data); 281 return arr_elements_used; 282 fail: 283 free(values_head); 284 free(file_data); 285 free(*arr); 286 *arr = NULL; 287 return 0; 288 } 289 290 static int 291 fuzz_parse_json_num(struct spdk_json_val *val, uint64_t max_val, uint64_t *val_ptr) 292 { 293 uint64_t tmp_val; 294 int rc; 295 296 rc = spdk_json_number_to_uint64(val, &tmp_val); 297 if (rc || tmp_val > max_val) { 298 return -EINVAL; 299 } else { 300 *val_ptr = tmp_val; 301 return 0; 302 } 303 } 304