From 0b4732520fbe50445cd05df58c7475659ee0a6f3 Mon Sep 17 00:00:00 2001 From: NRK Date: Sat, 28 Jan 2023 18:45:13 +0600 Subject: rc: block SIGCHLD during pid list operations the pid list will be accessed inside the SIGCHLD signal handler. so we must ensure SIGCHLD handler doesn't get invoked while the list is at an inconsistent state making it unsafe to interact with. Co-authored-by: Dominique MARTINET Bug: https://github.com/OpenRC/openrc/issues/589#issuecomment-1406588576 --- src/openrc/rc.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/openrc/rc.c b/src/openrc/rc.c index d162b514..b6bb811b 100644 --- a/src/openrc/rc.c +++ b/src/openrc/rc.c @@ -351,16 +351,31 @@ static char *get_krunlevel(void) static void add_pid(pid_t pid) { + sigset_t sset, old; RC_PID *p = xmalloc(sizeof(*p)); p->pid = pid; + + /* this list will be accessed inside the SIGCHLD signal handler. + * so we need to ensure that the SIGCHLD handler doesn't get invoked + * while the list is at an inconsistent state. + */ + sigemptyset(&sset); + sigaddset(&sset, SIGCHLD); + sigprocmask(SIG_SETMASK, &sset, &old); LIST_INSERT_HEAD(&service_pids, p, entries); + sigprocmask(SIG_SETMASK, &old, NULL); } static void remove_pid(pid_t pid, bool inside_signal) { + sigset_t sset, old; RC_PID *p, *tmp; + /* same rationale for blocking SIGCHLD as add_pid() */ + sigemptyset(&sset); + sigaddset(&sset, SIGCHLD); + sigprocmask(SIG_SETMASK, &sset, &old); LIST_FOREACH(p, &service_pids, entries) { if (p->pid == pid) { LIST_REMOVE(p, entries); @@ -375,6 +390,7 @@ remove_pid(pid_t pid, bool inside_signal) free(p); } } + sigprocmask(SIG_SETMASK, &old, NULL); } static void -- cgit v1.2.3