#include <fcntl.h>
#include <sys/wait.h>
#include "syscall.h"
+#include "lock.h"
#include "pthread_impl.h"
#include "fdop.h"
-#include "libc.h"
struct args {
int p[2];
char *const *argv, *const *envp;
};
-void __get_handler_set(sigset_t *);
-
static int __sys_dup2(int old, int new)
{
#ifdef SYS_dup2
break;
case FDOP_DUP2:
fd = op->srcfd;
+ if (fd == p) {
+ ret = -EBADF;
+ goto fail;
+ }
if (fd != op->fd) {
if ((ret=__sys_dup2(fd, op->fd))<0)
goto fail;
__syscall(SYS_close, fd);
}
break;
+ case FDOP_CHDIR:
+ ret = __syscall(SYS_chdir, op->path);
+ if (ret<0) goto fail;
+ break;
+ case FDOP_FCHDIR:
+ ret = __syscall(SYS_fchdir, op->fd);
+ if (ret<0) goto fail;
+ break;
}
}
}
int ec=0, cs;
struct args args;
- if (pipe2(args.p, O_CLOEXEC))
- return errno;
-
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
args.path = 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;
if (!ec && res) *res = pid;
+fail:
pthread_sigmask(SIG_SETMASK, &args.oldmask, 0);
pthread_setcancelstate(cs, 0);