Bläddra i källkod

Make libcontainer's CapabilitiesMask into a []string (Capabilities).

Docker-DCO-1.1-Signed-off-by: Victor Marmol <vmarmol@google.com> (github: vmarmol)
Victor Marmol 11 år sedan
förälder
incheckning
92614928ce

+ 9 - 2
daemon/execdriver/native/configuration/parse.go

@@ -109,12 +109,19 @@ func memorySwap(container *libcontainer.Container, context interface{}, value st
 }
 
 func addCap(container *libcontainer.Container, context interface{}, value string) error {
-	container.CapabilitiesMask[value] = true
+	container.Capabilities = append(container.Capabilities, value)
 	return nil
 }
 
 func dropCap(container *libcontainer.Container, context interface{}, value string) error {
-	container.CapabilitiesMask[value] = false
+	// If the capability is specified multiple times, remove all instances.
+	for i, capability := range container.Capabilities {
+		if capability == value {
+			container.Capabilities = append(container.Capabilities[:i], container.Capabilities[i+1:]...)
+		}
+	}
+
+	// The capability wasn't found so we will drop it anyways.
 	return nil
 }
 

+ 17 - 8
daemon/execdriver/native/configuration/parse_test.go

@@ -4,8 +4,19 @@ import (
 	"testing"
 
 	"github.com/dotcloud/docker/daemon/execdriver/native/template"
+	"github.com/dotcloud/docker/pkg/libcontainer"
 )
 
