Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ PHP NEWS
(ndossche)
. Fixed bug #66095 (Hide libmagic dynamic symbols). (orlitzky)

- GD:
. imagesetstyle()/imagefilter()/imagecrop() check array argument entries
types. (David Carlier)

- Hash:
. Upgrade xxHash to 0.8.2. (timwolla)

Expand Down
5 changes: 5 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ PHP 8.6 UPGRADE NOTES
5. Changed Functions
========================================

- GD:
. imagesetstyle(), imagefilter() and imagecrop() filter their
array arguments types/values and raise a TypeError/ValueError
accordingly.

- mysqli:
. The return structure of mysqli_get_charset() no longer contains
the undocumented "comment" element. The value of "charsetnr" is
Expand Down
63 changes: 57 additions & 6 deletions ext/gd/gd.c
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,20 @@ PHP_FUNCTION(imagesetstyle)
stylearr = safe_emalloc(num_styles, sizeof(int), 0);

ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(styles), item) {
stylearr[index++] = zval_get_long(item);
bool failed = false;
ZVAL_DEREF(item);
zend_long tmp = zval_try_get_long(item, &failed);
if (failed) {
efree(stylearr);
zend_argument_type_error(2, "must only have elements of type int, %s given", zend_zval_type_name(item));
RETURN_THROWS();
}
if (ZEND_LONG_EXCEEDS_INT(tmp)) {
efree(stylearr);
zend_argument_value_error(2, "elements must be between %d and %d", INT_MIN, INT_MAX);
RETURN_THROWS();
}
stylearr[index++] = (int) tmp;
} ZEND_HASH_FOREACH_END();

gdImageSetStyle(im, stylearr, index);
Expand Down Expand Up @@ -3595,7 +3608,20 @@ static void php_image_filter_scatter(INTERNAL_FUNCTION_PARAMETERS)
colors = safe_emalloc(num_colors, sizeof(int), 0);

ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(hash_colors), color) {
*(colors + i++) = (int) zval_get_long(color);
bool failed = false;
ZVAL_DEREF(color);
zend_long tmp = zval_try_get_long(color, &failed);
if (failed) {
efree(colors);
zend_argument_type_error(5, "must be of type int, %s given", zend_zval_type_name(color));
RETURN_THROWS();
}
if (tmp < 0 || ZEND_LONG_INT_OVFL(tmp)) {
efree(colors);
zend_argument_value_error(5, "value must be between 0 and %d", INT_MAX);
RETURN_THROWS();
}
colors[i++] = (int) tmp;
} ZEND_HASH_FOREACH_END();

RETVAL_BOOL(gdImageScatterColor(im, (int)scatter_sub, (int)scatter_plus, colors, num_colors));
Expand Down Expand Up @@ -3763,6 +3789,23 @@ PHP_FUNCTION(imageantialias)
}
/* }}} */

static bool php_gd_zval_try_get_c_int(zval *tmp, const char *field, int *res) {
zend_long r;
bool failed = false;
ZVAL_DEREF(tmp);
r = zval_try_get_long(tmp, &failed);
if (failed) {
zend_argument_type_error(2, "\"%s\" key must be of type int, %s given", field, zend_zval_type_name(tmp));
return false;
}
if (UNEXPECTED(ZEND_LONG_EXCEEDS_INT(r))) {
zend_argument_value_error(2, "\"%s\" key must be between %d and %d", field, INT_MIN, INT_MAX);
return false;
}
*res = (int)r;
return true;
}

/* {{{ Crop an image using the given coordinates and size, x, y, width and height. */
PHP_FUNCTION(imagecrop)
{
Expand All @@ -3781,28 +3824,36 @@ PHP_FUNCTION(imagecrop)
im = php_gd_libgdimageptr_from_zval_p(IM);

if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "x", sizeof("x") -1)) != NULL) {
rect.x = zval_get_long(tmp);
if (!php_gd_zval_try_get_c_int(tmp, "x", &rect.x)) {
RETURN_THROWS();
}
} else {
zend_argument_value_error(2, "must have an \"x\" key");
RETURN_THROWS();
}

