Docker-DCO-1.1-Signed-off-by: Victor Vieux <vieux@docker.com> (github: vieux)
| ... | ... |
@@ -49,7 +49,10 @@ func finalizeNamespace(args *execdriver.InitArgs) error {
|
| 49 | 49 |
return fmt.Errorf("clear keep caps %s", err)
|
| 50 | 50 |
} |
| 51 | 51 |
|
| 52 |
- caps := execdriver.TweakCapabilities(container.Capabilities, strings.Split(args.CapAdd, " "), strings.Split(args.CapDrop, " ")) |
|
| 52 |
+ caps, err := execdriver.TweakCapabilities(container.Capabilities, strings.Split(args.CapAdd, " "), strings.Split(args.CapDrop, " ")) |
|
| 53 |
+ if err != nil {
|
|
| 54 |
+ return err |
|
| 55 |
+ } |
|
| 53 | 56 |
|
| 54 | 57 |
// drop all other capabilities |
| 55 | 58 |
if err := capabilities.DropCapabilities(caps); err != nil {
|
| ... | ... |
@@ -43,7 +43,9 @@ func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Config, e |
| 43 | 43 |
return nil, err |
| 44 | 44 |
} |
| 45 | 45 |
} else {
|
| 46 |
- d.setCapabilities(container, c) |
|
| 46 |
+ if err := d.setCapabilities(container, c); err != nil {
|
|
| 47 |
+ return nil, err |
|
| 48 |
+ } |
|
| 47 | 49 |
} |
| 48 | 50 |
|
| 49 | 51 |
if err := d.setupCgroups(container, c); err != nil {
|
| ... | ... |
@@ -138,8 +140,9 @@ func (d *driver) setPrivileged(container *libcontainer.Config) (err error) {
|
| 138 | 138 |
return nil |
| 139 | 139 |
} |
| 140 | 140 |
|
| 141 |
-func (d *driver) setCapabilities(container *libcontainer.Config, c *execdriver.Command) {
|
|
| 142 |
- container.Capabilities = execdriver.TweakCapabilities(container.Capabilities, c.CapAdd, c.CapDrop) |
|
| 141 |
+func (d *driver) setCapabilities(container *libcontainer.Config, c *execdriver.Command) (err error) {
|
|
| 142 |
+ container.Capabilities, err = execdriver.TweakCapabilities(container.Capabilities, c.CapAdd, c.CapDrop) |
|
| 143 |
+ return err |
|
| 143 | 144 |
} |
| 144 | 145 |
|
| 145 | 146 |
func (d *driver) setupCgroups(container *libcontainer.Config, c *execdriver.Command) error {
|
| ... | ... |
@@ -1,34 +1,63 @@ |
| 1 | 1 |
package execdriver |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "fmt" |
|
| 4 | 5 |
"strings" |
| 5 | 6 |
|
| 6 | 7 |
"github.com/docker/libcontainer/security/capabilities" |
| 7 | 8 |
"github.com/dotcloud/docker/utils" |
| 8 | 9 |
) |
| 9 | 10 |
|
| 10 |
-func TweakCapabilities(basics, adds, drops []string) []string {
|
|
| 11 |
- var caps []string |
|
| 11 |
+func TweakCapabilities(basics, adds, drops []string) ([]string, error) {
|
|
| 12 |
+ var ( |
|
| 13 |
+ newCaps []string |
|
| 14 |
+ allCaps = capabilities.GetAllCapabilities() |
|
| 15 |
+ ) |
|
| 12 | 16 |
|
| 17 |
+ // look for invalid cap in the drop list |
|
| 18 |
+ for _, cap := range drops {
|
|
| 19 |
+ if strings.ToLower(cap) == "all" {
|
|
| 20 |
+ continue |
|
| 21 |
+ } |
|
| 22 |
+ if !utils.StringsContainsNoCase(allCaps, cap) {
|
|
| 23 |
+ return nil, fmt.Errorf("Unknown capability: %s", cap)
|
|
| 24 |
+ } |
|
| 25 |
+ } |
|
| 26 |
+ |
|
| 27 |
+ // handle --cap-add=all |
|
| 13 | 28 |
if utils.StringsContainsNoCase(adds, "all") {
|
| 14 | 29 |
basics = capabilities.GetAllCapabilities() |
| 15 | 30 |
} |
| 16 | 31 |
|
| 17 | 32 |
if !utils.StringsContainsNoCase(drops, "all") {
|
| 18 | 33 |
for _, cap := range basics {
|
| 34 |
+ // skip `all` aready handled above |
|
| 35 |
+ if strings.ToLower(cap) == "all" {
|
|
| 36 |
+ continue |
|
| 37 |
+ } |
|
| 38 |
+ |
|
| 39 |
+ // if we don't drop `all`, add back all the non-dropped caps |
|
| 19 | 40 |
if !utils.StringsContainsNoCase(drops, cap) {
|
| 20 |
- caps = append(caps, cap) |
|
| 41 |
+ newCaps = append(newCaps, cap) |
|
| 21 | 42 |
} |
| 22 | 43 |
} |
| 23 | 44 |
} |
| 24 | 45 |
|
| 25 | 46 |
for _, cap := range adds {
|
| 47 |
+ // skip `all` aready handled above |
|
| 26 | 48 |
if strings.ToLower(cap) == "all" {
|
| 27 | 49 |
continue |
| 28 | 50 |
} |
| 29 |
- if !utils.StringsContainsNoCase(caps, cap) {
|
|
| 30 |
- caps = append(caps, cap) |
|
| 51 |
+ |
|
| 52 |
+ // look for invalid cap in the drop list |
|
| 53 |
+ if !utils.StringsContainsNoCase(allCaps, cap) {
|
|
| 54 |
+ return nil, fmt.Errorf("Unknown capability: %s", cap)
|
|
| 55 |
+ } |
|
| 56 |
+ |
|
| 57 |
+ // add cap if not already in the list |
|
| 58 |
+ if !utils.StringsContainsNoCase(newCaps, cap) {
|
|
| 59 |
+ newCaps = append(newCaps, cap) |
|
| 31 | 60 |
} |
| 32 | 61 |
} |
| 33 |
- return caps |
|
| 62 |
+ return newCaps, nil |
|
| 34 | 63 |
} |
| ... | ... |
@@ -783,6 +783,16 @@ func TestUnPrivilegedCanMknod(t *testing.T) {
|
| 783 | 783 |
logDone("run - test un-privileged can mknod")
|
| 784 | 784 |
} |
| 785 | 785 |
|
| 786 |
+func TestCapDropInvalid(t *testing.T) {
|
|
| 787 |
+ cmd := exec.Command(dockerBinary, "run", "--cap-drop=CHPASS", "busybox", "ls") |
|
| 788 |
+ out, _, err := runCommandWithOutput(cmd) |
|
| 789 |
+ if err == nil {
|
|
| 790 |
+ t.Fatal(err, out) |
|
| 791 |
+ } |
|
| 792 |
+ |
|
| 793 |
+ logDone("run - test --cap-drop=CHPASS invalid")
|
|
| 794 |
+} |
|
| 795 |
+ |
|
| 786 | 796 |
func TestCapDropCannotMknod(t *testing.T) {
|
| 787 | 797 |
cmd := exec.Command(dockerBinary, "run", "--cap-drop=MKNOD", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") |
| 788 | 798 |
out, _, err := runCommandWithOutput(cmd) |
| ... | ... |
@@ -814,7 +824,7 @@ func TestCapDropALLCannotMknod(t *testing.T) {
|
| 814 | 814 |
} |
| 815 | 815 |
|
| 816 | 816 |
func TestCapDropALLAddMknodCannotMknod(t *testing.T) {
|
| 817 |
- cmd := exec.Command(dockerBinary, "run", "--cap-drop=ALL --cap-add=MKNOD", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") |
|
| 817 |
+ cmd := exec.Command(dockerBinary, "run", "--cap-drop=ALL", "--cap-add=MKNOD", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") |
|
| 818 | 818 |
out, _, err := runCommandWithOutput(cmd) |
| 819 | 819 |
if err != nil {
|
| 820 | 820 |
t.Fatal(err, out) |
| ... | ... |
@@ -828,6 +838,16 @@ func TestCapDropALLAddMknodCannotMknod(t *testing.T) {
|
| 828 | 828 |
logDone("run - test --cap-drop=ALL --cap-add=MKNOD can mknod")
|
| 829 | 829 |
} |
| 830 | 830 |
|
| 831 |
+func TestCapAddInvalid(t *testing.T) {
|
|
| 832 |
+ cmd := exec.Command(dockerBinary, "run", "--cap-add=CHPASS", "busybox", "ls") |
|
| 833 |
+ out, _, err := runCommandWithOutput(cmd) |
|
| 834 |
+ if err == nil {
|
|
| 835 |
+ t.Fatal(err, out) |
|
| 836 |
+ } |
|
| 837 |
+ |
|
| 838 |
+ logDone("run - test --cap-add=CHPASS invalid")
|
|
| 839 |
+} |
|
| 840 |
+ |
|
| 831 | 841 |
func TestCapAddCanDownInterface(t *testing.T) {
|
| 832 | 842 |
cmd := exec.Command(dockerBinary, "run", "--cap-add=NET_ADMIN", "busybox", "sh", "-c", "ip link set eth0 down && echo ok") |
| 833 | 843 |
out, _, err := runCommandWithOutput(cmd) |
| ... | ... |
@@ -859,7 +879,7 @@ func TestCapAddALLCanDownInterface(t *testing.T) {
|
| 859 | 859 |
} |
| 860 | 860 |
|
| 861 | 861 |
func TestCapAddALLDropNetAdminCanDownInterface(t *testing.T) {
|
| 862 |
- cmd := exec.Command(dockerBinary, "run", "--cap-add=ALL --cap-drop=NET_ADMIN", "busybox", "sh", "-c", "ip link set eth0 down && echo ok") |
|
| 862 |
+ cmd := exec.Command(dockerBinary, "run", "--cap-add=ALL", "--cap-drop=NET_ADMIN", "busybox", "sh", "-c", "ip link set eth0 down && echo ok") |
|
| 863 | 863 |
out, _, err := runCommandWithOutput(cmd) |
| 864 | 864 |
if err == nil {
|
| 865 | 865 |
t.Fatal(err, out) |