]> granicus.if.org Git - php/commitdiff
Fixed bug #75111 (Memory disclosure or DoS via crafted .bmp image)
authorChristoph M. Becker <cmbecker69@gmx.de>
Thu, 24 Aug 2017 10:39:45 +0000 (12:39 +0200)
committerChristoph M. Becker <cmbecker69@gmx.de>
Thu, 24 Aug 2017 12:07:10 +0000 (14:07 +0200)
Crafted BMP images can cause dynamicSeek() to be called with a negative
position which must not be allowed, since dynamicSeek() works like
fseek() in SEEK_SET mode. We solve this by bailing out if `pos` is
negative, and let the image reading fail gracefully.

NEWS
ext/gd/libgd/gd_bmp.c
ext/gd/libgd/gd_io_dp.c
ext/gd/tests/bug75111.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 312477e151adf8f7f12675860eadcf0df038d1ba..a8e4e9467529892645596fbcf376fcbe87de4e44 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,9 @@ PHP                                                                        NEWS
 - CURL:
   . Fixed bug #75093 (OpenSSL support not detected). (Remi)
 
+- GD:
+  . Fixed bug #75111 (Memory disclosure or DoS via crafted .bmp image). (cmb)
+
 - PCRE:
   . Fixed bug #75089 (preg_grep() is not reporting PREG_BAD_UTF8_ERROR after
     first input string). (Dmitry)
index 93a9d616012f029bb7f54d2a71a41b42618d120a..8af8751299c8de1a01caa7325f29ce71b1be5455 100644 (file)
@@ -711,7 +711,9 @@ static int bmp_read_direct(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, b
        /* There is a chance the data isn't until later, would be wierd but it is possible */
        if (gdTell(infile) != header->off) {
                /* Should make sure we don't seek past the file size */
-               gdSeek(infile, header->off);
+               if (!gdSeek(infile, header->off)) {
+                       return 1;
+               }
        }
 
        /* The line must be divisible by 4, else its padded with NULLs */
@@ -806,7 +808,9 @@ static int bmp_read_1bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp
        /* There is a chance the data isn't until later, would be wierd but it is possible */
        if (gdTell(infile) != header->off) {
                /* Should make sure we don't seek past the file size */
-               gdSeek(infile, header->off);
+               if (!gdSeek(infile, header->off)) {
+                       return 1;
+               }
        }
 
        /* The line must be divisible by 4, else its padded with NULLs */
@@ -874,7 +878,9 @@ static int bmp_read_4bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp
        /* There is a chance the data isn't until later, would be wierd but it is possible */
        if (gdTell(infile) != header->off) {
                /* Should make sure we don't seek past the file size */
-               gdSeek(infile, header->off);
+               if (!gdSeek(infile, header->off)) {
+                       return 1;
+               }
        }
 
        /* The line must be divisible by 4, else its padded with NULLs */
@@ -959,7 +965,9 @@ static int bmp_read_8bit(gdImagePtr im, gdIOCtxPtr infile, bmp_info_t *info, bmp
        /* There is a chance the data isn't until later, would be wierd but it is possible */
        if (gdTell(infile) != header->off) {
                /* Should make sure we don't seek past the file size */
-               gdSeek(infile, header->off);
+               if (!gdSeek(infile, header->off)) {
+                       return 1;
+               }
        }
 
        /* The line must be divisible by 4, else its padded with NULLs */
index 4dcedde8ccbc4afa7825d0abdffe4ab948bebe1a..81b988157fb20d2f1c8643793df050a936bf7d59 100644 (file)
@@ -152,6 +152,9 @@ static int dynamicSeek (struct gdIOCtx *ctx, const int pos)
        dynamicPtr *dp;
        dpIOCtx *dctx;
 
+       if (pos < 0) {
+               return FALSE;
+       }
        dctx = (dpIOCtx *) ctx;
        dp = dctx->dp;
 
diff --git a/ext/gd/tests/bug75111.phpt b/ext/gd/tests/bug75111.phpt
new file mode 100644 (file)
index 0000000..3950799
--- /dev/null
@@ -0,0 +1,25 @@
+--TEST--
+Bug #75111 (Memory disclosure or DoS via crafted .bmp image)
+--SKIPIF--
+<?php
+if (!extension_loaded('gd')) die('skip gd extension not available');
+?>
+--FILE--
+<?php
+// craft BMP image
+$str  = hex2bin("424D3603000000000000");
+$str .= pack("V", -0x120000);   // offset of image data
+$str .= pack("V", 40);          // length of header
+$str .= pack("V", 256);         // width
+$str .= pack("V", 256);         // height
+$str .= hex2bin("01001800000000000000000000000000000000000000000000000000");
+
+var_dump(imagecreatefromstring($str));
+?>
+===DONE===
+--EXPECTF--
+Warning: imagecreatefromstring(): Passed data is not in 'BMP' format in %s on line %d
+
+Warning: imagecreatefromstring(): Couldn't create GD Image Stream out of Data in %s on line %d
+bool(false)
+===DONE===