Source file src/syscall/exec_freebsd.go

     1  // Copyright 2021 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  package syscall
     6  
     7  import (
     8  	"runtime"
     9  	"unsafe"
    10  )
    11  
    12  type SysProcAttr struct {
    13  	Chroot     string      // Chroot.
    14  	Credential *Credential // Credential.
    15  	Ptrace     bool        // Enable tracing.
    16  	Setsid     bool        // Create session.
    17  	// Setpgid sets the process group ID of the child to Pgid,
    18  	// or, if Pgid == 0, to the new child's process ID.
    19  	Setpgid bool
    20  	// Setctty sets the controlling terminal of the child to
    21  	// file descriptor Ctty. Ctty must be a descriptor number
    22  	// in the child process: an index into ProcAttr.Files.
    23  	// This is only meaningful if Setsid is true.
    24  	Setctty bool
    25  	Noctty  bool // Detach fd 0 from controlling terminal
    26  	Ctty    int  // Controlling TTY fd
    27  	// Foreground places the child process group in the foreground.
    28  	// This implies Setpgid. The Ctty field must be set to
    29  	// the descriptor of the controlling TTY.
    30  	// Unlike Setctty, in this case Ctty must be a descriptor
    31  	// number in the parent process.
    32  	Foreground bool
    33  	Pgid       int    // Child's process group ID if Setpgid.
    34  	Pdeathsig  Signal // Signal that the process will get when its parent dies (Linux and FreeBSD only)
    35  	Jail       int    // Jail to which the child process is attached (FreeBSD only).
    36  }
    37  
    38  const (
    39  	_P_PID = 0
    40  
    41  	_PROC_PDEATHSIG_CTL = 11
    42  )
    43  
    44  // Implemented in runtime package.
    45  func runtime_BeforeFork()
    46  func runtime_AfterFork()
    47  func runtime_AfterForkInChild()
    48  
    49  // Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
    50  // If a dup or exec fails, write the errno error to pipe.
    51  // (Pipe is close-on-exec so if exec succeeds, it will be closed.)
    52  // In the child, this function must not acquire any locks, because
    53  // they might have been locked at the time of the fork. This means
    54  // no rescheduling, no malloc calls, and no new stack segments.
    55  // For the same reason compiler does not race instrument it.
    56  // The calls to RawSyscall are okay because they are assembly
    57  // functions that do not grow the stack.
    58  //
    59  //go:norace
    60  func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
    61  	// Declare all variables at top in case any
    62  	// declarations require heap allocation (e.g., err1).
    63  	var (
    64  		r1              uintptr
    65  		err1            Errno
    66  		nextfd          int
    67  		i               int
    68  		pgrp            _C_int
    69  		cred            *Credential
    70  		ngroups, groups uintptr
    71  		upid            uintptr
    72  	)
    73  
    74  	rlim := origRlimitNofile.Load()
    75  
    76  	// Record parent PID so child can test if it has died.
    77  	ppid, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
    78  
    79  	// guard against side effects of shuffling fds below.
    80  	// Make sure that nextfd is beyond any currently open files so
    81  	// that we can't run the risk of overwriting any of them.
    82  	fd := make([]int, len(attr.Files))
    83  	nextfd = len(attr.Files)
    84  	for i, ufd := range attr.Files {
    85  		if nextfd < int(ufd) {
    86  			nextfd = int(ufd)
    87  		}
    88  		fd[i] = int(ufd)
    89  	}
    90  	nextfd++
    91  
    92  	// About to call fork.
    93  	// No more allocation or calls of non-assembly functions.
    94  	runtime_BeforeFork()
    95  	r1, _, err1 = RawSyscall(SYS_FORK, 0, 0, 0)
    96  	if err1 != 0 {
    97  		runtime_AfterFork()
    98  		return 0, err1
    99  	}
   100  
   101  	if r1 != 0 {
   102  		// parent; return PID
   103  		runtime_AfterFork()
   104  		return int(r1), 0
   105  	}
   106  
   107  	// Fork succeeded, now in child.
   108  
   109  	// Attach to the given jail, if any. The system call also changes the
   110  	// process' root and working directories to the jail's path directory.
   111  	if sys.Jail > 0 {
   112  		_, _, err1 = RawSyscall(SYS_JAIL_ATTACH, uintptr(sys.Jail), 0, 0)
   113  		if err1 != 0 {
   114  			goto childerror
   115  		}
   116  	}
   117  
   118  	// Enable tracing if requested.
   119  	if sys.Ptrace {
   120  		_, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0)
   121  		if err1 != 0 {
   122  			goto childerror
   123  		}
   124  	}
   125  
   126  	// Session ID
   127  	if sys.Setsid {
   128  		_, _, err1 = RawSyscall(SYS_SETSID, 0, 0, 0)
   129  		if err1 != 0 {
   130  			goto childerror
   131  		}
   132  	}
   133  
   134  	// Set process group
   135  	if sys.Setpgid || sys.Foreground {
   136  		// Place child in process group.
   137  		_, _, err1 = RawSyscall(SYS_SETPGID, 0, uintptr(sys.Pgid), 0)
   138  		if err1 != 0 {
   139  			goto childerror
   140  		}
   141  	}
   142  
   143  	if sys.Foreground {
   144  		// This should really be pid_t, however _C_int (aka int32) is
   145  		// generally equivalent.
   146  		pgrp = _C_int(sys.Pgid)
   147  		if pgrp == 0 {
   148  			r1, _, err1 = RawSyscall(SYS_GETPID, 0, 0, 0)
   149  			if err1 != 0 {
   150  				goto childerror
   151  			}
   152  
   153  			pgrp = _C_int(r1)
   154  		}
   155  
   156  		// Place process group in foreground.
   157  		_, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSPGRP), uintptr(unsafe.Pointer(&pgrp)))
   158  		if err1 != 0 {
   159  			goto childerror
   160  		}
   161  	}
   162  
   163  	// Restore the signal mask. We do this after TIOCSPGRP to avoid
   164  	// having the kernel send a SIGTTOU signal to the process group.
   165  	runtime_AfterForkInChild()
   166  
   167  	// Chroot
   168  	if chroot != nil {
   169  		_, _, err1 = RawSyscall(SYS_CHROOT, uintptr(unsafe.Pointer(chroot)), 0, 0)
   170  		if err1 != 0 {
   171  			goto childerror
   172  		}
   173  	}
   174  
   175  	// User and groups
   176  	if cred = sys.Credential; cred != nil {
   177  		ngroups = uintptr(len(cred.Groups))
   178  		groups = uintptr(0)
   179  		if ngroups > 0 {
   180  			groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
   181  		}
   182  		if !cred.NoSetGroups {
   183  			_, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, groups, 0)
   184  			if err1 != 0 {
   185  				goto childerror
   186  			}
   187  		}
   188  		_, _, err1 = RawSyscall(SYS_SETGID, uintptr(cred.Gid), 0, 0)
   189  		if err1 != 0 {
   190  			goto childerror
   191  		}
   192  		_, _, err1 = RawSyscall(SYS_SETUID, uintptr(cred.Uid), 0, 0)
   193  		if err1 != 0 {
   194  			goto childerror
   195  		}
   196  	}
   197  
   198  	// Chdir
   199  	if dir != nil {
   200  		_, _, err1 = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0)
   201  		if err1 != 0 {
   202  			goto childerror
   203  		}
   204  	}
   205  
   206  	// Parent death signal
   207  	if sys.Pdeathsig != 0 {
   208  		switch runtime.GOARCH {
   209  		case "386", "arm":
   210  			_, _, err1 = RawSyscall6(SYS_PROCCTL, _P_PID, 0, 0, _PROC_PDEATHSIG_CTL, uintptr(unsafe.Pointer(&sys.Pdeathsig)), 0)
   211  		default:
   212  			_, _, err1 = RawSyscall6(SYS_PROCCTL, _P_PID, 0, _PROC_PDEATHSIG_CTL, uintptr(unsafe.Pointer(&sys.Pdeathsig)), 0, 0)
   213  		}
   214  		if err1 != 0 {
   215  			goto childerror
   216  		}
   217  
   218  		// Signal self if parent is already dead. This might cause a
   219  		// duplicate signal in rare cases, but it won't matter when
   220  		// using SIGKILL.
   221  		r1, _, _ = RawSyscall(SYS_GETPPID, 0, 0, 0)
   222  		if r1 != ppid {
   223  			upid, _, _ = RawSyscall(SYS_GETPID, 0, 0, 0)
   224  			_, _, err1 = RawSyscall(SYS_KILL, upid, uintptr(sys.Pdeathsig), 0)
   225  			if err1 != 0 {
   226  				goto childerror
   227  			}
   228  		}
   229  	}
   230  
   231  	// Pass 1: look for fd[i] < i and move those up above len(fd)
   232  	// so that pass 2 won't stomp on an fd it needs later.
   233  	if pipe < nextfd {
   234  		_, _, err1 = RawSyscall(SYS_FCNTL, uintptr(pipe), F_DUP2FD_CLOEXEC, uintptr(nextfd))
   235  		if err1 != 0 {
   236  			goto childerror
   237  		}
   238  		pipe = nextfd
   239  		nextfd++
   240  	}
   241  	for i = 0; i < len(fd); i++ {
   242  		if fd[i] >= 0 && fd[i] < i {
   243  			if nextfd == pipe { // don't stomp on pipe
   244  				nextfd++
   245  			}
   246  			_, _, err1 = RawSyscall(SYS_FCNTL, uintptr(fd[i]), F_DUP2FD_CLOEXEC, uintptr(nextfd))
   247  			if err1 != 0 {
   248  				goto childerror
   249  			}
   250  			fd[i] = nextfd
   251  			nextfd++
   252  		}
   253  	}
   254  
   255  	// Pass 2: dup fd[i] down onto i.
   256  	for i = 0; i < len(fd); i++ {
   257  		if fd[i] == -1 {
   258  			RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
   259  			continue
   260  		}
   261  		if fd[i] == i {
   262  			// dup2(i, i) won't clear close-on-exec flag on Linux,
   263  			// probably not elsewhere either.
   264  			_, _, err1 = RawSyscall(SYS_FCNTL, uintptr(fd[i]), F_SETFD, 0)
   265  			if err1 != 0 {
   266  				goto childerror
   267  			}
   268  			continue
   269  		}
   270  		// The new fd is created NOT close-on-exec,
   271  		// which is exactly what we want.
   272  		_, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(i), 0)
   273  		if err1 != 0 {
   274  			goto childerror
   275  		}
   276  	}
   277  
   278  	// By convention, we don't close-on-exec the fds we are
   279  	// started with, so if len(fd) < 3, close 0, 1, 2 as needed.
   280  	// Programs that know they inherit fds >= 3 will need
   281  	// to set them close-on-exec.
   282  	for i = len(fd); i < 3; i++ {
   283  		RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
   284  	}
   285  
   286  	// Detach fd 0 from tty
   287  	if sys.Noctty {
   288  		_, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCNOTTY), 0)
   289  		if err1 != 0 {
   290  			goto childerror
   291  		}
   292  	}
   293  
   294  	// Set the controlling TTY to Ctty
   295  	if sys.Setctty {
   296  		_, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0)
   297  		if err1 != 0 {
   298  			goto childerror
   299  		}
   300  	}
   301  
   302  	// Restore original rlimit.
   303  	if rlim != nil {
   304  		RawSyscall(SYS_SETRLIMIT, uintptr(RLIMIT_NOFILE), uintptr(unsafe.Pointer(rlim)), 0)
   305  	}
   306  
   307  	// Time to exec.
   308  	_, _, err1 = RawSyscall(SYS_EXECVE,
   309  		uintptr(unsafe.Pointer(argv0)),
   310  		uintptr(unsafe.Pointer(&argv[0])),
   311  		uintptr(unsafe.Pointer(&envv[0])))
   312  
   313  childerror:
   314  	// send error code on pipe
   315  	RawSyscall(SYS_WRITE, uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1))
   316  	for {
   317  		RawSyscall(SYS_EXIT, 253, 0, 0)
   318  	}
   319  }
   320  

View as plain text