Merge pull request #5017 from AkihiroSuda/parse-cap
oci.WithPrivileged: set the current caps, not the known caps
This commit is contained in:
@@ -38,7 +38,6 @@ import (
|
||||
"github.com/opencontainers/runc/libcontainer/user"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/syndtr/gocapability/capability"
|
||||
)
|
||||
|
||||
// SpecOpts sets spec specific information to a newly generated OCI spec
|
||||
@@ -776,29 +775,6 @@ func WithCapabilities(caps []string) SpecOpts {
|
||||
}
|
||||
}
|
||||
|
||||
// WithAllCapabilities sets all linux capabilities for the process
|
||||
var WithAllCapabilities = func(ctx context.Context, client Client, c *containers.Container, s *Spec) error {
|
||||
return WithCapabilities(GetAllCapabilities())(ctx, client, c, s)
|
||||
}
|
||||
|
||||
// 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) {
|
||||
last = capability.CAP_BLOCK_SUSPEND
|
||||
}
|
||||
var caps []string
|
||||
for _, cap := range capability.List() {
|
||||
if cap > last {
|
||||
continue
|
||||
}
|
||||
caps = append(caps, "CAP_"+strings.ToUpper(cap.String()))
|
||||
}
|
||||
return caps
|
||||
}
|
||||
|
||||
func capsContain(caps []string, s string) bool {
|
||||
for _, c := range caps {
|
||||
if c == s {
|
||||
@@ -1132,7 +1108,7 @@ func WithDefaultUnixDevices(_ context.Context, _ Client, _ *containers.Container
|
||||
|
||||
// WithPrivileged sets up options for a privileged container
|
||||
var WithPrivileged = Compose(
|
||||
WithAllCapabilities,
|
||||
WithAllCurrentCapabilities,
|
||||
WithMaskedPaths(nil),
|
||||
WithReadonlyPaths(nil),
|
||||
WithWriteableSysfs,
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/containerd/containerd/containers"
|
||||
"github.com/containerd/containerd/pkg/cap"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
@@ -180,3 +181,19 @@ func WithCPUCFS(quota int64, period uint64) SpecOpts {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithAllCurrentCapabilities propagates the effective capabilities of the caller process to the container process.
|
||||
// The capability set may differ from WithAllKnownCapabilities when running in a container.
|
||||
var WithAllCurrentCapabilities = func(ctx context.Context, client Client, c *containers.Container, s *Spec) error {
|
||||
caps, err := cap.Current()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return WithCapabilities(caps)(ctx, client, c, s)
|
||||
}
|
||||
|
||||
// WithAllKnownCapabilities sets all the the known linux capabilities for the container process
|
||||
var WithAllKnownCapabilities = func(ctx context.Context, client Client, c *containers.Container, s *Spec) error {
|
||||
caps := cap.Known()
|
||||
return WithCapabilities(caps)(ctx, client, c, s)
|
||||
}
|
||||
|
||||
108
oci/spec_opts_linux_test.go
Normal file
108
oci/spec_opts_linux_test.go
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package oci
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
func TestAddCaps(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var s specs.Spec
|
||||
|
||||
if err := WithAddedCapabilities([]string{"CAP_CHOWN"})(context.Background(), 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 := WithAllKnownCapabilities(context.Background(), nil, nil, &s); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := WithDroppedCapabilities([]string{"CAP_CHOWN"})(context.Background(), 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)
|
||||
}
|
||||
}
|
||||
|
||||
// Add all capabilities back and drop a different cap.
|
||||
if err := WithAllKnownCapabilities(context.Background(), nil, nil, &s); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := WithDroppedCapabilities([]string{"CAP_FOWNER"})(context.Background(), 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_FOWNER") {
|
||||
t.Errorf("cap list %d contains dropped cap", i)
|
||||
}
|
||||
if !capsContain(cl, "CAP_CHOWN") {
|
||||
t.Errorf("cap list %d doesn't contain non-dropped cap", i)
|
||||
}
|
||||
}
|
||||
|
||||
// Drop all duplicated caps.
|
||||
if err := WithCapabilities([]string{"CAP_CHOWN", "CAP_CHOWN"})(context.Background(), nil, nil, &s); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := WithDroppedCapabilities([]string{"CAP_CHOWN"})(context.Background(), 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 len(cl) != 0 {
|
||||
t.Errorf("cap list %d is not empty", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
38
oci/spec_opts_nonlinux.go
Normal file
38
oci/spec_opts_nonlinux.go
Normal file
@@ -0,0 +1,38 @@
|
||||
// +build !linux
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package oci
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/containerd/containerd/containers"
|
||||
)
|
||||
|
||||
// WithAllCurrentCapabilities propagates the effective capabilities of the caller process to the container process.
|
||||
// The capability set may differ from WithAllKnownCapabilities when running in a container.
|
||||
//nolint: deadcode, unused
|
||||
var WithAllCurrentCapabilities = func(ctx context.Context, client Client, c *containers.Container, s *Spec) error {
|
||||
return WithCapabilities(nil)(ctx, client, c, s)
|
||||
}
|
||||
|
||||
// WithAllKnownCapabilities sets all the the known linux capabilities for the container process
|
||||
//nolint: deadcode, unused
|
||||
var WithAllKnownCapabilities = func(ctx context.Context, client Client, c *containers.Container, s *Spec) error {
|
||||
return WithCapabilities(nil)(ctx, client, c, s)
|
||||
}
|
||||
@@ -549,90 +549,6 @@ func TestWithImageConfigArgs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddCaps(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var s specs.Spec
|
||||
|
||||
if err := WithAddedCapabilities([]string{"CAP_CHOWN"})(context.Background(), 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(context.Background(), nil, nil, &s); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := WithDroppedCapabilities([]string{"CAP_CHOWN"})(context.Background(), 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)
|
||||
}
|
||||
}
|
||||
|
||||
// Add all capabilities back and drop a different cap.
|
||||
if err := WithAllCapabilities(context.Background(), nil, nil, &s); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := WithDroppedCapabilities([]string{"CAP_FOWNER"})(context.Background(), 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_FOWNER") {
|
||||
t.Errorf("cap list %d contains dropped cap", i)
|
||||
}
|
||||
if !capsContain(cl, "CAP_CHOWN") {
|
||||
t.Errorf("cap list %d doesn't contain non-dropped cap", i)
|
||||
}
|
||||
}
|
||||
|
||||
// Drop all duplicated caps.
|
||||
if err := WithCapabilities([]string{"CAP_CHOWN", "CAP_CHOWN"})(context.Background(), nil, nil, &s); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := WithDroppedCapabilities([]string{"CAP_CHOWN"})(context.Background(), 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 len(cl) != 0 {
|
||||
t.Errorf("cap list %d is not empty", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDevShmSize(t *testing.T) {
|
||||
t.Parallel()
|
||||
var (
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
|
||||
"github.com/containerd/containerd/containers"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/containerd/containerd/pkg/testutil"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
@@ -251,6 +252,10 @@ func TestPopulateDefaultUnixSpec(t *testing.T) {
|
||||
|
||||
func TestWithPrivileged(t *testing.T) {
|
||||
t.Parallel()
|
||||
if runtime.GOOS == "linux" {
|
||||
// because WithPrivileged depends on CapEff in /proc/self/status
|
||||
testutil.RequiresRoot(t)
|
||||
}
|
||||
|
||||
ctx := namespaces.WithNamespace(context.Background(), "testing")
|
||||
|
||||
@@ -272,6 +277,10 @@ func TestWithPrivileged(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if runtime.GOOS != "linux" {
|
||||
return
|
||||
}
|
||||
|
||||
if len(s.Process.Capabilities.Bounding) == 0 {
|
||||
t.Error("Expected capabilities to be set with privileged")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user