diff --git a/daemon/container.go b/daemon/container.go index aacd90a449..1efe511c85 100644 --- a/daemon/container.go +++ b/daemon/container.go @@ -254,6 +254,8 @@ func populateCommand(c *Container, env []string) error { Resources: resources, AllowedDevices: allowedDevices, AutoCreatedDevices: autoCreatedDevices, + CapAdd: c.hostConfig.CapAdd, + CapDrop: c.hostConfig.CapDrop, } c.command.SysProcAttr = &syscall.SysProcAttr{Setsid: true} c.command.Env = env diff --git a/daemon/execdriver/driver.go b/daemon/execdriver/driver.go index a3d3bc260a..0efd4fe71b 100644 --- a/daemon/execdriver/driver.go +++ b/daemon/execdriver/driver.go @@ -140,6 +140,8 @@ type Command struct { Mounts []Mount `json:"mounts"` AllowedDevices []*devices.Device `json:"allowed_devices"` AutoCreatedDevices []*devices.Device `json:"autocreated_devices"` + CapAdd []string `json:"cap_add"` + CapDrop []string `json:"cap_drop"` Terminal Terminal `json:"-"` // standard or tty terminal Console string `json:"-"` // dev/console path diff --git a/daemon/execdriver/native/create.go b/daemon/execdriver/native/create.go index f28507b046..bfcc078834 100644 --- a/daemon/execdriver/native/create.go +++ b/daemon/execdriver/native/create.go @@ -14,6 +14,7 @@ import ( "github.com/dotcloud/docker/daemon/execdriver" "github.com/dotcloud/docker/daemon/execdriver/native/configuration" "github.com/dotcloud/docker/daemon/execdriver/native/template" + "github.com/dotcloud/docker/utils" ) // createContainer populates and configures the container type with the @@ -42,6 +43,8 @@ func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Config, e if err := d.setPrivileged(container); err != nil { return nil, err } + } else { + d.setCapabilities(container, c) } if err := d.setupCgroups(container, c); err != nil { @@ -136,6 +139,23 @@ func (d *driver) setPrivileged(container *libcontainer.Config) (err error) { return nil } +func (d *driver) setCapabilities(container *libcontainer.Config, c *execdriver.Command) { + var caps []string + for _, cap := range container.Capabilities { + if !utils.StringsContains(c.CapDrop, cap) { + caps = append(caps, cap) + } + } + + for _, cap := range c.CapAdd { + if !utils.StringsContains(caps, cap) { + caps = append(caps, cap) + } + } + + container.Capabilities = caps +} + func (d *driver) setupCgroups(container *libcontainer.Config, c *execdriver.Command) error { if c.Resources != nil { container.Cgroups.CpuShares = c.Resources.CpuShares diff --git a/runconfig/hostconfig.go b/runconfig/hostconfig.go index f4aa69fe97..b10e103450 100644 --- a/runconfig/hostconfig.go +++ b/runconfig/hostconfig.go @@ -38,6 +38,8 @@ type HostConfig struct { VolumesFrom []string Devices []DeviceMapping NetworkMode NetworkMode + CapAdd []string + CapDrop []string } func ContainerHostConfigFromJob(job *engine.Job) *HostConfig { diff --git a/runconfig/parse.go b/runconfig/parse.go index f7d1d5963f..1574bf8f26 100644 --- a/runconfig/parse.go +++ b/runconfig/parse.go @@ -50,6 +50,8 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf flVolumesFrom opts.ListOpts flLxcOpts opts.ListOpts flEnvFile opts.ListOpts + flCapAdd opts.ListOpts + flCapDrop opts.ListOpts flAutoRemove = cmd.Bool([]string{"#rm", "-rm"}, false, "Automatically remove the container when it exits (incompatible with -d)") flDetach = cmd.Bool([]string{"d", "-detach"}, false, "Detached mode: run container in the background and print new container ID") @@ -86,6 +88,9 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf cmd.Var(&flVolumesFrom, []string{"#volumes-from", "-volumes-from"}, "Mount volumes from the specified container(s)") cmd.Var(&flLxcOpts, []string{"#lxc-conf", "-lxc-conf"}, "(lxc exec-driver only) Add custom lxc options --lxc-conf=\"lxc.cgroup.cpuset.cpus = 0,1\"") + cmd.Var(&flCapAdd, []string{"-cap-add"}, "Add Linux capability(ies)") + cmd.Var(&flCapDrop, []string{"-cap-drop"}, "Drop Linux capability(ies)") + if err := cmd.Parse(args); err != nil { return nil, nil, cmd, err } @@ -258,6 +263,8 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf VolumesFrom: flVolumesFrom.GetAll(), NetworkMode: netMode, Devices: deviceMappings, + CapAdd: flCapAdd.GetAll(), + CapDrop: flCapDrop.GetAll(), } if sysInfo != nil && flMemory > 0 && !sysInfo.SwapLimit { diff --git a/utils/utils.go b/utils/utils.go index ef28aceca7..085f493032 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -907,3 +907,12 @@ func ValidateContextDirectory(srcPath string) error { }) return finalError } + +func StringsContains(slice []string, s string) bool { + for _, ss := range slice { + if s == ss { + return true + } + } + return false +}