json-c-0.13.x: Fix CVE-2020-12762 - json-c through 0.14 has an integer overflow and out-of-bounds write ...pull/625/head
| @@ -135,6 +135,9 @@ array_list_del_idx( struct array_list *arr, size_t idx, size_t count ) | |||
| { | |||
| size_t i, stop; | |||
| /* Avoid overflow in calculation with large indices. */ | |||
| if (idx > SIZE_T_MAX - count) | |||
| return -1; | |||
| stop = idx + count; | |||
| if ( idx >= arr->length || stop > arr->length ) return -1; | |||
| for ( i = idx; i < stop; ++i ) { | |||
| @@ -12,12 +12,13 @@ | |||
| #include "config.h" | |||
| #include <stdio.h> | |||
| #include <string.h> | |||
| #include <stdlib.h> | |||
| #include <assert.h> | |||
| #include <limits.h> | |||
| #include <stdarg.h> | |||
| #include <stddef.h> | |||
| #include <limits.h> | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #ifdef HAVE_ENDIAN_H | |||
| # include <endian.h> /* attempt to define endianness */ | |||
| @@ -28,8 +29,8 @@ | |||
| # include <windows.h> /* Get InterlockedCompareExchange */ | |||
| #endif | |||
| #include "random_seed.h" | |||
| #include "linkhash.h" | |||
| #include "random_seed.h" | |||
| /* hash functions */ | |||
| static unsigned long lh_char_hash(const void *k); | |||
| @@ -498,7 +499,9 @@ struct lh_table* lh_table_new(int size, | |||
| int i; | |||
| struct lh_table *t; | |||
| t = (struct lh_table*)calloc(1, sizeof(struct lh_table)); | |||
| /* Allocate space for elements to avoid divisions by zero. */ | |||
| assert(size > 0); | |||
| t = (struct lh_table *)calloc(1, sizeof(struct lh_table)); | |||
| if (!t) | |||
| return NULL; | |||
| @@ -577,8 +580,12 @@ int lh_table_insert_w_hash(struct lh_table *t, const void *k, const void *v, con | |||
| unsigned long n; | |||
| if (t->count >= t->size * LH_LOAD_FACTOR) | |||
| if (lh_table_resize(t, t->size * 2) != 0) | |||
| { | |||
| /* Avoid signed integer overflow with large tables. */ | |||
| int new_size = (t->size > INT_MAX / 2) ? INT_MAX : (t->size * 2); | |||
| if (t->size == INT_MAX || lh_table_resize(t, new_size) != 0) | |||
| return -1; | |||
| } | |||
| n = h % t->size; | |||
| @@ -15,6 +15,7 @@ | |||
| #include "config.h" | |||
| #include <limits.h> | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| @@ -64,10 +65,16 @@ static int printbuf_extend(struct printbuf *p, int min_size) | |||
| if (p->size >= min_size) | |||
| return 0; | |||
| new_size = p->size * 2; | |||
| if (new_size < min_size + 8) | |||
| new_size = min_size + 8; | |||
| /* Prevent signed integer overflows with large buffers. */ | |||
| if (min_size > INT_MAX - 8) | |||
| return -1; | |||
| if (p->size > INT_MAX / 2) | |||
| new_size = min_size + 8; | |||
| else { | |||
| new_size = p->size * 2; | |||
| if (new_size < min_size + 8) | |||
| new_size = min_size + 8; | |||
| } | |||
| #ifdef PRINTBUF_DEBUG | |||
| MC_DEBUG("printbuf_memappend: realloc " | |||
| "bpos=%d min_size=%d old_size=%d new_size=%d\n", | |||
| @@ -82,14 +89,18 @@ static int printbuf_extend(struct printbuf *p, int min_size) | |||
| int printbuf_memappend(struct printbuf *p, const char *buf, int size) | |||
| { | |||
| if (p->size <= p->bpos + size + 1) { | |||
| if (printbuf_extend(p, p->bpos + size + 1) < 0) | |||
| return -1; | |||
| } | |||
| memcpy(p->buf + p->bpos, buf, size); | |||
| p->bpos += size; | |||
| p->buf[p->bpos]= '\0'; | |||
| return size; | |||
| /* Prevent signed integer overflows with large buffers. */ | |||
| if (size > INT_MAX - p->bpos - 1) | |||
| return -1; | |||
| if (p->size <= p->bpos + size + 1) | |||
| { | |||
| if (printbuf_extend(p, p->bpos + size + 1) < 0) | |||
| return -1; | |||
| } | |||
| memcpy(p->buf + p->bpos, buf, size); | |||
| p->bpos += size; | |||
| p->buf[p->bpos] = '\0'; | |||
| return size; | |||
| } | |||
| int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len) | |||
| @@ -98,6 +109,9 @@ int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len) | |||
| if (offset == -1) | |||
| offset = pb->bpos; | |||
| /* Prevent signed integer overflows with large buffers. */ | |||
| if (len > INT_MAX - offset) | |||
| return -1; | |||
| size_needed = offset + len; | |||
| if (pb->size < size_needed) | |||
| { | |||
| @@ -2,9 +2,11 @@ | |||
| * gcc -o utf8 utf8.c -I/home/y/include -L./.libs -ljson | |||
| */ | |||
| #include "config.h" | |||
| #include <assert.h> | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "config.h" | |||
| #include "json_inttypes.h" | |||
| #include "json_object.h" | |||
| @@ -24,6 +26,29 @@ void print_hex(const char* s) | |||
| putchar('\n'); | |||
| } | |||
| static void test_lot_of_adds(void); | |||
| static void test_lot_of_adds() | |||
| { | |||
| int ii; | |||
| char key[50]; | |||
| json_object *jobj = json_object_new_object(); | |||
| assert(jobj != NULL); | |||
| for (ii = 0; ii < 500; ii++) | |||
| { | |||
| snprintf(key, sizeof(key), "k%d", ii); | |||
| json_object *iobj = json_object_new_int(ii); | |||
| assert(iobj != NULL); | |||
| if (json_object_object_add(jobj, key, iobj)) | |||
| { | |||
| fprintf(stderr, "FAILED to add object #%d\n", ii); | |||
| abort(); | |||
| } | |||
| } | |||
| printf("%s\n", json_object_to_json_string(jobj)); | |||
| assert(json_object_object_length(jobj) == 500); | |||
| json_object_put(jobj); | |||
| } | |||
| int main(void) | |||
| { | |||
| const char *input = "\"\\ud840\\udd26,\\ud840\\udd27,\\ud800\\udd26,\\ud800\\udd27\""; | |||
| @@ -49,5 +74,8 @@ int main(void) | |||
| retval = 1; | |||
| } | |||
| json_object_put(parse_result); | |||
| test_lot_of_adds(); | |||
| return retval; | |||
| } | |||