]> git.ipfire.org Git - thirdparty/json-c.git/commitdiff
Fix various potential null ptr deref and int32 overflows 219/head
authorEven Rouault <even.rouault@spatialys.com>
Mon, 11 Jan 2016 11:15:54 +0000 (12:15 +0100)
committerEven Rouault <even.rouault@spatialys.com>
Mon, 11 Jan 2016 11:15:54 +0000 (12:15 +0100)
This fix errors that can happen when ingesting very large JSON files
when hitting the maximum heap size of the process.

arraylist.c
json_object.c
json_tokener.c

index 8efe006eb6de4ac7ccddeb21840481793029876f..65ddeaf25ac1a67dbfb73ae29df3f1c71f164e69 100644 (file)
@@ -11,6 +11,8 @@
 
 #include "config.h"
 
+#include <limits.h>
+
 #ifdef STDC_HEADERS
 # include <stdlib.h>
 # include <string.h>
@@ -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;
index e611103ee4808fa3090ac61c2f94d1c0f4dbee93..821ae10729f8c9d6cb7c2dbc92edbaa89cc81554 100644 (file)
@@ -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;
 }
 
index 752a7b394eb6ee3bd71e7d339069e928f0859772..8b65ee0219e6a296835062771ba6ff97272bf7ae 100644 (file)
@@ -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;