Skip to content

Commit 2bfad8f

Browse files
zhuizhuhaomengoranagrayossigo
authored
Bugfix: Lua cjson integer overflow issues (CVE-2022-24834) (#94)
* Fix integer overflows due to using wrong integer size. * Add assertions / panic when overflow still happens. Co-authored-by: Oran Agra <[email protected]> Co-authored-by: Yossi Gottlieb <[email protected]>
1 parent 881accc commit 2bfad8f

File tree

4 files changed

+55
-112
lines changed

4 files changed

+55
-112
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ env:
2727
- JOBS=3
2828
- LUAROCKS_VER=2.4.2
2929
matrix:
30-
#- LUA=1 LUA_DIR=/usr LUA_INCLUDE_DIR=$LUA_DIR/include/lua5.1
30+
#- LUA=1 LUA_DIR=/usr LUA_INCLUDE_DIR=$LUA_DIR/include/lua5.1
3131
- LUAJIT=1 LUA_DIR=/usr/local LUA_INCLUDE_DIR=$LUA_DIR/include/luajit-2.1 LUA_SUFFIX=--lua-suffix=jit
3232

3333
install:

lua_cjson.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include <stdint.h>
4141
#include <string.h>
4242
#include <math.h>
43+
#include <stdint.h>
4344
#include <limits.h>
4445
#include <lua.h>
4546
#include <lauxlib.h>
@@ -179,13 +180,13 @@ typedef struct {
179180

180181
typedef struct {
181182
json_token_type_t type;
182-
int index;
183+
size_t index;
183184
union {
184185
const char *string;
185186
double number;
186187
int boolean;
187188
} value;
188-
int string_len;
189+
size_t string_len;
189190
} json_token_t;
190191

191192
static const char *char2escape[256] = {
@@ -557,6 +558,8 @@ static void json_append_string(lua_State *l, strbuf_t *json, int lindex)
557558
* This buffer is reused constantly for small strings
558559
* If there are any excess pages, they won't be hit anyway.
559560
* This gains ~5% speedup. */
561+
if (len > SIZE_MAX / 6 - 3)
562+
abort(); /* Overflow check */
560563
strbuf_ensure_empty_length(json, len * 6 + 2);
561564

562565
strbuf_append_char_unsafe(json, '\"');
@@ -848,7 +851,7 @@ static int json_encode(lua_State *l)
848851
strbuf_t local_encode_buf;
849852
strbuf_t *encode_buf;
850853
char *json;
851-
int len;
854+
size_t len;
852855

853856
luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument");
854857

strbuf.c

Lines changed: 29 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <stdlib.h>
2727
#include <stdarg.h>
2828
#include <string.h>
29+
#include <stdint.h>
2930

3031
#include "strbuf.h"
3132

@@ -38,22 +39,22 @@ static void die(const char *fmt, ...)
3839
va_end(arg);
3940
fprintf(stderr, "\n");
4041

41-
exit(-1);
42+
abort();
4243
}
4344

44-
void strbuf_init(strbuf_t *s, int len)
45+
void strbuf_init(strbuf_t *s, size_t len)
4546
{
46-
int size;
47+
size_t size;
4748

48-
if (len <= 0)
49+
if (!len)
4950
size = STRBUF_DEFAULT_SIZE;
5051
else
51-
size = len + 1; /* \0 terminator */
52-
52+
size = len + 1;
53+
if (size < len)
54+
die("Overflow, len: %zu", len);
5355
s->buf = NULL;
5456
s->size = size;
5557
s->length = 0;
56-
s->increment = STRBUF_DEFAULT_INCREMENT;
5758
s->dynamic = 0;
5859
s->reallocs = 0;
5960
s->debug = 0;
@@ -65,7 +66,7 @@ void strbuf_init(strbuf_t *s, int len)
6566
strbuf_ensure_null(s);
6667
}
6768

68-
strbuf_t *strbuf_new(int len)
69+
strbuf_t *strbuf_new(size_t len)
6970
{
7071
strbuf_t *s;
7172

@@ -81,20 +82,10 @@ strbuf_t *strbuf_new(int len)
8182
return s;
8283
}
8384

84-
void strbuf_set_increment(strbuf_t *s, int increment)
85-
{
86-
/* Increment > 0: Linear buffer growth rate
87-
* Increment < -1: Exponential buffer growth rate */
88-
if (increment == 0 || increment == -1)
89-
die("BUG: Invalid string increment");
90-
91-
s->increment = increment;
92-
}
93-
9485
static inline void debug_stats(strbuf_t *s)
9586
{
9687
if (s->debug) {
97-
fprintf(stderr, "strbuf(%lx) reallocs: %d, length: %d, size: %d\n",
88+
fprintf(stderr, "strbuf(%lx) reallocs: %d, length: %zd, size: %zd\n",
9889
(long)s, s->reallocs, s->length, s->size);
9990
}
10091
}
@@ -113,7 +104,7 @@ void strbuf_free(strbuf_t *s)
113104
free(s);
114105
}
115106

116-
char *strbuf_free_to_string(strbuf_t *s, int *len)
107+
char *strbuf_free_to_string(strbuf_t *s, size_t *len)
117108
{
118109
char *buf;
119110

@@ -131,57 +122,63 @@ char *strbuf_free_to_string(strbuf_t *s, int *len)
131122
return buf;
132123
}
133124

134-
static int calculate_new_size(strbuf_t *s, int len)
125+
static size_t calculate_new_size(strbuf_t *s, size_t len)
135126
{
136-
int reqsize, newsize;
127+
size_t reqsize, newsize;
137128

138129
if (len <= 0)
139130
die("BUG: Invalid strbuf length requested");
140131

141132
/* Ensure there is room for optional NULL termination */
142133
reqsize = len + 1;
134+
if (reqsize < len)
135+
die("Overflow, len: %zu", len);
143136

144137
/* If the user has requested to shrink the buffer, do it exactly */
145138
if (s->size > reqsize)
146139
return reqsize;
147140

148141
newsize = s->size;
149-
if (s->increment < 0) {
142+
if (reqsize >= SIZE_MAX / 2) {
143+
newsize = reqsize;
144+
} else {
150145
/* Exponential sizing */
151146
while (newsize < reqsize)
152-
newsize *= -s->increment;
153-
} else if (s->increment != 0) {
154-
/* Linear sizing */
155-
newsize = ((newsize + s->increment - 1) / s->increment) * s->increment;
147+
newsize *= 2;
156148
}
157149

150+
if (newsize < reqsize)
151+
die("BUG: strbuf length would overflow, len: %zu", len);
152+
153+
158154
return newsize;
159155
}
160156

161157

162158
/* Ensure strbuf can handle a string length bytes long (ignoring NULL
163159
* optional termination). */
164-
void strbuf_resize(strbuf_t *s, int len)
160+
void strbuf_resize(strbuf_t *s, size_t len)
165161
{
166-
int newsize;
162+
size_t newsize;
167163

168164
newsize = calculate_new_size(s, len);
169165

170166
if (s->debug > 1) {
171-
fprintf(stderr, "strbuf(%lx) resize: %d => %d\n",
167+
fprintf(stderr, "strbuf(%lx) resize: %zd => %zd\n",
172168
(long)s, s->size, newsize);
173169
}
174170

175171
s->size = newsize;
176172
s->buf = realloc(s->buf, s->size);
177173
if (!s->buf)
178-
die("Out of memory");
174+
die("Out of memory, len: %zu", len);
179175
s->reallocs++;
180176
}
181177

182178
void strbuf_append_string(strbuf_t *s, const char *str)
183179
{
184-
int space, i;
180+
int i;
181+
size_t space;
185182

186183
space = strbuf_empty_length(s);
187184

@@ -197,55 +194,6 @@ void strbuf_append_string(strbuf_t *s, const char *str)
197194
}
198195
}
199196

200-
/* strbuf_append_fmt() should only be used when an upper bound
201-
* is known for the output string. */
202-
void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...)
203-
{
204-
va_list arg;
205-
int fmt_len;
206-
207-
strbuf_ensure_empty_length(s, len);
208-
209-
va_start(arg, fmt);
210-
fmt_len = vsnprintf(s->buf + s->length, len, fmt, arg);
211-
va_end(arg);
212-
213-
if (fmt_len < 0)
214-
die("BUG: Unable to convert number"); /* This should never happen.. */
215-
216-
s->length += fmt_len;
217-
}
218-
219-
/* strbuf_append_fmt_retry() can be used when the there is no known
220-
* upper bound for the output string. */
221-
void strbuf_append_fmt_retry(strbuf_t *s, const char *fmt, ...)
222-
{
223-
va_list arg;
224-
int fmt_len, try;
225-
int empty_len;
226-
227-
/* If the first attempt to append fails, resize the buffer appropriately
228-
* and try again */
229-
for (try = 0; ; try++) {
230-
va_start(arg, fmt);
231-
/* Append the new formatted string */
232-
/* fmt_len is the length of the string required, excluding the
233-
* trailing NULL */
234-
empty_len = strbuf_empty_length(s);
235-
/* Add 1 since there is also space to store the terminating NULL. */
236-
fmt_len = vsnprintf(s->buf + s->length, empty_len + 1, fmt, arg);
237-
va_end(arg);
238-
239-
if (fmt_len <= empty_len)
240-
break; /* SUCCESS */
241-
if (try > 0)
242-
die("BUG: length of formatted string changed");
243-
244-
strbuf_resize(s, s->length + fmt_len);
245-
}
246-
247-
s->length += fmt_len;
248-
}
249197

250198
/* vi:ai et sw=4 ts=4:
251199
*/

strbuf.h

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,13 @@
3232

3333
/* Size: Total bytes allocated to *buf
3434
* Length: String length, excluding optional NULL terminator.
35-
* Increment: Allocation increments when resizing the string buffer.
3635
* Dynamic: True if created via strbuf_new()
3736
*/
3837

3938
typedef struct {
4039
char *buf;
41-
int size;
42-
int length;
43-
int increment;
40+
size_t size;
41+
size_t length;
4442
int dynamic;
4543
int reallocs;
4644
int debug;
@@ -49,33 +47,27 @@ typedef struct {
4947
#ifndef STRBUF_DEFAULT_SIZE
5048
#define STRBUF_DEFAULT_SIZE 1023
5149
#endif
52-
#ifndef STRBUF_DEFAULT_INCREMENT
53-
#define STRBUF_DEFAULT_INCREMENT -2
54-
#endif
5550

5651
/* Initialise */
57-
extern strbuf_t *strbuf_new(int len);
58-
extern void strbuf_init(strbuf_t *s, int len);
59-
extern void strbuf_set_increment(strbuf_t *s, int increment);
52+
extern strbuf_t *strbuf_new(size_t len);
53+
extern void strbuf_init(strbuf_t *s, size_t len);
6054

6155
/* Release */
6256
extern void strbuf_free(strbuf_t *s);
63-
extern char *strbuf_free_to_string(strbuf_t *s, int *len);
57+
extern char *strbuf_free_to_string(strbuf_t *s, size_t *len);
6458

6559
/* Management */
66-
extern void strbuf_resize(strbuf_t *s, int len);
67-
static int strbuf_empty_length(strbuf_t *s);
68-
static int strbuf_length(strbuf_t *s);
69-
static char *strbuf_string(strbuf_t *s, int *len);
70-
static void strbuf_ensure_empty_length(strbuf_t *s, int len);
60+
extern void strbuf_resize(strbuf_t *s, size_t len);
61+
static size_t strbuf_empty_length(strbuf_t *s);
62+
static size_t strbuf_length(strbuf_t *s);
63+
static char *strbuf_string(strbuf_t *s, size_t *len);
64+
static void strbuf_ensure_empty_length(strbuf_t *s, size_t len);
7165
static char *strbuf_empty_ptr(strbuf_t *s);
72-
static void strbuf_extend_length(strbuf_t *s, int len);
66+
static void strbuf_extend_length(strbuf_t *s, size_t len);
7367
static void strbuf_set_length(strbuf_t *s, int len);
7468

7569
/* Update */
76-
extern void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...);
77-
extern void strbuf_append_fmt_retry(strbuf_t *s, const char *format, ...);
78-
static void strbuf_append_mem(strbuf_t *s, const char *c, int len);
70+
static void strbuf_append_mem(strbuf_t *s, const char *c, size_t len);
7971
extern void strbuf_append_string(strbuf_t *s, const char *str);
8072
static void strbuf_append_char(strbuf_t *s, const char c);
8173
static void strbuf_ensure_null(strbuf_t *s);
@@ -93,12 +85,12 @@ static inline int strbuf_allocated(strbuf_t *s)
9385

9486
/* Return bytes remaining in the string buffer
9587
* Ensure there is space for a NULL terminator. */
96-
static inline int strbuf_empty_length(strbuf_t *s)
88+
static inline size_t strbuf_empty_length(strbuf_t *s)
9789
{
9890
return s->size - s->length - 1;
9991
}
10092

101-
static inline void strbuf_ensure_empty_length(strbuf_t *s, int len)
93+
static inline void strbuf_ensure_empty_length(strbuf_t *s, size_t len)
10294
{
10395
if (len > strbuf_empty_length(s))
10496
strbuf_resize(s, s->length + len);
@@ -114,12 +106,12 @@ static inline void strbuf_set_length(strbuf_t *s, int len)
114106
s->length = len;
115107
}
116108

117-
static inline void strbuf_extend_length(strbuf_t *s, int len)
109+
static inline void strbuf_extend_length(strbuf_t *s, size_t len)
118110
{
119111
s->length += len;
120112
}
121113

122-
static inline int strbuf_length(strbuf_t *s)
114+
static inline size_t strbuf_length(strbuf_t *s)
123115
{
124116
return s->length;
125117
}
@@ -135,14 +127,14 @@ static inline void strbuf_append_char_unsafe(strbuf_t *s, const char c)
135127
s->buf[s->length++] = c;
136128
}
137129

138-
static inline void strbuf_append_mem(strbuf_t *s, const char *c, int len)
130+
static inline void strbuf_append_mem(strbuf_t *s, const char *c, size_t len)
139131
{
140132
strbuf_ensure_empty_length(s, len);
141133
memcpy(s->buf + s->length, c, len);
142134
s->length += len;
143135
}
144136

145-
static inline void strbuf_append_mem_unsafe(strbuf_t *s, const char *c, int len)
137+
static inline void strbuf_append_mem_unsafe(strbuf_t *s, const char *c, size_t len)
146138
{
147139
memcpy(s->buf + s->length, c, len);
148140
s->length += len;
@@ -153,7 +145,7 @@ static inline void strbuf_ensure_null(strbuf_t *s)
153145
s->buf[s->length] = 0;
154146
}
155147

156-
static inline char *strbuf_string(strbuf_t *s, int *len)
148+
static inline char *strbuf_string(strbuf_t *s, size_t *len)
157149
{
158150
if (len)
159151
*len = s->length;

0 commit comments

Comments
 (0)