From 43ed08a462621f8875274a1840e8b68e56de4387 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Sun, 8 Nov 2026 07:29:28 -0500 Subject: [PATCH] ext/gd: Reject out-of-range XBM dimensions The bundled GD XBM reader parsed width and height with sscanf("%d"), whose behaviour on overflow is undefined; glibc wraps 4294967298 to 2, so imagecreatefromxbm() decoded a 2-pixel image from a file declaring a width of 4294967298. Parse the value with strtol() and accept only 1 to INT_MAX. libgd/libgd#1050 carries the same parse change upstream. --- NEWS | 4 ++++ ext/gd/libgd/gd_xbm.c | 32 +++++++++++++++++++----------- ext/gd/tests/xbm_out_of_range.phpt | 32 ++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 12 deletions(-) create mode 100644 ext/gd/tests/xbm_out_of_range.phpt diff --git a/NEWS b/NEWS index 0dd463bcdc75..620dd9a07665 100644 --- a/NEWS +++ b/NEWS @@ -18,6 +18,10 @@ PHP NEWS . Fixed bug GH-25268 (NULL php_libxml_ref_obj dereference in dom_objects_store_clone_obj when cloning Dom\Notation). (David Carlier) +- GD: + . Fixed imagecreatefromxbm() accepting XBM files with out-of-range + dimensions. (Ilia Alshanetsky) + - MBString: . Fixed stack overflow in mb_check_encoding() and mb_convert_encoding() with deeply nested arrays. (Eyüp Can Akman) diff --git a/ext/gd/libgd/gd_xbm.c b/ext/gd/libgd/gd_xbm.c index 8efb34fbb0d4..475276477983 100644 --- a/ext/gd/libgd/gd_xbm.c +++ b/ext/gd/libgd/gd_xbm.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include "gd.h" #include "gdhelpers.h" #include "gd_errors.h" @@ -34,7 +36,9 @@ gdImagePtr gdImageCreateFromXbm(FILE * fd) char fline[MAX_XBM_LINE_SIZE]; char iname[MAX_XBM_LINE_SIZE]; char *type; - int value; + char *end; + int offset; + long value; unsigned int width = 0, height = 0; int fail = 0; int max_bit = 0; @@ -52,18 +56,22 @@ gdImagePtr gdImageCreateFromXbm(FILE * fd) if (strlen(fline) == MAX_XBM_LINE_SIZE-1) { return 0; } - if (sscanf(fline, "#define %s %d", iname, &value) == 2) { - if (!(type = strrchr(iname, '_'))) { - type = iname; - } else { - type++; - } + if (sscanf(fline, "#define %s %n", iname, &offset) == 1) { + errno = 0; + value = strtol(fline + offset, &end, 10); + if (end != fline + offset && errno == 0 && value > 0 && value <= INT_MAX) { + if (!(type = strrchr(iname, '_'))) { + type = iname; + } else { + type++; + } - if (!strcmp("width", type)) { - width = (unsigned int) value; - } - if (!strcmp("height", type)) { - height = (unsigned int) value; + if (!strcmp("width", type)) { + width = (unsigned int) value; + } + if (!strcmp("height", type)) { + height = (unsigned int) value; + } } } else { if ( sscanf(fline, "static unsigned char %s = {", iname) == 1 diff --git a/ext/gd/tests/xbm_out_of_range.phpt b/ext/gd/tests/xbm_out_of_range.phpt new file mode 100644 index 000000000000..4e809d97b011 --- /dev/null +++ b/ext/gd/tests/xbm_out_of_range.phpt @@ -0,0 +1,32 @@ +--TEST-- +imagecreatefromxbm() rejects out-of-range XBM dimensions +--EXTENSIONS-- +gd +--SKIPIF-- + +--FILE-- + +--CLEAN-- + +--EXPECTF-- +4294967298 x 1 + +Warning: imagecreatefromxbm(): "%s" is not a valid XBM file in %s on line %d +bool(false) +1 x 4294967298 + +Warning: imagecreatefromxbm(): "%s" is not a valid XBM file in %s on line %d +bool(false)