diff --git a/configs/config.go b/configs/config.go index ca433b28..d8e2c9eb 100644 --- a/configs/config.go +++ b/configs/config.go @@ -49,12 +49,6 @@ type Config struct { // Hostname optionally sets the container's hostname if provided Hostname string `json:"hostname,omitempty"` - // User will set the uid and gid of the executing process running inside the container - User string `json:"user,omitempty"` - - // WorkingDir will change the processes current working directory inside the container's rootfs - WorkingDir string `json:"working_dir,omitempty"` - // Console is the path to the console allocated to the container. Console string `json:"console,omitempty"` diff --git a/linux_init.go b/linux_init.go index ecb770b3..9b28af63 100644 --- a/linux_init.go +++ b/linux_init.go @@ -31,6 +31,8 @@ const ( type initConfig struct { Args []string `json:"args,omitempty"` Env []string `json:"env,omitempty"` + Cwd string `json:"cwd,omitempty"` + User string `json:"user,omitempty"` Config *configs.Config `json:"config,omitempty"` } @@ -49,24 +51,19 @@ func newContainerInit(t initType, pipe *os.File) (initer, error) { switch t { case initSetns: return &linuxSetnsInit{ - args: config.Args, - env: config.Env, - config: config.Config, + config: config, }, nil case initUserns: return &linuxUsernsInit{ - args: config.Args, - env: config.Env, - config: config.Config, + config: config, }, nil case initUsernsSetup: return &linuxUsernsSideCar{ - config: config.Config, + config: config, }, nil case initStandard: return &linuxStandardInit{ config: config, - env: config.Env, }, nil } return nil, fmt.Errorf("unknown init type %q", t) @@ -90,7 +87,7 @@ func populateProcessEnvironment(env []string) error { // finalizeNamespace drops the caps, sets the correct user // and working dir, and closes any leaky file descriptors // before execing the command inside the namespace -func finalizeNamespace(config *configs.Config) error { +func finalizeNamespace(config *initConfig) error { // Ensure that all non-standard fds we may have accidentally // inherited are marked close-on-exec so they stay out of the // container @@ -98,7 +95,7 @@ func finalizeNamespace(config *configs.Config) error { return err } // drop capabilities in bounding set before changing user - if err := capabilities.DropBoundingSet(config.Capabilities); err != nil { + if err := capabilities.DropBoundingSet(config.Config.Capabilities); err != nil { return err } // preserve existing capabilities while we change users @@ -112,12 +109,12 @@ func finalizeNamespace(config *configs.Config) error { return err } // drop all other capabilities - if err := capabilities.DropCapabilities(config.Capabilities); err != nil { + if err := capabilities.DropCapabilities(config.Config.Capabilities); err != nil { return err } - if config.WorkingDir != "" { - if err := syscall.Chdir(config.WorkingDir); err != nil { - return fmt.Errorf("chdir to %s %s", config.WorkingDir, err) + if config.Cwd != "" { + if err := syscall.Chdir(config.Cwd); err != nil { + return err } } return nil @@ -143,7 +140,7 @@ func joinExistingNamespaces(namespaces []configs.Namespace) error { } // setupUser changes the groups, gid, and uid for the user inside the container -func setupUser(config *configs.Config) error { +func setupUser(config *initConfig) error { // Set up defaults. defaultExecUser := user.ExecUser{ Uid: syscall.Getuid(), @@ -160,22 +157,22 @@ func setupUser(config *configs.Config) error { } execUser, err := user.GetExecUserPath(config.User, &defaultExecUser, passwdPath, groupPath) if err != nil { - return fmt.Errorf("get supplementary groups %s", err) + return err } - suppGroups := append(execUser.Sgids, config.AdditionalGroups...) + suppGroups := append(execUser.Sgids, config.Config.AdditionalGroups...) if err := syscall.Setgroups(suppGroups); err != nil { - return fmt.Errorf("setgroups %s", err) + return err } if err := system.Setgid(execUser.Gid); err != nil { - return fmt.Errorf("setgid %s", err) + return err } if err := system.Setuid(execUser.Uid); err != nil { - return fmt.Errorf("setuid %s", err) + return err } // if we didn't get HOME already, set it based on the user's HOME if envHome := os.Getenv("HOME"); envHome == "" { if err := os.Setenv("HOME", execUser.Home); err != nil { - return fmt.Errorf("set HOME %s", err) + return err } } return nil diff --git a/linux_setns_init.go b/linux_setns_init.go index a9a1d27c..2d91475b 100644 --- a/linux_setns_init.go +++ b/linux_setns_init.go @@ -4,7 +4,6 @@ package libcontainer import ( "github.com/docker/libcontainer/apparmor" - "github.com/docker/libcontainer/configs" "github.com/docker/libcontainer/label" "github.com/docker/libcontainer/system" ) @@ -12,25 +11,23 @@ import ( // linuxSetnsInit performs the container's initialization for running a new process // inside an existing container. type linuxSetnsInit struct { - args []string - env []string - config *configs.Config + config *initConfig } func (l *linuxSetnsInit) Init() error { - if err := setupRlimits(l.config); err != nil { + if err := setupRlimits(l.config.Config); err != nil { return err } if err := finalizeNamespace(l.config); err != nil { return err } - if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil { + if err := apparmor.ApplyProfile(l.config.Config.AppArmorProfile); err != nil { return err } - if l.config.ProcessLabel != "" { - if err := label.SetProcessLabel(l.config.ProcessLabel); err != nil { + if l.config.Config.ProcessLabel != "" { + if err := label.SetProcessLabel(l.config.Config.ProcessLabel); err != nil { return err } } - return system.Execv(l.args[0], l.args[0:], l.env) + return system.Execv(l.config.Args[0], l.config.Args[0:], l.config.Env) } diff --git a/linux_standard_init.go b/linux_standard_init.go index f69a4bdb..2fe558e7 100644 --- a/linux_standard_init.go +++ b/linux_standard_init.go @@ -16,7 +16,6 @@ import ( type linuxStandardInit struct { config *initConfig - env []string } func (l *linuxStandardInit) Init() error { @@ -74,7 +73,7 @@ func (l *linuxStandardInit) Init() error { if err != nil { return err } - if err := finalizeNamespace(l.config.Config); err != nil { + if err := finalizeNamespace(l.config); err != nil { return err } // finalizeNamespace can change user/group which clears the parent death @@ -87,5 +86,5 @@ func (l *linuxStandardInit) Init() error { if syscall.Getppid() == 1 { return syscall.Kill(syscall.Getpid(), syscall.SIGKILL) } - return system.Execv(l.config.Args[0], l.config.Args[0:], l.env) + return system.Execv(l.config.Args[0], l.config.Args[0:], l.config.Env) } diff --git a/linux_userns_init.go b/linux_userns_init.go index b44c191e..71f2a96e 100644 --- a/linux_userns_init.go +++ b/linux_userns_init.go @@ -6,7 +6,6 @@ import ( "syscall" "github.com/docker/libcontainer/apparmor" - "github.com/docker/libcontainer/configs" consolepkg "github.com/docker/libcontainer/console" "github.com/docker/libcontainer/label" "github.com/docker/libcontainer/security/restrict" @@ -14,17 +13,15 @@ import ( ) type linuxUsernsInit struct { - args []string - env []string - config *configs.Config + config *initConfig } func (l *linuxUsernsInit) Init() error { // join any namespaces via a path to the namespace fd if provided - if err := joinExistingNamespaces(l.config.Namespaces); err != nil { + if err := joinExistingNamespaces(l.config.Config.Namespaces); err != nil { return err } - console := l.config.Console + console := l.config.Config.Console if console != "" { if err := consolepkg.OpenAndDup("/dev/console"); err != nil { return err @@ -38,24 +35,24 @@ func (l *linuxUsernsInit) Init() error { return err } } - if l.config.WorkingDir == "" { - l.config.WorkingDir = "/" + if l.config.Cwd == "" { + l.config.Cwd = "/" } - if err := setupRlimits(l.config); err != nil { + if err := setupRlimits(l.config.Config); err != nil { return err } - if hostname := l.config.Hostname; hostname != "" { + if hostname := l.config.Config.Hostname; hostname != "" { if err := syscall.Sethostname([]byte(hostname)); err != nil { return err } } - if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil { + if err := apparmor.ApplyProfile(l.config.Config.AppArmorProfile); err != nil { return err } - if err := label.SetProcessLabel(l.config.ProcessLabel); err != nil { + if err := label.SetProcessLabel(l.config.Config.ProcessLabel); err != nil { return err } - if l.config.RestrictSys { + if l.config.Config.RestrictSys { if err := restrict.Restrict("proc/sys", "proc/sysrq-trigger", "proc/irq", "proc/bus"); err != nil { return err } @@ -77,5 +74,5 @@ func (l *linuxUsernsInit) Init() error { if syscall.Getppid() == 1 { return syscall.Kill(syscall.Getpid(), syscall.SIGKILL) } - return system.Execv(l.args[0], l.args[0:], l.env) + return system.Execv(l.config.Args[0], l.config.Args[0:], l.config.Env) } diff --git a/linux_userns_sidecar_init.go b/linux_userns_sidecar_init.go index 7ac7dc43..514b9dd4 100644 --- a/linux_userns_sidecar_init.go +++ b/linux_userns_sidecar_init.go @@ -15,20 +15,20 @@ import ( // except the user namespace, so it run as root in the root user namespace // to perform these operations. type linuxUsernsSideCar struct { - config *configs.Config + config *initConfig } func (l *linuxUsernsSideCar) Init() error { - if err := setupNetwork(l.config); err != nil { + if err := setupNetwork(l.config.Config); err != nil { return err } - if err := setupRoute(l.config); err != nil { + if err := setupRoute(l.config.Config); err != nil { return err } label.Init() // InitializeMountNamespace() can be executed only for a new mount namespace - if l.config.Namespaces.Contains(configs.NEWNET) { - if err := mount.InitializeMountNamespace(l.config); err != nil { + if l.config.Config.Namespaces.Contains(configs.NEWNET) { + if err := mount.InitializeMountNamespace(l.config.Config); err != nil { return err } } diff --git a/process.go b/process.go index a1528c55..d361f98f 100644 --- a/process.go +++ b/process.go @@ -11,6 +11,13 @@ type Process struct { // Env specifies the environment variables for the process. Env []string + // User will set the uid and gid of the executing process running inside the container + // local to the contaienr's user and group configuration. + User string + + // Cwd will change the processes current working directory inside the container's rootfs. + Cwd string + // Stdin is a pointer to a reader which provides the standard input stream. Stdin io.Reader