diff --git a/exec.go b/exec.go index 528d3ade1..4c04e6587 100644 --- a/exec.go +++ b/exec.go @@ -48,7 +48,7 @@ following will output a list of processes running in the container: Usage: "UID (format: [:])", }, cli.StringFlag{ - Name: "process,p", + Name: "process, p", Usage: "path to the process.json", }, cli.BoolFlag{ @@ -60,6 +60,23 @@ following will output a list of processes running in the container: Value: "", Usage: "specify the file to write the process id to", }, + cli.StringFlag{ + Name: "process-label", + Usage: "set the asm process label for the process commonly used with selinux", + }, + cli.StringFlag{ + Name: "apparmor", + Usage: "set the apparmor profile for the process", + }, + cli.BoolFlag{ + Name: "no-new-privs", + Usage: "set the no new privileges value for the process", + }, + cli.StringSliceFlag{ + Name: "cap, c", + Value: &cli.StringSlice{}, + Usage: "add a capability to the bounding set for the process", + }, }, Action: func(context *cli.Context) { if os.Geteuid() != 0 { @@ -118,6 +135,15 @@ func getProcess(context *cli.Context, bundle string) (*specs.Process, error) { if context.String("cwd") != "" { p.Cwd = context.String("cwd") } + if ap := context.String("apparmor"); ap != "" { + p.ApparmorProfile = ap + } + if l := context.String("process-label"); l != "" { + p.SelinuxLabel = l + } + if caps := context.StringSlice("cap"); len(caps) > 0 { + p.Capabilities = caps + } // append the passed env variables for _, e := range context.StringSlice("env") { p.Env = append(p.Env, e) @@ -126,6 +152,9 @@ func getProcess(context *cli.Context, bundle string) (*specs.Process, error) { if context.IsSet("tty") { p.Terminal = context.Bool("tty") } + if context.IsSet("no-new-privs") { + p.NoNewPrivileges = context.Bool("no-new-privs") + } // override the user, if passed if context.String("user") != "" { u := strings.SplitN(context.String("user"), ":", 2) diff --git a/libcontainer/configs/config.go b/libcontainer/configs/config.go index 0325d58a8..668fa5e30 100644 --- a/libcontainer/configs/config.go +++ b/libcontainer/configs/config.go @@ -128,11 +128,11 @@ type Config struct { // AppArmorProfile specifies the profile to apply to the process running in the container and is // change at the time the process is execed - AppArmorProfile string `json:"apparmor_profile"` + AppArmorProfile string `json:"apparmor_profile,omitempty"` // ProcessLabel specifies the label to apply to the process running in the container. It is // commonly used by selinux - ProcessLabel string `json:"process_label"` + ProcessLabel string `json:"process_label,omitempty"` // Rlimits specifies the resource limits, such as max open files, to set in the container // If Rlimits are not set, the container will inherit rlimits from the parent process @@ -172,7 +172,7 @@ type Config struct { Seccomp *Seccomp `json:"seccomp"` // NoNewPrivileges controls whether processes in the container can gain additional privileges. - NoNewPrivileges bool `json:"no_new_privileges"` + NoNewPrivileges bool `json:"no_new_privileges,omitempty"` // Hooks are a collection of actions to perform at various container lifecycle events. // Hooks are not able to be marshaled to json but they are also not needed to. diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go index 01781f36a..8e308fa62 100644 --- a/libcontainer/container_linux.go +++ b/libcontainer/container_linux.go @@ -319,7 +319,7 @@ func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, parentPipe, } func (c *linuxContainer) newInitConfig(process *Process) *initConfig { - return &initConfig{ + cfg := &initConfig{ Config: c.config, Args: process.Args, Env: process.Env, @@ -329,7 +329,20 @@ func (c *linuxContainer) newInitConfig(process *Process) *initConfig { Capabilities: process.Capabilities, PassedFilesCount: len(process.ExtraFiles), ContainerId: c.ID(), + NoNewPrivileges: c.config.NoNewPrivileges, + AppArmorProfile: c.config.AppArmorProfile, + ProcessLabel: c.config.ProcessLabel, } + if process.NoNewPrivileges != nil { + cfg.NoNewPrivileges = *process.NoNewPrivileges + } + if process.AppArmorProfile != "" { + cfg.AppArmorProfile = process.AppArmorProfile + } + if process.Label != "" { + cfg.ProcessLabel = process.Label + } + return cfg } func newPipe() (parent *os.File, child *os.File, err error) { diff --git a/libcontainer/init_linux.go b/libcontainer/init_linux.go index dd641e871..5b78b85a1 100644 --- a/libcontainer/init_linux.go +++ b/libcontainer/init_linux.go @@ -48,6 +48,9 @@ type initConfig struct { Env []string `json:"env"` Cwd string `json:"cwd"` Capabilities []string `json:"capabilities"` + ProcessLabel string `json:"process_label"` + AppArmorProfile string `json:"apparmor_profile"` + NoNewPrivileges bool `json:"no_new_privileges"` User string `json:"user"` Config *configs.Config `json:"config"` Console string `json:"console"` diff --git a/libcontainer/process.go b/libcontainer/process.go index 8b4c558bd..9b82cfaca 100644 --- a/libcontainer/process.go +++ b/libcontainer/process.go @@ -48,6 +48,16 @@ type Process struct { // All capabilities not specified will be dropped from the processes capability mask Capabilities []string + // AppArmorProfile specifies the profile to apply to the process and is + // changed at the time the process is execed + AppArmorProfile string + + // Label specifies the label to apply to the process. It is commonly used by selinux + Label string + + // NoNewPrivileges controls whether processes can gain additional privileges. + NoNewPrivileges *bool + ops processOperations } diff --git a/libcontainer/setns_init_linux.go b/libcontainer/setns_init_linux.go index de356bce8..2dfec9b79 100644 --- a/libcontainer/setns_init_linux.go +++ b/libcontainer/setns_init_linux.go @@ -34,7 +34,7 @@ func (l *linuxSetnsInit) Init() error { if err := setOomScoreAdj(l.config.Config.OomScoreAdj); err != nil { return err } - if l.config.Config.NoNewPrivileges { + if l.config.NoNewPrivileges { if err := system.Prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); err != nil { return err } @@ -47,11 +47,11 @@ func (l *linuxSetnsInit) Init() error { if err := finalizeNamespace(l.config); err != nil { return err } - if err := apparmor.ApplyProfile(l.config.Config.AppArmorProfile); err != nil { + if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil { return err } - if l.config.Config.ProcessLabel != "" { - if err := label.SetProcessLabel(l.config.Config.ProcessLabel); err != nil { + if l.config.ProcessLabel != "" { + if err := label.SetProcessLabel(l.config.ProcessLabel); err != nil { return err } } diff --git a/libcontainer/standard_init_linux.go b/libcontainer/standard_init_linux.go index 935b2eead..134205d55 100644 --- a/libcontainer/standard_init_linux.go +++ b/libcontainer/standard_init_linux.go @@ -91,10 +91,10 @@ func (l *linuxStandardInit) Init() error { return err } } - if err := apparmor.ApplyProfile(l.config.Config.AppArmorProfile); err != nil { + if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil { return err } - if err := label.SetProcessLabel(l.config.Config.ProcessLabel); err != nil { + if err := label.SetProcessLabel(l.config.ProcessLabel); err != nil { return err } @@ -117,7 +117,7 @@ func (l *linuxStandardInit) Init() error { if err != nil { return err } - if l.config.Config.NoNewPrivileges { + if l.config.NoNewPrivileges { if err := system.Prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); err != nil { return err } diff --git a/spec.go b/spec.go index e0e8abdf5..9c9146d31 100644 --- a/spec.go +++ b/spec.go @@ -245,10 +245,9 @@ func createLibcontainerConfig(cgroupName string, spec *specs.LinuxSpec) (*config rootfsPath = filepath.Join(cwd, rootfsPath) } config := &configs.Config{ - Rootfs: rootfsPath, - Capabilities: spec.Process.Capabilities, - Readonlyfs: spec.Root.Readonly, - Hostname: spec.Hostname, + Rootfs: rootfsPath, + Readonlyfs: spec.Root.Readonly, + Hostname: spec.Hostname, Labels: []string{ "bundle=" + cwd, }, @@ -303,9 +302,6 @@ func createLibcontainerConfig(cgroupName string, spec *specs.LinuxSpec) (*config } config.Seccomp = seccomp config.Sysctl = spec.Linux.Sysctl - config.ProcessLabel = spec.Process.SelinuxLabel - config.AppArmorProfile = spec.Process.ApparmorProfile - config.NoNewPrivileges = spec.Process.NoNewPrivileges if oomScoreAdj := spec.Linux.Resources.OOMScoreAdj; oomScoreAdj != nil { config.OomScoreAdj = *oomScoreAdj } diff --git a/utils.go b/utils.go index 0477973a3..64412189b 100644 --- a/utils.go +++ b/utils.go @@ -219,8 +219,12 @@ func newProcess(p specs.Process) *libcontainer.Process { Args: p.Args, Env: p.Env, // TODO: fix libcontainer's API to better support uid/gid in a typesafe way. - User: fmt.Sprintf("%d:%d", p.User.UID, p.User.GID), - Cwd: p.Cwd, + User: fmt.Sprintf("%d:%d", p.User.UID, p.User.GID), + Cwd: p.Cwd, + Capabilities: p.Capabilities, + Label: p.SelinuxLabel, + NoNewPrivileges: &p.NoNewPrivileges, + AppArmorProfile: p.ApparmorProfile, } }