if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "y", sizeof("y") - 1)) != NULL) {
rect.y = zval_get_long(tmp);
if (!php_gd_zval_try_get_c_int(tmp, "y", &rect.y)) {
RETURN_THROWS();
}
} else {
zend_argument_value_error(2, "must have a \"y\" key");
RETURN_THROWS();
}

if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "width", sizeof("width") - 1)) != NULL) {
rect.width = zval_get_long(tmp);
if (!php_gd_zval_try_get_c_int(tmp, "width", &rect.width)) {
RETURN_THROWS();
}
} else {
zend_argument_value_error(2, "must have a \"width\" key");
RETURN_THROWS();
}

if ((tmp = zend_hash_str_find(Z_ARRVAL_P(z_rect), "height", sizeof("height") - 1)) != NULL) {
rect.height = zval_get_long(tmp);
if (!php_gd_zval_try_get_c_int(tmp, "height", &rect.height)) {
RETURN_THROWS();
}
} else {
zend_argument_value_error(2, "must have a \"height\" key");
RETURN_THROWS();
Expand Down
21 changes: 12 additions & 9 deletions ext/gd/tests/bug66356.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ gd
$img = imagecreatetruecolor(10, 10);

// POC #1
var_dump(imagecrop($img, array("x" => "a", "y" => 0, "width" => 10, "height" => 10)));
var_dump(imagecrop($img, array("x" => 0, "y" => 0, "width" => 10, "height" => 10)));

$arr = array("x" => "a", "y" => "12b", "width" => 10, "height" => 10);
var_dump(imagecrop($img, $arr));
$arr = array("x" => 2147483647, "y" => 2147483647, "width" => 10, "height" => 10);
try {
imagecrop($img, $arr);
} catch (\ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}
print_r($arr);

// POC #2
Expand All @@ -28,22 +32,21 @@ var_dump(imagecrop($img, array("x" => 0, "y" => 0, "width" => 65535, "height" =>
--EXPECTF--
object(GdImage)#2 (0) {
}
object(GdImage)#2 (0) {
}
imagecrop(): Argument #2 ($rectangle) overflow with "x" and "width" keys
Array
(
[x] => a
[y] => 12b
[x] => 2147483647
[y] => 2147483647
[width] => 10
[height] => 10
)

Warning: imagecrop(): %cne parameter to a memory allocation multiplication is negative or zero, failing operation gracefully
in %s on line %d
bool(false)
object(GdImage)#2 (0) {
object(GdImage)#3 (0) {
}
object(GdImage)#2 (0) {
object(GdImage)#3 (0) {
}

Warning: imagecrop(): %croduct of memory allocation multiplication would exceed INT_MAX, failing operation gracefully
Expand Down
92 changes: 92 additions & 0 deletions ext/gd/tests/gh18005.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
--TEST--
GH-18005: imagesetstyle, imagefilter, imagecrop array values type checks
--EXTENSIONS--
gd
--SKIPIF--
<?php
if (PHP_INT_SIZE != 8) die('skip this test is for 64bit platforms only');
?>
--FILE--
<?php
class A {}
$img = imagecreatetruecolor(1, 1);
try {
imagesetstyle($img, [0, new A()]);
} catch (\TypeError $e) {
echo $e->getMessage() . PHP_EOL;
}
try {
imagesetstyle($img, [0, PHP_INT_MIN]);
} catch (\ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}
try {
imagefilter($img, IMG_FILTER_SCATTER, 0, 0, [new A()]);
} catch (\TypeError $e) {
echo $e->getMessage() . PHP_EOL;
}
try {
imagefilter($img, IMG_FILTER_SCATTER, 0, 0, [-1]);
} catch (\ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}
try {
imagecrop($img, ["x" => PHP_INT_MIN, "y" => 0, "width" => 0, "height" => 0]);
} catch (\ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}
try {
imagecrop($img, ["x" => 0, "y" => PHP_INT_MIN, "width" => 0, "height" => 0]);
} catch (\ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}
try {
imagecrop($img, ["x" => 0, "y" => 0, "width" => PHP_INT_MAX, "height" => 0]);
} catch (\ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}
try {
imagecrop($img, ["x" => 0, "y" => 0, "width" => 0, "height" => PHP_INT_MAX]);
} catch (\ValueError $e) {
echo $e->getMessage() . PHP_EOL;
}

