From 77a4276a8c210e1faa2e8c13421e9a3d62772340 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Mon, 11 Jan 2016 12:15:54 +0100 Subject: [PATCH] Fix various potential null ptr deref and int32 overflows This fix errors that can happen when ingesting very large JSON files when hitting the maximum heap size of the process. --- arraylist.c | 16 +++++++++++++--- json_object.c | 5 +++++ json_tokener.c | 21 ++++++++++++++++++++- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/arraylist.c b/arraylist.c index 8efe006..65ddeaf 100644 --- a/arraylist.c +++ b/arraylist.c @@ -11,6 +11,8 @@ #include "config.h" +#include + #ifdef STDC_HEADERS # include # include @@ -62,10 +64,17 @@ static int array_list_expand_internal(struct array_list *arr, int max) int new_size; if(max < arr->size) return 0; - new_size = arr->size << 1; - if (new_size < max) + /* Avoid undefined behaviour on int32 overflow */ + if( arr->size >= INT_MAX / 2 ) new_size = max; - if(!(t = realloc(arr->array, new_size*sizeof(void*)))) return -1; + else + { + new_size = arr->size << 1; + if (new_size < max) + new_size = max; + } + if((size_t)new_size > (~((size_t)0)) / sizeof(void*)) return -1; + if(!(t = realloc(arr->array, ((size_t)new_size)*sizeof(void*)))) return -1; arr->array = (void**)t; (void)memset(arr->array + arr->size, 0, (new_size-arr->size)*sizeof(void*)); arr->size = new_size; @@ -75,6 +84,7 @@ static int array_list_expand_internal(struct array_list *arr, int max) int array_list_put_idx(struct array_list *arr, int idx, void *data) { + if( idx < 0 || idx > INT_MAX - 1 ) return -1; if(array_list_expand_internal(arr, idx+1)) return -1; if(arr->array[idx]) arr->free_fn(arr->array[idx]); arr->array[idx] = data; diff --git a/json_object.c b/json_object.c index e611103..821ae10 100644 --- a/json_object.c +++ b/json_object.c @@ -934,6 +934,11 @@ struct json_object* json_object_new_array(void) jso->_delete = &json_object_array_delete; jso->_to_json_string = &json_object_array_to_json_string; jso->o.c_array = array_list_new(&json_object_array_entry_free); + if(jso->o.c_array == NULL) + { + free(jso); + return NULL; + } return jso; } diff --git a/json_tokener.c b/json_tokener.c index 752a7b3..8b65ee0 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -286,11 +286,15 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, state = json_tokener_state_eatws; saved_state = json_tokener_state_object_field_start; current = json_object_new_object(); + if(current == NULL) + goto out; break; case '[': state = json_tokener_state_eatws; saved_state = json_tokener_state_array; current = json_object_new_array(); + if(current == NULL) + goto out; break; case 'I': case 'i': @@ -376,6 +380,8 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, if (tok->st_pos == json_inf_str_len) { current = json_object_new_double(is_negative ? -INFINITY : INFINITY); + if(current == NULL) + goto out; saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; goto redo_char; @@ -413,6 +419,8 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, if (tok->st_pos == json_nan_str_len) { current = json_object_new_double(NAN); + if (current == NULL) + goto out; saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; goto redo_char; @@ -486,6 +494,8 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, if(c == tok->quote_char) { printbuf_memappend_fast(tok->pb, case_start, str-case_start); current = json_object_new_string_len(tok->pb->buf, tok->pb->bpos); + if(current == NULL) + goto out; saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; break; @@ -646,6 +656,8 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, ) { if(tok->st_pos == json_true_str_len) { current = json_object_new_boolean(1); + if(current == NULL) + goto out; saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; goto redo_char; @@ -655,6 +667,8 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, || (strncmp(json_false_str, tok->pb->buf, size2) == 0)) { if(tok->st_pos == json_false_str_len) { current = json_object_new_boolean(0); + if(current == NULL) + goto out; saved_state = json_tokener_state_finish; state = json_tokener_state_eatws; goto redo_char; @@ -737,10 +751,14 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, goto out; } current = json_object_new_int64(num64); + if(current == NULL) + goto out; } else if(tok->is_double && json_parse_double(tok->pb->buf, &numd) == 0) { current = json_object_new_double_s(numd, tok->pb->buf); + if(current == NULL) + goto out; } else { tok->err = json_tokener_error_parse_number; goto out; @@ -775,7 +793,8 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok, break; case json_tokener_state_array_add: - json_object_array_add(current, obj); + if( json_object_array_add(current, obj) != 0 ) + goto out; saved_state = json_tokener_state_array_sep; state = json_tokener_state_eatws; goto redo_char; -- 2.40.0