diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/process/posix_spawn.c | 13 | ||||
| -rw-r--r-- | src/process/system.c | 65 | ||||
| -rw-r--r-- | src/stdio/popen.c | 68 | ||||
| -rw-r--r-- | src/unistd/pipe2.c | 20 | 
4 files changed, 110 insertions, 56 deletions
| diff --git a/src/process/posix_spawn.c b/src/process/posix_spawn.c index 8a6ff6db..e8557487 100644 --- a/src/process/posix_spawn.c +++ b/src/process/posix_spawn.c @@ -4,6 +4,7 @@  #include <stdint.h>  #include <fcntl.h>  #include "syscall.h" +#include "pthread_impl.h"  #include "fdop.h"  #include "libc.h" @@ -30,7 +31,7 @@ int __posix_spawnx(pid_t *restrict res, const char *restrict path,  	if (!attr) attr = &dummy_attr; -	sigprocmask(SIG_BLOCK, (void *)(uint64_t []){-1}, &oldmask); +	sigprocmask(SIG_BLOCK, SIGALL_SET, &oldmask);  	__acquire_ptc();  	pid = __vfork(); @@ -43,14 +44,14 @@ int __posix_spawnx(pid_t *restrict res, const char *restrict path,  		return 0;  	} -	for (i=1; i<=64; i++) { +	for (i=1; i<=8*__SYSCALL_SSLEN; i++) {  		struct sigaction sa; -		sigaction(i, 0, &sa); -		if (sa.sa_handler!=SIG_IGN || +		__libc_sigaction(i, 0, &sa); +		if (sa.sa_handler!=SIG_DFL && (sa.sa_handler!=SIG_IGN ||  		    ((attr->__flags & POSIX_SPAWN_SETSIGDEF) -		     && sigismember(&attr->__def, i) )) { +		     && sigismember(&attr->__def, i) ))) {  			sa.sa_handler = SIG_DFL; -			sigaction(i, &sa, 0); +			__libc_sigaction(i, &sa, 0);  		}  	} diff --git a/src/process/system.c b/src/process/system.c index 0f1c07b5..c8f26008 100644 --- a/src/process/system.c +++ b/src/process/system.c @@ -3,43 +3,62 @@  #include <signal.h>  #include <sys/wait.h>  #include <errno.h> +#include "pthread_impl.h" +#include "libc.h" + +static void dummy_0() +{ +} +weak_alias(dummy_0, __acquire_ptc); +weak_alias(dummy_0, __release_ptc); + +pid_t __vfork(void);  int system(const char *cmd)  {  	pid_t pid; -	sigset_t old, new; -	struct sigaction sa, oldint, oldquit; -	int status; +	sigset_t old; +	struct sigaction sa = { .sa_handler = SIG_IGN }, oldint, oldquit; +	int status = -1, i;  	if (!cmd) return 1; -	sa.sa_handler = SIG_IGN; -	sigemptyset(&sa.sa_mask); -	sa.sa_flags = 0; -  	sigaction(SIGINT, &sa, &oldint);  	sigaction(SIGQUIT, &sa, &oldquit); -	sigaddset(&sa.sa_mask, SIGCHLD); -	sigprocmask(SIG_BLOCK, &new, &old); +	sigprocmask(SIG_BLOCK, SIGALL_SET, &old); + +	__acquire_ptc(); +	pid = __vfork(); +	__release_ptc(); -	pid = fork(); -	if (pid <= 0) { +	if (pid > 0) { +		sigset_t new = old; +		sigaddset(&new, SIGCHLD); +		sigprocmask(SIG_BLOCK, &new, 0); +		while (waitpid(pid, &status, 0) && errno == EINTR); +	} + +	if (pid) {  		sigaction(SIGINT, &oldint, NULL);  		sigaction(SIGQUIT, &oldquit, NULL);  		sigprocmask(SIG_SETMASK, &old, NULL); -		if (pid == 0) { -			execl("/bin/sh", "sh", "-c", cmd, (char *)0); -			_exit(127); -		} -		return -1; +		return status;  	} -	while (waitpid(pid, &status, 0) == -1) -		if (errno != EINTR) { -			status = -1; -			break; + +	/* Before we can unblock signals in the child, all signal +	 * handlers must be eliminated -- even implementation-internal +	 * ones. Otherwise, a signal handler could run in the child +	 * and clobber the parent's memory (due to vfork). */ +	for (i=1; i<=8*__SYSCALL_SSLEN; i++) { +		struct sigaction sa; +		__libc_sigaction(i, 0, &sa); +		if (sa.sa_handler!=SIG_IGN && sa.sa_handler!=SIG_DFL) { +			sa.sa_handler = SIG_DFL; +			__libc_sigaction(i, &sa, 0);  		} -	sigaction(SIGINT, &oldint, NULL); -	sigaction(SIGQUIT, &oldquit, NULL); +	} +  	sigprocmask(SIG_SETMASK, &old, NULL); -	return status; +	execl("/bin/sh", "sh", "-c", cmd, (char *)0); +	_exit(127);  } diff --git a/src/stdio/popen.c b/src/stdio/popen.c index 4f9d6e9e..0c9f24e3 100644 --- a/src/stdio/popen.c +++ b/src/stdio/popen.c @@ -1,18 +1,22 @@ +#include <fcntl.h>  #include "stdio_impl.h" +#include "pthread_impl.h"  #include "syscall.h" -static inline void nc_close(int fd) +static void dummy_0()  { -	__syscall(SYS_close, fd);  } -#define close(x) nc_close(x) +weak_alias(dummy_0, __acquire_ptc); +weak_alias(dummy_0, __release_ptc); + +pid_t __vfork(void);  FILE *popen(const char *cmd, const char *mode)  { -	int p[2]; -	int op; +	int p[2], op, i;  	pid_t pid;  	FILE *f; +	sigset_t old;  	const char *modes = "rw", *mi = strchr(modes, *mode);  	if (mi) { @@ -22,29 +26,45 @@ FILE *popen(const char *cmd, const char *mode)  		return 0;  	} -	if (pipe(p)) return NULL; +	if (pipe2(p, O_CLOEXEC)) return NULL;  	f = fdopen(p[op], mode);  	if (!f) { -		close(p[0]); -		close(p[1]); +		__syscall(SYS_close, p[0]); +		__syscall(SYS_close, p[1]);  		return NULL;  	} + +	sigprocmask(SIG_BLOCK, SIGALL_SET, &old); -	pid = fork(); -	switch (pid) { -	case -1: -		fclose(f); -		close(p[0]); -		close(p[1]); -		return NULL; -	case 0: -		if (dup2(p[1-op], 1-op) < 0) _exit(127); -		if (p[0] != 1-op) close(p[0]); -		if (p[1] != 1-op) close(p[1]); -		execl("/bin/sh", "sh", "-c", cmd, (char *)0); -		_exit(127); +	__acquire_ptc(); +	pid = __vfork(); +	__release_ptc(); + +	if (pid) { +		__syscall(SYS_close, p[1-op]); +		sigprocmask(SIG_BLOCK, SIGALL_SET, &old); +		if (pid < 0) { +			fclose(f); +			return 0; +		} +		f->pipe_pid = pid; +		return f; +	} + +	/* See notes in system.c for why this is needed. */ +	for (i=1; i<=8*__SYSCALL_SSLEN; i++) { +		struct sigaction sa; +		__libc_sigaction(i, 0, &sa); +		if (sa.sa_handler!=SIG_IGN && sa.sa_handler!=SIG_DFL) { +			sa.sa_handler = SIG_DFL; +			__libc_sigaction(i, &sa, 0); +		}  	} -	close(p[1-op]); -	f->pipe_pid = pid; -	return f; +	if (dup2(p[1-op], 1-op) < 0) _exit(127); +	fcntl(1-op, F_SETFD, 0); +	if (p[0] != 1-op) __syscall(SYS_close, p[0]); +	if (p[1] != 1-op) __syscall(SYS_close, p[1]); +	sigprocmask(SIG_SETMASK, &old, 0); +	execl("/bin/sh", "sh", "-c", cmd, (char *)0); +	_exit(127);  } diff --git a/src/unistd/pipe2.c b/src/unistd/pipe2.c index 83282bb9..04e0c128 100644 --- a/src/unistd/pipe2.c +++ b/src/unistd/pipe2.c @@ -1,8 +1,22 @@ -#define _GNU_SOURCE  #include <unistd.h> +#include <errno.h> +#include <fcntl.h>  #include "syscall.h" -int pipe2(int fd[2], int flg) +int pipe2(int fd[2], int flag)  { -	return syscall(SYS_pipe2, fd, flg); +	if (!flag) return syscall(SYS_pipe, fd); +	int ret = __syscall(SYS_pipe2, fd, flag); +	if (ret != -ENOSYS) return __syscall_ret(ret); +	ret = syscall(SYS_pipe, fd); +	if (ret) return __syscall_ret(ret); +	if (flag & O_CLOEXEC) { +		fcntl(fd[0], F_SETFD, FD_CLOEXEC); +		fcntl(fd[1], F_SETFD, FD_CLOEXEC); +	} +	if (flag & O_NONBLOCK) { +		fcntl(fd[0], F_SETFL, fcntl(fd[0], F_GETFL) | O_NONBLOCK); +		fcntl(fd[1], F_SETFL, fcntl(fd[1], F_GETFL) | O_NONBLOCK); +	} +	return 0;  } | 
