summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph M. Becker <cmbecker69@gmx.de>2017-08-24 12:39:45 +0200
committerChristoph M. Becker <cmbecker69@gmx.de>2017-08-24 14:07:10 +0200
commit5cd348c1d606b890abae076a38e47effcfda79be (patch)
tree5e5bd768ef68311a08d1b7fe49fbc8c441840e1d
parentcf6f25bd37f2dc36f1443f07406a89040c50db65 (diff)
downloadphp-git-5cd348c1d606b890abae076a38e47effcfda79be.tar.gz
Fixed bug #75111 (Memory disclosure or DoS via crafted .bmp image)
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.
-rw-r--r--NEWS3
-rw-r--r--ext/gd/libgd/gd_bmp.c16
-rw-r--r--ext/gd/libgd/gd_io_dp.c3
-rw-r--r--ext/gd/tests/bug75111.phpt25
4 files changed, 43 insertions, 4 deletions
diff --git a/NEWS b/NEWS
index 312477e151..a8e4e94675 100644
--- 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)
diff --git a/ext/gd/libgd/gd_bmp.c b/ext/gd/libgd/gd_bmp.c
index 93a9d61601..8af8751299 100644
--- a/ext/gd/libgd/gd_bmp.c
+++ b/ext/gd/libgd/gd_bmp.c
@@ -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 */
diff --git a/ext/gd/libgd/gd_io_dp.c b/ext/gd/libgd/gd_io_dp.c
index 4dcedde8cc..81b988157f 100644
--- a/ext/gd/libgd/gd_io_dp.c
+++ b/ext/gd/libgd/gd_io_dp.c
@@ -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
index 0000000000..3950799730
--- /dev/null
+++ b/ext/gd/tests/bug75111.phpt
@@ -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===