From 5cd348c1d606b890abae076a38e47effcfda79be Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" 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. --- NEWS | 3 +++ ext/gd/libgd/gd_bmp.c | 16 ++++++++++++---- ext/gd/libgd/gd_io_dp.c | 3 +++ ext/gd/tests/bug75111.phpt | 25 +++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 ext/gd/tests/bug75111.phpt 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-- + +--FILE-- + +===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.50.1