+// Checks whether the expected capability is specified in the capabilities.
+func hasCapability(expected string, capabilities []string) bool {
+	for _, capability := range capabilities {
+		if capability == expected {
+			return true
+		}
+	}
+	return false
+}
+
 func TestSetReadonlyRootFs(t *testing.T) {
 	var (
 		container = template.New()
@@ -39,10 +50,10 @@ func TestConfigurationsDoNotConflict(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	if !container1.CapabilitiesMask["NET_ADMIN"] {
+	if !hasCapability("NET_ADMIN", container1.Capabilities) {
 		t.Fatal("container one should have NET_ADMIN enabled")
 	}
-	if container2.CapabilitiesMask["NET_ADMIN"] {
+	if hasCapability("NET_ADMIN", container2.Capabilities) {
 		t.Fatal("container two should not have NET_ADMIN enabled")
 	}
 }
@@ -138,10 +149,10 @@ func TestAddCap(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	if !container.CapabilitiesMask["MKNOD"] {
+	if !hasCapability("MKNOD", container.Capabilities) {
 		t.Fatal("container should have MKNOD enabled")
 	}
-	if !container.CapabilitiesMask["SYS_ADMIN"] {
+	if !hasCapability("SYS_ADMIN", container.Capabilities) {
 		t.Fatal("container should have SYS_ADMIN enabled")
 	}
 }
@@ -154,14 +165,12 @@ func TestDropCap(t *testing.T) {
 		}
 	)
 	// enabled all caps like in privileged mode
-	for key := range container.CapabilitiesMask {
-		container.CapabilitiesMask[key] = true
-	}
+	container.Capabilities = libcontainer.GetAllCapabilities()
 	if err := ParseConfiguration(container, nil, opts); err != nil {
 		t.Fatal(err)
 	}
 
-	if container.CapabilitiesMask["MKNOD"] {
+	if hasCapability("MKNOD", container.Capabilities) {
 		t.Fatal("container should not have MKNOD enabled")
 	}
 }

+ 1 - 3
daemon/execdriver/native/create.go

@@ -98,9 +98,7 @@ func (d *driver) createNetwork(container *libcontainer.Container, c *execdriver.
 }
 
 func (d *driver) setPrivileged(container *libcontainer.Container) error {
-	for key := range container.CapabilitiesMask {
-		container.CapabilitiesMask[key] = true
-	}
+	container.Capabilities = libcontainer.GetAllCapabilities()
 	container.Cgroups.DeviceAccess = true
 
 	delete(container.Context, "restrictions")

+ 7 - 22
daemon/execdriver/native/template/default_template.go

@@ -9,28 +9,13 @@ import (
 // New returns the docker default configuration for libcontainer
 func New() *libcontainer.Container {
 	container := &libcontainer.Container{
-		CapabilitiesMask: map[string]bool{
-			"SETPCAP":        false,
-			"SYS_MODULE":     false,
-			"SYS_RAWIO":      false,
-			"SYS_PACCT":      false,
-			"SYS_ADMIN":      false,
-			"SYS_NICE":       false,
-			"SYS_RESOURCE":   false,
-			"SYS_TIME":       false,
-			"SYS_TTY_CONFIG": false,
-			"AUDIT_WRITE":    false,
-			"AUDIT_CONTROL":  false,
-			"MAC_OVERRIDE":   false,
-			"MAC_ADMIN":      false,
-			"NET_ADMIN":      false,
-			"MKNOD":          true,
-			"SYSLOG":         false,
-			"SETUID":         true,
-			"SETGID":         true,
-			"CHOWN":          true,
-			"NET_RAW":        true,
-			"DAC_OVERRIDE":   true,
+		Capabilities: []string{
+			"MKNOD",
+			"SETUID",
+			"SETGID",
+			"CHOWN",
+			"NET_RAW",
+			"DAC_OVERRIDE",
 		},
 		Namespaces: map[string]bool{
 			"NEWNS":  true,

+ 13 - 13
pkg/libcontainer/container.go

@@ -11,19 +11,19 @@ type Context map[string]string
 // Container defines configuration options for how a
 // container is setup inside a directory and how a process should be executed
 type Container struct {
-	Hostname         string          `json:"hostname,omitempty"`          // hostname
-	ReadonlyFs       bool            `json:"readonly_fs,omitempty"`       // set the containers rootfs as readonly
-	NoPivotRoot      bool            `json:"no_pivot_root,omitempty"`     // this can be enabled if you are running in ramdisk
-	User             string          `json:"user,omitempty"`              // user to execute the process as
-	WorkingDir       string          `json:"working_dir,omitempty"`       // current working directory
-	Env              []string        `json:"environment,omitempty"`       // environment to set
-	Tty              bool            `json:"tty,omitempty"`               // setup a proper tty or not
-	Namespaces       map[string]bool `json:"namespaces,omitempty"`        // namespaces to apply
-	CapabilitiesMask map[string]bool `json:"capabilities_mask,omitempty"` // capabilities to drop
-	Networks         []*Network      `json:"networks,omitempty"`          // nil for host's network stack
-	Cgroups          *cgroups.Cgroup `json:"cgroups,omitempty"`           // cgroups
-	Context          Context         `json:"context,omitempty"`           // generic context for specific options (apparmor, selinux)
-	Mounts           Mounts          `json:"mounts,omitempty"`
+	Hostname     string          `json:"hostname,omitempty"`      // hostname
+	ReadonlyFs   bool            `json:"readonly_fs,omitempty"`   // set the containers rootfs as readonly
+	NoPivotRoot  bool            `json:"no_pivot_root,omitempty"` // this can be enabled if you are running in ramdisk
+	User         string          `json:"user,omitempty"`          // user to execute the process as
+	WorkingDir   string          `json:"working_dir,omitempty"`   // current working directory
+	Env          []string        `json:"environment,omitempty"`   // environment to set
+	Tty          bool            `json:"tty,omitempty"`           // setup a proper tty or not
+	Namespaces   map[string]bool `json:"namespaces,omitempty"`    // namespaces to apply
+	Capabilities []string        `json:"capabilities,omitempty"`  // capabilities given to the container
+	Networks     []*Network      `json:"networks,omitempty"`      // nil for host's network stack
+	Cgroups      *cgroups.Cgroup `json:"cgroups,omitempty"`       // cgroups
+	Context      Context         `json:"context,omitempty"`       // generic context for specific options (apparmor, selinux)
+	Mounts       Mounts          `json:"mounts,omitempty"`
 }
 
 // Network defines configuration for a container's networking stack

+ 3 - 18
pkg/libcontainer/container.json

@@ -24,24 +24,9 @@
       "mtu": 1500
     }
   ],
-  "capabilities_mask": {
-    "SYSLOG": false,
-    "MKNOD": true,
-    "NET_ADMIN": false,
-    "MAC_ADMIN": false,
-    "MAC_OVERRIDE": false,
-    "AUDIT_CONTROL": false,
-    "AUDIT_WRITE": false,
-    "SYS_TTY_CONFIG": false,
-    "SETPCAP": false,
-    "SYS_MODULE": false,
-    "SYS_RAWIO": false,
-    "SYS_PACCT": false,
-    "SYS_ADMIN": false,
-    "SYS_NICE": false,
-    "SYS_RESOURCE": false,
-    "SYS_TIME": false
-  },
+  "capabilities": [
+    "MKNOD"
+  ],
   "cgroups": {
     "name": "docker-koye",
     "parent": "docker"

+ 13 - 8
pkg/libcontainer/container_test.go

@@ -6,6 +6,16 @@ import (
 	"testing"
 )
 
+// Checks whether the expected capability is specified in the capabilities.
+func hasCapability(expected string, capabilities []string) bool {
+	for _, capability := range capabilities {
+		if capability == expected {
+			return true
+		}
+	}
+	return false
+}
+
 func TestContainerJsonFormat(t *testing.T) {
 	f, err := os.Open("container.json")
 	if err != nil {
@@ -37,22 +47,17 @@ func TestContainerJsonFormat(t *testing.T) {
 		t.Fail()
 	}
 
-	if _, exists := container.CapabilitiesMask["SYS_ADMIN"]; !exists {
-		t.Log("capabilities mask should contain SYS_ADMIN")
-		t.Fail()
-	}
-
-	if container.CapabilitiesMask["SYS_ADMIN"] {
+	if hasCapability("SYS_ADMIN", container.Capabilities) {
 		t.Log("SYS_ADMIN should not be enabled in capabilities mask")
 		t.Fail()
 	}
 
-	if !container.CapabilitiesMask["MKNOD"] {
+	if !hasCapability("MKNOD", container.Capabilities) {
 		t.Log("MKNOD should be enabled in capabilities mask")
 		t.Fail()
 	}
 
-	if container.CapabilitiesMask["SYS_CHROOT"] {
+	if hasCapability("SYS_CHROOT", container.Capabilities) {
 		t.Log("capabilities mask should not contain SYS_CHROOT")
 		t.Fail()
 	}

+ 4 - 6
pkg/libcontainer/security/capabilities/capabilities.go

@@ -26,14 +26,12 @@ func DropCapabilities(container *libcontainer.Container) error {
 	return nil
 }
 
-// getCapabilitiesMask returns the capabilities that should not be dropped by the container.
+// getEnabledCapabilities returns the capabilities that should not be dropped by the container.
 func getEnabledCapabilities(container *libcontainer.Container) []capability.Cap {
 	keep := []capability.Cap{}
-	for key, enabled := range container.CapabilitiesMask {
-		if enabled {
-			if c := libcontainer.GetCapability(key); c != nil {
-				keep = append(keep, c.Value)
-			}
+	for _, capability := range container.Capabilities {
+		if c := libcontainer.GetCapability(capability); c != nil {
+			keep = append(keep, c.Value)
 		}
 	}
 	return keep

+ 8 - 0
pkg/libcontainer/types.go

@@ -123,6 +123,14 @@ func GetCapability(key string) *Capability {
 	return nil
 }
 
+func GetAllCapabilities() []string {
+	output := make([]string, len(capabilityList))
+	for i, capability := range capabilityList {
+		output[i] = capability.String()
+	}
+	return output
+}
+
 // Contains returns true if the specified Capability is
 // in the slice
 func (c Capabilities) Contains(capp string) bool {