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