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 aix solaris 6 7// This file handles forkAndExecInChild function for OS using libc syscall like AIX or Solaris. 8 9package syscall 10 11import ( 12 "unsafe" 13) 14 15type SysProcAttr struct { 16 Chroot string // Chroot. 17 Credential *Credential // Credential. 18 Setsid bool // Create session. 19 Setpgid bool // Set process group ID to Pgid, or, if Pgid == 0, to new pid. 20 Setctty bool // Set controlling terminal to fd Ctty 21 Noctty bool // Detach fd 0 from controlling terminal 22 Ctty int // Controlling TTY fd 23 Foreground bool // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY) 24 Pgid int // Child's process group ID if Setpgid. 25} 26 27// Implemented in runtime package. 28func runtime_BeforeFork() 29func runtime_AfterFork() 30func runtime_AfterForkInChild() 31 32func chdir(path uintptr) (err Errno) 33func chroot1(path uintptr) (err Errno) 34func close(fd uintptr) (err Errno) 35func dup2child(old uintptr, new uintptr) (val uintptr, err Errno) 36func execve(path uintptr, argv uintptr, envp uintptr) (err Errno) 37func exit(code uintptr) 38func fcntl1(fd uintptr, cmd uintptr, arg uintptr) (val uintptr, err Errno) 39func forkx(flags uintptr) (pid uintptr, err Errno) 40func getpid() (pid uintptr, err Errno) 41func ioctl(fd uintptr, req uintptr, arg uintptr) (err Errno) 42func setgid(gid uintptr) (err Errno) 43func setgroups1(ngid uintptr, gid uintptr) (err Errno) 44func setsid() (pid uintptr, err Errno) 45func setuid(uid uintptr) (err Errno) 46func setpgid(pid uintptr, pgid uintptr) (err Errno) 47func write1(fd uintptr, buf uintptr, nbyte uintptr) (n uintptr, err Errno) 48 49// syscall defines this global on our behalf to avoid a build dependency on other platforms 50func init() { 51 execveLibc = execve 52} 53 54// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child. 55// If a dup or exec fails, write the errno error to pipe. 56// (Pipe is close-on-exec so if exec succeeds, it will be closed.) 57// In the child, this function must not acquire any locks, because 58// they might have been locked at the time of the fork. This means 59// no rescheduling, no malloc calls, and no new stack segments. 60// 61// We call hand-crafted syscalls, implemented in 62// ../runtime/syscall_solaris.go, rather than generated libc wrappers 63// because we need to avoid lazy-loading the functions (might malloc, 64// split the stack, or acquire mutexes). We can't call RawSyscall 65// because it's not safe even for BSD-subsystem calls. 66//go:norace 67func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) { 68 // Declare all variables at top in case any 69 // declarations require heap allocation (e.g., err1). 70 var ( 71 r1 uintptr 72 err1 Errno 73 nextfd int 74 i int 75 ) 76 77 // guard against side effects of shuffling fds below. 78 // Make sure that nextfd is beyond any currently open files so 79 // that we can't run the risk of overwriting any of them. 80 fd := make([]int, len(attr.Files)) 81 nextfd = len(attr.Files) 82 for i, ufd := range attr.Files { 83 if nextfd < int(ufd) { 84 nextfd = int(ufd) 85 } 86 fd[i] = int(ufd) 87 } 88 nextfd++ 89 90 // About to call fork. 91 // No more allocation or calls of non-assembly functions. 92 runtime_BeforeFork() 93 r1, err1 = forkx(0x1) // FORK_NOSIGCHLD 94 if err1 != 0 { 95 runtime_AfterFork() 96 return 0, err1 97 } 98 99 if r1 != 0 { 100 // parent; return PID 101 runtime_AfterFork() 102 return int(r1), 0 103 } 104 105 // Fork succeeded, now in child. 106 107 runtime_AfterForkInChild() 108 109 // Session ID 110 if sys.Setsid { 111 _, err1 = setsid() 112 if err1 != 0 { 113 goto childerror 114 } 115 } 116 117 // Set process group 118 if sys.Setpgid || sys.Foreground { 119 // Place child in process group. 120 err1 = setpgid(0, uintptr(sys.Pgid)) 121 if err1 != 0 { 122 goto childerror 123 } 124 } 125 126 if sys.Foreground { 127 pgrp := _Pid_t(sys.Pgid) 128 if pgrp == 0 { 129 r1, err1 = getpid() 130 if err1 != 0 { 131 goto childerror 132 } 133 134 pgrp = _Pid_t(r1) 135 } 136 137 // Place process group in foreground. 138 err1 = ioctl(uintptr(sys.Ctty), uintptr(TIOCSPGRP), uintptr(unsafe.Pointer(&pgrp))) 139 if err1 != 0 { 140 goto childerror 141 } 142 } 143 144 // Chroot 145 if chroot != nil { 146 err1 = chroot1(uintptr(unsafe.Pointer(chroot))) 147 if err1 != 0 { 148 goto childerror 149 } 150 } 151 152 // User and groups 153 if cred := sys.Credential; cred != nil { 154 ngroups := uintptr(len(cred.Groups)) 155 groups := uintptr(0) 156 if ngroups > 0 { 157 groups = uintptr(unsafe.Pointer(&cred.Groups[0])) 158 } 159 if !cred.NoSetGroups { 160 err1 = setgroups1(ngroups, groups) 161 if err1 != 0 { 162 goto childerror 163 } 164 } 165 err1 = setgid(uintptr(cred.Gid)) 166 if err1 != 0 { 167 goto childerror 168 } 169 err1 = setuid(uintptr(cred.Uid)) 170 if err1 != 0 { 171 goto childerror 172 } 173 } 174 175 // Chdir 176 if dir != nil { 177 err1 = chdir(uintptr(unsafe.Pointer(dir))) 178 if err1 != 0 { 179 goto childerror 180 } 181 } 182 183 // Pass 1: look for fd[i] < i and move those up above len(fd) 184 // so that pass 2 won't stomp on an fd it needs later. 185 if pipe < nextfd { 186 _, err1 = dup2child(uintptr(pipe), uintptr(nextfd)) 187 if err1 != 0 { 188 goto childerror 189 } 190 fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC) 191 pipe = nextfd 192 nextfd++ 193 } 194 for i = 0; i < len(fd); i++ { 195 if fd[i] >= 0 && fd[i] < int(i) { 196 if nextfd == pipe { // don't stomp on pipe 197 nextfd++ 198 } 199 _, err1 = dup2child(uintptr(fd[i]), uintptr(nextfd)) 200 if err1 != 0 { 201 goto childerror 202 } 203 _, err1 = fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC) 204 if err1 != 0 { 205 goto childerror 206 } 207 fd[i] = nextfd 208 nextfd++ 209 } 210 } 211 212 // Pass 2: dup fd[i] down onto i. 213 for i = 0; i < len(fd); i++ { 214 if fd[i] == -1 { 215 close(uintptr(i)) 216 continue 217 } 218 if fd[i] == int(i) { 219 // dup2(i, i) won't clear close-on-exec flag on Linux, 220 // probably not elsewhere either. 221 _, err1 = fcntl1(uintptr(fd[i]), F_SETFD, 0) 222 if err1 != 0 { 223 goto childerror 224 } 225 continue 226 } 227 // The new fd is created NOT close-on-exec, 228 // which is exactly what we want. 229 _, err1 = dup2child(uintptr(fd[i]), uintptr(i)) 230 if err1 != 0 { 231 goto childerror 232 } 233 } 234 235 // By convention, we don't close-on-exec the fds we are 236 // started with, so if len(fd) < 3, close 0, 1, 2 as needed. 237 // Programs that know they inherit fds >= 3 will need 238 // to set them close-on-exec. 239 for i = len(fd); i < 3; i++ { 240 close(uintptr(i)) 241 } 242 243 // Detach fd 0 from tty 244 if sys.Noctty { 245 err1 = ioctl(0, uintptr(TIOCNOTTY), 0) 246 if err1 != 0 { 247 goto childerror 248 } 249 } 250 251 // Set the controlling TTY to Ctty 252 if sys.Setctty { 253 // On AIX, TIOCSCTTY is undefined 254 if TIOCSCTTY == 0 { 255 err1 = ENOSYS 256 goto childerror 257 } 258 err1 = ioctl(uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0) 259 if err1 != 0 { 260 goto childerror 261 } 262 } 263 264 // Time to exec. 265 err1 = execve( 266 uintptr(unsafe.Pointer(argv0)), 267 uintptr(unsafe.Pointer(&argv[0])), 268 uintptr(unsafe.Pointer(&envv[0]))) 269 270childerror: 271 // send error code on pipe 272 write1(uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1)) 273 for { 274 exit(253) 275 } 276} 277