1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

ext/pcntl: Reject negative values in pcntl_alarm()

internal refactorings:

- pcntl_signal_get_handler() max signals handling simplification,
 reusing the num_signals global.
- pcntl_alarm() accepts a zend_long (signed) but passes it to alarm(),
which takes an unsigned int. Negative values silently wrap to large
unsigned values, scheduling an alarm far in the future instead of
raising an error. Also reject large values above unsigned long
max value.

close GH-21282
This commit is contained in:
David Carlier
2026-02-23 21:56:02 +00:00
parent e045b881cf
commit 9b01f51701
3 changed files with 48 additions and 13 deletions

View File

@@ -105,6 +105,10 @@ PHP 8.6 UPGRADE NOTES
. Output of openssl_x509_parse() contains criticalExtensions listing all
critical certificate extensions.
- PCNTL:
. pcntl_alarm() now throws a ValueError if the seconds argument is
lower than zero or greater than platform's UINT_MAX.
- Phar:
. Phar::mungServer() now supports reference values.

View File

@@ -212,7 +212,7 @@ PHP_RINIT_FUNCTION(pcntl)
PCNTL_G(last_error) = 0;
PCNTL_G(num_signals) = NSIG;
#ifdef SIGRTMAX
/* At least FreeBSD reports an incorrecrt NSIG that does not include realtime signals.
/* At least FreeBSD reports an incorrect NSIG that does not include realtime signals.
* As SIGRTMAX may be a dynamic value, adjust the value in INIT. */
if (NSIG < SIGRTMAX + 1) {
PCNTL_G(num_signals) = SIGRTMAX + 1;
@@ -314,6 +314,11 @@ PHP_FUNCTION(pcntl_alarm)
Z_PARAM_LONG(seconds);
ZEND_PARSE_PARAMETERS_END();
if (seconds < 0 || seconds > UINT_MAX) {
zend_argument_value_error(1, "must be between 0 and %u", UINT_MAX);
RETURN_THROWS();
}
RETURN_LONG((zend_long) alarm(seconds));
}
/* }}} */
@@ -870,17 +875,8 @@ PHP_FUNCTION(pcntl_signal_get_handler)
Z_PARAM_LONG(signo)
ZEND_PARSE_PARAMETERS_END();
// note: max signal on mac is SIGUSR2 (31), no real time signals.
int sigmax = NSIG - 1;
#if defined(SIGRTMAX)
// oddily enough, NSIG on freebsd reports only 32 whereas SIGRTMIN starts at 65.
if (sigmax < SIGRTMAX) {
sigmax = SIGRTMAX;
}
#endif
if (signo < 1 || signo > sigmax) {
zend_argument_value_error(1, "must be between 1 and %d", sigmax);
if (signo < 1 || signo >= PCNTL_G(num_signals)) {
zend_argument_value_error(1, "must be between 1 and %d", PCNTL_G(num_signals) - 1);
RETURN_THROWS();
}
@@ -1153,7 +1149,7 @@ static void pcntl_siginfo_to_zval(int signo, siginfo_t *siginfo, zval *user_sigi
case SIGFPE:
case SIGSEGV:
case SIGBUS:
add_assoc_double_ex(user_siginfo, "addr", sizeof("addr")-1, (zend_long)siginfo->si_addr);
add_assoc_long_ex(user_siginfo, "addr", sizeof("addr")-1, (zend_long)siginfo->si_addr);
break;
#if defined(SIGPOLL) && !defined(__CYGWIN__)
case SIGPOLL:

View File

@@ -0,0 +1,35 @@
--TEST--
pcntl_alarm() rejects invalid values
--EXTENSIONS--
pcntl
--SKIPIF--
<?php if (PHP_INT_SIZE < 8) die("skip 64-bit only"); ?>
--FILE--
<?php
try {
pcntl_alarm(-1);
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
try {
pcntl_alarm(PHP_INT_MIN);
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
try {
pcntl_alarm(PHP_INT_MAX);
} catch (\ValueError $e) {
echo $e->getMessage() . \PHP_EOL;
}
var_dump(pcntl_alarm(0));
?>
--EXPECTF--
pcntl_alarm(): Argument #1 ($seconds) must be between 0 and %d
pcntl_alarm(): Argument #1 ($seconds) must be between 0 and %d
pcntl_alarm(): Argument #1 ($seconds) must be between 0 and %d
int(0)