try {
imagecrop($img, ["x" => new A(), "y" => 0, "width" => 0, "height" => 0]);
} catch (\TypeError $e) {
echo $e->getMessage() . PHP_EOL;
}
try {
imagecrop($img, ["x" => 0, "y" => new A(), "width" => 0, "height" => 0]);
} catch (\TypeError $e) {
echo $e->getMessage() . PHP_EOL;
}
try {
imagecrop($img, ["x" => 0, "y" => 0, "width" => new A(), "height" => 0]);
} catch (\TypeError $e) {
echo $e->getMessage() . PHP_EOL;
}
try {
imagecrop($img, ["x" => 0, "y" => 0, "width" => 0, "height" => new A()]);
} catch (\TypeError $e) {
echo $e->getMessage() . PHP_EOL;
}

$one = 1;
var_dump(imagecrop($img, ["x" => &$one, "y" => &$one, "width" => &$one, "height" => &$one]));
?>
--EXPECTF--
imagesetstyle(): Argument #2 ($style) must only have elements of type int, A given
imagesetstyle(): Argument #2 ($style) elements must be between %i and %d
imagefilter(): Argument #5 must be of type int, A given
imagefilter(): Argument #5 value must be between 0 and 2147483647
imagecrop(): Argument #2 ($rectangle) "x" key must be between %i and %d
imagecrop(): Argument #2 ($rectangle) "y" key must be between %i and %d
imagecrop(): Argument #2 ($rectangle) "width" key must be between %i and %d
imagecrop(): Argument #2 ($rectangle) "height" key must be between %i and %d
imagecrop(): Argument #2 ($rectangle) "x" key must be of type int, A given
imagecrop(): Argument #2 ($rectangle) "y" key must be of type int, A given
imagecrop(): Argument #2 ($rectangle) "width" key must be of type int, A given
imagecrop(): Argument #2 ($rectangle) "height" key must be of type int, A given
object(GdImage)#2 (0) {
}
3 changes: 0 additions & 3 deletions ext/pcntl/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,6 @@ int main(void) {
[AC_DEFINE([HAVE_SCHED_GETCPU], [1],
[Define to 1 if the 'sched_getcpu' function is properly supported.])])

