]> Cypherpunks.ru repositories - gostls13.git/blob - src/syscall/exec_libc2.go
cmd/compile/internal/inline: score call sites exposed by inlines
[gostls13.git] / src / syscall / exec_libc2.go
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 }