소스 검색

Merge pull request #46221 from thaJeztah/24.0_backport_capabilites

[24.0 backport] Do not drop effective&permitted set
Bjorn Neergaard 1 년 전
부모
커밋
ad7a03eb33
4개의 변경된 파일163개의 추가작업 그리고 13개의 파일을 삭제
  1. 108 0
      integration/capabilities/capabilities_linux_test.go
  2. 33 0
      integration/capabilities/main_linux_test.go
  3. 18 0
      integration/internal/container/ops.go
  4. 4 13
      oci/oci.go

+ 108 - 0
integration/capabilities/capabilities_linux_test.go

@@ -0,0 +1,108 @@
+package capabilities
+
+import (
+	"bytes"
+	"context"
+	"io"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/docker/docker/api/types"
+	"github.com/docker/docker/integration/internal/container"
+	"github.com/docker/docker/pkg/stdcopy"
+	"github.com/docker/docker/testutil/fakecontext"
+
+	"gotest.tools/v3/assert"
+	"gotest.tools/v3/poll"
+)
+
+func TestNoNewPrivileges(t *testing.T) {
+	defer setupTest(t)()
+
+	withFileCapability := `
+		FROM debian:bullseye-slim
+		RUN apt-get update && apt-get install -y libcap2-bin --no-install-recommends
+		RUN setcap CAP_DAC_OVERRIDE=+eip /bin/cat
+		RUN echo "hello" > /txt && chown 0:0 /txt && chmod 700 /txt
+		RUN useradd -u 1500 test
+	`
+	imageTag := "captest"
+
+	source := fakecontext.New(t, "", fakecontext.WithDockerfile(withFileCapability))
+	defer source.Close()
+
+	client := testEnv.APIClient()
+
+	// Build image
+	ctx := context.TODO()
+	resp, err := client.ImageBuild(ctx,
+		source.AsTarReader(t),
+		types.ImageBuildOptions{
+			Tags: []string{imageTag},
+		})
+	assert.NilError(t, err)
+	_, err = io.Copy(io.Discard, resp.Body)
+	assert.NilError(t, err)
+	resp.Body.Close()
+
+	testCases := []struct {
+		doc            string
+		opts           []func(*container.TestContainerConfig)
+		stdOut, stdErr string
+	}{
+		{
+			doc: "CapabilityRequested=true",
+			opts: []func(*container.TestContainerConfig){
+				container.WithUser("test"),
+				container.WithCapability("CAP_DAC_OVERRIDE"),
+			},
+			stdOut: "hello",
+		},
+		{
+			doc: "CapabilityRequested=false",
+			opts: []func(*container.TestContainerConfig){
+				container.WithUser("test"),
+				container.WithDropCapability("CAP_DAC_OVERRIDE"),
+			},
+			stdErr: "exec /bin/cat: operation not permitted",
+		},
+	}
+
+	for _, tc := range testCases {
+		tc := tc
+		t.Run(tc.doc, func(t *testing.T) {
+			// Run the container with the image
+			opts := append(tc.opts,
+				container.WithImage(imageTag),
+				container.WithCmd("/bin/cat", "/txt"),
+				container.WithSecurityOpt("no-new-privileges=true"),
+			)
+			cid := container.Run(ctx, t, client, opts...)
+			poll.WaitOn(t, container.IsInState(ctx, client, cid, "exited"), poll.WithDelay(100*time.Millisecond))
+
+			// Assert on outputs
+			logReader, err := client.ContainerLogs(ctx, cid, types.ContainerLogsOptions{
+				ShowStdout: true,
+				ShowStderr: true,
+			})
+			assert.NilError(t, err)
+			defer logReader.Close()
+
+			var actualStdout, actualStderr bytes.Buffer
+			_, err = stdcopy.StdCopy(&actualStdout, &actualStderr, logReader)
+			assert.NilError(t, err)
+
+			stdOut := strings.TrimSpace(actualStdout.String())
+			stdErr := strings.TrimSpace(actualStderr.String())
+			if stdOut != tc.stdOut {
+				t.Fatalf("test produced invalid output: %q, expected %q. Stderr:%q", stdOut, tc.stdOut, stdErr)
+			}
+			if stdErr != tc.stdErr {
+				t.Fatalf("test produced invalid error: %q, expected %q. Stdout:%q", stdErr, tc.stdErr, stdOut)
+
+			}
+		})
+	}
+
+}

+ 33 - 0
integration/capabilities/main_linux_test.go

@@ -0,0 +1,33 @@
+package capabilities
+
+import (
+	"fmt"
+	"os"
+	"testing"
+
+	"github.com/docker/docker/testutil/environment"
+)
+
+var testEnv *environment.Execution
+
+func TestMain(m *testing.M) {
+	var err error
+	testEnv, err = environment.New()
+	if err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
+	err = environment.EnsureFrozenImagesLinux(testEnv)
+	if err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
+
+	testEnv.Print()
+	os.Exit(m.Run())
+}
+
+func setupTest(t *testing.T) func() {
+	environment.ProtectAll(t, testEnv)
+	return func() { testEnv.Clean(t) }
+}

+ 18 - 0
integration/internal/container/ops.go

@@ -237,3 +237,21 @@ func WithRuntime(name string) func(*TestContainerConfig) {
 		c.HostConfig.Runtime = name
 	}
 }
+
+func WithCapability(capabilities ...string) func(*TestContainerConfig) {
+	return func(c *TestContainerConfig) {
+		c.HostConfig.CapAdd = append(c.HostConfig.CapAdd, capabilities...)
+	}
+}
+
+func WithDropCapability(capabilities ...string) func(*TestContainerConfig) {
+	return func(c *TestContainerConfig) {
+		c.HostConfig.CapDrop = append(c.HostConfig.CapDrop, capabilities...)
+	}
+}
+
+func WithSecurityOpt(opt string) func(*TestContainerConfig) {
+	return func(c *TestContainerConfig) {
+		c.HostConfig.SecurityOpt = append(c.HostConfig.SecurityOpt, opt)
+	}
+}

+ 4 - 13
oci/oci.go

@@ -23,19 +23,10 @@ func SetCapabilities(s *specs.Spec, caplist []string) error {
 	if s.Process == nil {
 		s.Process = &specs.Process{}
 	}
-	// setUser has already been executed here
-	if s.Process.User.UID == 0 {
-		s.Process.Capabilities = &specs.LinuxCapabilities{
-			Effective: caplist,
-			Bounding:  caplist,
-			Permitted: caplist,
-		}
-	} else {
-		// Do not set Effective and Permitted capabilities for non-root users,
-		// to match what execve does.
-		s.Process.Capabilities = &specs.LinuxCapabilities{
-			Bounding: caplist,
-		}
+	s.Process.Capabilities = &specs.LinuxCapabilities{
+		Effective: caplist,
+		Bounding:  caplist,
+		Permitted: caplist,
 	}
 	return nil
 }