summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-devtools/json-c/json-c/0003-Fix-integer-overflows.patch
blob: c944302102cdfa636cc7cb15efd0b3aace8f8f5c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
From d07b91014986900a3a75f306d302e13e005e9d67 Mon Sep 17 00:00:00 2001
From: Tobias Stoeckmann <tobias@stoeckmann.org>
Date: Mon, 4 May 2020 19:47:25 +0200
Subject: [PATCH] Fix integer overflows.

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 |  7 +++++--
 printbuf.c | 19 ++++++++++++++++---
 2 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/linkhash.c b/linkhash.c
index f05cc38030..51e90b13a2 100644
--- a/linkhash.c
+++ b/linkhash.c
@@ -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;
 
diff --git a/printbuf.c b/printbuf.c
index 976c12dde5..00822fac4f 100644
--- a/printbuf.c
+++ b/printbuf.c
@@ -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)
       return -1;
@@ -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)
 	{