php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Return to Bug #75111
Patch fix-75111 revision 2017-08-24 10:53 UTC by cmb@php.net

Patch fix-75111 for GD related Bug #75111

Patch version 2017-08-24 10:53 UTC

Return to Bug #75111 | Download this patch
Patch Revisions:

Developer: cmb@php.net

From 2813fb1bf72cd106229518d05e57e55ad056017a Mon Sep 17 00:00:00 2001
From: "Christoph M. Becker" <cmbecker69@gmx.de>
Date: Thu, 24 Aug 2017 12:39:45 +0200
Subject: [PATCH] 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.
---
 ext/gd/libgd/gd_bmp.c      | 16 ++++++++++++----
 ext/gd/libgd/gd_io_dp.c    |  3 +++
 ext/gd/tests/bug75111.phpt | 25 +++++++++++++++++++++++++
 3 files changed, 40 insertions(+), 4 deletions(-)
 create mode 100644 ext/gd/tests/bug75111.phpt

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===
-- 
2.14.1.windows.1

 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Mar 28 16:01:29 2024 UTC