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