OLD | NEW |
(Empty) | |
| 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 linux |
| 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 new pid (SYSV setpgrp) |
| 19 Setctty bool // Set controlling terminal to fd Ctty (only mean
ingful if Setsid is set) |
| 20 Noctty bool // Detach fd 0 from controlling terminal |
| 21 Ctty int // Controlling TTY fd (Linux only) |
| 22 Pdeathsig Signal // Signal that the process will get when its pare
nt dies (Linux only) |
| 23 Cloneflags uintptr // Flags for clone calls (Linux only) |
| 24 } |
| 25 |
| 26 // Implemented in runtime package. |
| 27 func runtime_BeforeFork() |
| 28 func runtime_AfterFork() |
| 29 |
| 30 // Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child. |
| 31 // If a dup or exec fails, write the errno error to pipe. |
| 32 // (Pipe is close-on-exec so if exec succeeds, it will be closed.) |
| 33 // In the child, this function must not acquire any locks, because |
| 34 // they might have been locked at the time of the fork. This means |
| 35 // no rescheduling, no malloc calls, and no new stack segments. |
| 36 // For the same reason compiler does not race instrument it. |
| 37 // The calls to RawSyscall are okay because they are assembly |
| 38 // functions that do not grow the stack. |
| 39 func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
*ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) { |
| 40 // Declare all variables at top in case any |
| 41 // declarations require heap allocation (e.g., err1). |
| 42 var ( |
| 43 r1 uintptr |
| 44 err1 Errno |
| 45 nextfd int |
| 46 i int |
| 47 ) |
| 48 |
| 49 // Guard against side effects of shuffling fds below. |
| 50 // Make sure that nextfd is beyond any currently open files so |
| 51 // that we can't run the risk of overwriting any of them. |
| 52 fd := make([]int, len(attr.Files)) |
| 53 nextfd = len(attr.Files) |
| 54 for i, ufd := range attr.Files { |
| 55 if nextfd < int(ufd) { |
| 56 nextfd = int(ufd) |
| 57 } |
| 58 fd[i] = int(ufd) |
| 59 } |
| 60 nextfd++ |
| 61 |
| 62 // About to call fork. |
| 63 // No more allocation or calls of non-assembly functions. |
| 64 runtime_BeforeFork() |
| 65 r1, _, err1 = RawSyscall6(SYS_CLONE, uintptr(SIGCHLD)|sys.Cloneflags, 0,
0, 0, 0, 0) |
| 66 if err1 != 0 { |
| 67 runtime_AfterFork() |
| 68 return 0, err1 |
| 69 } |
| 70 |
| 71 if r1 != 0 { |
| 72 // parent; return PID |
| 73 runtime_AfterFork() |
| 74 return int(r1), 0 |
| 75 } |
| 76 |
| 77 // Fork succeeded, now in child. |
| 78 |
| 79 // Parent death signal |
| 80 if sys.Pdeathsig != 0 { |
| 81 _, _, err1 = RawSyscall6(SYS_PRCTL, PR_SET_PDEATHSIG, uintptr(sy
s.Pdeathsig), 0, 0, 0, 0) |
| 82 if err1 != 0 { |
| 83 goto childerror |
| 84 } |
| 85 |
| 86 // Signal self if parent is already dead. This might cause a |
| 87 // duplicate signal in rare cases, but it won't matter when |
| 88 // using SIGKILL. |
| 89 r1, _, _ = RawSyscall(SYS_GETPPID, 0, 0, 0) |
| 90 if r1 == 1 { |
| 91 pid, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) |
| 92 _, _, err1 := RawSyscall(SYS_KILL, pid, uintptr(sys.Pdea
thsig), 0) |
| 93 if err1 != 0 { |
| 94 goto childerror |
| 95 } |
| 96 } |
| 97 } |
| 98 |
| 99 // Enable tracing if requested. |
| 100 if sys.Ptrace { |
| 101 _, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0,
0) |
| 102 if err1 != 0 { |
| 103 goto childerror |
| 104 } |
| 105 } |
| 106 |
| 107 // Session ID |
| 108 if sys.Setsid { |
| 109 _, _, err1 = RawSyscall(SYS_SETSID, 0, 0, 0) |
| 110 if err1 != 0 { |
| 111 goto childerror |
| 112 } |
| 113 } |
| 114 |
| 115 // Set process group |
| 116 if sys.Setpgid { |
| 117 _, _, err1 = RawSyscall(SYS_SETPGID, 0, 0, 0) |
| 118 if err1 != 0 { |
| 119 goto childerror |
| 120 } |
| 121 } |
| 122 |
| 123 // Chroot |
| 124 if chroot != nil { |
| 125 _, _, err1 = RawSyscall(SYS_CHROOT, uintptr(unsafe.Pointer(chroo
t)), 0, 0) |
| 126 if err1 != 0 { |
| 127 goto childerror |
| 128 } |
| 129 } |
| 130 |
| 131 // User and groups |
| 132 if cred := sys.Credential; cred != nil { |
| 133 ngroups := uintptr(len(cred.Groups)) |
| 134 var groups unsafe.Pointer |
| 135 if ngroups > 0 { |
| 136 groups = unsafe.Pointer(&cred.Groups[0]) |
| 137 } |
| 138 _, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, uintptr(groups),
0) |
| 139 if err1 != 0 { |
| 140 goto childerror |
| 141 } |
| 142 _, _, err1 = RawSyscall(SYS_SETGID, uintptr(cred.Gid), 0, 0) |
| 143 if err1 != 0 { |
| 144 goto childerror |
| 145 } |
| 146 _, _, err1 = RawSyscall(SYS_SETUID, uintptr(cred.Uid), 0, 0) |
| 147 if err1 != 0 { |
| 148 goto childerror |
| 149 } |
| 150 } |
| 151 |
| 152 // Chdir |
| 153 if dir != nil { |
| 154 _, _, err1 = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)),
0, 0) |
| 155 if err1 != 0 { |
| 156 goto childerror |
| 157 } |
| 158 } |
| 159 |
| 160 // Pass 1: look for fd[i] < i and move those up above len(fd) |
| 161 // so that pass 2 won't stomp on an fd it needs later. |
| 162 if pipe < nextfd { |
| 163 _, _, err1 = RawSyscall(SYS_DUP2, uintptr(pipe), uintptr(nextfd)
, 0) |
| 164 if err1 != 0 { |
| 165 goto childerror |
| 166 } |
| 167 RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC) |
| 168 pipe = nextfd |
| 169 nextfd++ |
| 170 } |
| 171 for i = 0; i < len(fd); i++ { |
| 172 if fd[i] >= 0 && fd[i] < int(i) { |
| 173 _, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintpt
r(nextfd), 0) |
| 174 if err1 != 0 { |
| 175 goto childerror |
| 176 } |
| 177 RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEX
EC) |
| 178 fd[i] = nextfd |
| 179 nextfd++ |
| 180 if nextfd == pipe { // don't stomp on pipe |
| 181 nextfd++ |
| 182 } |
| 183 } |
| 184 } |
| 185 |
| 186 // Pass 2: dup fd[i] down onto i. |
| 187 for i = 0; i < len(fd); i++ { |
| 188 if fd[i] == -1 { |
| 189 RawSyscall(SYS_CLOSE, uintptr(i), 0, 0) |
| 190 continue |
| 191 } |
| 192 if fd[i] == int(i) { |
| 193 // dup2(i, i) won't clear close-on-exec flag on Linux, |
| 194 // probably not elsewhere either. |
| 195 _, _, err1 = RawSyscall(SYS_FCNTL, uintptr(fd[i]), F_SET
FD, 0) |
| 196 if err1 != 0 { |
| 197 goto childerror |
| 198 } |
| 199 continue |
| 200 } |
| 201 // The new fd is created NOT close-on-exec, |
| 202 // which is exactly what we want. |
| 203 _, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(i), 0) |
| 204 if err1 != 0 { |
| 205 goto childerror |
| 206 } |
| 207 } |
| 208 |
| 209 // By convention, we don't close-on-exec the fds we are |
| 210 // started with, so if len(fd) < 3, close 0, 1, 2 as needed. |
| 211 // Programs that know they inherit fds >= 3 will need |
| 212 // to set them close-on-exec. |
| 213 for i = len(fd); i < 3; i++ { |
| 214 RawSyscall(SYS_CLOSE, uintptr(i), 0, 0) |
| 215 } |
| 216 |
| 217 // Detach fd 0 from tty |
| 218 if sys.Noctty { |
| 219 _, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCNOTTY), 0) |
| 220 if err1 != 0 { |
| 221 goto childerror |
| 222 } |
| 223 } |
| 224 |
| 225 // Set the controlling TTY to Ctty |
| 226 if sys.Setctty && sys.Ctty >= 0 { |
| 227 _, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TI
OCSCTTY), 0) |
| 228 if err1 != 0 { |
| 229 goto childerror |
| 230 } |
| 231 } |
| 232 |
| 233 // Time to exec. |
| 234 _, _, err1 = RawSyscall(SYS_EXECVE, |
| 235 uintptr(unsafe.Pointer(argv0)), |
| 236 uintptr(unsafe.Pointer(&argv[0])), |
| 237 uintptr(unsafe.Pointer(&envv[0]))) |
| 238 |
| 239 childerror: |
| 240 // send error code on pipe |
| 241 RawSyscall(SYS_WRITE, uintptr(pipe), uintptr(unsafe.Pointer(&err1)), uns
afe.Sizeof(err1)) |
| 242 for { |
| 243 RawSyscall(SYS_EXIT, 253, 0, 0) |
| 244 } |
| 245 } |
| 246 |
| 247 // Try to open a pipe with O_CLOEXEC set on both file descriptors. |
| 248 func forkExecPipe(p []int) (err error) { |
| 249 err = Pipe2(p, O_CLOEXEC) |
| 250 // pipe2 was added in 2.6.27 and our minimum requirement is 2.6.23, so i
t |
| 251 // might not be implemented. |
| 252 if err == ENOSYS { |
| 253 if err = Pipe(p); err != nil { |
| 254 return |
| 255 } |
| 256 if _, err = fcntl(p[0], F_SETFD, FD_CLOEXEC); err != nil { |
| 257 return |
| 258 } |
| 259 _, err = fcntl(p[1], F_SETFD, FD_CLOEXEC) |
| 260 } |
| 261 return |
| 262 } |
OLD | NEW |