aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNRK <nrk@disroot.org>2023-01-28 18:45:13 +0600
committerWilliam Hubbs <w.d.hubbs@gmail.com>2023-04-24 19:20:19 -0500
commit0b4732520fbe50445cd05df58c7475659ee0a6f3 (patch)
treef0c85b195239d5c82d8951ef08214b43f1833b48
parentbbd3acfc678a891b9ec2b021ad9f745c34e554f7 (diff)
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 <dominique.martinet@atmark-techno.com> Bug: https://github.com/OpenRC/openrc/issues/589#issuecomment-1406588576
-rw-r--r--src/openrc/rc.c16
1 files changed, 16 insertions, 0 deletions
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