about summary refs log tree commit diff
path: root/src/process
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2020-10-01 14:53:12 -0400
committerRich Felker <dalias@aerifal.cx>2020-10-14 20:27:12 -0400
commitb7bc966522d73e1dc420b5ee6fc7a2e78099a08c (patch)
tree56b9e575aba31d4d44f626c942641badb2dccefe /src/process
parent25ea9f712c30c32957de493d4711ee39d0bbb024 (diff)
downloadmusl-b7bc966522d73e1dc420b5ee6fc7a2e78099a08c.tar.gz
musl-b7bc966522d73e1dc420b5ee6fc7a2e78099a08c.tar.xz
musl-b7bc966522d73e1dc420b5ee6fc7a2e78099a08c.zip
fix posix_spawn interaction with fork and abort by taking lock
this change prevents the child created concurrently with abort from
seeing the SIGABRT disposition change from SIG_IGN to SIG_DFL (other
changes are not visible anyway) and prevents leaking the write end of
the child pipe to children created by fork in another thread, which
may block return of posix_spawn indefinitely if the forked child does
not exit or exec.

along with other changes, this suggests that __abort_lock should
perhaps eventually be renamed to reflect that it's becoming a broader
lock on related "process lifetime" state.
Diffstat (limited to 'src/process')
-rw-r--r--src/process/posix_spawn.c16
1 files changed, 13 insertions, 3 deletions
diff --git a/src/process/posix_spawn.c b/src/process/posix_spawn.c
index 29652197..728551b3 100644
--- a/src/process/posix_spawn.c
+++ b/src/process/posix_spawn.c
@@ -6,6 +6,7 @@
 #include <fcntl.h>
 #include <sys/wait.h>
 #include "syscall.h"
+#include "lock.h"
 #include "pthread_impl.h"
 #include "fdop.h"
 
@@ -170,9 +171,6 @@ int posix_spawn(pid_t *restrict res, const char *restrict path,
 	int ec=0, cs;
 	struct args args;
 
-	if (pipe2(args.p, O_CLOEXEC))
-		return errno;
-
 	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
 
 	args.path = path;
@@ -182,9 +180,20 @@ int posix_spawn(pid_t *restrict res, const char *restrict path,
 	args.envp = envp;
 	pthread_sigmask(SIG_BLOCK, SIGALL_SET, &args.oldmask);
 
+	/* The lock guards both against seeing a SIGABRT disposition change
+	 * by abort and against leaking the pipe fd to fork-without-exec. */
+	LOCK(__abort_lock);
+
+	if (pipe2(args.p, O_CLOEXEC)) {
+		UNLOCK(__abort_lock);
+		ec = errno;
+		goto fail;
+	}
+
 	pid = __clone(child, stack+sizeof stack,
 		CLONE_VM|CLONE_VFORK|SIGCHLD, &args);
 	close(args.p[1]);
+	UNLOCK(__abort_lock);
 
 	if (pid > 0) {
 		if (read(args.p[0], &ec, sizeof ec) != sizeof ec) ec = 0;
@@ -197,6 +206,7 @@ int posix_spawn(pid_t *restrict res, const char *restrict path,
 
 	if (!ec && res) *res = pid;
 
+fail:
 	pthread_sigmask(SIG_SETMASK, &args.oldmask, 0);
 	pthread_setcancelstate(cs, 0);