diff --git a/container.go b/container.go index ddcc6cab..5acdff3d 100644 --- a/container.go +++ b/container.go @@ -18,8 +18,8 @@ type Container struct { 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 Namespaces `json:"namespaces,omitempty"` // namespaces to apply - CapabilitiesMask Capabilities `json:"capabilities_mask,omitempty"` // capabilities to drop + 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) diff --git a/container.json b/container.json index 20c11219..33d79600 100644 --- a/container.json +++ b/container.json @@ -1,151 +1,62 @@ { - "mounts" : [ - { - "type" : "devtmpfs" - } - ], - "tty" : true, - "environment" : [ - "HOME=/", - "PATH=PATH=$PATH:/bin:/usr/bin:/sbin:/usr/sbin", - "container=docker", - "TERM=xterm-256color" - ], - "hostname" : "koye", - "cgroups" : { - "parent" : "docker", - "name" : "docker-koye" - }, - "capabilities_mask" : [ - { - "value" : 8, - "key" : "SETPCAP", - "enabled" : false + "namespaces": { + "NEWNET": true, + "NEWPID": true, + "NEWIPC": true, + "NEWUTS": true, + "NEWNS": true + }, + "networks": [ + { + "gateway": "localhost", + "type": "loopback", + "address": "127.0.0.1/0", + "mtu": 1500 + }, + { + "gateway": "172.17.42.1", + "context": { + "prefix": "veth", + "bridge": "docker0" }, - { - "enabled" : false, - "value" : 16, - "key" : "SYS_MODULE" - }, - { - "value" : 17, - "key" : "SYS_RAWIO", - "enabled" : false - }, - { - "key" : "SYS_PACCT", - "value" : 20, - "enabled" : false - }, - { - "value" : 21, - "key" : "SYS_ADMIN", - "enabled" : false - }, - { - "value" : 23, - "key" : "SYS_NICE", - "enabled" : false - }, - { - "value" : 24, - "key" : "SYS_RESOURCE", - "enabled" : false - }, - { - "key" : "SYS_TIME", - "value" : 25, - "enabled" : false - }, - { - "enabled" : false, - "value" : 26, - "key" : "SYS_TTY_CONFIG" - }, - { - "key" : "AUDIT_WRITE", - "value" : 29, - "enabled" : false - }, - { - "value" : 30, - "key" : "AUDIT_CONTROL", - "enabled" : false - }, - { - "enabled" : false, - "key" : "MAC_OVERRIDE", - "value" : 32 - }, - { - "enabled" : false, - "key" : "MAC_ADMIN", - "value" : 33 - }, - { - "key" : "NET_ADMIN", - "value" : 12, - "enabled" : false - }, - { - "value" : 27, - "key" : "MKNOD", - "enabled" : true - }, - { - "value" : 34, - "key" : "SYSLOG", - "enabled" : false - } - ], - "networks" : [ - { - "mtu" : 1500, - "address" : "127.0.0.1/0", - "type" : "loopback", - "gateway" : "localhost" - }, - { - "mtu" : 1500, - "address" : "172.17.42.2/16", - "type" : "veth", - "context" : { - "bridge" : "docker0", - "prefix" : "veth" - }, - "gateway" : "172.17.42.1" - } - ], - "namespaces" : [ - { - "key" : "NEWNS", - "value" : 131072, - "enabled" : true, - "file" : "mnt" - }, - { - "key" : "NEWUTS", - "value" : 67108864, - "enabled" : true, - "file" : "uts" - }, - { - "enabled" : true, - "file" : "ipc", - "key" : "NEWIPC", - "value" : 134217728 - }, - { - "file" : "pid", - "enabled" : true, - "value" : 536870912, - "key" : "NEWPID" - }, - { - "enabled" : true, - "file" : "net", - "key" : "NEWNET", - "value" : 1073741824 - } - ] + "type": "veth", + "address": "172.17.42.2/16", + "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 + }, + "cgroups": { + "name": "docker-koye", + "parent": "docker" + }, + "hostname": "koye", + "environment": [ + "HOME=/", + "PATH=PATH=$PATH:/bin:/usr/bin:/sbin:/usr/sbin", + "container=docker", + "TERM=xterm-256color" + ], + "tty": true, + "mounts": [ + { + "type": "devtmpfs" + } + ] } diff --git a/container_test.go b/container_test.go index d710a6a5..c02385af 100644 --- a/container_test.go +++ b/container_test.go @@ -15,7 +15,7 @@ func TestContainerJsonFormat(t *testing.T) { var container *Container if err := json.NewDecoder(f).Decode(&container); err != nil { - t.Fatal("failed to decode container config") + t.Fatalf("failed to decode container config: %s", err) } if container.Hostname != "koye" { t.Log("hostname is not set") @@ -27,32 +27,32 @@ func TestContainerJsonFormat(t *testing.T) { t.Fail() } - if !container.Namespaces.Contains("NEWNET") { + if !container.Namespaces["NEWNET"] { t.Log("namespaces should contain NEWNET") t.Fail() } - if container.Namespaces.Contains("NEWUSER") { + if container.Namespaces["NEWUSER"] { t.Log("namespaces should not contain NEWUSER") t.Fail() } - if !container.CapabilitiesMask.Contains("SYS_ADMIN") { + if _, exists := container.CapabilitiesMask["SYS_ADMIN"]; !exists { t.Log("capabilities mask should contain SYS_ADMIN") t.Fail() } - if container.CapabilitiesMask.Get("SYS_ADMIN").Enabled { + if container.CapabilitiesMask["SYS_ADMIN"] { t.Log("SYS_ADMIN should not be enabled in capabilities mask") t.Fail() } - if !container.CapabilitiesMask.Get("MKNOD").Enabled { + if !container.CapabilitiesMask["MKNOD"] { t.Log("MKNOD should be enabled in capabilities mask") t.Fail() } - if container.CapabilitiesMask.Contains("SYS_CHROOT") { + if container.CapabilitiesMask["SYS_CHROOT"] { t.Log("capabilities mask should not contain SYS_CHROOT") t.Fail() } diff --git a/nsinit/exec.go b/nsinit/exec.go index 8886efeb..5d0d772a 100644 --- a/nsinit/exec.go +++ b/nsinit/exec.go @@ -159,10 +159,12 @@ func InitializeNetworking(container *libcontainer.Container, nspid int, pipe *Sy // GetNamespaceFlags parses the container's Namespaces options to set the correct // flags on clone, unshare, and setns -func GetNamespaceFlags(namespaces libcontainer.Namespaces) (flag int) { - for _, ns := range namespaces { - if ns.Enabled { - flag |= ns.Value +func GetNamespaceFlags(namespaces map[string]bool) (flag int) { + for key, enabled := range namespaces { + if enabled { + if ns := libcontainer.GetNamespace(key); ns != nil { + flag |= ns.Value + } } } return flag diff --git a/nsinit/execin.go b/nsinit/execin.go index 608437f8..40b95093 100644 --- a/nsinit/execin.go +++ b/nsinit/execin.go @@ -23,11 +23,13 @@ func ExecIn(container *libcontainer.Container, nspid int, args []string) (int, e return -1, err } - for _, nsv := range container.Namespaces { + for key, enabled := range container.Namespaces { // skip the PID namespace on unshare because it it not supported - if nsv.Enabled && nsv.Key != "NEWPID" { - if err := system.Unshare(nsv.Value); err != nil { - return -1, err + if enabled && key != "NEWPID" { + if ns := libcontainer.GetNamespace(key); ns != nil { + if err := system.Unshare(ns.Value); err != nil { + return -1, err + } } } } @@ -59,7 +61,7 @@ func ExecIn(container *libcontainer.Container, nspid int, args []string) (int, e // if the container has a new pid and mount namespace we need to // remount proc and sys to pick up the changes - if container.Namespaces.Contains("NEWNS") && container.Namespaces.Contains("NEWPID") { + if container.Namespaces["NEWNS"] && container.Namespaces["NEWPID"] { pid, err := system.Fork() if err != nil { return -1, err @@ -102,13 +104,18 @@ dropAndExec: } func getNsFds(pid int, container *libcontainer.Container) ([]uintptr, error) { - fds := make([]uintptr, len(container.Namespaces)) - for i, ns := range container.Namespaces { - f, err := os.OpenFile(filepath.Join("/proc/", strconv.Itoa(pid), "ns", ns.File), os.O_RDONLY, 0) - if err != nil { - return fds, err + fds := []uintptr{} + + for key, enabled := range container.Namespaces { + if enabled { + if ns := libcontainer.GetNamespace(key); ns != nil { + f, err := os.OpenFile(filepath.Join("/proc/", strconv.Itoa(pid), "ns", ns.File), os.O_RDONLY, 0) + if err != nil { + return fds, err + } + fds = append(fds, f.Fd()) + } } - fds[i] = f.Fd() } return fds, nil } diff --git a/nsinit/unsupported.go b/nsinit/unsupported.go index f213f2ec..929b3dba 100644 --- a/nsinit/unsupported.go +++ b/nsinit/unsupported.go @@ -23,6 +23,6 @@ func SetupCgroups(container *libcontainer.Container, nspid int) (cgroups.ActiveC return nil, libcontainer.ErrUnsupported } -func GetNamespaceFlags(namespaces libcontainer.Namespaces) (flag int) { +func GetNamespaceFlags(namespaces map[string]bool) (flag int) { return 0 } diff --git a/security/capabilities/capabilities.go b/security/capabilities/capabilities.go index 4b81e708..ad13e672 100644 --- a/security/capabilities/capabilities.go +++ b/security/capabilities/capabilities.go @@ -1,9 +1,10 @@ package capabilities import ( + "os" + "github.com/dotcloud/docker/pkg/libcontainer" "github.com/syndtr/gocapability/capability" - "os" ) // DropCapabilities drops capabilities for the current process based @@ -26,9 +27,11 @@ func DropCapabilities(container *libcontainer.Container) error { // getCapabilitiesMask returns the specific cap mask values for the libcontainer types func getCapabilitiesMask(container *libcontainer.Container) []capability.Cap { drop := []capability.Cap{} - for _, c := range container.CapabilitiesMask { - if !c.Enabled { - drop = append(drop, c.Value) + for key, enabled := range container.CapabilitiesMask { + if !enabled { + if c := libcontainer.GetCapability(key); c != nil { + drop = append(drop, c.Value) + } } } return drop diff --git a/types.go b/types.go index f5fe6cff..8f056c81 100644 --- a/types.go +++ b/types.go @@ -2,6 +2,7 @@ package libcontainer import ( "errors" + "github.com/syndtr/gocapability/capability" ) @@ -38,31 +39,30 @@ var ( namespaceList = Namespaces{} capabilityList = Capabilities{ - {Key: "SETPCAP", Value: capability.CAP_SETPCAP, Enabled: false}, - {Key: "SYS_MODULE", Value: capability.CAP_SYS_MODULE, Enabled: false}, - {Key: "SYS_RAWIO", Value: capability.CAP_SYS_RAWIO, Enabled: false}, - {Key: "SYS_PACCT", Value: capability.CAP_SYS_PACCT, Enabled: false}, - {Key: "SYS_ADMIN", Value: capability.CAP_SYS_ADMIN, Enabled: false}, - {Key: "SYS_NICE", Value: capability.CAP_SYS_NICE, Enabled: false}, - {Key: "SYS_RESOURCE", Value: capability.CAP_SYS_RESOURCE, Enabled: false}, - {Key: "SYS_TIME", Value: capability.CAP_SYS_TIME, Enabled: false}, - {Key: "SYS_TTY_CONFIG", Value: capability.CAP_SYS_TTY_CONFIG, Enabled: false}, - {Key: "MKNOD", Value: capability.CAP_MKNOD, Enabled: false}, - {Key: "AUDIT_WRITE", Value: capability.CAP_AUDIT_WRITE, Enabled: false}, - {Key: "AUDIT_CONTROL", Value: capability.CAP_AUDIT_CONTROL, Enabled: false}, - {Key: "MAC_OVERRIDE", Value: capability.CAP_MAC_OVERRIDE, Enabled: false}, - {Key: "MAC_ADMIN", Value: capability.CAP_MAC_ADMIN, Enabled: false}, - {Key: "NET_ADMIN", Value: capability.CAP_NET_ADMIN, Enabled: false}, - {Key: "SYSLOG", Value: capability.CAP_SYSLOG, Enabled: false}, + {Key: "SETPCAP", Value: capability.CAP_SETPCAP}, + {Key: "SYS_MODULE", Value: capability.CAP_SYS_MODULE}, + {Key: "SYS_RAWIO", Value: capability.CAP_SYS_RAWIO}, + {Key: "SYS_PACCT", Value: capability.CAP_SYS_PACCT}, + {Key: "SYS_ADMIN", Value: capability.CAP_SYS_ADMIN}, + {Key: "SYS_NICE", Value: capability.CAP_SYS_NICE}, + {Key: "SYS_RESOURCE", Value: capability.CAP_SYS_RESOURCE}, + {Key: "SYS_TIME", Value: capability.CAP_SYS_TIME}, + {Key: "SYS_TTY_CONFIG", Value: capability.CAP_SYS_TTY_CONFIG}, + {Key: "MKNOD", Value: capability.CAP_MKNOD}, + {Key: "AUDIT_WRITE", Value: capability.CAP_AUDIT_WRITE}, + {Key: "AUDIT_CONTROL", Value: capability.CAP_AUDIT_CONTROL}, + {Key: "MAC_OVERRIDE", Value: capability.CAP_MAC_OVERRIDE}, + {Key: "MAC_ADMIN", Value: capability.CAP_MAC_ADMIN}, + {Key: "NET_ADMIN", Value: capability.CAP_NET_ADMIN}, + {Key: "SYSLOG", Value: capability.CAP_SYSLOG}, } ) type ( Namespace struct { - Key string `json:"key,omitempty"` - Enabled bool `json:"enabled,omitempty"` - Value int `json:"value,omitempty"` - File string `json:"file,omitempty"` + Key string `json:"key,omitempty"` + Value int `json:"value,omitempty"` + File string `json:"file,omitempty"` } Namespaces []*Namespace ) @@ -98,9 +98,8 @@ func (n Namespaces) Get(ns string) *Namespace { type ( Capability struct { - Key string `json:"key,omitempty"` - Enabled bool `json:"enabled"` - Value capability.Cap `json:"value,omitempty"` + Key string `json:"key,omitempty"` + Value capability.Cap `json:"value,omitempty"` } Capabilities []*Capability ) diff --git a/types_linux.go b/types_linux.go index 1f937e0c..c14531df 100644 --- a/types_linux.go +++ b/types_linux.go @@ -6,11 +6,11 @@ import ( func init() { namespaceList = Namespaces{ - {Key: "NEWNS", Value: syscall.CLONE_NEWNS, File: "mnt", Enabled: true}, - {Key: "NEWUTS", Value: syscall.CLONE_NEWUTS, File: "uts", Enabled: true}, - {Key: "NEWIPC", Value: syscall.CLONE_NEWIPC, File: "ipc", Enabled: true}, - {Key: "NEWUSER", Value: syscall.CLONE_NEWUSER, File: "user", Enabled: true}, - {Key: "NEWPID", Value: syscall.CLONE_NEWPID, File: "pid", Enabled: true}, - {Key: "NEWNET", Value: syscall.CLONE_NEWNET, File: "net", Enabled: true}, + {Key: "NEWNS", Value: syscall.CLONE_NEWNS, File: "mnt"}, + {Key: "NEWUTS", Value: syscall.CLONE_NEWUTS, File: "uts"}, + {Key: "NEWIPC", Value: syscall.CLONE_NEWIPC, File: "ipc"}, + {Key: "NEWUSER", Value: syscall.CLONE_NEWUSER, File: "user"}, + {Key: "NEWPID", Value: syscall.CLONE_NEWPID, File: "pid"}, + {Key: "NEWNET", Value: syscall.CLONE_NEWNET, File: "net"}, } }