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.
5 // +build darwin freebsd netbsd openbsd
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
24 // Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
25 // If a dup or exec fails, write the errno error to pipe.
26 // (Pipe is close-on-exec so if exec succeeds, it will be closed.)
27 // In the child, this function must not acquire any locks, because
28 // they might have been locked at the time of the fork. This means
29 // no rescheduling, no malloc calls, and no new stack segments.
30 // The calls to RawSyscall are okay because they are assembly
31 // functions that do not grow the stack.
32 func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
33 // Declare all variables at top in case any
34 // declarations require heap allocation (e.g., err1).
42 // guard against side effects of shuffling fds below.
43 fd := append([]int(nil), attr.Files...)
45 // About to call fork.
46 // No more allocation or calls of non-assembly functions.
57 // Fork succeeded, now in child.
59 // Enable tracing if requested.
61 err1 = raw_trace(_PTRACE_TRACEME, 0, nil, nil)
77 err1 = raw_setpgid(0, 0)
85 err1 = raw_chroot(chroot)
92 if cred := sys.Credential; cred != nil {
93 ngroups := len(cred.Groups)
95 err2 := setgroups(0, nil)
102 groups := make([]Gid_t, ngroups)
103 for i, v := range cred.Groups {
106 err2 := setgroups(ngroups, &groups[0])
116 err2 := Setgid(int(cred.Gid))
121 err2 = Setuid(int(cred.Uid))
130 err1 = raw_chdir(dir)
136 // Pass 1: look for fd[i] < i and move those up above len(fd)
137 // so that pass 2 won't stomp on an fd it needs later.
138 nextfd = int(len(fd))
140 _, err2 := Dup2(pipe, nextfd)
145 raw_fcntl(nextfd, F_SETFD, FD_CLOEXEC)
149 for i = 0; i < len(fd); i++ {
150 if fd[i] >= 0 && fd[i] < int(i) {
151 _, err2 := Dup2(fd[i], nextfd)
156 raw_fcntl(nextfd, F_SETFD, F_CLOEXEC)
159 if nextfd == pipe { // don't stomp on pipe
165 // Pass 2: dup fd[i] down onto i.
166 for i = 0; i < len(fd); i++ {
172 // dup2(i, i) won't clear close-on-exec flag on Linux,
173 // probably not elsewhere either.
174 _, err1 = raw_fcntl(fd[i], F_SETFD, 0)
180 // The new fd is created NOT close-on-exec,
181 // which is exactly what we want.
182 _, err2 := Dup2(fd[i], i)
189 // By convention, we don't close-on-exec the fds we are
190 // started with, so if len(fd) < 3, close 0, 1, 2 as needed.
191 // Programs that know they inherit fds >= 3 will need
192 // to set them close-on-exec.
193 for i = len(fd); i < 3; i++ {
197 // Detach fd 0 from tty
199 _, err1 = raw_ioctl(0, IOTCNOTTY, 0)
207 _, err1 = raw_ioctl(TIOCSCTTY, 0)
214 err1 = raw_execve(argv0, &argv[0], &envv[0])
217 // send error code on pipe
218 raw_write(pipe, (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1)))
223 // Calling panic is not actually safe,
224 // but the for loop above won't break
225 // and this shuts up the compiler.