json-c-0.12.x: Fix CVE-2020-12762 - json-c through 0.14 has an integer overflow and out-of-bounds write ...json-c-0.12
@@ -10,6 +10,7 @@ | |||||
* | * | ||||
*/ | */ | ||||
#include <assert.h> | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
@@ -431,6 +432,8 @@ struct lh_table* lh_table_new(int size, const char *name, | |||||
int i; | int i; | ||||
struct lh_table *t; | struct lh_table *t; | ||||
/* Allocate space for elements to avoid divisions by zero. */ | |||||
assert(size > 0); | |||||
t = (struct lh_table*)calloc(1, sizeof(struct lh_table)); | t = (struct lh_table*)calloc(1, sizeof(struct lh_table)); | ||||
if(!t) lh_abort("lh_table_new: calloc failed\n"); | if(!t) lh_abort("lh_table_new: calloc failed\n"); | ||||
t->count = 0; | t->count = 0; | ||||
@@ -495,7 +498,14 @@ int lh_table_insert(struct lh_table *t, void *k, const void *v) | |||||
unsigned long h, n; | unsigned long h, n; | ||||
t->inserts++; | t->inserts++; | ||||
if(t->count >= t->size * LH_LOAD_FACTOR) lh_table_resize(t, t->size * 2); | |||||
if (t->count >= t->size * LH_LOAD_FACTOR) { | |||||
/* 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) | |||||
return -1; | |||||
lh_table_resize(t, new_size); | |||||
} | |||||
h = t->hash_fn(k); | h = t->hash_fn(k); | ||||
n = h % t->size; | n = h % t->size; | ||||
@@ -15,6 +15,7 @@ | |||||
#include "config.h" | #include "config.h" | ||||
#include <limits.h> | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
@@ -63,7 +64,16 @@ static int printbuf_extend(struct printbuf *p, int min_size) | |||||
if (p->size >= min_size) | if (p->size >= min_size) | ||||
return 0; | return 0; | ||||
new_size = json_max(p->size * 2, 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 | #ifdef PRINTBUF_DEBUG | ||||
MC_DEBUG("printbuf_memappend: realloc " | MC_DEBUG("printbuf_memappend: realloc " | ||||
"bpos=%d min_size=%d old_size=%d new_size=%d\n", | "bpos=%d min_size=%d old_size=%d new_size=%d\n", | ||||
@@ -78,6 +88,9 @@ static int printbuf_extend(struct printbuf *p, int min_size) | |||||
int printbuf_memappend(struct printbuf *p, const char *buf, int size) | int printbuf_memappend(struct printbuf *p, const char *buf, int 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 (p->size <= p->bpos + size + 1) { | ||||
if (printbuf_extend(p, p->bpos + size + 1) < 0) | if (printbuf_extend(p, p->bpos + size + 1) < 0) | ||||
return -1; | return -1; | ||||
@@ -94,6 +107,9 @@ int printbuf_memset(struct printbuf *pb, int offset, int charvalue, int len) | |||||
if (offset == -1) | if (offset == -1) | ||||
offset = pb->bpos; | offset = pb->bpos; | ||||
/* Prevent signed integer overflows with large buffers. */ | |||||
if (len > INT_MAX - offset) | |||||
return -1; | |||||
size_needed = offset + len; | size_needed = offset + len; | ||||
if (pb->size < size_needed) | if (pb->size < size_needed) | ||||
{ | { | ||||
@@ -2,9 +2,11 @@ | |||||
* gcc -o utf8 utf8.c -I/home/y/include -L./.libs -ljson | * gcc -o utf8 utf8.c -I/home/y/include -L./.libs -ljson | ||||
*/ | */ | ||||
#include "config.h" | |||||
#include <assert.h> | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | |||||
#include <string.h> | #include <string.h> | ||||
#include "config.h" | |||||
#include "json_inttypes.h" | #include "json_inttypes.h" | ||||
#include "json_object.h" | #include "json_object.h" | ||||
@@ -24,6 +26,30 @@ void print_hex( const char* s) | |||||
printf("\n"); | printf("\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); | |||||
json_object_object_add(jobj, key, iobj); | |||||
if (json_object_object_get_ex(jobj, key, &iobj) == FALSE) | |||||
{ | |||||
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() | int main() | ||||
{ | { | ||||
const char *input = "\"\\ud840\\udd26,\\ud840\\udd27,\\ud800\\udd26,\\ud800\\udd27\""; | const char *input = "\"\\ud840\\udd26,\\ud840\\udd27,\\ud800\\udd26,\\ud800\\udd27\""; | ||||
@@ -49,5 +75,8 @@ int main() | |||||
retval = 1; | retval = 1; | ||||
} | } | ||||
json_object_put(parse_result); | json_object_put(parse_result); | ||||
test_lot_of_adds(); | |||||
return retval; | return retval; | ||||
} | } |