github.com/criyle/go-sandbox@v0.10.3/pkg/forkexec/fork_child_darwin.go (about) 1 package forkexec 2 3 import ( 4 "syscall" 5 "unsafe" 6 ) 7 8 // Reference to src/syscall/exec_darwin.go 9 //go:norace 10 func forkAndExecInChild(r *Runner, argv0 *byte, argv, env []*byte, workdir, profile *byte, p [2]int) (r1 uintptr, err1 syscall.Errno) { 11 var ( 12 err2 syscall.Errno 13 errBuf *byte 14 ) 15 16 // similar to exec_linux, avoid side effect by shuffling around 17 fd, nextfd := prepareFds(r.Files) 18 pipe := p[1] 19 20 // About to call fork. 21 // No more allocation or calls of non-assembly functions. 22 beforeFork() 23 24 // UnshareFlags (new namespaces) is activated by clone syscall 25 r1, _, err1 = rawSyscall(libc_fork_trampoline_addr, 0, 0, 0) 26 if err1 != 0 || r1 != 0 { 27 // in parent process, immediate return 28 return 29 } 30 31 // In child process 32 afterForkInChild() 33 // Notice: cannot call any GO functions beyond this point 34 35 // Close write end of pipe 36 if _, _, err1 = rawSyscall(libc_close_trampoline_addr, uintptr(p[0]), 0, 0); err1 != 0 { 37 goto childerror 38 } 39 40 // Set pg id 41 _, _, err1 = rawSyscall(libc_setpgid_trampoline_addr, 0, 0, 0) 42 if err1 != 0 { 43 goto childerror 44 } 45 46 // Pass 1 & pass 2 assigns fds for child process 47 // Pass 1: fd[i] < i => nextfd 48 if pipe < nextfd { 49 _, _, err1 = rawSyscall(libc_dup2_trampoline_addr, uintptr(pipe), uintptr(nextfd), 0) 50 if err1 != 0 { 51 goto childerror 52 } 53 rawSyscall(libc_fcntl_trampoline_addr, uintptr(nextfd), syscall.F_SETFD, syscall.FD_CLOEXEC) 54 pipe = nextfd 55 nextfd++ 56 } 57 for i := 0; i < len(fd); i++ { 58 if fd[i] >= 0 && fd[i] < int(i) { 59 // Avoid fd rewrite 60 if nextfd == pipe { 61 nextfd++ 62 } 63 _, _, err1 = rawSyscall(libc_dup2_trampoline_addr, uintptr(fd[i]), uintptr(nextfd), 0) 64 if err1 != 0 { 65 goto childerror 66 } 67 rawSyscall(libc_fcntl_trampoline_addr, uintptr(nextfd), syscall.F_SETFD, syscall.FD_CLOEXEC) 68 // Set up close on exec 69 fd[i] = nextfd 70 nextfd++ 71 } 72 } 73 // Pass 2: fd[i] => i 74 for i := 0; i < len(fd); i++ { 75 if fd[i] == -1 { 76 rawSyscall(libc_close_trampoline_addr, uintptr(i), 0, 0) 77 continue 78 } 79 if fd[i] == int(i) { 80 // dup2(i, i) will not clear close on exec flag, need to reset the flag 81 _, _, err1 = rawSyscall(libc_fcntl_trampoline_addr, uintptr(fd[i]), syscall.F_SETFD, 0) 82 if err1 != 0 { 83 goto childerror 84 } 85 continue 86 } 87 _, _, err1 = rawSyscall(libc_dup2_trampoline_addr, uintptr(fd[i]), uintptr(i), 0) 88 if err1 != 0 { 89 goto childerror 90 } 91 } 92 93 // chdir for child 94 if workdir != nil { 95 _, _, err1 = rawSyscall(libc_chdir_trampoline_addr, uintptr(unsafe.Pointer(workdir)), 0, 0) 96 if err1 != 0 { 97 goto childerror 98 } 99 } 100 101 // Set limit 102 for _, rlim := range r.RLimits { 103 _, _, err1 = rawSyscall(libc_setrlimit_trampoline_addr, uintptr(rlim.Res), uintptr(unsafe.Pointer(&rlim.Rlim)), 0) 104 if err1 != 0 { 105 if err1 == syscall.EINVAL && (rlim.Res == syscall.RLIMIT_DATA || rlim.Res == syscall.RLIMIT_AS) { 106 continue 107 } 108 goto childerror 109 } 110 } 111 112 // Load sandbox profile 113 if profile != nil { 114 r1, _, err1 = rawSyscall(libc_sandbox_init_trampoline_addr, uintptr(unsafe.Pointer(profile)), 0, uintptr(unsafe.Pointer(&errBuf))) 115 if err1 != 0 { 116 goto childerror 117 } 118 if r1 != 0 { 119 err1 = 253 120 goto childerror 121 } 122 rawSyscall(libc_sandbox_free_error_trampoline_addr, uintptr(unsafe.Pointer(errBuf)), 0, 0) 123 } 124 125 // Sync before exec 126 err2 = 0 127 r1, _, err1 = rawSyscall(libc_write_trampoline_addr, uintptr(pipe), uintptr(unsafe.Pointer(&err2)), unsafe.Sizeof(err2)) 128 if r1 == 0 || err1 != 0 { 129 goto childerror 130 } 131 132 r1, _, err1 = rawSyscall(libc_read_trampoline_addr, uintptr(pipe), uintptr(unsafe.Pointer(&err2)), unsafe.Sizeof(err2)) 133 if r1 == 0 || err1 != 0 { 134 goto childerror 135 } 136 137 // Time to exec. 138 _, _, err1 = rawSyscall(libc_execve_trampoline_addr, 139 uintptr(unsafe.Pointer(argv0)), 140 uintptr(unsafe.Pointer(&argv[0])), 141 uintptr(unsafe.Pointer(&env[0]))) 142 143 childerror: 144 // send error code on pipe 145 rawSyscall(libc_write_trampoline_addr, uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1)) 146 for { 147 rawSyscall(libc_exit_trampoline_addr, uintptr(err1+err2), 0, 0) 148 } 149 }