]> granicus.if.org Git - json-c/commitdiff
Fix integer overflows.
authorTobias Stoeckmann <tobias@stoeckmann.org>
Mon, 4 May 2020 17:47:25 +0000 (19:47 +0200)
committerTobias Stoeckmann <tobias@stoeckmann.org>
Wed, 6 May 2020 18:46:12 +0000 (20:46 +0200)
The data structures linkhash and printbuf are limited to 2 GB in size
due to a signed integer being used to track their current size.

If too much data is added, then size variable can overflow, which is
an undefined behaviour in C programming language.

Assuming that a signed int overflow just leads to a negative value,
like it happens on many sytems (Linux i686/amd64 with gcc), then
printbuf is vulnerable to an out of boundary write on 64 bit systems.

linkhash.c
printbuf.c

index f05cc38030bf4679f486965a105793100dccd263..51e90b13a25c26a1e85a250d5e28729f6a7a4f19 100644 (file)
@@ -580,9 +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)
+       if (t->count >= t->size * LH_LOAD_FACTOR) {
+               /* Avoid signed integer overflow with large tables. */
+               int new_size = INT_MAX / 2 < t->size ? t->size * 2 : INT_MAX;
+               if (t->size == INT_MAX || lh_table_resize(t, new_size) != 0)
                        return -1;
+       }
 
        n = h % t->size;
 
index 976c12dde5a36e4879625290be2e09caf737a5dd..00822fac4f19ebe6f9a5aaafea51ebf38070086b 100644 (file)
@@ -15,6 +15,7 @@
 
 #include "config.h"
 
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -65,10 +66,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)
+       /* 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",
@@ -83,6 +90,9 @@ static int printbuf_extend(struct printbuf *p, int min_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 (printbuf_extend(p, p->bpos + size + 1) < 0)
@@ -100,6 +110,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)
        {