diff options
Diffstat (limited to 'src/pkg/syscall/exec_unix.go')
| -rw-r--r-- | src/pkg/syscall/exec_unix.go | 102 | 
1 files changed, 82 insertions, 20 deletions
| diff --git a/src/pkg/syscall/exec_unix.go b/src/pkg/syscall/exec_unix.go index 2e09539ee..b6cb1baa2 100644 --- a/src/pkg/syscall/exec_unix.go +++ b/src/pkg/syscall/exec_unix.go @@ -96,13 +96,16 @@ func SetNonblock(fd int, nonblocking bool) (errno int) {  // no rescheduling, no malloc calls, and no new stack segments.  // The calls to RawSyscall are okay because they are assembly  // functions that do not grow the stack. -func forkAndExecInChild(argv0 *byte, argv []*byte, envv []*byte, traceme bool, dir *byte, fd []int, pipe int) (pid int, err int) { +func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, pipe int) (pid int, err int) {  	// Declare all variables at top in case any  	// declarations require heap allocation (e.g., err1).  	var r1, r2, err1 uintptr  	var nextfd int  	var i int +	// guard against side effects of shuffling fds below. +	fd := append([]int(nil), attr.Files...) +  	darwin := OS == "darwin"  	// About to call fork. @@ -128,13 +131,50 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []*byte, traceme bool, d  	// Fork succeeded, now in child.  	// Enable tracing if requested. -	if traceme { +	if attr.Ptrace {  		_, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0)  		if err1 != 0 {  			goto childerror  		}  	} +	// Session ID +	if attr.Setsid { +		_, _, err1 = RawSyscall(SYS_SETSID, 0, 0, 0) +		if err1 != 0 { +			goto childerror +		} +	} + +	// Chroot +	if chroot != nil { +		_, _, err1 = RawSyscall(SYS_CHROOT, uintptr(unsafe.Pointer(chroot)), 0, 0) +		if err1 != 0 { +			goto childerror +		} +	} + +	// User and groups +	if attr.Credential != nil { +		ngroups := uintptr(len(attr.Credential.Groups)) +		groups := uintptr(0) +		if ngroups > 0 { +			groups = uintptr(unsafe.Pointer(&attr.Credential.Groups[0])) +		} +		_, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, groups, 0) +		if err1 != 0 { +			goto childerror +		} +		_, _, err1 = RawSyscall(SYS_SETGID, uintptr(attr.Credential.Gid), 0, 0) +		if err1 != 0 { +			goto childerror +		} +		_, _, err1 = RawSyscall(SYS_SETUID, uintptr(attr.Credential.Uid), 0, 0) +		if err1 != 0 { +			goto childerror +		} +	} +  	// Chdir  	if dir != nil {  		_, _, err1 = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0) @@ -220,28 +260,55 @@ childerror:  	panic("unreached")  } -func forkExec(argv0 string, argv []string, envv []string, traceme bool, dir string, fd []int) (pid int, err int) { +type Credential struct { +	Uid    uint32   // User ID. +	Gid    uint32   // Group ID. +	Groups []uint32 // Supplementary group IDs. +} + +type ProcAttr struct { +	Setsid     bool        // Create session. +	Ptrace     bool        // Enable tracing. +	Dir        string      // Current working directory. +	Env        []string    // Environment. +	Files      []int       // File descriptors. +	Chroot     string      // Chroot. +	Credential *Credential // Credential. +} + +var zeroAttributes ProcAttr + +func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {  	var p [2]int  	var n int  	var err1 uintptr  	var wstatus WaitStatus +	if attr == nil { +		attr = &zeroAttributes +	} +  	p[0] = -1  	p[1] = -1  	// Convert args to C form.  	argv0p := StringBytePtr(argv0)  	argvp := StringArrayPtr(argv) -	envvp := StringArrayPtr(envv) -	var dirp *byte -	if len(dir) > 0 { -		dirp = StringBytePtr(dir) -	} +	envvp := StringArrayPtr(attr.Env)  	if OS == "freebsd" && len(argv[0]) > len(argv0) {  		argvp[0] = argv0p  	} +	var chroot *byte +	if attr.Chroot != "" { +		chroot = StringBytePtr(attr.Chroot) +	} +	var dir *byte +	if attr.Dir != "" { +		dir = StringBytePtr(attr.Dir) +	} +  	// Acquire the fork lock so that no other threads  	// create new fds that are not yet close-on-exec  	// before we fork. @@ -259,7 +326,7 @@ func forkExec(argv0 string, argv []string, envv []string, traceme bool, dir stri  	}  	// Kick off child. -	pid, err = forkAndExecInChild(argv0p, argvp, envvp, traceme, dirp, fd, p[1]) +	pid, err = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, p[1])  	if err != 0 {  	error:  		if p[0] >= 0 { @@ -297,13 +364,14 @@ func forkExec(argv0 string, argv []string, envv []string, traceme bool, dir stri  }  // Combination of fork and exec, careful to be thread safe. -func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int) (pid int, err int) { -	return forkExec(argv0, argv, envv, false, dir, fd) +func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) { +	return forkExec(argv0, argv, attr)  } -// PtraceForkExec is like ForkExec, but starts the child in a traced state. -func PtraceForkExec(argv0 string, argv []string, envv []string, dir string, fd []int) (pid int, err int) { -	return forkExec(argv0, argv, envv, true, dir, fd) +// StartProcess wraps ForkExec for package os. +func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid, handle int, err int) { +	pid, err = forkExec(argv0, argv, attr) +	return pid, 0, err  }  // Ordinary exec. @@ -314,9 +382,3 @@ func Exec(argv0 string, argv []string, envv []string) (err int) {  		uintptr(unsafe.Pointer(&StringArrayPtr(envv)[0])))  	return int(err1)  } - -// StartProcess wraps ForkExec for package os. -func StartProcess(argv0 string, argv []string, envv []string, dir string, fd []int) (pid, handle int, err int) { -	pid, err = forkExec(argv0, argv, envv, false, dir, fd) -	return pid, 0, err -} | 
