Get rid of exec.cmd struct and setuid file
This commit is contained in:
parent
806c3c28b8
commit
587031f14d
|
@ -70,7 +70,7 @@ type Executor interface {
|
|||
|
||||
// Command provides access the underlying Cmd struct in case the Executor
|
||||
// interface doesn't expose the functionality you need.
|
||||
Command() *cmd
|
||||
Command() *exec.Cmd
|
||||
}
|
||||
|
||||
// Command is a mirror of exec.Command that returns a platform-specific Executor
|
||||
|
@ -100,17 +100,3 @@ func OpenId(id string) (Executor, error) {
|
|||
}
|
||||
return executor, nil
|
||||
}
|
||||
|
||||
// Cmd is an extension of exec.Cmd that incorporates functionality for
|
||||
// re-attaching to processes, dropping priviledges, etc., based on platform-
|
||||
// specific implementations.
|
||||
type cmd struct {
|
||||
exec.Cmd
|
||||
|
||||
// Resources is used to limit CPU and RAM used by the process, by way of
|
||||
// cgroups or a similar mechanism.
|
||||
Resources structs.Resources
|
||||
|
||||
// RunAs may be a username or Uid. The implementation will decide how to use it.
|
||||
RunAs string
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package executor
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
|
@ -15,10 +16,9 @@ import (
|
|||
// BasicExecutor should work everywhere, and as a result does not include
|
||||
// any resource restrictions or runas capabilities.
|
||||
type BasicExecutor struct {
|
||||
cmd
|
||||
cmd exec.Cmd
|
||||
}
|
||||
|
||||
// TODO: Update to use the Spawner.
|
||||
// TODO: Have raw_exec use this as well.
|
||||
func NewBasicExecutor() Executor {
|
||||
return &BasicExecutor{}
|
||||
|
@ -36,7 +36,7 @@ func (e *BasicExecutor) ConfigureTaskDir(taskName string, alloc *allocdir.AllocD
|
|||
if !ok {
|
||||
return fmt.Errorf("Error finding task dir for (%s)", taskName)
|
||||
}
|
||||
e.Dir = taskDir
|
||||
e.cmd.Dir = taskDir
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ func (e *BasicExecutor) Start() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e.Cmd.Args = parsed
|
||||
e.cmd.Args = parsed
|
||||
|
||||
// We don't want to call ourself. We want to call Start on our embedded Cmd
|
||||
return e.cmd.Start()
|
||||
|
@ -77,7 +77,7 @@ func (e *BasicExecutor) Open(pid string) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("Failed to reopen pid %d: %v", pidNum, err)
|
||||
}
|
||||
e.Process = process
|
||||
e.cmd.Process = process
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -99,9 +99,9 @@ func (e *BasicExecutor) Shutdown() error {
|
|||
}
|
||||
|
||||
func (e *BasicExecutor) ForceStop() error {
|
||||
return e.Process.Kill()
|
||||
return e.cmd.Process.Kill()
|
||||
}
|
||||
|
||||
func (e *BasicExecutor) Command() *cmd {
|
||||
func (e *BasicExecutor) Command() *exec.Cmd {
|
||||
return &e.cmd
|
||||
}
|
||||
|
|
|
@ -6,8 +6,10 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
|
@ -44,7 +46,7 @@ func NewExecutor() Executor {
|
|||
|
||||
// Linux executor is designed to run on linux kernel 2.8+.
|
||||
type LinuxExecutor struct {
|
||||
cmd
|
||||
cmd exec.Cmd
|
||||
user *user.User
|
||||
|
||||
// Isolation configurations.
|
||||
|
@ -57,7 +59,7 @@ type LinuxExecutor struct {
|
|||
spawn *spawn.Spawner
|
||||
}
|
||||
|
||||
func (e *LinuxExecutor) Command() *cmd {
|
||||
func (e *LinuxExecutor) Command() *exec.Cmd {
|
||||
return &e.cmd
|
||||
}
|
||||
|
||||
|
@ -114,45 +116,47 @@ func (e *LinuxExecutor) ID() (string, error) {
|
|||
return buffer.String(), nil
|
||||
}
|
||||
|
||||
// runAs takes a user id as a string and looks up the user. It stores the
|
||||
// results in the executor and returns an error if the user could not be found.
|
||||
// runAs takes a user id as a string and looks up the user, and sets the command
|
||||
// to execute as that user.
|
||||
func (e *LinuxExecutor) runAs(userid string) error {
|
||||
errs := new(multierror.Error)
|
||||
|
||||
// First, try to lookup the user by uid
|
||||
u, err := user.LookupId(userid)
|
||||
if err == nil {
|
||||
e.user = u
|
||||
return nil
|
||||
} else {
|
||||
errs = multierror.Append(errs, err)
|
||||
u, err := user.Lookup(userid)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to identify user %v: %v", userid, err)
|
||||
}
|
||||
|
||||
// Lookup failed, so try by username instead
|
||||
u, err = user.Lookup(userid)
|
||||
if err == nil {
|
||||
e.user = u
|
||||
return nil
|
||||
} else {
|
||||
errs = multierror.Append(errs, err)
|
||||
// Convert the uid and gid
|
||||
uid, err := strconv.ParseUint(u.Uid, 10, 32)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to convert userid to uint32: %s", err)
|
||||
}
|
||||
gid, err := strconv.ParseUint(u.Gid, 10, 32)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to convert groupid to uint32: %s", err)
|
||||
}
|
||||
|
||||
// If we got here we failed to lookup based on id and username, so we'll
|
||||
// return those errors.
|
||||
return fmt.Errorf("Failed to identify user to run as: %s", errs)
|
||||
// Set the command to run as that user and group.
|
||||
if e.cmd.SysProcAttr == nil {
|
||||
e.cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
}
|
||||
if e.cmd.SysProcAttr.Credential == nil {
|
||||
e.cmd.SysProcAttr.Credential = &syscall.Credential{}
|
||||
}
|
||||
e.cmd.SysProcAttr.Credential.Uid = uint32(uid)
|
||||
e.cmd.SysProcAttr.Credential.Gid = uint32(gid)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *LinuxExecutor) Start() error {
|
||||
// Run as "nobody" user so we don't leak root privilege to the spawned
|
||||
// process.
|
||||
if err := e.runAs("nobody"); err == nil && e.user != nil {
|
||||
e.cmd.SetUID(e.user.Uid)
|
||||
e.cmd.SetGID(e.user.Gid)
|
||||
if err := e.runAs("nobody"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Parse the commands arguments and replace instances of Nomad environment
|
||||
// variables.
|
||||
envVars, err := environment.ParseFromList(e.Cmd.Env)
|
||||
envVars, err := environment.ParseFromList(e.cmd.Env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -165,16 +169,16 @@ func (e *LinuxExecutor) Start() error {
|
|||
}
|
||||
e.cmd.Path = parsedPath[0]
|
||||
|
||||
combined := strings.Join(e.Cmd.Args, " ")
|
||||
combined := strings.Join(e.cmd.Args, " ")
|
||||
parsed, err := args.ParseAndReplace(combined, envVars.Map())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e.Cmd.Args = parsed
|
||||
e.cmd.Args = parsed
|
||||
|
||||
spawnState := filepath.Join(e.allocDir, fmt.Sprintf("%s_%s", e.taskName, "exit_status"))
|
||||
e.spawn = spawn.NewSpawner(spawnState)
|
||||
e.spawn.SetCommand(&e.cmd.Cmd)
|
||||
e.spawn.SetCommand(&e.cmd)
|
||||
e.spawn.SetChroot(e.taskDir)
|
||||
e.spawn.SetLogs(&spawn.Logs{
|
||||
Stdout: filepath.Join(e.taskDir, allocdir.TaskLocal, fmt.Sprintf("%v.stdout", e.taskName)),
|
||||
|
@ -283,13 +287,13 @@ func (e *LinuxExecutor) ConfigureTaskDir(taskName string, alloc *allocdir.AllocD
|
|||
}
|
||||
|
||||
// Set the tasks AllocDir environment variable.
|
||||
env, err := environment.ParseFromList(e.Cmd.Env)
|
||||
env, err := environment.ParseFromList(e.cmd.Env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
env.SetAllocDir(filepath.Join("/", allocdir.SharedAllocName))
|
||||
env.SetTaskLocalDir(filepath.Join("/", allocdir.TaskLocal))
|
||||
e.Cmd.Env = env.List()
|
||||
e.cmd.Env = env.List()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
// +build !windows
|
||||
|
||||
package executor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// SetUID changes the Uid for this command (must be set before starting)
|
||||
func (c *cmd) SetUID(userid string) error {
|
||||
uid, err := strconv.ParseUint(userid, 10, 32)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to convert userid to uint32: %s", err)
|
||||
}
|
||||
if c.SysProcAttr == nil {
|
||||
c.SysProcAttr = &syscall.SysProcAttr{}
|
||||
}
|
||||
if c.SysProcAttr.Credential == nil {
|
||||
c.SysProcAttr.Credential = &syscall.Credential{}
|
||||
}
|
||||
c.SysProcAttr.Credential.Uid = uint32(uid)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetGID changes the Gid for this command (must be set before starting)
|
||||
func (c *cmd) SetGID(groupid string) error {
|
||||
gid, err := strconv.ParseUint(groupid, 10, 32)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to convert groupid to uint32: %s", err)
|
||||
}
|
||||
if c.SysProcAttr == nil {
|
||||
c.SysProcAttr = &syscall.SysProcAttr{}
|
||||
}
|
||||
if c.SysProcAttr.Credential == nil {
|
||||
c.SysProcAttr.Credential = &syscall.Credential{}
|
||||
}
|
||||
c.SysProcAttr.Credential.Gid = uint32(gid)
|
||||
return nil
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package executor
|
||||
|
||||
// SetUID changes the Uid for this command (must be set before starting)
|
||||
func (c *cmd) SetUID(userid string) error {
|
||||
// TODO implement something for windows
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetGID changes the Gid for this command (must be set before starting)
|
||||
func (c *cmd) SetGID(groupid string) error {
|
||||
// TODO implement something for windows
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue