Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add additional capability handling opts #3099

Merged
merged 1 commit into from Mar 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
63 changes: 60 additions & 3 deletions oci/spec_opts.go
Expand Up @@ -33,7 +33,7 @@ import (
"github.com/containerd/containerd/namespaces"
"github.com/containerd/containerd/platforms"
"github.com/containerd/continuity/fs"
"github.com/opencontainers/image-spec/specs-go/v1"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/opencontainers/runc/libcontainer/user"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
Expand Down Expand Up @@ -741,9 +741,11 @@ func WithCapabilities(caps []string) SpecOpts {
}

// WithAllCapabilities sets all linux capabilities for the process
var WithAllCapabilities = WithCapabilities(getAllCapabilities())
var WithAllCapabilities = WithCapabilities(GetAllCapabilities())

func getAllCapabilities() []string {
// GetAllCapabilities returns all caps up to CAP_LAST_CAP
// or CAP_BLOCK_SUSPEND on RHEL6
func GetAllCapabilities() []string {
last := capability.CAP_LAST_CAP
// hack for RHEL6 which has no /proc/sys/kernel/cap_last_cap
if last == capability.Cap(63) {
Expand All @@ -759,6 +761,61 @@ func getAllCapabilities() []string {
return caps
}

func capsContain(caps []string, s string) bool {
for _, c := range caps {
if c == s {
return true
}
}
return false
}

func removeCap(caps *[]string, s string) {
for i, c := range *caps {
if c == s {
*caps = append((*caps)[:i], (*caps)[i+1:]...)
}
}
}

// WithAddedCapabilities adds the provided capabilities
func WithAddedCapabilities(caps []string) SpecOpts {
return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
setCapabilities(s)
for _, c := range caps {
for _, cl := range []*[]string{
&s.Process.Capabilities.Bounding,
&s.Process.Capabilities.Effective,
&s.Process.Capabilities.Permitted,
&s.Process.Capabilities.Inheritable,
} {
if !capsContain(*cl, c) {
*cl = append(*cl, c)
}
}
}
return nil
}
}

// WithDroppedCapabilities removes the provided capabilities
func WithDroppedCapabilities(caps []string) SpecOpts {
return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error {
setCapabilities(s)
for _, c := range caps {
for _, cl := range []*[]string{
&s.Process.Capabilities.Bounding,
&s.Process.Capabilities.Effective,
&s.Process.Capabilities.Permitted,
&s.Process.Capabilities.Inheritable,
} {
removeCap(cl, c)
}
}
return nil
}
}

// WithAmbientCapabilities set the Linux ambient capabilities for the process
// Ambient capabilities should only be set for non-root users or the caller should
// understand how these capabilities are used and set
Expand Down
44 changes: 44 additions & 0 deletions oci/spec_opts_test.go
Expand Up @@ -422,3 +422,47 @@ func TestWithImageConfigArgs(t *testing.T) {
t.Fatal(err)
}
}

func TestAddCaps(t *testing.T) {
t.Parallel()

var s specs.Spec

if err := WithAddedCapabilities([]string{"CAP_CHOWN"})(nil, nil, nil, &s); err != nil {
t.Fatal(err)
}
for i, cl := range [][]string{
s.Process.Capabilities.Bounding,
s.Process.Capabilities.Effective,
s.Process.Capabilities.Permitted,
s.Process.Capabilities.Inheritable,
} {
if !capsContain(cl, "CAP_CHOWN") {
t.Errorf("cap list %d does not contain added cap", i)
}
}
}

func TestDropCaps(t *testing.T) {
t.Parallel()

var s specs.Spec

if err := WithAllCapabilities(nil, nil, nil, &s); err != nil {
t.Fatal(err)
}
if err := WithDroppedCapabilities([]string{"CAP_CHOWN"})(nil, nil, nil, &s); err != nil {
t.Fatal(err)
}

for i, cl := range [][]string{
s.Process.Capabilities.Bounding,
s.Process.Capabilities.Effective,
s.Process.Capabilities.Permitted,
s.Process.Capabilities.Inheritable,
} {
if capsContain(cl, "CAP_CHOWN") {
t.Errorf("cap list %d contains dropped cap", i)
}
}
}