diff --git a/daemon/execdriver/lxc/lxc_init_linux.go b/daemon/execdriver/lxc/lxc_init_linux.go index 0117b9dbef..40956e442b 100644 --- a/daemon/execdriver/lxc/lxc_init_linux.go +++ b/daemon/execdriver/lxc/lxc_init_linux.go @@ -49,7 +49,10 @@ func finalizeNamespace(args *execdriver.InitArgs) error { return fmt.Errorf("clear keep caps %s", err) } - caps := execdriver.TweakCapabilities(container.Capabilities, strings.Split(args.CapAdd, " "), strings.Split(args.CapDrop, " ")) + caps, err := execdriver.TweakCapabilities(container.Capabilities, strings.Split(args.CapAdd, " "), strings.Split(args.CapDrop, " ")) + if err != nil { + return err + } // drop all other capabilities if err := capabilities.DropCapabilities(caps); err != nil { diff --git a/daemon/execdriver/native/create.go b/daemon/execdriver/native/create.go index b735151eb5..13f81c7180 100644 --- a/daemon/execdriver/native/create.go +++ b/daemon/execdriver/native/create.go @@ -43,7 +43,9 @@ func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Config, e return nil, err } } else { - d.setCapabilities(container, c) + if err := d.setCapabilities(container, c); err != nil { + return nil, err + } } if err := d.setupCgroups(container, c); err != nil { @@ -138,8 +140,9 @@ func (d *driver) setPrivileged(container *libcontainer.Config) (err error) { return nil } -func (d *driver) setCapabilities(container *libcontainer.Config, c *execdriver.Command) { - container.Capabilities = execdriver.TweakCapabilities(container.Capabilities, c.CapAdd, c.CapDrop) +func (d *driver) setCapabilities(container *libcontainer.Config, c *execdriver.Command) (err error) { + container.Capabilities, err = execdriver.TweakCapabilities(container.Capabilities, c.CapAdd, c.CapDrop) + return err } func (d *driver) setupCgroups(container *libcontainer.Config, c *execdriver.Command) error { diff --git a/daemon/execdriver/utils.go b/daemon/execdriver/utils.go index c3e856e32e..90c5177421 100644 --- a/daemon/execdriver/utils.go +++ b/daemon/execdriver/utils.go @@ -1,34 +1,63 @@ package execdriver import ( + "fmt" "strings" "github.com/docker/libcontainer/security/capabilities" "github.com/dotcloud/docker/utils" ) -func TweakCapabilities(basics, adds, drops []string) []string { - var caps []string +func TweakCapabilities(basics, adds, drops []string) ([]string, error) { + var ( + newCaps []string + allCaps = capabilities.GetAllCapabilities() + ) + // look for invalid cap in the drop list + for _, cap := range drops { + if strings.ToLower(cap) == "all" { + continue + } + if !utils.StringsContainsNoCase(allCaps, cap) { + return nil, fmt.Errorf("Unknown capability: %s", cap) + } + } + + // handle --cap-add=all if utils.StringsContainsNoCase(adds, "all") { basics = capabilities.GetAllCapabilities() } if !utils.StringsContainsNoCase(drops, "all") { for _, cap := range basics { + // skip `all` aready handled above + if strings.ToLower(cap) == "all" { + continue + } + + // if we don't drop `all`, add back all the non-dropped caps if !utils.StringsContainsNoCase(drops, cap) { - caps = append(caps, cap) + newCaps = append(newCaps, cap) } } } for _, cap := range adds { + // skip `all` aready handled above if strings.ToLower(cap) == "all" { continue } - if !utils.StringsContainsNoCase(caps, cap) { - caps = append(caps, cap) + + // look for invalid cap in the drop list + if !utils.StringsContainsNoCase(allCaps, cap) { + return nil, fmt.Errorf("Unknown capability: %s", cap) + } + + // add cap if not already in the list + if !utils.StringsContainsNoCase(newCaps, cap) { + newCaps = append(newCaps, cap) } } - return caps + return newCaps, nil } diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index 32af41f4e7..dba8e7fe28 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -783,6 +783,16 @@ func TestUnPrivilegedCanMknod(t *testing.T) { logDone("run - test un-privileged can mknod") } +func TestCapDropInvalid(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "--cap-drop=CHPASS", "busybox", "ls") + out, _, err := runCommandWithOutput(cmd) + if err == nil { + t.Fatal(err, out) + } + + logDone("run - test --cap-drop=CHPASS invalid") +} + func TestCapDropCannotMknod(t *testing.T) { cmd := exec.Command(dockerBinary, "run", "--cap-drop=MKNOD", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") out, _, err := runCommandWithOutput(cmd) @@ -814,7 +824,7 @@ func TestCapDropALLCannotMknod(t *testing.T) { } func TestCapDropALLAddMknodCannotMknod(t *testing.T) { - cmd := exec.Command(dockerBinary, "run", "--cap-drop=ALL --cap-add=MKNOD", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") + cmd := exec.Command(dockerBinary, "run", "--cap-drop=ALL", "--cap-add=MKNOD", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") out, _, err := runCommandWithOutput(cmd) if err != nil { t.Fatal(err, out) @@ -828,6 +838,16 @@ func TestCapDropALLAddMknodCannotMknod(t *testing.T) { logDone("run - test --cap-drop=ALL --cap-add=MKNOD can mknod") } +func TestCapAddInvalid(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "--cap-add=CHPASS", "busybox", "ls") + out, _, err := runCommandWithOutput(cmd) + if err == nil { + t.Fatal(err, out) + } + + logDone("run - test --cap-add=CHPASS invalid") +} + func TestCapAddCanDownInterface(t *testing.T) { cmd := exec.Command(dockerBinary, "run", "--cap-add=NET_ADMIN", "busybox", "sh", "-c", "ip link set eth0 down && echo ok") out, _, err := runCommandWithOutput(cmd) @@ -859,7 +879,7 @@ func TestCapAddALLCanDownInterface(t *testing.T) { } func TestCapAddALLDropNetAdminCanDownInterface(t *testing.T) { - cmd := exec.Command(dockerBinary, "run", "--cap-add=ALL --cap-drop=NET_ADMIN", "busybox", "sh", "-c", "ip link set eth0 down && echo ok") + cmd := exec.Command(dockerBinary, "run", "--cap-add=ALL", "--cap-drop=NET_ADMIN", "busybox", "sh", "-c", "ip link set eth0 down && echo ok") out, _, err := runCommandWithOutput(cmd) if err == nil { t.Fatal(err, out)