Fix GH-8517: FPM child pointer can be potentially uninitialized

There might be a moment when the child log event is executed after
freeing a child. That could possibly happen if the child output is
triggered at the same as the terminating of the child. Then the output
event could be potentially processed after the terminating event which
would cause this kind of issue.

The issue might got more visible after introducing the log_stream on
a child because it is more likely that this cannot be dereferenced
after free. However it is very hard to reproduce this issue so there
is no test for this.

The fix basically prevents passing a child pointer and instead passes
the child PID and then looks the child up by the PID when it is being
processed. This is obviously slower but it is a safe way to do it and
the slow down should not be hopefully visible in a way that it would
overload a master process.
This commit is contained in:
Jakub Zelenka 2022-08-28 14:58:42 +01:00
parent 1767f32cb6
commit c9c1934ff0
No known key found for this signature in database
GPG Key ID: 1C0779DC5C0A9DE4
4 changed files with 12 additions and 6 deletions

2
NEWS
View File

@ -15,6 +15,8 @@ PHP NEWS
#66694). (Petr Sumbera)
. Fixed bug #68207 (Setting fastcgi.error_header can result in a WARNING).
(Jakub Zelenka)
. Fixed bug GH-8517 (Random crash of FPM master process in
fpm_stdio_child_said). (Jakub Zelenka)
- MBString:
. Fixed bug GH-9535 (The behavior of mb_strcut in mbstring has been changed in

View File

@ -120,7 +120,7 @@ static void fpm_child_unlink(struct fpm_child_s *child) /* {{{ */
}
/* }}} */
static struct fpm_child_s *fpm_child_find(pid_t pid) /* {{{ */
struct fpm_child_s *fpm_child_find(pid_t pid) /* {{{ */
{
struct fpm_worker_pool_s *wp;
struct fpm_child_s *child = 0;

View File

@ -10,13 +10,14 @@
#include "fpm_events.h"
#include "zlog.h"
struct fpm_child_s;
int fpm_children_create_initial(struct fpm_worker_pool_s *wp);
int fpm_children_free(struct fpm_child_s *child);
void fpm_children_bury(void);
int fpm_children_init_main(void);
int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop, int nb_to_spawn, int is_debug);
struct fpm_child_s;
struct fpm_child_s *fpm_child_find(pid_t pid);
struct fpm_child_s {
struct fpm_child_s *prev, *next;

View File

@ -181,7 +181,10 @@ static void fpm_stdio_child_said(struct fpm_event_s *ev, short which, void *arg)
if (!arg) {
return;
}
child = (struct fpm_child_s *)arg;
child = fpm_child_find((intptr_t) arg);
if (!child) {
return;
}
is_stdout = (fd == child->fd_stdout);
if (is_stdout) {
@ -327,10 +330,10 @@ int fpm_stdio_parent_use_pipes(struct fpm_child_s *child) /* {{{ */
child->fd_stdout = fd_stdout[0];
child->fd_stderr = fd_stderr[0];
fpm_event_set(&child->ev_stdout, child->fd_stdout, FPM_EV_READ, fpm_stdio_child_said, child);
fpm_event_set(&child->ev_stdout, child->fd_stdout, FPM_EV_READ, fpm_stdio_child_said, (void *) (intptr_t) child->pid);
fpm_event_add(&child->ev_stdout, 0);
fpm_event_set(&child->ev_stderr, child->fd_stderr, FPM_EV_READ, fpm_stdio_child_said, child);
fpm_event_set(&child->ev_stderr, child->fd_stderr, FPM_EV_READ, fpm_stdio_child_said, (void *) (intptr_t) child->pid);
fpm_event_add(&child->ev_stderr, 0);
return 0;
}