AC_CHECK_TYPE([siginfo_t], [PCNTL_CFLAGS="-DHAVE_STRUCT_SIGINFO_T"],,
[#include <signal.h>])

PHP_NEW_EXTENSION([pcntl],
[pcntl.c php_signal.c],
[$ext_shared],
Expand Down
32 changes: 8 additions & 24 deletions ext/pcntl/pcntl.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,12 +185,8 @@ ZEND_GET_MODULE(pcntl)

static void (*orig_interrupt_function)(zend_execute_data *execute_data);

#ifdef HAVE_STRUCT_SIGINFO_T
static void pcntl_signal_handler(int, siginfo_t*, void*);
static void pcntl_siginfo_to_zval(int, siginfo_t*, zval*);
#else
static void pcntl_signal_handler(int);
#endif
static void pcntl_signal_dispatch(void);
static void pcntl_signal_dispatch_tick_function(int dummy_int, void *dummy_pointer);
static void pcntl_interrupt_function(zend_execute_data *execute_data);
Expand Down Expand Up @@ -240,7 +236,7 @@ PHP_RSHUTDOWN_FUNCTION(pcntl)
/* Reset all signals to their default disposition */
ZEND_HASH_FOREACH_NUM_KEY_VAL(&PCNTL_G(php_signal_table), signo, handle) {
if (Z_TYPE_P(handle) != IS_LONG || Z_LVAL_P(handle) != (zend_long)SIG_DFL) {
php_signal(signo, (Sigfunc *)(zend_long)SIG_DFL, 0);
php_signal(signo, (Sigfunc *)(zend_long)SIG_DFL, false);
}
} ZEND_HASH_FOREACH_END();

Expand Down Expand Up @@ -835,7 +831,7 @@ PHP_FUNCTION(pcntl_signal)
zend_argument_value_error(2, "must be either SIG_DFL or SIG_IGN when an integer value is given");
RETURN_THROWS();
}
if (php_signal(signo, (Sigfunc *) Z_LVAL_P(handle), (int) restart_syscalls) == (void *)SIG_ERR) {
if (php_signal(signo, (Sigfunc *) Z_LVAL_P(handle), restart_syscalls) == (void *)SIG_ERR) {
PCNTL_G(last_error) = errno;
php_error_docref(NULL, E_WARNING, "Error assigning signal");
RETURN_FALSE;
Expand Down Expand Up @@ -1007,8 +1003,7 @@ PHP_FUNCTION(pcntl_sigprocmask)
/* }}} */
#endif

#ifdef HAVE_STRUCT_SIGINFO_T
# ifdef HAVE_SIGWAITINFO
#ifdef HAVE_SIGWAITINFO

/* {{{ Synchronously wait for queued signals */
PHP_FUNCTION(pcntl_sigwaitinfo)
Expand Down Expand Up @@ -1050,8 +1045,9 @@ PHP_FUNCTION(pcntl_sigwaitinfo)
RETURN_LONG(signal_no);
}
/* }}} */
# endif
# ifdef HAVE_SIGTIMEDWAIT
#endif

#ifdef HAVE_SIGTIMEDWAIT
/* {{{ Wait for queued signals */
PHP_FUNCTION(pcntl_sigtimedwait)
{
Expand Down Expand Up @@ -1113,7 +1109,7 @@ PHP_FUNCTION(pcntl_sigtimedwait)
RETURN_LONG(signal_no);
}
/* }}} */
# endif
#endif

static void pcntl_siginfo_to_zval(int signo, siginfo_t *siginfo, zval *user_siginfo) /* {{{ */
{
Expand Down Expand Up @@ -1183,7 +1179,6 @@ static void pcntl_siginfo_to_zval(int signo, siginfo_t *siginfo, zval *user_sigi
}
}
/* }}} */
#endif

#ifdef HAVE_GETPRIORITY
/* {{{ Get the priority of any process */
Expand Down Expand Up @@ -1325,11 +1320,7 @@ PHP_FUNCTION(pcntl_strerror)
/* }}} */

/* Our custom signal handler that calls the appropriate php_function */
#ifdef HAVE_STRUCT_SIGINFO_T
static void pcntl_signal_handler(int signo, siginfo_t *siginfo, void *context)
#else
static void pcntl_signal_handler(int signo)
#endif
{
struct php_pcntl_pending_signal *psig = PCNTL_G(spares);
if (!psig) {
Expand All @@ -1341,9 +1332,7 @@ static void pcntl_signal_handler(int signo)
psig->signo = signo;
psig->next = NULL;

#ifdef HAVE_STRUCT_SIGINFO_T
psig->siginfo = *siginfo;
#endif

/* the head check is important, as the tick handler cannot atomically clear both
* the head and tail */
Expand Down Expand Up @@ -1395,19 +1384,14 @@ void pcntl_signal_dispatch(void)
if ((handle = zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo)) != NULL) {
if (Z_TYPE_P(handle) != IS_LONG) {
ZVAL_LONG(&params[0], queue->signo);
#ifdef HAVE_STRUCT_SIGINFO_T
array_init(&params[1]);
pcntl_siginfo_to_zval(queue->signo, &queue->siginfo, &params[1]);
#else
ZVAL_NULL(&params[1]);
#endif

/* Call php signal handler - Note that we do not report errors, and we ignore the return value */
call_user_function(NULL, NULL, handle, &retval, 2, params);
zval_ptr_dtor(&retval);
#ifdef HAVE_STRUCT_SIGINFO_T
zval_ptr_dtor(&params[1]);
#endif

if (EG(exception)) {
break;
}
Expand Down
Loading