diff --git a/libcontainer/capabilities/capabilities.go b/libcontainer/capabilities/capabilities.go index adbf6330c..dea33159b 100644 --- a/libcontainer/capabilities/capabilities.go +++ b/libcontainer/capabilities/capabilities.go @@ -10,9 +10,18 @@ import ( "github.com/syndtr/gocapability/capability" ) -const allCapabilityTypes = capability.CAPS | capability.BOUNDS | capability.AMBS +const allCapabilityTypes = capability.CAPS | capability.BOUNDING | capability.AMBIENT -var capabilityMap map[string]capability.Cap +var ( + capabilityMap map[string]capability.Cap + capTypes = []capability.CapType{ + capability.BOUNDING, + capability.PERMITTED, + capability.INHERITABLE, + capability.EFFECTIVE, + capability.AMBIENT, + } +) func init() { capabilityMap = make(map[string]capability.Cap, capability.CAP_LAST_CAP+1) @@ -24,37 +33,41 @@ func init() { } } -// New creates a new Caps from the given Capabilities config. +// New creates a new Caps from the given Capabilities config. Unknown Capabilities +// or Capabilities that are unavailable in the current environment produce an error. func New(capConfig *configs.Capabilities) (*Caps, error) { var ( - err error - caps Caps + err error + c = Caps{caps: make(map[capability.CapType][]capability.Cap, len(capTypes))} ) - if caps.bounding, err = capSlice(capConfig.Bounding); err != nil { + if c.caps[capability.BOUNDING], err = capSlice(capConfig.Bounding); err != nil { return nil, err } - if caps.effective, err = capSlice(capConfig.Effective); err != nil { + if c.caps[capability.EFFECTIVE], err = capSlice(capConfig.Effective); err != nil { return nil, err } - if caps.inheritable, err = capSlice(capConfig.Inheritable); err != nil { + if c.caps[capability.INHERITABLE], err = capSlice(capConfig.Inheritable); err != nil { return nil, err } - if caps.permitted, err = capSlice(capConfig.Permitted); err != nil { + if c.caps[capability.PERMITTED], err = capSlice(capConfig.Permitted); err != nil { return nil, err } - if caps.ambient, err = capSlice(capConfig.Ambient); err != nil { + if c.caps[capability.AMBIENT], err = capSlice(capConfig.Ambient); err != nil { return nil, err } - if caps.pid, err = capability.NewPid2(0); err != nil { + if c.pid, err = capability.NewPid2(0); err != nil { return nil, err } - if err = caps.pid.Load(); err != nil { + if err = c.pid.Load(); err != nil { return nil, err } - return &caps, nil + return &c, nil } +// capSlice converts the slice of capability names in caps, to their numeric +// equivalent, and returns them as a slice. Unknown or unavailable capabilities +// produce an error. func capSlice(caps []string) ([]capability.Cap, error) { out := make([]capability.Cap, len(caps)) for i, c := range caps { @@ -69,28 +82,22 @@ func capSlice(caps []string) ([]capability.Cap, error) { // Caps holds the capabilities for a container. type Caps struct { - pid capability.Capabilities - bounding []capability.Cap - effective []capability.Cap - inheritable []capability.Cap - permitted []capability.Cap - ambient []capability.Cap + pid capability.Capabilities + caps map[capability.CapType][]capability.Cap } // ApplyBoundingSet sets the capability bounding set to those specified in the whitelist. func (c *Caps) ApplyBoundingSet() error { - c.pid.Clear(capability.BOUNDS) - c.pid.Set(capability.BOUNDS, c.bounding...) - return c.pid.Apply(capability.BOUNDS) + c.pid.Clear(capability.BOUNDING) + c.pid.Set(capability.BOUNDING, c.caps[capability.BOUNDING]...) + return c.pid.Apply(capability.BOUNDING) } // Apply sets all the capabilities for the current process in the config. func (c *Caps) ApplyCaps() error { c.pid.Clear(allCapabilityTypes) - c.pid.Set(capability.BOUNDS, c.bounding...) - c.pid.Set(capability.PERMITTED, c.permitted...) - c.pid.Set(capability.INHERITABLE, c.inheritable...) - c.pid.Set(capability.EFFECTIVE, c.effective...) - c.pid.Set(capability.AMBIENT, c.ambient...) + for _, g := range capTypes { + c.pid.Set(g, c.caps[g]...) + } return c.pid.Apply(allCapabilityTypes) } diff --git a/libcontainer/capabilities/capabilities_linux_test.go b/libcontainer/capabilities/capabilities_linux_test.go new file mode 100644 index 000000000..36b8d186a --- /dev/null +++ b/libcontainer/capabilities/capabilities_linux_test.go @@ -0,0 +1,39 @@ +package capabilities + +import ( + "testing" + + "github.com/opencontainers/runc/libcontainer/configs" + "github.com/syndtr/gocapability/capability" +) + +func TestNew(t *testing.T) { + cs := []string{"CAP_CHOWN"} + conf := configs.Capabilities{ + Bounding: cs, + Effective: cs, + Inheritable: cs, + Permitted: cs, + Ambient: cs, + } + + caps, err := New(&conf) + if err != nil { + t.Error(err) + } + + if len(caps.caps) != len(capTypes) { + t.Errorf("expected %d capability types, got %d: %v", len(capTypes), len(caps.caps), caps.caps) + } + + for _, cType := range capTypes { + if i := len(caps.caps[cType]); i != 1 { + t.Errorf("expected 1 capability for %s, got %d: %v", cType, i, caps.caps[cType]) + continue + } + if caps.caps[cType][0] != capability.CAP_CHOWN { + t.Errorf("expected CAP_CHOWN, got %s: ", caps.caps[cType][0]) + continue + } + } +}