From 513d89eec5a6b6211e354e05e4951478ee216d8d Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Wed, 17 Mar 2021 17:10:15 +0100 Subject: [PATCH 1/2] capabilities: use BOUNDING/AMBIENT instead of their alias Signed-off-by: Sebastiaan van Stijn --- libcontainer/capabilities/capabilities.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libcontainer/capabilities/capabilities.go b/libcontainer/capabilities/capabilities.go index adbf6330c48..7ffe3c2d91f 100644 --- a/libcontainer/capabilities/capabilities.go +++ b/libcontainer/capabilities/capabilities.go @@ -10,7 +10,7 @@ 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 @@ -79,15 +79,15 @@ type Caps struct { // 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.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.BOUNDING, c.bounding...) c.pid.Set(capability.PERMITTED, c.permitted...) c.pid.Set(capability.INHERITABLE, c.inheritable...) c.pid.Set(capability.EFFECTIVE, c.effective...) From 997e89420d2cd1b17a7e8543dbe3277e1f9cebef Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Wed, 17 Mar 2021 17:16:34 +0100 Subject: [PATCH 2/2] capabilities.Caps: use a map for capability-types Signed-off-by: Sebastiaan van Stijn --- libcontainer/capabilities/capabilities.go | 55 +++++++++++-------- .../capabilities/capabilities_linux_test.go | 39 +++++++++++++ 2 files changed, 70 insertions(+), 24 deletions(-) create mode 100644 libcontainer/capabilities/capabilities_linux_test.go diff --git a/libcontainer/capabilities/capabilities.go b/libcontainer/capabilities/capabilities.go index 7ffe3c2d91f..dea33159ba3 100644 --- a/libcontainer/capabilities/capabilities.go +++ b/libcontainer/capabilities/capabilities.go @@ -12,7 +12,16 @@ import ( 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.BOUNDING) - c.pid.Set(capability.BOUNDING, c.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.BOUNDING, 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 00000000000..36b8d186a1f --- /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 + } + } +}