github.com/ccccaoqing/test@v0.0.0-20220510085219-3985d23445c0/src/syscall/exec_bsd.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build darwin dragonfly freebsd netbsd openbsd 6 7 package syscall 8 9 import ( 10 "runtime" 11 "unsafe" 12 ) 13 14 type SysProcAttr struct { 15 Chroot string // Chroot. 16 Credential *Credential // Credential. 17 Ptrace bool // Enable tracing. 18 Setsid bool // Create session. 19 Setpgid bool // Set process group ID to new pid (SYSV setpgrp) 20 Setctty bool // Set controlling terminal to fd 0 21 Noctty bool // Detach fd 0 from controlling terminal 22 } 23 24 // Implemented in runtime package. 25 func runtime_BeforeFork() 26 func runtime_AfterFork() 27 28 // Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child. 29 // If a dup or exec fails, write the errno error to pipe. 30 // (Pipe is close-on-exec so if exec succeeds, it will be closed.) 31 // In the child, this function must not acquire any locks, because 32 // they might have been locked at the time of the fork. This means 33 // no rescheduling, no malloc calls, and no new stack segments. 34 // For the same reason compiler does not race instrument it. 35 // The calls to RawSyscall are okay because they are assembly 36 // functions that do not grow the stack. 37 func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) { 38 // Declare all variables at top in case any 39 // declarations require heap allocation (e.g., err1). 40 var ( 41 r1, r2 uintptr 42 err1 Errno 43 nextfd int 44 i int 45 ) 46 47 // guard against side effects of shuffling fds below. 48 // Make sure that nextfd is beyond any currently open files so 49 // that we can't run the risk of overwriting any of them. 50 fd := make([]int, len(attr.Files)) 51 nextfd = len(attr.Files) 52 for i, ufd := range attr.Files { 53 if nextfd < int(ufd) { 54 nextfd = int(ufd) 55 } 56 fd[i] = int(ufd) 57 } 58 nextfd++ 59 60 darwin := runtime.GOOS == "darwin" 61 62 // About to call fork. 63 // No more allocation or calls of non-assembly functions. 64 runtime_BeforeFork() 65 r1, r2, err1 = RawSyscall(SYS_FORK, 0, 0, 0) 66 if err1 != 0 { 67 runtime_AfterFork() 68 return 0, err1 69 } 70 71 // On Darwin: 72 // r1 = child pid in both parent and child. 73 // r2 = 0 in parent, 1 in child. 74 // Convert to normal Unix r1 = 0 in child. 75 if darwin && r2 == 1 { 76 r1 = 0 77 } 78 79 if r1 != 0 { 80 // parent; return PID 81 runtime_AfterFork() 82 return int(r1), 0 83 } 84 85 // Fork succeeded, now in child. 86 87 // Enable tracing if requested. 88 if sys.Ptrace { 89 _, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0) 90 if err1 != 0 { 91 goto childerror 92 } 93 } 94 95 // Session ID 96 if sys.Setsid { 97 _, _, err1 = RawSyscall(SYS_SETSID, 0, 0, 0) 98 if err1 != 0 { 99 goto childerror 100 } 101 } 102 103 // Set process group 104 if sys.Setpgid { 105 _, _, err1 = RawSyscall(SYS_SETPGID, 0, 0, 0) 106 if err1 != 0 { 107 goto childerror 108 } 109 } 110 111 // Chroot 112 if chroot != nil { 113 _, _, err1 = RawSyscall(SYS_CHROOT, uintptr(unsafe.Pointer(chroot)), 0, 0) 114 if err1 != 0 { 115 goto childerror 116 } 117 } 118 119 // User and groups 120 if cred := sys.Credential; cred != nil { 121 ngroups := uintptr(len(cred.Groups)) 122 groups := uintptr(0) 123 if ngroups > 0 { 124 groups = uintptr(unsafe.Pointer(&cred.Groups[0])) 125 } 126 _, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, groups, 0) 127 if err1 != 0 { 128 goto childerror 129 } 130 _, _, err1 = RawSyscall(SYS_SETGID, uintptr(cred.Gid), 0, 0) 131 if err1 != 0 { 132 goto childerror 133 } 134 _, _, err1 = RawSyscall(SYS_SETUID, uintptr(cred.Uid), 0, 0) 135 if err1 != 0 { 136 goto childerror 137 } 138 } 139 140 // Chdir 141 if dir != nil { 142 _, _, err1 = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0) 143 if err1 != 0 { 144 goto childerror 145 } 146 } 147 148 // Pass 1: look for fd[i] < i and move those up above len(fd) 149 // so that pass 2 won't stomp on an fd it needs later. 150 if pipe < nextfd { 151 _, _, err1 = RawSyscall(SYS_DUP2, uintptr(pipe), uintptr(nextfd), 0) 152 if err1 != 0 { 153 goto childerror 154 } 155 RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC) 156 pipe = nextfd 157 nextfd++ 158 } 159 for i = 0; i < len(fd); i++ { 160 if fd[i] >= 0 && fd[i] < int(i) { 161 _, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(nextfd), 0) 162 if err1 != 0 { 163 goto childerror 164 } 165 RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC) 166 fd[i] = nextfd 167 nextfd++ 168 if nextfd == pipe { // don't stomp on pipe 169 nextfd++ 170 } 171 } 172 } 173 174 // Pass 2: dup fd[i] down onto i. 175 for i = 0; i < len(fd); i++ { 176 if fd[i] == -1 { 177 RawSyscall(SYS_CLOSE, uintptr(i), 0, 0) 178 continue 179 } 180 if fd[i] == int(i) { 181 // dup2(i, i) won't clear close-on-exec flag on Linux, 182 // probably not elsewhere either. 183 _, _, err1 = RawSyscall(SYS_FCNTL, uintptr(fd[i]), F_SETFD, 0) 184 if err1 != 0 { 185 goto childerror 186 } 187 continue 188 } 189 // The new fd is created NOT close-on-exec, 190 // which is exactly what we want. 191 _, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(i), 0) 192 if err1 != 0 { 193 goto childerror 194 } 195 } 196 197 // By convention, we don't close-on-exec the fds we are 198 // started with, so if len(fd) < 3, close 0, 1, 2 as needed. 199 // Programs that know they inherit fds >= 3 will need 200 // to set them close-on-exec. 201 for i = len(fd); i < 3; i++ { 202 RawSyscall(SYS_CLOSE, uintptr(i), 0, 0) 203 } 204 205 // Detach fd 0 from tty 206 if sys.Noctty { 207 _, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCNOTTY), 0) 208 if err1 != 0 { 209 goto childerror 210 } 211 } 212 213 // Make fd 0 the tty 214 if sys.Setctty { 215 _, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCSCTTY), 0) 216 if err1 != 0 { 217 goto childerror 218 } 219 } 220 221 // Time to exec. 222 _, _, err1 = RawSyscall(SYS_EXECVE, 223 uintptr(unsafe.Pointer(argv0)), 224 uintptr(unsafe.Pointer(&argv[0])), 225 uintptr(unsafe.Pointer(&envv[0]))) 226 227 childerror: 228 // send error code on pipe 229 RawSyscall(SYS_WRITE, uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1)) 230 for { 231 RawSyscall(SYS_EXIT, 253, 0, 0) 232 } 233 } 234 235 // Try to open a pipe with O_CLOEXEC set on both file descriptors. 236 func forkExecPipe(p []int) error { 237 err := Pipe(p) 238 if err != nil { 239 return err 240 } 241 _, err = fcntl(p[0], F_SETFD, FD_CLOEXEC) 242 if err != nil { 243 return err 244 } 245 _, err = fcntl(p[1], F_SETFD, FD_CLOEXEC) 246 return err 247 }