Browse Source

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.
tags/json-c-0.13-20171207
Even Rouault 9 years ago
parent
commit
77a4276a8c
3 changed files with 38 additions and 4 deletions
  1. +13
    -3
      arraylist.c
  2. +5
    -0
      json_object.c
  3. +20
    -1
      json_tokener.c

+ 13
- 3
arraylist.c View File

@@ -11,6 +11,8 @@


#include "config.h" #include "config.h"


#include <limits.h>

#ifdef STDC_HEADERS #ifdef STDC_HEADERS
# include <stdlib.h> # include <stdlib.h>
# include <string.h> # include <string.h>
@@ -62,10 +64,17 @@ static int array_list_expand_internal(struct array_list *arr, int max)
int new_size; int new_size;


if(max < arr->size) return 0; 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; 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; arr->array = (void**)t;
(void)memset(arr->array + arr->size, 0, (new_size-arr->size)*sizeof(void*)); (void)memset(arr->array + arr->size, 0, (new_size-arr->size)*sizeof(void*));
arr->size = new_size; arr->size = new_size;
@@ -75,6 +84,7 @@ static int array_list_expand_internal(struct array_list *arr, int max)
int int
array_list_put_idx(struct array_list *arr, int idx, void *data) 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(array_list_expand_internal(arr, idx+1)) return -1;
if(arr->array[idx]) arr->free_fn(arr->array[idx]); if(arr->array[idx]) arr->free_fn(arr->array[idx]);
arr->array[idx] = data; arr->array[idx] = data;


+ 5
- 0
json_object.c View File

@@ -934,6 +934,11 @@ struct json_object* json_object_new_array(void)
jso->_delete = &json_object_array_delete; jso->_delete = &json_object_array_delete;
jso->_to_json_string = &json_object_array_to_json_string; jso->_to_json_string = &json_object_array_to_json_string;
jso->o.c_array = array_list_new(&json_object_array_entry_free); jso->o.c_array = array_list_new(&json_object_array_entry_free);
if(jso->o.c_array == NULL)
{
free(jso);
return NULL;
}
return jso; return jso;
} }




+ 20
- 1
json_tokener.c View File

@@ -286,11 +286,15 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
state = json_tokener_state_eatws; state = json_tokener_state_eatws;
saved_state = json_tokener_state_object_field_start; saved_state = json_tokener_state_object_field_start;
current = json_object_new_object(); current = json_object_new_object();
if(current == NULL)
goto out;
break; break;
case '[': case '[':
state = json_tokener_state_eatws; state = json_tokener_state_eatws;
saved_state = json_tokener_state_array; saved_state = json_tokener_state_array;
current = json_object_new_array(); current = json_object_new_array();
if(current == NULL)
goto out;
break; break;
case 'I': case 'I':
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) if (tok->st_pos == json_inf_str_len)
{ {
current = json_object_new_double(is_negative ? -INFINITY : INFINITY); current = json_object_new_double(is_negative ? -INFINITY : INFINITY);
if(current == NULL)
goto out;
saved_state = json_tokener_state_finish; saved_state = json_tokener_state_finish;
state = json_tokener_state_eatws; state = json_tokener_state_eatws;
goto redo_char; 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) if (tok->st_pos == json_nan_str_len)
{ {
current = json_object_new_double(NAN); current = json_object_new_double(NAN);
if (current == NULL)
goto out;
saved_state = json_tokener_state_finish; saved_state = json_tokener_state_finish;
state = json_tokener_state_eatws; state = json_tokener_state_eatws;
goto redo_char; goto redo_char;
@@ -486,6 +494,8 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
if(c == tok->quote_char) { if(c == tok->quote_char) {
printbuf_memappend_fast(tok->pb, case_start, str-case_start); printbuf_memappend_fast(tok->pb, case_start, str-case_start);
current = json_object_new_string_len(tok->pb->buf, tok->pb->bpos); current = json_object_new_string_len(tok->pb->buf, tok->pb->bpos);
if(current == NULL)
goto out;
saved_state = json_tokener_state_finish; saved_state = json_tokener_state_finish;
state = json_tokener_state_eatws; state = json_tokener_state_eatws;
break; break;
@@ -646,6 +656,8 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
) { ) {
if(tok->st_pos == json_true_str_len) { if(tok->st_pos == json_true_str_len) {
current = json_object_new_boolean(1); current = json_object_new_boolean(1);
if(current == NULL)
goto out;
saved_state = json_tokener_state_finish; saved_state = json_tokener_state_finish;
state = json_tokener_state_eatws; state = json_tokener_state_eatws;
goto redo_char; 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)) { || (strncmp(json_false_str, tok->pb->buf, size2) == 0)) {
if(tok->st_pos == json_false_str_len) { if(tok->st_pos == json_false_str_len) {
current = json_object_new_boolean(0); current = json_object_new_boolean(0);
if(current == NULL)
goto out;
saved_state = json_tokener_state_finish; saved_state = json_tokener_state_finish;
state = json_tokener_state_eatws; state = json_tokener_state_eatws;
goto redo_char; goto redo_char;
@@ -737,10 +751,14 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
goto out; goto out;
} }
current = json_object_new_int64(num64); current = json_object_new_int64(num64);
if(current == NULL)
goto out;
} }
else if(tok->is_double && json_parse_double(tok->pb->buf, &numd) == 0) else if(tok->is_double && json_parse_double(tok->pb->buf, &numd) == 0)
{ {
current = json_object_new_double_s(numd, tok->pb->buf); current = json_object_new_double_s(numd, tok->pb->buf);
if(current == NULL)
goto out;
} else { } else {
tok->err = json_tokener_error_parse_number; tok->err = json_tokener_error_parse_number;
goto out; goto out;
@@ -775,7 +793,8 @@ struct json_object* json_tokener_parse_ex(struct json_tokener *tok,
break; break;


case json_tokener_state_array_add: 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; saved_state = json_tokener_state_array_sep;
state = json_tokener_state_eatws; state = json_tokener_state_eatws;
goto redo_char; goto redo_char;


Loading…
Cancel
Save