Add support for process overrides of settings

This commit adds support to libcontainer to allow caps, no new privs,
apparmor, and selinux process label to the process struct so that it can
be used together of override the base settings on the container config
per individual process.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
Michael Crosby 2016-03-03 10:44:33 -08:00
parent aa9660027b
commit 3cc90bd2d8
9 changed files with 76 additions and 21 deletions

31
exec.go
View File

@ -48,7 +48,7 @@ following will output a list of processes running in the container:
Usage: "UID (format: <uid>[:<gid>])",
},
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)

View File

@ -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.

View File

@ -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) {

View File

@ -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"`

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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
}

10
spec.go
View File

@ -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
}

View File

@ -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,
}
}