diff options
Diffstat (limited to 'libgo/syscalls/exec.go')
-rw-r--r-- | libgo/syscalls/exec.go | 101 |
1 files changed, 90 insertions, 11 deletions
diff --git a/libgo/syscalls/exec.go b/libgo/syscalls/exec.go index 450c7e5938d..04d0ef88f82 100644 --- a/libgo/syscalls/exec.go +++ b/libgo/syscalls/exec.go @@ -13,8 +13,14 @@ import "unsafe" func libc_fcntl(fd int, cmd int, arg int) int __asm__ ("fcntl") func libc_fork() Pid_t __asm__ ("fork") func libc_setsid() Pid_t __asm__ ("setsid") +func libc_setpgid(Pid_t, Pid_t) int __asm__ ("setpgid") +func libc_chroot(path *byte) int __asm__ ("chroot") +func libc_setuid(Uid_t) int __asm__ ("setuid") +func libc_setgid(Gid_t) int __asm__ ("setgid") +func libc_setgroups(Size_t, *Gid_t) int __asm__ ("setgroups") func libc_chdir(name *byte) int __asm__ ("chdir") func libc_dup2(int, int) int __asm__ ("dup2") +func libc_ioctl(int, int) int __asm__ ("ioctl") func libc_execve(*byte, **byte, **byte) int __asm__ ("execve") func libc_sysexit(int) __asm__ ("_exit") @@ -24,7 +30,7 @@ func libc_sysexit(int) __asm__ ("_exit") // In the child, this function must not acquire any locks, because // they might have been locked at the time of the fork. This means // no rescheduling, no malloc calls, and no new stack segments. -func forkAndExecInChild(argv0 *byte, argv, envv []*byte, dir *byte, attr *ProcAttr, pipe int) (pid int, err int) { +func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, 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 @@ -51,19 +57,51 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, dir *byte, attr *ProcAt // Fork succeeded, now in child. // Enable tracing if requested. - if attr.Ptrace { + if sys.Ptrace { if libc_ptrace(_PTRACE_TRACEME, 0, 0, nil) < 0 { goto childerror } } // Session ID - if attr.Setsid { + if sys.Setsid { if libc_setsid() == Pid_t(-1) { goto childerror } } + // Set process group + if sys.Setpgid { + if libc_setpgid(0, 0) < 0 { + goto childerror + } + } + + // Chroot + if chroot != nil { + if libc_chroot(chroot) < 0 { + goto childerror + } + } + + // User and groups + if cred := sys.Credential; cred != nil { + ngroups := uintptr(len(cred.Groups)) + var groups *Gid_t + if ngroups > 0 { + groups = (*Gid_t)(unsafe.Pointer(&cred.Groups[0])) + } + if libc_setgroups(Size_t(ngroups), groups) < 0 { + goto childerror + } + if libc_setgid(Gid_t(cred.Gid)) < 0 { + goto childerror + } + if libc_setuid(Uid_t(cred.Uid)) < 0 { + goto childerror + } + } + // Chdir if dir != nil { if libc_chdir(dir) < 0 { @@ -129,6 +167,20 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, dir *byte, attr *ProcAt libc_close(i) } + // Detach fd 0 from tty + if sys.Noctty { + if libc_ioctl(0, TIOCNOTTY) < 0 { + goto childerror + } + } + + // Make fd 0 the tty + if sys.Setctty { + if libc_ioctl(0, TIOCSCTTY) < 0 { + goto childerror + } + } + // Time to exec. libc_execve(argv0, &argv[0], &envv[0]) @@ -147,16 +199,35 @@ childerror: panic("unreached") } +// Credential holds user and group identities to be assumed +// by a child process started by StartProcess. +type Credential struct { + Uid uint32 // User ID. + Gid uint32 // Group ID. + Groups []uint32 // Supplementary group IDs. +} +// ProcAttr holds attributes that will be applied to a new process started +// by StartProcess. type ProcAttr struct { - Setsid bool // Create session. - Ptrace bool // Enable tracing. - Dir string // Current working directory. - Env []string // Environment. - Files []int // File descriptors. + Dir string // Current working directory. + Env []string // Environment. + Files []int // File descriptors. + Sys *SysProcAttr } -var zeroAttributes ProcAttr +type SysProcAttr struct { + Chroot string // Chroot. + Credential *Credential // Credential. + Ptrace bool // Enable tracing. + Setsid bool // Create session. + Setpgid bool // Set process group ID to new pid (SYSV setpgrp) + Setctty bool // Set controlling terminal to fd 0 + Noctty bool // Detach fd 0 from controlling terminal +} + +var zeroProcAttr ProcAttr +var zeroSysProcAttr SysProcAttr func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) { var p [2]int @@ -165,7 +236,11 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) { var wstatus WaitStatus if attr == nil { - attr = &zeroAttributes + attr = &zeroProcAttr + } + sys := attr.Sys + if sys == nil { + sys = &zeroSysProcAttr } p[0] = -1 @@ -180,6 +255,10 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) { argvp[0] = argv0p } + var chroot *byte + if sys.Chroot != "" { + chroot = StringBytePtr(sys.Chroot) + } var dir *byte if attr.Dir != "" { dir = StringBytePtr(attr.Dir) @@ -202,7 +281,7 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) { } // Kick off child. - pid, err = forkAndExecInChild(argv0p, argvp, envvp, dir, attr, p[1]) + pid, err = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1]) if err != 0 { error: if p[0] >= 0 { |