Fix use of uninitialized memory in pcntl SIGCHLD handling

psig needs to stay the tail, so that we don't get a dangling element on the end.

Closes GH-11536
This commit is contained in:
Ilija Tovilo 2023-06-26 11:13:40 +02:00
parent 8ec5a10916
commit 003cf9da78
No known key found for this signature in database
GPG key ID: A4F5D403F118200A
2 changed files with 17 additions and 13 deletions

View file

@ -1338,15 +1338,13 @@ static void pcntl_signal_handler(int signo, siginfo_t *siginfo, void *context)
static void pcntl_signal_handler(int signo) static void pcntl_signal_handler(int signo)
#endif #endif
{ {
struct php_pcntl_pending_signal *psig; struct php_pcntl_pending_signal *psig_first = PCNTL_G(spares);
if (!psig_first) {
psig = PCNTL_G(spares);
if (!psig) {
/* oops, too many signals for us to track, so we'll forget about this one */ /* oops, too many signals for us to track, so we'll forget about this one */
return; return;
} }
struct php_pcntl_pending_signal *psig_first = psig; struct php_pcntl_pending_signal *psig = NULL;
/* Standard signals may be merged into a single one. /* Standard signals may be merged into a single one.
* POSIX specifies that SIGCHLD has the si_pid field (https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html), * POSIX specifies that SIGCHLD has the si_pid field (https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html),
@ -1365,13 +1363,14 @@ static void pcntl_signal_handler(int signo)
pid = waitpid(WAIT_ANY, &status, WNOHANG | WUNTRACED); pid = waitpid(WAIT_ANY, &status, WNOHANG | WUNTRACED);
} while (pid <= 0 && errno == EINTR); } while (pid <= 0 && errno == EINTR);
if (pid <= 0) { if (pid <= 0) {
if (UNEXPECTED(psig == psig_first)) { if (UNEXPECTED(!psig)) {
/* Don't handle multiple, revert back to the single signal handling. */ /* The child might've been consumed by another thread and will be handled there. */
goto single_signal; return;
} }
break; break;
} }
psig = psig ? psig->next : psig_first;
psig->signo = signo; psig->signo = signo;
#ifdef HAVE_STRUCT_SIGINFO_T #ifdef HAVE_STRUCT_SIGINFO_T
@ -1379,14 +1378,12 @@ static void pcntl_signal_handler(int signo)
psig->siginfo.si_pid = pid; psig->siginfo.si_pid = pid;
#endif #endif
if (EXPECTED(psig->next)) { if (UNEXPECTED(!psig->next)) {
psig = psig->next;
} else {
break; break;
} }
} }
} else { } else {
single_signal:; psig = psig_first;
psig->signo = signo; psig->signo = signo;
#ifdef HAVE_STRUCT_SIGINFO_T #ifdef HAVE_STRUCT_SIGINFO_T

View file

@ -14,10 +14,11 @@ $processes = [];
pcntl_async_signals(true); pcntl_async_signals(true);
pcntl_signal(SIGCHLD, function($sig, $info) use (&$processes) { pcntl_signal(SIGCHLD, function($sig, $info) use (&$processes) {
echo "SIGCHLD\n";
unset($processes[$info['pid']]); unset($processes[$info['pid']]);
}, false); }, false);
foreach (range(0, 5) as $i) { for ($i = 0; $i <= 5; $i++) {
$process = proc_open('echo $$ > /dev/null', [], $pipes); $process = proc_open('echo $$ > /dev/null', [], $pipes);
$pid = proc_get_status($process)['pid']; $pid = proc_get_status($process)['pid'];
$processes[$pid] = $process; $processes[$pid] = $process;
@ -32,4 +33,10 @@ while (!empty($processes) && $iters > 0) {
var_dump(empty($processes)); var_dump(empty($processes));
?> ?>
--EXPECT-- --EXPECT--
SIGCHLD
SIGCHLD
SIGCHLD
SIGCHLD
SIGCHLD
SIGCHLD
bool(true) bool(true)