Skip to content

Commit f39d6da

Browse files
ctrlcctrlvsaitoha
authored andcommitted
[SECURITY] Verify LZW code fits in 12 bits before we use it
The type `unsigned short`, which is the type of the LZW code, is much larger than the max of an LZW code, causing a wild pointer. That causes an array overflow. Long term, this library should jettison this unnecessary GIF code, and use a better maintained library for it. In the meantime, however, the issue is simple enough to solve, so I've done so. Resolves CVE-2020-19668. Closes #136. Closes #7.
1 parent 3a08ee5 commit f39d6da

File tree

1 file changed

+18
-9
lines changed

1 file changed

+18
-9
lines changed

src/fromgif.c

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,8 @@ typedef struct
6969
unsigned char suffix;
7070
} gif_lzw;
7171

72-
enum {
73-
gif_lzw_max_code_size = 12
74-
};
72+
#define GIF_LZW_MAX_CODE_SIZE 12
73+
#define GIF_LZW_MAX 0xFFF // 0b1111_1111_1111
7574

7675
typedef struct
7776
{
@@ -80,7 +79,7 @@ typedef struct
8079
int flags, bgindex, ratio, transparent, eflags;
8180
unsigned char pal[256][3];
8281
unsigned char lpal[256][3];
83-
gif_lzw codes[1 << gif_lzw_max_code_size];
82+
gif_lzw codes[1 << GIF_LZW_MAX_CODE_SIZE];
8483
unsigned char *color_table;
8584
int parse, step;
8685
int lflags;
@@ -272,20 +271,25 @@ gif_init_frame(
272271
}
273272

274273

275-
static void
274+
static SIXELSTATUS
276275
gif_out_code(
277276
gif_t /* in */ *g,
278277
unsigned short /* in */ code
279278
)
280279
{
280+
if (code > GIF_LZW_MAX) {
281+
sixel_helper_set_additional_message("gif_out_code() failed; GIF file corrupt");
282+
return SIXEL_RUNTIME_ERROR;
283+
}
284+
281285
/* recurse to decode the prefixes, since the linked-list is backwards,
282286
and working backwards through an interleaved image would be nasty */
283287
if (g->codes[code].prefix >= 0) {
284288
gif_out_code(g, (unsigned short)g->codes[code].prefix);
285289
}
286290

287291
if (g->cur_y >= g->max_y) {
288-
return;
292+
return SIXEL_OK;
289293
}
290294

291295
g->out[g->cur_x + g->cur_y * g->max_x] = g->codes[code].suffix;
@@ -308,6 +312,8 @@ gif_out_code(
308312
--g->parse;
309313
}
310314
}
315+
316+
return SIXEL_OK;
311317
}
312318

313319

@@ -325,7 +331,7 @@ gif_process_raster(
325331

326332
/* LZW Minimum Code Size */
327333
lzw_cs = gif_get8(s);
328-
if (lzw_cs > gif_lzw_max_code_size) {
334+
if (lzw_cs > GIF_LZW_MAX_CODE_SIZE) {
329335
sixel_helper_set_additional_message(
330336
"Unsupported GIF (LZW code size)");
331337
status = SIXEL_RUNTIME_ERROR;
@@ -377,7 +383,7 @@ gif_process_raster(
377383
return SIXEL_OK;
378384
} else if (code <= avail) {
379385
if (oldcode >= 0) {
380-
if (avail < (1 << gif_lzw_max_code_size)) {
386+
if (avail < (1 << GIF_LZW_MAX_CODE_SIZE)) {
381387
p = &g->codes[avail++];
382388
p->prefix = (signed short) oldcode;
383389
p->first = g->codes[oldcode].first;
@@ -390,7 +396,10 @@ gif_process_raster(
390396
goto end;
391397
}
392398

393-
gif_out_code(g, (unsigned short) code);
399+
status = gif_out_code(g, (unsigned short) code);
400+
if (status != SIXEL_OK) {
401+
goto end;
402+
}
394403

395404
if ((avail & codemask) == 0 && avail <= 0x0FFF) {
396405
codesize++;

0 commit comments

Comments
 (0)