exec_solaris.go 6.1 KB

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