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