gitlab.com/Raven-IO/raven-delve@v1.22.4/pkg/proc/native/exec_darwin.c (about) 1 //+build darwin,macnative 2 3 #include "exec_darwin.h" 4 #include "stdio.h" 5 6 extern char** environ; 7 8 int 9 close_exec_pipe(int fd[2]) { 10 if (pipe(fd) < 0) return -1; 11 if (fcntl(fd[0], F_SETFD, FD_CLOEXEC) < 0) return -1; 12 if (fcntl(fd[1], F_SETFD, FD_CLOEXEC) < 0) return -1; 13 return 0; 14 } 15 16 int 17 fork_exec(char *argv0, char **argv, int size, 18 char *wd, 19 task_t *task, 20 mach_port_t *port_set, 21 mach_port_t *exception_port, 22 mach_port_t *notification_port) 23 { 24 // Since we're using mach exceptions instead of signals, 25 // we need to coordinate between parent and child via pipes 26 // to ensure that the parent has set the exception ports on 27 // the child task before it execs. 28 int fd[2]; 29 if (close_exec_pipe(fd) < 0) return -1; 30 31 // Create another pipe to signal the parent on exec. 32 int efd[2]; 33 if (close_exec_pipe(efd) < 0) return -1; 34 35 kern_return_t kret; 36 pid_t pid = fork(); 37 if (pid > 0) { 38 // In parent. 39 close(fd[0]); 40 close(efd[1]); 41 kret = acquire_mach_task(pid, task, port_set, exception_port, notification_port); 42 if (kret != KERN_SUCCESS) return -1; 43 44 char msg = 'c'; 45 write(fd[1], &msg, 1); 46 close(fd[1]); 47 48 char w; 49 size_t n = read(efd[0], &w, 1); 50 close(efd[0]); 51 if (n != 0) { 52 // Child died, reap it. 53 waitpid(pid, NULL, 0); 54 return -1; 55 } 56 return pid; 57 } 58 59 // Fork succeeded, we are in the child. 60 int pret, cret; 61 char sig; 62 63 close(fd[1]); 64 read(fd[0], &sig, 1); 65 close(fd[0]); 66 67 // Create a new process group. 68 if (setpgid(0, 0) < 0) { 69 perror("setpgid"); 70 exit(1); 71 } 72 73 // Set errno to zero before a call to ptrace. 74 // It is documented that ptrace can return -1 even 75 // for successful calls. 76 errno = 0; 77 pret = ptrace(PT_TRACE_ME, 0, 0, 0); 78 if (pret != 0 && errno != 0) { 79 perror("ptrace"); 80 exit(1); 81 } 82 83 // Change working directory if wd is not empty. 84 if (wd && wd[0]) { 85 errno = 0; 86 cret = chdir(wd); 87 if (cret != 0 && errno != 0) { 88 char *error_msg; 89 asprintf(&error_msg, "%s '%s'", "chdir", wd); 90 perror(error_msg); 91 exit(1); 92 } 93 } 94 95 errno = 0; 96 pret = ptrace(PT_SIGEXC, 0, 0, 0); 97 if (pret != 0 && errno != 0) { 98 perror("ptrace"); 99 exit(1); 100 } 101 102 sleep(1); 103 104 // Create the child process. 105 execve(argv0, argv, environ); 106 107 // We should never reach here, but if we did something went wrong. 108 // Write a message to parent to alert that exec failed. 109 char msg = 'd'; 110 write(efd[1], &msg, 1); 111 close(efd[1]); 112 113 exit(1); 114 }