proc: Set close-on-exec flag on fork pipes
This commit is contained in:
parent
26ce16f1db
commit
4fd02c829a
@ -2,6 +2,14 @@
|
|||||||
|
|
||||||
extern char** environ;
|
extern char** environ;
|
||||||
|
|
||||||
|
int
|
||||||
|
close_exec_pipe(int fd[2]) {
|
||||||
|
if (pipe(fd) < 0) return -1;
|
||||||
|
if (fcntl(fd[0], F_SETFD, FD_CLOEXEC) < 0) return -1;
|
||||||
|
if (fcntl(fd[1], F_SETFD, FD_CLOEXEC) < 0) return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
fork_exec(char *argv0, char **argv, int size,
|
fork_exec(char *argv0, char **argv, int size,
|
||||||
mach_port_name_t *task,
|
mach_port_name_t *task,
|
||||||
@ -9,23 +17,23 @@ fork_exec(char *argv0, char **argv, int size,
|
|||||||
mach_port_t *exception_port,
|
mach_port_t *exception_port,
|
||||||
mach_port_t *notification_port)
|
mach_port_t *notification_port)
|
||||||
{
|
{
|
||||||
// In order to call PT_SIGEXC below, we must ensure that we have acquired the mach task first.
|
// Since we're using mach exceptions instead of signals,
|
||||||
// We facilitate this by creating a pipe and using it to let the forked process know that we've
|
// we need to coordinate between parent and child via pipes
|
||||||
// finishing acquiring the mach task, and it can go ahead with the calls to PT_TRACE_ME and PT_SIGEXC.
|
// to ensure that the parent has set the exception ports on
|
||||||
|
// the child task before it execs.
|
||||||
int fd[2];
|
int fd[2];
|
||||||
if (pipe(fd) < 0) return -1;
|
if (close_exec_pipe(fd) < 0) return -1;
|
||||||
|
|
||||||
// Create another pipe so that we know when we're about to exec. This ensures that control only returns
|
// Create another pipe to signal the parent on exec.
|
||||||
// back to Go-land when we call exec, effectively eliminating a race condition between launching the new
|
int efd[2];
|
||||||
// process and trying to read its memory.
|
if (close_exec_pipe(efd) < 0) return -1;
|
||||||
int wfd[2];
|
|
||||||
if (pipe(wfd) < 0) return -1;
|
|
||||||
|
|
||||||
kern_return_t kret;
|
kern_return_t kret;
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
if (pid > 0) {
|
if (pid > 0) {
|
||||||
// In parent.
|
// In parent.
|
||||||
close(fd[0]);
|
close(fd[0]);
|
||||||
|
close(efd[1]);
|
||||||
kret = acquire_mach_task(pid, task, port_set, exception_port, notification_port);
|
kret = acquire_mach_task(pid, task, port_set, exception_port, notification_port);
|
||||||
if (kret != KERN_SUCCESS) return -1;
|
if (kret != KERN_SUCCESS) return -1;
|
||||||
|
|
||||||
@ -33,10 +41,14 @@ fork_exec(char *argv0, char **argv, int size,
|
|||||||
write(fd[1], &msg, 1);
|
write(fd[1], &msg, 1);
|
||||||
close(fd[1]);
|
close(fd[1]);
|
||||||
|
|
||||||
char w;
|
char w;
|
||||||
read(wfd[0], &w, 1);
|
size_t n = read(efd[0], &w, 1);
|
||||||
close(wfd[0]);
|
close(efd[0]);
|
||||||
|
if (n != 0) {
|
||||||
|
// Child died, reap it.
|
||||||
|
waitpid(pid, NULL, 0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,13 +76,14 @@ fork_exec(char *argv0, char **argv, int size,
|
|||||||
pret = ptrace(PT_SIGEXC, 0, 0, 0);
|
pret = ptrace(PT_SIGEXC, 0, 0, 0);
|
||||||
if (pret != 0 && errno != 0) return -errno;
|
if (pret != 0 && errno != 0) return -errno;
|
||||||
|
|
||||||
char msg = 'd';
|
|
||||||
write(wfd[1], &msg, 1);
|
|
||||||
close(wfd[1]);
|
|
||||||
|
|
||||||
// Create the child process.
|
// Create the child process.
|
||||||
execve(argv0, argv, environ);
|
execve(argv0, argv, environ);
|
||||||
|
|
||||||
// We should never reach here, but if we did something went wrong.
|
// We should never reach here, but if we did something went wrong.
|
||||||
|
// Write a message to parent to alert that exec failed.
|
||||||
|
char msg = 'd';
|
||||||
|
write(efd[1], &msg, 1);
|
||||||
|
close(efd[1]);
|
||||||
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <sys/ptrace.h>
|
#include <sys/ptrace.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
int
|
int
|
||||||
fork_exec(char *, char **, int, mach_port_name_t*, mach_port_t*, mach_port_t*, mach_port_t*);
|
fork_exec(char *, char **, int, mach_port_name_t*, mach_port_t*, mach_port_t*, mach_port_t*);
|
||||||
|
Loading…
Reference in New Issue
Block a user