diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-04-26 09:55:32 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-04-26 09:55:32 +0200 |
commit | 7b15ed9ef455b6b66c6b376898a88aef5d6a9970 (patch) | |
tree | 3ef530baa80cdf29436ba981f5783be6b4d2202b /src/pkg/syscall/exec_unix.go | |
parent | 50104cc32a498f7517a51c8dc93106c51c7a54b4 (diff) | |
download | golang-7b15ed9ef455b6b66c6b376898a88aef5d6a9970.tar.gz |
Imported Upstream version 2011.04.13upstream/2011.04.13
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 -} |