2009-02-15 19:35:52 -08:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
2021-02-19 18:35:10 -05:00
|
|
|
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
2018-09-28 15:24:32 +02:00
|
|
|
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
build: add build comments to core packages
The go/build package already recognizes
system-specific file names like
mycode_darwin.go
mycode_darwin_386.go
mycode_386.s
However, it is also common to write files that
apply to multiple architectures, so a recent CL added
to go/build the ability to process comments
listing a set of conditions for building. For example:
// +build darwin freebsd openbsd/386
says that this file should be compiled only on
OS X, FreeBSD, or 32-bit x86 OpenBSD systems.
These conventions are not yet documented
(hence this long CL description).
This CL adds build comments to the multi-system
files in the core library, a step toward making it
possible to use go/build to build them.
With this change go/build can handle crypto/rand,
exec, net, path/filepath, os/user, and time.
os and syscall need additional adjustments.
R=golang-dev, r, gri, r, gustavo
CC=golang-dev
https://golang.org/cl/5011046
2011-09-15 16:48:57 -04:00
|
|
|
|
2009-02-15 19:35:52 -08:00
|
|
|
// Fork, exec, wait, etc.
|
|
|
|
|
|
|
|
|
|
package syscall
|
|
|
|
|
|
|
|
|
|
import (
|
2020-05-01 12:26:30 -07:00
|
|
|
errorspkg "errors"
|
2019-03-02 11:14:46 -08:00
|
|
|
"internal/bytealg"
|
2012-01-14 06:40:55 +09:00
|
|
|
"runtime"
|
2009-12-15 15:40:16 -08:00
|
|
|
"sync"
|
|
|
|
|
"unsafe"
|
2009-02-15 19:35:52 -08:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Lock synchronizing creation of new file descriptors with fork.
|
|
|
|
|
//
|
|
|
|
|
// We want the child in a fork/exec sequence to inherit only the
|
2016-03-01 23:21:55 +00:00
|
|
|
// file descriptors we intend. To do that, we mark all file
|
2009-02-15 19:35:52 -08:00
|
|
|
// descriptors close-on-exec and then, in the child, explicitly
|
|
|
|
|
// unmark the ones we want the exec'ed program to keep.
|
|
|
|
|
// Unix doesn't make this easy: there is, in general, no way to
|
2016-03-01 23:21:55 +00:00
|
|
|
// allocate a new file descriptor close-on-exec. Instead you
|
2009-02-15 19:35:52 -08:00
|
|
|
// have to allocate the descriptor and then mark it close-on-exec.
|
|
|
|
|
// If a fork happens between those two events, the child's exec
|
|
|
|
|
// will inherit an unwanted file descriptor.
|
|
|
|
|
//
|
|
|
|
|
// This lock solves that race: the create new fd/mark close-on-exec
|
|
|
|
|
// operation is done holding ForkLock for reading, and the fork itself
|
2016-03-01 23:21:55 +00:00
|
|
|
// is done holding ForkLock for writing. At least, that's the idea.
|
2009-02-15 19:35:52 -08:00
|
|
|
// There are some complications.
|
|
|
|
|
//
|
|
|
|
|
// Some system calls that create new file descriptors can block
|
|
|
|
|
// for arbitrarily long times: open on a hung NFS server or named
|
2016-03-01 23:21:55 +00:00
|
|
|
// pipe, accept on a socket, and so on. We can't reasonably grab
|
2009-02-15 19:35:52 -08:00
|
|
|
// the lock across those operations.
|
|
|
|
|
//
|
|
|
|
|
// It is worse to inherit some file descriptors than others.
|
|
|
|
|
// If a non-malicious child accidentally inherits an open ordinary file,
|
2016-03-01 23:21:55 +00:00
|
|
|
// that's not a big deal. On the other hand, if a long-lived child
|
2009-02-15 19:35:52 -08:00
|
|
|
// accidentally inherits the write end of a pipe, then the reader
|
|
|
|
|
// of that pipe will not see EOF until that child exits, potentially
|
2016-03-01 23:21:55 +00:00
|
|
|
// causing the parent program to hang. This is a common problem
|
2009-02-15 19:35:52 -08:00
|
|
|
// in threaded C programs that use popen.
|
|
|
|
|
//
|
|
|
|
|
// Luckily, the file descriptors that are most important not to
|
|
|
|
|
// inherit are not the ones that can take an arbitrarily long time
|
|
|
|
|
// to create: pipe returns instantly, and the net package uses
|
|
|
|
|
// non-blocking I/O to accept on a listening socket.
|
|
|
|
|
// The rules for which file descriptor-creating operations use the
|
|
|
|
|
// ForkLock are as follows:
|
|
|
|
|
//
|
2016-03-01 23:21:55 +00:00
|
|
|
// 1) Pipe. Does not block. Use the ForkLock.
|
|
|
|
|
// 2) Socket. Does not block. Use the ForkLock.
|
|
|
|
|
// 3) Accept. If using non-blocking mode, use the ForkLock.
|
2009-02-15 19:35:52 -08:00
|
|
|
// Otherwise, live with the race.
|
2016-03-01 23:21:55 +00:00
|
|
|
// 4) Open. Can block. Use O_CLOEXEC if available (Linux).
|
2009-02-15 19:35:52 -08:00
|
|
|
// Otherwise, live with the race.
|
2016-03-01 23:21:55 +00:00
|
|
|
// 5) Dup. Does not block. Use the ForkLock.
|
2009-02-15 19:35:52 -08:00
|
|
|
// On Linux, could use fcntl F_DUPFD_CLOEXEC
|
|
|
|
|
// instead of the ForkLock, but only for dup(fd, -1).
|
|
|
|
|
|
|
|
|
|
var ForkLock sync.RWMutex
|
|
|
|
|
|
2015-05-18 15:50:00 -04:00
|
|
|
// StringSlicePtr converts a slice of strings to a slice of pointers
|
|
|
|
|
// to NUL-terminated byte arrays. If any string contains a NUL byte
|
|
|
|
|
// this function panics instead of returning an error.
|
|
|
|
|
//
|
|
|
|
|
// Deprecated: Use SlicePtrFromStrings instead.
|
2011-06-11 09:25:18 +10:00
|
|
|
func StringSlicePtr(ss []string) []*byte {
|
2009-12-15 15:40:16 -08:00
|
|
|
bb := make([]*byte, len(ss)+1)
|
2009-02-15 19:35:52 -08:00
|
|
|
for i := 0; i < len(ss); i++ {
|
2009-11-09 12:07:39 -08:00
|
|
|
bb[i] = StringBytePtr(ss[i])
|
2009-02-15 19:35:52 -08:00
|
|
|
}
|
2009-12-15 15:40:16 -08:00
|
|
|
bb[len(ss)] = nil
|
|
|
|
|
return bb
|
2009-02-15 19:35:52 -08:00
|
|
|
}
|
|
|
|
|
|
syscall: return EINVAL when string arguments have NUL characters
Since NUL usually terminates strings in underlying syscalls, allowing
it when converting string arguments is a security risk, especially
when dealing with filenames. For example, a program might reason that
filename like "/root/..\x00/" is a subdirectory or "/root/" and allow
access to it, while underlying syscall will treat "\x00" as an end of
that string and the actual filename will be "/root/..", which might
be unexpected. Returning EINVAL when string arguments have NUL in
them makes sure this attack vector is unusable.
R=golang-dev, r, bradfitz, fullung, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/6458050
2012-08-05 17:24:32 -04:00
|
|
|
// SlicePtrFromStrings converts a slice of strings to a slice of
|
2015-05-18 15:50:00 -04:00
|
|
|
// pointers to NUL-terminated byte arrays. If any string contains
|
syscall: return EINVAL when string arguments have NUL characters
Since NUL usually terminates strings in underlying syscalls, allowing
it when converting string arguments is a security risk, especially
when dealing with filenames. For example, a program might reason that
filename like "/root/..\x00/" is a subdirectory or "/root/" and allow
access to it, while underlying syscall will treat "\x00" as an end of
that string and the actual filename will be "/root/..", which might
be unexpected. Returning EINVAL when string arguments have NUL in
them makes sure this attack vector is unusable.
R=golang-dev, r, bradfitz, fullung, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/6458050
2012-08-05 17:24:32 -04:00
|
|
|
// a NUL byte, it returns (nil, EINVAL).
|
|
|
|
|
func SlicePtrFromStrings(ss []string) ([]*byte, error) {
|
2019-03-02 11:14:46 -08:00
|
|
|
n := 0
|
|
|
|
|
for _, s := range ss {
|
|
|
|
|
if bytealg.IndexByteString(s, 0) != -1 {
|
|
|
|
|
return nil, EINVAL
|
syscall: return EINVAL when string arguments have NUL characters
Since NUL usually terminates strings in underlying syscalls, allowing
it when converting string arguments is a security risk, especially
when dealing with filenames. For example, a program might reason that
filename like "/root/..\x00/" is a subdirectory or "/root/" and allow
access to it, while underlying syscall will treat "\x00" as an end of
that string and the actual filename will be "/root/..", which might
be unexpected. Returning EINVAL when string arguments have NUL in
them makes sure this attack vector is unusable.
R=golang-dev, r, bradfitz, fullung, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/6458050
2012-08-05 17:24:32 -04:00
|
|
|
}
|
2019-03-02 11:14:46 -08:00
|
|
|
n += len(s) + 1 // +1 for NUL
|
|
|
|
|
}
|
|
|
|
|
bb := make([]*byte, len(ss)+1)
|
|
|
|
|
b := make([]byte, n)
|
|
|
|
|
n = 0
|
|
|
|
|
for i, s := range ss {
|
|
|
|
|
bb[i] = &b[n]
|
|
|
|
|
copy(b[n:], s)
|
|
|
|
|
n += len(s) + 1
|
syscall: return EINVAL when string arguments have NUL characters
Since NUL usually terminates strings in underlying syscalls, allowing
it when converting string arguments is a security risk, especially
when dealing with filenames. For example, a program might reason that
filename like "/root/..\x00/" is a subdirectory or "/root/" and allow
access to it, while underlying syscall will treat "\x00" as an end of
that string and the actual filename will be "/root/..", which might
be unexpected. Returning EINVAL when string arguments have NUL in
them makes sure this attack vector is unusable.
R=golang-dev, r, bradfitz, fullung, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/6458050
2012-08-05 17:24:32 -04:00
|
|
|
}
|
|
|
|
|
return bb, nil
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-15 15:40:16 -08:00
|
|
|
func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) }
|
2009-06-01 22:14:57 -07:00
|
|
|
|
2011-11-13 22:44:52 -05:00
|
|
|
func SetNonblock(fd int, nonblocking bool) (err error) {
|
2009-12-15 15:40:16 -08:00
|
|
|
flag, err := fcntl(fd, F_GETFL, 0)
|
2011-11-13 22:44:52 -05:00
|
|
|
if err != nil {
|
2009-11-09 12:07:39 -08:00
|
|
|
return err
|
2009-02-15 19:35:52 -08:00
|
|
|
}
|
2009-06-01 22:14:57 -07:00
|
|
|
if nonblocking {
|
2009-11-09 12:07:39 -08:00
|
|
|
flag |= O_NONBLOCK
|
2009-06-01 22:14:57 -07:00
|
|
|
} else {
|
2016-03-29 14:09:22 +02:00
|
|
|
flag &^= O_NONBLOCK
|
2009-06-01 22:14:57 -07:00
|
|
|
}
|
2009-12-15 15:40:16 -08:00
|
|
|
_, err = fcntl(fd, F_SETFL, flag)
|
|
|
|
|
return err
|
2009-02-15 19:35:52 -08:00
|
|
|
}
|
|
|
|
|
|
2011-06-27 19:07:49 -04:00
|
|
|
// Credential holds user and group identities to be assumed
|
|
|
|
|
// by a child process started by StartProcess.
|
2011-03-29 14:29:22 -04:00
|
|
|
type Credential struct {
|
2017-02-10 04:10:48 -02:00
|
|
|
Uid uint32 // User ID.
|
|
|
|
|
Gid uint32 // Group ID.
|
|
|
|
|
Groups []uint32 // Supplementary group IDs.
|
|
|
|
|
NoSetGroups bool // If true, don't set supplementary groups
|
2011-03-29 14:29:22 -04:00
|
|
|
}
|
2011-03-15 14:41:19 -04:00
|
|
|
|
2011-06-27 19:07:49 -04:00
|
|
|
// ProcAttr holds attributes that will be applied to a new process started
|
|
|
|
|
// by StartProcess.
|
2011-03-15 14:41:19 -04:00
|
|
|
type ProcAttr struct {
|
2012-02-11 08:47:19 +11:00
|
|
|
Dir string // Current working directory.
|
|
|
|
|
Env []string // Environment.
|
|
|
|
|
Files []uintptr // File descriptors.
|
2011-06-14 10:49:34 -04:00
|
|
|
Sys *SysProcAttr
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var zeroProcAttr ProcAttr
|
|
|
|
|
var zeroSysProcAttr SysProcAttr
|
2011-03-15 14:41:19 -04:00
|
|
|
|
2011-11-13 22:44:52 -05:00
|
|
|
func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
|
2009-12-15 15:40:16 -08:00
|
|
|
var p [2]int
|
|
|
|
|
var n int
|
2011-11-13 22:44:52 -05:00
|
|
|
var err1 Errno
|
2009-12-15 15:40:16 -08:00
|
|
|
var wstatus WaitStatus
|
2009-02-15 19:35:52 -08:00
|
|
|
|
2011-03-15 14:41:19 -04:00
|
|
|
if attr == nil {
|
2011-06-14 10:49:34 -04:00
|
|
|
attr = &zeroProcAttr
|
|
|
|
|
}
|
|
|
|
|
sys := attr.Sys
|
|
|
|
|
if sys == nil {
|
|
|
|
|
sys = &zeroSysProcAttr
|
2011-03-15 14:41:19 -04:00
|
|
|
}
|
|
|
|
|
|
2009-12-15 15:40:16 -08:00
|
|
|
p[0] = -1
|
|
|
|
|
p[1] = -1
|
2009-02-15 19:35:52 -08:00
|
|
|
|
|
|
|
|
// Convert args to C form.
|
syscall: return EINVAL when string arguments have NUL characters
Since NUL usually terminates strings in underlying syscalls, allowing
it when converting string arguments is a security risk, especially
when dealing with filenames. For example, a program might reason that
filename like "/root/..\x00/" is a subdirectory or "/root/" and allow
access to it, while underlying syscall will treat "\x00" as an end of
that string and the actual filename will be "/root/..", which might
be unexpected. Returning EINVAL when string arguments have NUL in
them makes sure this attack vector is unusable.
R=golang-dev, r, bradfitz, fullung, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/6458050
2012-08-05 17:24:32 -04:00
|
|
|
argv0p, err := BytePtrFromString(argv0)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
|
|
|
|
argvp, err := SlicePtrFromStrings(argv)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
|
|
|
|
envvp, err := SlicePtrFromStrings(attr.Env)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
2009-02-15 19:35:52 -08:00
|
|
|
|
2014-03-01 18:56:50 -05:00
|
|
|
if (runtime.GOOS == "freebsd" || runtime.GOOS == "dragonfly") && len(argv[0]) > len(argv0) {
|
2011-03-06 14:57:05 -05:00
|
|
|
argvp[0] = argv0p
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-29 14:29:22 -04:00
|
|
|
var chroot *byte
|
2011-06-14 10:49:34 -04:00
|
|
|
if sys.Chroot != "" {
|
syscall: return EINVAL when string arguments have NUL characters
Since NUL usually terminates strings in underlying syscalls, allowing
it when converting string arguments is a security risk, especially
when dealing with filenames. For example, a program might reason that
filename like "/root/..\x00/" is a subdirectory or "/root/" and allow
access to it, while underlying syscall will treat "\x00" as an end of
that string and the actual filename will be "/root/..", which might
be unexpected. Returning EINVAL when string arguments have NUL in
them makes sure this attack vector is unusable.
R=golang-dev, r, bradfitz, fullung, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/6458050
2012-08-05 17:24:32 -04:00
|
|
|
chroot, err = BytePtrFromString(sys.Chroot)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
2011-03-29 14:29:22 -04:00
|
|
|
}
|
2011-03-15 14:41:19 -04:00
|
|
|
var dir *byte
|
|
|
|
|
if attr.Dir != "" {
|
syscall: return EINVAL when string arguments have NUL characters
Since NUL usually terminates strings in underlying syscalls, allowing
it when converting string arguments is a security risk, especially
when dealing with filenames. For example, a program might reason that
filename like "/root/..\x00/" is a subdirectory or "/root/" and allow
access to it, while underlying syscall will treat "\x00" as an end of
that string and the actual filename will be "/root/..", which might
be unexpected. Returning EINVAL when string arguments have NUL in
them makes sure this attack vector is unusable.
R=golang-dev, r, bradfitz, fullung, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/6458050
2012-08-05 17:24:32 -04:00
|
|
|
dir, err = BytePtrFromString(attr.Dir)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
2011-03-15 14:41:19 -04:00
|
|
|
}
|
|
|
|
|
|
2020-05-01 12:26:30 -07:00
|
|
|
// Both Setctty and Foreground use the Ctty field,
|
|
|
|
|
// but they give it slightly different meanings.
|
|
|
|
|
if sys.Setctty && sys.Foreground {
|
|
|
|
|
return 0, errorspkg.New("both Setctty and Foreground set in SysProcAttr")
|
|
|
|
|
}
|
|
|
|
|
if sys.Setctty && sys.Ctty >= len(attr.Files) {
|
|
|
|
|
return 0, errorspkg.New("Setctty set but Ctty not valid in child")
|
|
|
|
|
}
|
|
|
|
|
|
2009-02-15 19:35:52 -08:00
|
|
|
// Acquire the fork lock so that no other threads
|
|
|
|
|
// create new fds that are not yet close-on-exec
|
|
|
|
|
// before we fork.
|
2009-12-15 15:40:16 -08:00
|
|
|
ForkLock.Lock()
|
2009-02-15 19:35:52 -08:00
|
|
|
|
|
|
|
|
// Allocate child status pipe close on exec.
|
2013-01-10 17:04:55 -08:00
|
|
|
if err = forkExecPipe(p[:]); err != nil {
|
2009-11-09 12:07:39 -08:00
|
|
|
goto error
|
2009-02-15 19:35:52 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Kick off child.
|
2011-11-13 22:44:52 -05:00
|
|
|
pid, err1 = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1])
|
|
|
|
|
if err1 != 0 {
|
|
|
|
|
err = Errno(err1)
|
2011-06-17 06:07:13 -04:00
|
|
|
goto error
|
2009-02-15 19:35:52 -08:00
|
|
|
}
|
2009-12-15 15:40:16 -08:00
|
|
|
ForkLock.Unlock()
|
2009-02-15 19:35:52 -08:00
|
|
|
|
|
|
|
|
// Read child error status from pipe.
|
2009-12-15 15:40:16 -08:00
|
|
|
Close(p[1])
|
internal/poll, os: loop on EINTR
Historically we've assumed that we can install all signal handlers
with the SA_RESTART flag set, and let the system restart slow functions
if a signal is received. Therefore, we don't have to worry about EINTR.
This is only partially true, and we've added EINTR checks already for
connect, and open/read on Darwin, and sendfile on Solaris.
Other cases have turned up in #36644, #38033, and #38836.
Also, #20400 points out that when Go code is included in a C program,
the C program may install its own signal handlers without SA_RESTART.
In that case, Go code will see EINTR no matter what it does.
So, go ahead and check for EINTR. We don't check in the syscall package;
people using syscalls directly may want to check for EINTR themselves.
But we do check for EINTR in the higher level APIs in os and net,
and retry the system call if we see it.
This change looks safe, but of course we may be missing some cases
where we need to check for EINTR. As such cases turn up, we can add
tests to runtime/testdata/testprogcgo/eintr.go, and fix the code.
If there are any such cases, their handling after this change will be
no worse than it is today.
For #22838
Fixes #20400
Fixes #36644
Fixes #38033
Fixes #38836
Change-Id: I7e46ca8cafed0429c7a2386cc9edc9d9d47a6896
Reviewed-on: https://go-review.googlesource.com/c/go/+/232862
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
2020-05-07 21:34:54 -07:00
|
|
|
for {
|
|
|
|
|
n, err = readlen(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1)))
|
|
|
|
|
if err != EINTR {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-12-15 15:40:16 -08:00
|
|
|
Close(p[0])
|
2011-11-13 22:44:52 -05:00
|
|
|
if err != nil || n != 0 {
|
2011-06-17 16:12:14 -04:00
|
|
|
if n == int(unsafe.Sizeof(err1)) {
|
2011-11-13 22:44:52 -05:00
|
|
|
err = Errno(err1)
|
2009-02-15 19:35:52 -08:00
|
|
|
}
|
2011-11-13 22:44:52 -05:00
|
|
|
if err == nil {
|
2009-11-09 12:07:39 -08:00
|
|
|
err = EPIPE
|
2009-02-15 19:35:52 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Child failed; wait for it to exit, to make sure
|
|
|
|
|
// the zombies don't accumulate.
|
2009-12-15 15:40:16 -08:00
|
|
|
_, err1 := Wait4(pid, &wstatus, 0, nil)
|
2009-02-15 19:35:52 -08:00
|
|
|
for err1 == EINTR {
|
2009-11-09 12:07:39 -08:00
|
|
|
_, err1 = Wait4(pid, &wstatus, 0, nil)
|
2009-02-15 19:35:52 -08:00
|
|
|
}
|
2009-12-15 15:40:16 -08:00
|
|
|
return 0, err
|
2009-02-15 19:35:52 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Read got EOF, so pipe closed on exec, so exec succeeded.
|
2011-11-13 22:44:52 -05:00
|
|
|
return pid, nil
|
2011-06-17 06:07:13 -04:00
|
|
|
|
|
|
|
|
error:
|
|
|
|
|
if p[0] >= 0 {
|
|
|
|
|
Close(p[0])
|
|
|
|
|
Close(p[1])
|
|
|
|
|
}
|
|
|
|
|
ForkLock.Unlock()
|
|
|
|
|
return 0, err
|
2009-02-15 19:35:52 -08:00
|
|
|
}
|
|
|
|
|
|
2009-07-14 15:09:39 -07:00
|
|
|
// Combination of fork and exec, careful to be thread safe.
|
2011-11-13 22:44:52 -05:00
|
|
|
func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
|
2011-03-15 14:41:19 -04:00
|
|
|
return forkExec(argv0, argv, attr)
|
2009-07-14 15:09:39 -07:00
|
|
|
}
|
|
|
|
|
|
2011-03-15 14:41:19 -04:00
|
|
|
// StartProcess wraps ForkExec for package os.
|
2012-02-02 14:08:48 -05:00
|
|
|
func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
|
2011-03-15 14:41:19 -04:00
|
|
|
pid, err = forkExec(argv0, argv, attr)
|
|
|
|
|
return pid, 0, err
|
2009-07-14 15:09:39 -07:00
|
|
|
}
|
|
|
|
|
|
2017-05-20 17:22:36 +01:00
|
|
|
// Implemented in runtime package.
|
|
|
|
|
func runtime_BeforeExec()
|
|
|
|
|
func runtime_AfterExec()
|
|
|
|
|
|
2018-09-28 15:24:32 +02:00
|
|
|
// execveLibc is non-nil on OS using libc syscall, set to execve in exec_libc.go; this
|
2017-06-28 10:58:44 -07:00
|
|
|
// avoids a build dependency for other platforms.
|
2018-11-07 15:27:16 -08:00
|
|
|
var execveLibc func(path uintptr, argv uintptr, envp uintptr) Errno
|
|
|
|
|
var execveDarwin func(path *byte, argv **byte, envp **byte) error
|
2020-11-16 04:47:56 +11:00
|
|
|
var execveOpenBSD func(path *byte, argv **byte, envp **byte) error
|
2017-06-28 10:58:44 -07:00
|
|
|
|
2016-09-13 23:31:07 -07:00
|
|
|
// Exec invokes the execve(2) system call.
|
2011-11-13 22:44:52 -05:00
|
|
|
func Exec(argv0 string, argv []string, envv []string) (err error) {
|
syscall: return EINVAL when string arguments have NUL characters
Since NUL usually terminates strings in underlying syscalls, allowing
it when converting string arguments is a security risk, especially
when dealing with filenames. For example, a program might reason that
filename like "/root/..\x00/" is a subdirectory or "/root/" and allow
access to it, while underlying syscall will treat "\x00" as an end of
that string and the actual filename will be "/root/..", which might
be unexpected. Returning EINVAL when string arguments have NUL in
them makes sure this attack vector is unusable.
R=golang-dev, r, bradfitz, fullung, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/6458050
2012-08-05 17:24:32 -04:00
|
|
|
argv0p, err := BytePtrFromString(argv0)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
argvp, err := SlicePtrFromStrings(argv)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
envvp, err := SlicePtrFromStrings(envv)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2017-05-20 17:22:36 +01:00
|
|
|
runtime_BeforeExec()
|
2017-06-28 10:58:44 -07:00
|
|
|
|
2018-11-07 15:27:16 -08:00
|
|
|
var err1 error
|
2019-04-29 13:50:49 +00:00
|
|
|
if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" || runtime.GOOS == "aix" {
|
|
|
|
|
// RawSyscall should never be used on Solaris, illumos, or AIX.
|
2018-09-28 15:24:32 +02:00
|
|
|
err1 = execveLibc(
|
2017-06-28 10:58:44 -07:00
|
|
|
uintptr(unsafe.Pointer(argv0p)),
|
|
|
|
|
uintptr(unsafe.Pointer(&argvp[0])),
|
|
|
|
|
uintptr(unsafe.Pointer(&envvp[0])))
|
2020-09-16 16:59:58 -04:00
|
|
|
} else if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
|
2018-11-07 15:27:16 -08:00
|
|
|
// Similarly on Darwin.
|
|
|
|
|
err1 = execveDarwin(argv0p, &argvp[0], &envvp[0])
|
2021-04-21 12:24:27 +02:00
|
|
|
} else if runtime.GOOS == "openbsd" && (runtime.GOARCH == "amd64" || runtime.GOARCH == "arm64") {
|
2020-11-16 04:47:56 +11:00
|
|
|
// Similarly on OpenBSD.
|
|
|
|
|
err1 = execveOpenBSD(argv0p, &argvp[0], &envvp[0])
|
2017-06-28 10:58:44 -07:00
|
|
|
} else {
|
|
|
|
|
_, _, err1 = RawSyscall(SYS_EXECVE,
|
|
|
|
|
uintptr(unsafe.Pointer(argv0p)),
|
|
|
|
|
uintptr(unsafe.Pointer(&argvp[0])),
|
|
|
|
|
uintptr(unsafe.Pointer(&envvp[0])))
|
|
|
|
|
}
|
2017-05-20 17:22:36 +01:00
|
|
|
runtime_AfterExec()
|
2017-06-28 10:58:44 -07:00
|
|
|
return err1
|
2009-02-15 19:35:52 -08:00
|
|
|
}
|