diff options
author | NRK <nrk@disroot.org> | 2023-01-28 18:45:13 +0600 |
---|---|---|
committer | William Hubbs <w.d.hubbs@gmail.com> | 2023-04-24 19:20:19 -0500 |
commit | 0b4732520fbe50445cd05df58c7475659ee0a6f3 (patch) | |
tree | f0c85b195239d5c82d8951ef08214b43f1833b48 | |
parent | bbd3acfc678a891b9ec2b021ad9f745c34e554f7 (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.c | 16 |
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 |