github.com/gidoBOSSftw5731/go/src@v0.0.0-20210226122457-d24b0edbf019/syscall/exec_libc2.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 //go:build darwin || (openbsd && amd64) || (openbsd && arm64) 6 // +build darwin openbsd,amd64 openbsd,arm64 7 8 package syscall 9 10 import ( 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 sets the process group ID of the child to Pgid, 20 // or, if Pgid == 0, to the new child's process ID. 21 Setpgid bool 22 // Setctty sets the controlling terminal of the child to 23 // file descriptor Ctty. Ctty must be a descriptor number 24 // in the child process: an index into ProcAttr.Files. 25 // This is only meaningful if Setsid is true. 26 Setctty bool 27 Noctty bool // Detach fd 0 from controlling terminal 28 Ctty int // Controlling TTY fd 29 // Foreground places the child process group in the foreground. 30 // This implies Setpgid. The Ctty field must be set to 31 // the descriptor of the controlling TTY. 32 // Unlike Setctty, in this case Ctty must be a descriptor 33 // number in the parent process. 34 Foreground bool 35 Pgid int // Child's process group ID if Setpgid. 36 } 37 38 // Implemented in runtime package. 39 func runtime_BeforeFork() 40 func runtime_AfterFork() 41 func runtime_AfterForkInChild() 42 43 // Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child. 44 // If a dup or exec fails, write the errno error to pipe. 45 // (Pipe is close-on-exec so if exec succeeds, it will be closed.) 46 // In the child, this function must not acquire any locks, because 47 // they might have been locked at the time of the fork. This means 48 // no rescheduling, no malloc calls, and no new stack segments. 49 // For the same reason compiler does not race instrument it. 50 // The calls to rawSyscall are okay because they are assembly 51 // functions that do not grow the stack. 52 //go:norace 53 func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) { 54 // Declare all variables at top in case any 55 // declarations require heap allocation (e.g., err1). 56 var ( 57 r1 uintptr 58 err1 Errno 59 nextfd int 60 i int 61 ) 62 63 // guard against side effects of shuffling fds below. 64 // Make sure that nextfd is beyond any currently open files so 65 // that we can't run the risk of overwriting any of them. 66 fd := make([]int, len(attr.Files)) 67 nextfd = len(attr.Files) 68 for i, ufd := range attr.Files { 69 if nextfd < int(ufd) { 70 nextfd = int(ufd) 71 } 72 fd[i] = int(ufd) 73 } 74 nextfd++ 75 76 // About to call fork. 77 // No more allocation or calls of non-assembly functions. 78 runtime_BeforeFork() 79 r1, _, err1 = rawSyscall(funcPC(libc_fork_trampoline), 0, 0, 0) 80 if err1 != 0 { 81 runtime_AfterFork() 82 return 0, err1 83 } 84 85 if r1 != 0 { 86 // parent; return PID 87 runtime_AfterFork() 88 return int(r1), 0 89 } 90 91 // Fork succeeded, now in child. 92 93 runtime_AfterForkInChild() 94 95 // Enable tracing if requested. 96 if sys.Ptrace { 97 if err := ptrace(PTRACE_TRACEME, 0, 0, 0); err != nil { 98 err1 = err.(Errno) 99 goto childerror 100 } 101 } 102 103 // Session ID 104 if sys.Setsid { 105 _, _, err1 = rawSyscall(funcPC(libc_setsid_trampoline), 0, 0, 0) 106 if err1 != 0 { 107 goto childerror 108 } 109 } 110 111 // Set process group 112 if sys.Setpgid || sys.Foreground { 113 // Place child in process group. 114 _, _, err1 = rawSyscall(funcPC(libc_setpgid_trampoline), 0, uintptr(sys.Pgid), 0) 115 if err1 != 0 { 116 goto childerror 117 } 118 } 119 120 if sys.Foreground { 121 pgrp := sys.Pgid 122 if pgrp == 0 { 123 r1, _, err1 = rawSyscall(funcPC(libc_getpid_trampoline), 0, 0, 0) 124 if err1 != 0 { 125 goto childerror 126 } 127 128 pgrp = int(r1) 129 } 130 131 // Place process group in foreground. 132 _, _, err1 = rawSyscall(funcPC(libc_ioctl_trampoline), uintptr(sys.Ctty), uintptr(TIOCSPGRP), uintptr(unsafe.Pointer(&pgrp))) 133 if err1 != 0 { 134 goto childerror 135 } 136 } 137 138 // Chroot 139 if chroot != nil { 140 _, _, err1 = rawSyscall(funcPC(libc_chroot_trampoline), uintptr(unsafe.Pointer(chroot)), 0, 0) 141 if err1 != 0 { 142 goto childerror 143 } 144 } 145 146 // User and groups 147 if cred := sys.Credential; cred != nil { 148 ngroups := uintptr(len(cred.Groups)) 149 groups := uintptr(0) 150 if ngroups > 0 { 151 groups = uintptr(unsafe.Pointer(&cred.Groups[0])) 152 } 153 if !cred.NoSetGroups { 154 _, _, err1 = rawSyscall(funcPC(libc_setgroups_trampoline), ngroups, groups, 0) 155 if err1 != 0 { 156 goto childerror 157 } 158 } 159 _, _, err1 = rawSyscall(funcPC(libc_setgid_trampoline), uintptr(cred.Gid), 0, 0) 160 if err1 != 0 { 161 goto childerror 162 } 163 _, _, err1 = rawSyscall(funcPC(libc_setuid_trampoline), uintptr(cred.Uid), 0, 0) 164 if err1 != 0 { 165 goto childerror 166 } 167 } 168 169 // Chdir 170 if dir != nil { 171 _, _, err1 = rawSyscall(funcPC(libc_chdir_trampoline), uintptr(unsafe.Pointer(dir)), 0, 0) 172 if err1 != 0 { 173 goto childerror 174 } 175 } 176 177 // Pass 1: look for fd[i] < i and move those up above len(fd) 178 // so that pass 2 won't stomp on an fd it needs later. 179 if pipe < nextfd { 180 _, _, err1 = rawSyscall(funcPC(libc_dup2_trampoline), uintptr(pipe), uintptr(nextfd), 0) 181 if err1 != 0 { 182 goto childerror 183 } 184 rawSyscall(funcPC(libc_fcntl_trampoline), uintptr(nextfd), F_SETFD, FD_CLOEXEC) 185 pipe = nextfd 186 nextfd++ 187 } 188 for i = 0; i < len(fd); i++ { 189 if fd[i] >= 0 && fd[i] < int(i) { 190 if nextfd == pipe { // don't stomp on pipe 191 nextfd++ 192 } 193 _, _, err1 = rawSyscall(funcPC(libc_dup2_trampoline), uintptr(fd[i]), uintptr(nextfd), 0) 194 if err1 != 0 { 195 goto childerror 196 } 197 rawSyscall(funcPC(libc_fcntl_trampoline), uintptr(nextfd), F_SETFD, FD_CLOEXEC) 198 fd[i] = nextfd 199 nextfd++ 200 } 201 } 202 203 // Pass 2: dup fd[i] down onto i. 204 for i = 0; i < len(fd); i++ { 205 if fd[i] == -1 { 206 rawSyscall(funcPC(libc_close_trampoline), uintptr(i), 0, 0) 207 continue 208 } 209 if fd[i] == int(i) { 210 // dup2(i, i) won't clear close-on-exec flag on Linux, 211 // probably not elsewhere either. 212 _, _, err1 = rawSyscall(funcPC(libc_fcntl_trampoline), uintptr(fd[i]), F_SETFD, 0) 213 if err1 != 0 { 214 goto childerror 215 } 216 continue 217 } 218 // The new fd is created NOT close-on-exec, 219 // which is exactly what we want. 220 _, _, err1 = rawSyscall(funcPC(libc_dup2_trampoline), uintptr(fd[i]), uintptr(i), 0) 221 if err1 != 0 { 222 goto childerror 223 } 224 } 225 226 // By convention, we don't close-on-exec the fds we are 227 // started with, so if len(fd) < 3, close 0, 1, 2 as needed. 228 // Programs that know they inherit fds >= 3 will need 229 // to set them close-on-exec. 230 for i = len(fd); i < 3; i++ { 231 rawSyscall(funcPC(libc_close_trampoline), uintptr(i), 0, 0) 232 } 233 234 // Detach fd 0 from tty 235 if sys.Noctty { 236 _, _, err1 = rawSyscall(funcPC(libc_ioctl_trampoline), 0, uintptr(TIOCNOTTY), 0) 237 if err1 != 0 { 238 goto childerror 239 } 240 } 241 242 // Set the controlling TTY to Ctty 243 if sys.Setctty { 244 _, _, err1 = rawSyscall(funcPC(libc_ioctl_trampoline), uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0) 245 if err1 != 0 { 246 goto childerror 247 } 248 } 249 250 // Time to exec. 251 _, _, err1 = rawSyscall(funcPC(libc_execve_trampoline), 252 uintptr(unsafe.Pointer(argv0)), 253 uintptr(unsafe.Pointer(&argv[0])), 254 uintptr(unsafe.Pointer(&envv[0]))) 255 256 childerror: 257 // send error code on pipe 258 rawSyscall(funcPC(libc_write_trampoline), uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1)) 259 for { 260 rawSyscall(funcPC(libc_exit_trampoline), 253, 0, 0) 261 } 262 }