exec_darwin.c 1.9 KB
Newer Older
1 2
#include "exec_darwin.h"

3 4
extern char** environ;

5
int
6
fork_exec(char *argv0, char **argv, int size,
7 8 9 10 11
		mach_port_name_t *task,
		mach_port_t *port_set,
		mach_port_t *exception_port,
		mach_port_t *notification_port)
{
12 13 14
	// In order to call PT_SIGEXC below, we must ensure that we have acquired the mach task first.
	// We facilitate this by creating a pipe and using it to let the forked process know that we've
	// finishing acquiring the mach task, and it can go ahead with the calls to PT_TRACE_ME and PT_SIGEXC.
15 16 17
	int fd[2];
	if (pipe(fd) < 0) return -1;

A
aarzilli 已提交
18 19 20 21 22 23
       // Create another pipe so that we know when we're about to exec. This ensures that control only returns
       // back to Go-land when we call exec, effectively eliminating a race condition between launching the new
       // process and trying to read its memory.
       int wfd[2];
       if (pipe(wfd) < 0) return -1;

24 25 26 27 28 29 30 31 32 33 34
	kern_return_t kret;
	pid_t pid = fork();
	if (pid > 0) {
		// In parent.
		close(fd[0]);
		kret = acquire_mach_task(pid, task, port_set, exception_port, notification_port);
		if (kret != KERN_SUCCESS) return -1;

		char msg = 'c';
		write(fd[1], &msg, 1);
		close(fd[1]);
A
aarzilli 已提交
35 36 37 38 39

               char w;
               read(wfd[0], &w, 1);
               close(wfd[0]);

40 41 42 43 44 45 46 47 48 49 50
		return pid;
	}

	// Fork succeeded, we are in the child.
	int pret;
	char sig;

	close(fd[1]);
	read(fd[0], &sig, 1);
	close(fd[0]);

51 52 53
	// Create a new process group.
	if (setpgid(0, 0) < 0) {
		return -1;
54 55
	}

56 57 58 59 60 61 62 63 64 65 66
	// Set errno to zero before a call to ptrace.
	// It is documented that ptrace can return -1 even
	// for successful calls.
	errno = 0;
	pret = ptrace(PT_TRACE_ME, 0, 0, 0);
	if (pret != 0 && errno != 0) return -errno;

	errno = 0;
	pret = ptrace(PT_SIGEXC, 0, 0, 0);
	if (pret != 0 && errno != 0) return -errno;

A
aarzilli 已提交
67 68 69 70
	char msg = 'd';
	write(wfd[1], &msg, 1);
	close(wfd[1]);

71
	// Create the child process.
72 73 74
	execve(argv0, argv, environ);

	// We should never reach here, but if we did something went wrong.
75 76
	exit(1);
}