about summary refs log tree commit diff
path: root/src/process
diff options
context:
space:
mode:
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);