Skip to content

Commit 757be0a

Browse files
authored
Merge pull request #5017 from AkihiroSuda/parse-cap
oci.WithPrivileged: set the current caps, not the known caps
2 parents 9173d3e + 51f985c commit 757be0a

13 files changed

Lines changed: 530 additions & 117 deletions

oci/spec_opts.go

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ import (
3838
"github.com/opencontainers/runc/libcontainer/user"
3939
specs "github.com/opencontainers/runtime-spec/specs-go"
4040
"github.com/pkg/errors"
41-
"github.com/syndtr/gocapability/capability"
4241
)
4342

4443
// SpecOpts sets spec specific information to a newly generated OCI spec
@@ -776,29 +775,6 @@ func WithCapabilities(caps []string) SpecOpts {
776775
}
777776
}
778777

779-
// WithAllCapabilities sets all linux capabilities for the process
780-
var WithAllCapabilities = func(ctx context.Context, client Client, c *containers.Container, s *Spec) error {
781-
return WithCapabilities(GetAllCapabilities())(ctx, client, c, s)
782-
}
783-
784-
// GetAllCapabilities returns all caps up to CAP_LAST_CAP
785-
// or CAP_BLOCK_SUSPEND on RHEL6
786-
func GetAllCapabilities() []string {
787-
last := capability.CAP_LAST_CAP
788-
// hack for RHEL6 which has no /proc/sys/kernel/cap_last_cap
789-
if last == capability.Cap(63) {
790-
last = capability.CAP_BLOCK_SUSPEND
791-
}
792-
var caps []string
793-
for _, cap := range capability.List() {
794-
if cap > last {
795-
continue
796-
}
797-
caps = append(caps, "CAP_"+strings.ToUpper(cap.String()))
798-
}
799-
return caps
800-
}
801-
802778
func capsContain(caps []string, s string) bool {
803779
for _, c := range caps {
804780
if c == s {
@@ -1132,7 +1108,7 @@ func WithDefaultUnixDevices(_ context.Context, _ Client, _ *containers.Container
11321108

11331109
// WithPrivileged sets up options for a privileged container
11341110
var WithPrivileged = Compose(
1135-
WithAllCapabilities,
1111+
WithAllCurrentCapabilities,
11361112
WithMaskedPaths(nil),
11371113
WithReadonlyPaths(nil),
11381114
WithWriteableSysfs,

oci/spec_opts_linux.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"path/filepath"
2626

2727
"github.com/containerd/containerd/containers"
28+
"github.com/containerd/containerd/pkg/cap"
2829
specs "github.com/opencontainers/runtime-spec/specs-go"
2930
"golang.org/x/sys/unix"
3031
)
@@ -180,3 +181,19 @@ func WithCPUCFS(quota int64, period uint64) SpecOpts {
180181
return nil
181182
}
182183
}
184+
185+
// WithAllCurrentCapabilities propagates the effective capabilities of the caller process to the container process.
186+
// The capability set may differ from WithAllKnownCapabilities when running in a container.
187+
var WithAllCurrentCapabilities = func(ctx context.Context, client Client, c *containers.Container, s *Spec) error {
188+
caps, err := cap.Current()
189+
if err != nil {
190+
return err
191+
}
192+
return WithCapabilities(caps)(ctx, client, c, s)
193+
}
194+
195+
// WithAllKnownCapabilities sets all the the known linux capabilities for the container process
196+
var WithAllKnownCapabilities = func(ctx context.Context, client Client, c *containers.Container, s *Spec) error {
197+
caps := cap.Known()
198+
return WithCapabilities(caps)(ctx, client, c, s)
199+
}

oci/spec_opts_linux_test.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
Copyright The containerd Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package oci
18+
19+
import (
20+
"context"
21+
"testing"
22+
23+
specs "github.com/opencontainers/runtime-spec/specs-go"
24+
)
25+
26+
func TestAddCaps(t *testing.T) {
27+
t.Parallel()
28+
29+
var s specs.Spec
30+
31+
if err := WithAddedCapabilities([]string{"CAP_CHOWN"})(context.Background(), nil, nil, &s); err != nil {
32+
t.Fatal(err)
33+
}
34+
for i, cl := range [][]string{
35+
s.Process.Capabilities.Bounding,
36+
s.Process.Capabilities.Effective,
37+
s.Process.Capabilities.Permitted,
38+
s.Process.Capabilities.Inheritable,
39+
} {
40+
if !capsContain(cl, "CAP_CHOWN") {
41+
t.Errorf("cap list %d does not contain added cap", i)
42+
}
43+
}
44+
}
45+
46+
func TestDropCaps(t *testing.T) {
47+
t.Parallel()
48+
49+
var s specs.Spec
50+
51+
if err := WithAllKnownCapabilities(context.Background(), nil, nil, &s); err != nil {
52+
t.Fatal(err)
53+
}
54+
if err := WithDroppedCapabilities([]string{"CAP_CHOWN"})(context.Background(), nil, nil, &s); err != nil {
55+
t.Fatal(err)
56+
}
57+
58+
for i, cl := range [][]string{
59+
s.Process.Capabilities.Bounding,
60+
s.Process.Capabilities.Effective,
61+
s.Process.Capabilities.Permitted,
62+
s.Process.Capabilities.Inheritable,
63+
} {
64+
if capsContain(cl, "CAP_CHOWN") {
65+
t.Errorf("cap list %d contains dropped cap", i)
66+
}
67+
}
68+
69+
// Add all capabilities back and drop a different cap.
70+
if err := WithAllKnownCapabilities(context.Background(), nil, nil, &s); err != nil {
71+
t.Fatal(err)
72+
}
73+
if err := WithDroppedCapabilities([]string{"CAP_FOWNER"})(context.Background(), nil, nil, &s); err != nil {
74+
t.Fatal(err)
75+
}
76+
77+
for i, cl := range [][]string{
78+
s.Process.Capabilities.Bounding,
79+
s.Process.Capabilities.Effective,
80+
s.Process.Capabilities.Permitted,
81+
s.Process.Capabilities.Inheritable,
82+
} {
83+
if capsContain(cl, "CAP_FOWNER") {
84+
t.Errorf("cap list %d contains dropped cap", i)
85+
}
86+
if !capsContain(cl, "CAP_CHOWN") {
87+
t.Errorf("cap list %d doesn't contain non-dropped cap", i)
88+
}
89+
}
90+
91+
// Drop all duplicated caps.
92+
if err := WithCapabilities([]string{"CAP_CHOWN", "CAP_CHOWN"})(context.Background(), nil, nil, &s); err != nil {
93+
t.Fatal(err)
94+
}
95+
if err := WithDroppedCapabilities([]string{"CAP_CHOWN"})(context.Background(), nil, nil, &s); err != nil {
96+
t.Fatal(err)
97+
}
98+
for i, cl := range [][]string{
99+
s.Process.Capabilities.Bounding,
100+
s.Process.Capabilities.Effective,
101+
s.Process.Capabilities.Permitted,
102+
s.Process.Capabilities.Inheritable,
103+
} {
104+
if len(cl) != 0 {
105+
t.Errorf("cap list %d is not empty", i)
106+
}
107+
}
108+
}

oci/spec_opts_nonlinux.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// +build !linux
2+
3+
/*
4+
Copyright The containerd Authors.
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
*/
18+
19+
package oci
20+
21+
import (
22+
"context"
23+
24+
"github.com/containerd/containerd/containers"
25+
)
26+
27+
// WithAllCurrentCapabilities propagates the effective capabilities of the caller process to the container process.
28+
// The capability set may differ from WithAllKnownCapabilities when running in a container.
29+
//nolint: deadcode, unused
30+
var WithAllCurrentCapabilities = func(ctx context.Context, client Client, c *containers.Container, s *Spec) error {
31+
return WithCapabilities(nil)(ctx, client, c, s)
32+
}
33+
34+
// WithAllKnownCapabilities sets all the the known linux capabilities for the container process
35+
//nolint: deadcode, unused
36+
var WithAllKnownCapabilities = func(ctx context.Context, client Client, c *containers.Container, s *Spec) error {
37+
return WithCapabilities(nil)(ctx, client, c, s)
38+
}

oci/spec_opts_test.go

Lines changed: 0 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -549,90 +549,6 @@ func TestWithImageConfigArgs(t *testing.T) {
549549
}
550550
}
551551

552-
func TestAddCaps(t *testing.T) {
553-
t.Parallel()
554-
555-
var s specs.Spec
556-
557-
if err := WithAddedCapabilities([]string{"CAP_CHOWN"})(context.Background(), nil, nil, &s); err != nil {
558-
t.Fatal(err)
559-
}
560-
for i, cl := range [][]string{
561-
s.Process.Capabilities.Bounding,
562-
s.Process.Capabilities.Effective,
563-
s.Process.Capabilities.Permitted,
564-
s.Process.Capabilities.Inheritable,
565-
} {
566-
if !capsContain(cl, "CAP_CHOWN") {
567-
t.Errorf("cap list %d does not contain added cap", i)
568-
}
569-
}
570-
}
571-
572-
func TestDropCaps(t *testing.T) {
573-
t.Parallel()
574-
575-
var s specs.Spec
576-
577-
if err := WithAllCapabilities(context.Background(), nil, nil, &s); err != nil {
578-
t.Fatal(err)
579-
}
580-
if err := WithDroppedCapabilities([]string{"CAP_CHOWN"})(context.Background(), nil, nil, &s); err != nil {
581-
t.Fatal(err)
582-
}
583-
584-
for i, cl := range [][]string{
585-
s.Process.Capabilities.Bounding,
586-
s.Process.Capabilities.Effective,
587-
s.Process.Capabilities.Permitted,
588-
s.Process.Capabilities.Inheritable,
589-
} {
590-
if capsContain(cl, "CAP_CHOWN") {
591-
t.Errorf("cap list %d contains dropped cap", i)
592-
}
593-
}
594-
595-
// Add all capabilities back and drop a different cap.
596-
if err := WithAllCapabilities(context.Background(), nil, nil, &s); err != nil {
597-
t.Fatal(err)
598-
}
599-
if err := WithDroppedCapabilities([]string{"CAP_FOWNER"})(context.Background(), nil, nil, &s); err != nil {
600-
t.Fatal(err)
601-
}
602-
603-
for i, cl := range [][]string{
604-
s.Process.Capabilities.Bounding,
605-
s.Process.Capabilities.Effective,
606-
s.Process.Capabilities.Permitted,
607-
s.Process.Capabilities.Inheritable,
608-
} {
609-
if capsContain(cl, "CAP_FOWNER") {
610-
t.Errorf("cap list %d contains dropped cap", i)
611-
}
612-
if !capsContain(cl, "CAP_CHOWN") {
613-
t.Errorf("cap list %d doesn't contain non-dropped cap", i)
614-
}
615-
}
616-
617-
// Drop all duplicated caps.
618-
if err := WithCapabilities([]string{"CAP_CHOWN", "CAP_CHOWN"})(context.Background(), nil, nil, &s); err != nil {
619-
t.Fatal(err)
620-
}
621-
if err := WithDroppedCapabilities([]string{"CAP_CHOWN"})(context.Background(), nil, nil, &s); err != nil {
622-
t.Fatal(err)
623-
}
624-
for i, cl := range [][]string{
625-
s.Process.Capabilities.Bounding,
626-
s.Process.Capabilities.Effective,
627-
s.Process.Capabilities.Permitted,
628-
s.Process.Capabilities.Inheritable,
629-
} {
630-
if len(cl) != 0 {
631-
t.Errorf("cap list %d is not empty", i)
632-
}
633-
}
634-
}
635-
636552
func TestDevShmSize(t *testing.T) {
637553
t.Parallel()
638554
var (

oci/spec_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
"github.com/containerd/containerd/containers"
2525
"github.com/containerd/containerd/namespaces"
26+
"github.com/containerd/containerd/pkg/testutil"
2627
specs "github.com/opencontainers/runtime-spec/specs-go"
2728
)
2829

@@ -251,6 +252,10 @@ func TestPopulateDefaultUnixSpec(t *testing.T) {
251252

252253
func TestWithPrivileged(t *testing.T) {
253254
t.Parallel()
255+
if runtime.GOOS == "linux" {
256+
// because WithPrivileged depends on CapEff in /proc/self/status
257+
testutil.RequiresRoot(t)
258+
}
254259

255260
ctx := namespaces.WithNamespace(context.Background(), "testing")
256261

@@ -272,6 +277,10 @@ func TestWithPrivileged(t *testing.T) {
272277
t.Fatal(err)
273278
}
274279

280+
if runtime.GOOS != "linux" {
281+
return
282+
}
283+
275284
if len(s.Process.Capabilities.Bounding) == 0 {
276285
t.Error("Expected capabilities to be set with privileged")
277286
}

0 commit comments

Comments
 (0)