Skip to content

Commit 2cea4a3

Browse files
ext/gd: fix undefined behavior with GIFs with problematic LZW compression data
Apply the changes from libgd/libgd@9fa3abd in order to fix undefined behavior from out-of-bounds reads when creating a GIF with problematic LZW compression data.
1 parent 30ba021 commit 2cea4a3

2 files changed

Lines changed: 71 additions & 0 deletions

File tree

‎ext/gd/libgd/gd_gif_in.c‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,12 +517,20 @@ LWZReadByte_(gdIOCtx *fd, LZW_STATIC_DATA *sd, char flag, int input_code_size, i
517517
/* Bad compressed data stream */
518518
return -1;
519519
}
520+
if(code >= (1 << MAX_LWZ_BITS)) {
521+
/* Corrupted code */
522+
return -1;
523+
}
520524
*sd->sp++ = sd->table[1][code];
521525
if (code == sd->table[0][code]) {
522526
/* Oh well */
523527
}
524528
code = sd->table[0][code];
525529
}
530+
if(code >= (1 << MAX_LWZ_BITS)) {
531+
/* Corrupted code */
532+
return -1;
533+
}
526534

527535
*sd->sp++ = sd->firstcode = sd->table[1][code];
528536

‎ext/gd/tests/gif-oob.phpt‎

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
--TEST--
2+
GIF OOB array access when using code size of 12
3+
--EXTENSIONS--
4+
gd
5+
--FILE--
6+
<?php
7+
8+
$fileHeaderParts = [
9+
"signature" => "GIF",
10+
"version" => "89a",
11+
];
12+
$fileHeader = implode("", $fileHeaderParts);
13+
14+
$logicalScreenDescriptorParts = [
15+
// little-endian format
16+
"width" => "\x04\x00",
17+
"height" => "\x04\x00",
18+
// packed data: global color table flag (most significant bit),
19+
// color resolution (3 bits, only meaningful if global color table is enabled
20+
// and we don't enable it here)
21+
// sort flag (one bit, again only meaningful if global color table is enabled)
22+
// size of global color table (3 bits)
23+
"packed_info" => "\x00",
24+
"background_color_index" => "\x00",
25+
"pixel_aspect_ratio" => "\x00",
26+
];
27+
$logicalScreenDescriptor = implode("", $logicalScreenDescriptorParts);
28+
29+
$startImage = ",";
30+
31+
$imgDescParts = [
32+
// little-ending format
33+
"left" => "\x00\x00",
34+
"top" => "\x00\x00",
35+
"width" => "\x04\x00",
36+
"height" => "\x04\x00",
37+
// more packed data: local color table flag, interlace flag, sort flag,
38+
// 2 bits reserved for future use, then 3 bits for size of local color
39+
// table, which we don't have
40+
"packed_info" => "\x00",
41+
];
42+
$imgDesc = implode("", $imgDescParts);
43+
44+
$imgDataParts = [
45+
"lzw_min_code_size" => "\x0c", // 12
46+
"sub_block_num_bytes" => "\x05",
47+
// Data in the block: 3 12-bit codes, and then 4 trailing 0 bits
48+
"sub_block_bytes" => "\xff\x5f\x00\x06\x40",
49+
// end of data
50+
"end" => "\x00"
51+
];
52+
$imgData = implode("", $imgDataParts);
53+
54+
$trailer = ";";
55+
56+
$source = $fileHeader . $logicalScreenDescriptor . $startImage . $imgDesc . $imgData . $trailer;
57+
$img = imagecreatefromstring($source);
58+
var_dump($img);
59+
60+
?>
61+
--EXPECTF--
62+
object(GdImage)#%d (0) {
63+
}

0 commit comments

Comments
 (0)