exec_bsd.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  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. //go:build aix || darwin || dragonfly || netbsd || openbsd || solaris
  5. package syscall
  6. import (
  7. "runtime"
  8. "unsafe"
  9. )
  10. type SysProcAttr struct {
  11. Chroot string // Chroot.
  12. Credential *Credential // Credential.
  13. Ptrace bool // Enable tracing.
  14. Setsid bool // Create session.
  15. // Setpgid sets the process group ID of the child to Pgid,
  16. // or, if Pgid == 0, to the new child's process ID.
  17. Setpgid bool
  18. // Setctty sets the controlling terminal of the child to
  19. // file descriptor Ctty. Ctty must be a descriptor number
  20. // in the child process: an index into ProcAttr.Files.
  21. // This is only meaningful if Setsid is true.
  22. Setctty bool
  23. Noctty bool // Detach fd 0 from controlling terminal
  24. Ctty int // Controlling TTY fd
  25. // Foreground places the child process group in the foreground.
  26. // This implies Setpgid. The Ctty field must be set to
  27. // the descriptor of the controlling TTY.
  28. // Unlike Setctty, in this case Ctty must be a descriptor
  29. // number in the parent process.
  30. Foreground bool
  31. Pgid int // Child's process group ID if Setpgid.
  32. }
  33. // Implemented in runtime package.
  34. func runtime_BeforeFork()
  35. func runtime_AfterFork()
  36. func runtime_AfterForkInChild()
  37. // Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
  38. // If a dup or exec fails, write the errno error to pipe.
  39. // (Pipe is close-on-exec so if exec succeeds, it will be closed.)
  40. // In the child, this function must not acquire any locks, because
  41. // they might have been locked at the time of the fork. This means
  42. // no rescheduling, no malloc calls, and no new stack segments.
  43. // For the same reason compiler does not race instrument it.
  44. // The calls to RawSyscall are okay because they are assembly
  45. // functions that do not grow the stack.
  46. //go:norace
  47. func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
  48. // Declare all variables at top in case any
  49. // declarations require heap allocation (e.g., err1).
  50. var (
  51. r1 Pid_t
  52. err1 Errno
  53. nextfd int
  54. i int
  55. )
  56. // guard against side effects of shuffling fds below.
  57. // Make sure that nextfd is beyond any currently open files so
  58. // that we can't run the risk of overwriting any of them.
  59. fd := make([]int, len(attr.Files))
  60. nextfd = len(attr.Files)
  61. for i, ufd := range attr.Files {
  62. if nextfd < int(ufd) {
  63. nextfd = int(ufd)
  64. }
  65. fd[i] = int(ufd)
  66. }
  67. nextfd++
  68. // About to call fork.
  69. // No more allocation or calls of non-assembly functions.
  70. runtime_BeforeFork()
  71. r1, err1 = raw_fork()
  72. if err1 != 0 {
  73. runtime_AfterFork()
  74. return 0, err1
  75. }
  76. if r1 != 0 {
  77. // parent; return PID
  78. runtime_AfterFork()
  79. return int(r1), 0
  80. }
  81. // Fork succeeded, now in child.
  82. // Enable tracing if requested.
  83. if sys.Ptrace {
  84. err1 = raw_ptrace(_PTRACE_TRACEME, 0, 0, 0)
  85. if err1 != 0 {
  86. goto childerror
  87. }
  88. }
  89. // Session ID
  90. if sys.Setsid {
  91. err1 = raw_setsid()
  92. if err1 != 0 {
  93. goto childerror
  94. }
  95. }
  96. // Set process group
  97. if sys.Setpgid || sys.Foreground {
  98. // Place child in process group.
  99. err1 = raw_setpgid(0, sys.Pgid)
  100. if err1 != 0 {
  101. goto childerror
  102. }
  103. }
  104. if sys.Foreground {
  105. pgrp := Pid_t(sys.Pgid)
  106. if pgrp == 0 {
  107. pgrp = raw_getpid()
  108. }
  109. // Place process group in foreground.
  110. _, err1 = raw_ioctl_ptr(sys.Ctty, TIOCSPGRP, unsafe.Pointer(&pgrp))
  111. if err1 != 0 {
  112. goto childerror
  113. }
  114. }
  115. // Restore the signal mask. We do this after TIOCSPGRP to avoid
  116. // having the kernel send a SIGTTOU signal to the process group.
  117. runtime_AfterForkInChild()
  118. // Chroot
  119. if chroot != nil {
  120. err1 = raw_chroot(chroot)
  121. if err1 != 0 {
  122. goto childerror
  123. }
  124. }
  125. // User and groups
  126. if cred := sys.Credential; cred != nil {
  127. ngroups := len(cred.Groups)
  128. var groups unsafe.Pointer
  129. if ngroups > 0 {
  130. gids := make([]Gid_t, ngroups)
  131. for i, v := range cred.Groups {
  132. gids[i] = Gid_t(v)
  133. }
  134. groups = unsafe.Pointer(&gids[0])
  135. }
  136. if !cred.NoSetGroups {
  137. err1 = raw_setgroups(ngroups, groups)
  138. if err1 != 0 {
  139. goto childerror
  140. }
  141. }
  142. err2 := Setgid(int(cred.Gid))
  143. if err2 != nil {
  144. err1 = err2.(Errno)
  145. goto childerror
  146. }
  147. err2 = Setuid(int(cred.Uid))
  148. if err2 != nil {
  149. err1 = err2.(Errno)
  150. goto childerror
  151. }
  152. }
  153. // Chdir
  154. if dir != nil {
  155. err1 = raw_chdir(dir)
  156. if err1 != 0 {
  157. goto childerror
  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. switch runtime.GOOS {
  164. case "netbsd":
  165. err1 = raw_dup3(pipe, nextfd, O_CLOEXEC)
  166. if err1 != 0 {
  167. goto childerror
  168. }
  169. default:
  170. err1 = raw_dup2(pipe, nextfd)
  171. if err1 != 0 {
  172. goto childerror
  173. }
  174. raw_fcntl(nextfd, F_SETFD, FD_CLOEXEC)
  175. }
  176. pipe = nextfd
  177. nextfd++
  178. }
  179. for i = 0; i < len(fd); i++ {
  180. if fd[i] >= 0 && fd[i] < int(i) {
  181. if nextfd == pipe { // don't stomp on pipe
  182. nextfd++
  183. }
  184. switch runtime.GOOS {
  185. case "netbsd":
  186. err1 = raw_dup3(fd[i], nextfd, O_CLOEXEC)
  187. if err1 != 0 {
  188. goto childerror
  189. }
  190. default:
  191. err1 = raw_dup2(fd[i], nextfd)
  192. if err1 != 0 {
  193. goto childerror
  194. }
  195. raw_fcntl(nextfd, F_SETFD, FD_CLOEXEC)
  196. }
  197. fd[i] = nextfd
  198. nextfd++
  199. }
  200. }
  201. // Pass 2: dup fd[i] down onto i.
  202. for i = 0; i < len(fd); i++ {
  203. if fd[i] == -1 {
  204. raw_close(i)
  205. continue
  206. }
  207. if fd[i] == int(i) {
  208. // dup2(i, i) won't clear close-on-exec flag on Linux,
  209. // probably not elsewhere either.
  210. _, err1 = raw_fcntl(fd[i], F_SETFD, 0)
  211. if err1 != 0 {
  212. goto childerror
  213. }
  214. continue
  215. }
  216. // The new fd is created NOT close-on-exec,
  217. // which is exactly what we want.
  218. err1 = raw_dup2(fd[i], i)
  219. if err1 != 0 {
  220. goto childerror
  221. }
  222. }
  223. // By convention, we don't close-on-exec the fds we are
  224. // started with, so if len(fd) < 3, close 0, 1, 2 as needed.
  225. // Programs that know they inherit fds >= 3 will need
  226. // to set them close-on-exec.
  227. for i = len(fd); i < 3; i++ {
  228. raw_close(i)
  229. }
  230. // Detach fd 0 from tty
  231. if sys.Noctty {
  232. _, err1 = raw_ioctl(0, TIOCNOTTY, 0)
  233. if err1 != 0 {
  234. goto childerror
  235. }
  236. }
  237. // Set the controlling TTY to Ctty
  238. if sys.Setctty {
  239. if TIOCSCTTY == 0 {
  240. err1 = ENOSYS
  241. goto childerror
  242. }
  243. _, err1 = raw_ioctl(sys.Ctty, TIOCSCTTY, 0)
  244. if err1 != 0 {
  245. goto childerror
  246. }
  247. }
  248. // Time to exec.
  249. err1 = raw_execve(argv0, &argv[0], &envv[0])
  250. childerror:
  251. // send error code on pipe
  252. raw_write(pipe, (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1)))
  253. for {
  254. raw_exit(253)
  255. }
  256. }