aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDominique Martinet <dominique.martinet@atmark-techno.com>2023-02-02 13:11:59 +0900
committerWilliam Hubbs <w.d.hubbs@gmail.com>2023-04-24 22:06:53 -0500
commit863e1a5c87056bf5b0c4ce6a02ecb818b0b2ba13 (patch)
tree2969f19023a7edb26e83f40562b1b81573f77705
parent0b9c3c080388476519ac3385c21518cc5a94735a (diff)
openrc-run: fix rc_parallel race in svc_exec
svc_exec waits until SIGCHLD comes in to close its input, but in rc_parallel case the SIGCHLD might be unrelated. Checking the proper pid is found in signal handler and only signaling signal_pipe the status code directly avoids this problem.
-rw-r--r--src/openrc-run/openrc-run.c37
1 files changed, 23 insertions, 14 deletions
diff --git a/src/openrc-run/openrc-run.c b/src/openrc-run/openrc-run.c
index bf64a1b3..6b28a809 100644
--- a/src/openrc-run/openrc-run.c
+++ b/src/openrc-run/openrc-run.c
@@ -107,7 +107,8 @@ static RC_STRINGLIST *deptypes_mwua; /* need+want+use+after deps for stopping */
static void
handle_signal(int sig)
{
- int serrno = errno;
+ int serrno = errno, status;
+ pid_t pid;
const char *signame = NULL;
struct winsize ws;
@@ -117,12 +118,13 @@ handle_signal(int sig)
break;
case SIGCHLD:
- if (signal_pipe[1] > -1) {
- if (write(signal_pipe[1], &sig, sizeof(sig)) == -1)
- eerror("%s: send: %s",
- service, strerror(errno));
- } else
- rc_waitpid(-1);
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+ if (signal_pipe[1] > -1 && pid == service_pid) {
+ if (write(signal_pipe[1], &status, sizeof(status)) == -1)
+ eerror("%s: send: %s",
+ service, strerror(errno));
+ }
+ }
break;
case SIGWINCH:
@@ -438,6 +440,7 @@ svc_exec(const char *arg1, const char *arg2)
if (errno != EINTR) {
eerror("%s: poll: %s",
service, strerror(errno));
+ ret = -1;
break;
}
}
@@ -448,9 +451,20 @@ svc_exec(const char *arg1, const char *arg2)
write_prefix(buffer, bytes, &prefixed);
}
- /* Only SIGCHLD signals come down this pipe */
- if (fd[0].revents & (POLLIN | POLLHUP))
+ /* signal_pipe receives service_pid's exit status */
+ if (fd[0].revents & (POLLIN | POLLHUP)) {
+ if ((s = read(signal_pipe[0], &ret, sizeof(ret))) != sizeof(ret)) {
+ eerror("%s: receive failed: %s", service,
+ s < 0 ? strerror(errno) : "short read");
+ ret = -1;
+ break;
+ }
+ ret = WEXITSTATUS(ret);
+ if (ret != 0 && errno == ECHILD)
+ /* killall5 -9 could cause this */
+ ret = 0;
break;
+ }
}
}
@@ -473,11 +487,6 @@ svc_exec(const char *arg1, const char *arg2)
master_tty = -1;
}
- ret = rc_waitpid(service_pid);
- ret = WEXITSTATUS(ret);
- if (ret != 0 && errno == ECHILD)
- /* killall5 -9 could cause this */
- ret = 0;
service_pid = 0;
return ret;