github.com/pwn-term/docker@v0.0.0-20210616085119-6e977cce2565/moby/integration/build/build_userns_linux_test.go (about)

     1  package build // import "github.com/docker/docker/integration/build"
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"context"
     7  	"io"
     8  	"io/ioutil"
     9  	"os"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/docker/docker/api/types"
    14  	"github.com/docker/docker/integration/internal/container"
    15  	"github.com/docker/docker/pkg/stdcopy"
    16  	"github.com/docker/docker/testutil/daemon"
    17  	"github.com/docker/docker/testutil/fakecontext"
    18  	"gotest.tools/v3/assert"
    19  	"gotest.tools/v3/skip"
    20  )
    21  
    22  // Implements a test for https://github.com/moby/moby/issues/41723
    23  // Images built in a user-namespaced daemon should have capabilities serialised in
    24  // VFS_CAP_REVISION_2 (no user-namespace root uid) format rather than V3 (that includes
    25  // the root uid).
    26  func TestBuildUserNamespaceValidateCapabilitiesAreV2(t *testing.T) {
    27  	skip.If(t, testEnv.DaemonInfo.OSType != "linux")
    28  	skip.If(t, testEnv.IsRemoteDaemon())
    29  	skip.If(t, !testEnv.IsUserNamespaceInKernel())
    30  	skip.If(t, testEnv.IsRootless())
    31  
    32  	const imageTag = "capabilities:1.0"
    33  
    34  	tmp, err := ioutil.TempDir("", "integration-")
    35  	assert.NilError(t, err)
    36  	defer os.RemoveAll(tmp)
    37  
    38  	dUserRemap := daemon.New(t)
    39  	dUserRemap.StartWithBusybox(t, "--userns-remap", "default")
    40  	dUserRemapRunning := true
    41  	defer func() {
    42  		if dUserRemapRunning {
    43  			dUserRemap.Stop(t)
    44  		}
    45  	}()
    46  
    47  	dockerfile := `
    48  		FROM debian:bullseye
    49  		RUN setcap CAP_NET_BIND_SERVICE=+eip /bin/sleep
    50  	`
    51  
    52  	ctx := context.Background()
    53  	source := fakecontext.New(t, "", fakecontext.WithDockerfile(dockerfile))
    54  	defer source.Close()
    55  
    56  	clientUserRemap := dUserRemap.NewClientT(t)
    57  	resp, err := clientUserRemap.ImageBuild(ctx,
    58  		source.AsTarReader(t),
    59  		types.ImageBuildOptions{
    60  			Tags: []string{imageTag},
    61  		})
    62  	assert.NilError(t, err)
    63  	defer resp.Body.Close()
    64  	buf := make([]byte, 1024)
    65  	for {
    66  		n, err := resp.Body.Read(buf)
    67  		if err != nil && err != io.EOF {
    68  			t.Fatalf("Error reading ImageBuild response: %v", err)
    69  			break
    70  		}
    71  		if n == 0 {
    72  			break
    73  		}
    74  	}
    75  
    76  	reader, err := clientUserRemap.ImageSave(ctx, []string{imageTag})
    77  	assert.NilError(t, err, "failed to download capabilities image")
    78  	defer reader.Close()
    79  
    80  	tar, err := os.Create(tmp + "/image.tar")
    81  	assert.NilError(t, err, "failed to create image tar file")
    82  	defer tar.Close()
    83  
    84  	_, err = io.Copy(tar, reader)
    85  	assert.NilError(t, err, "failed to write image tar file")
    86  
    87  	dUserRemap.Stop(t)
    88  	dUserRemap.Cleanup(t)
    89  	dUserRemapRunning = false
    90  
    91  	dNoUserRemap := daemon.New(t)
    92  	dNoUserRemap.StartWithBusybox(t)
    93  	defer dNoUserRemap.Stop(t)
    94  
    95  	clientNoUserRemap := dNoUserRemap.NewClientT(t)
    96  
    97  	tarFile, err := os.Open(tmp + "/image.tar")
    98  	assert.NilError(t, err, "failed to open image tar file")
    99  
   100  	tarReader := bufio.NewReader(tarFile)
   101  	loadResp, err := clientNoUserRemap.ImageLoad(ctx, tarReader, false)
   102  	assert.NilError(t, err, "failed to load image tar file")
   103  	defer loadResp.Body.Close()
   104  	for {
   105  		n, err := loadResp.Body.Read(buf)
   106  		if err != nil && err != io.EOF {
   107  			t.Fatalf("Error reading ImageLoad response: %v", err)
   108  			break
   109  		}
   110  		if n == 0 {
   111  			break
   112  		}
   113  	}
   114  
   115  	cid := container.Run(ctx, t, clientNoUserRemap,
   116  		container.WithImage(imageTag),
   117  		container.WithCmd("/sbin/getcap", "-n", "/bin/sleep"),
   118  	)
   119  	logReader, err := clientNoUserRemap.ContainerLogs(ctx, cid, types.ContainerLogsOptions{
   120  		ShowStdout: true,
   121  	})
   122  	assert.NilError(t, err)
   123  
   124  	actualStdout := new(bytes.Buffer)
   125  	actualStderr := ioutil.Discard
   126  	_, err = stdcopy.StdCopy(actualStdout, actualStderr, logReader)
   127  	assert.NilError(t, err)
   128  	if strings.TrimSpace(actualStdout.String()) != "/bin/sleep cap_net_bind_service=eip" {
   129  		// Activate when fix is merged: https://github.com/moby/moby/pull/41724
   130  		//t.Fatalf("run produced invalid output: %q, expected %q", actualStdout.String(), "/bin/sleep cap_net_bind_service=eip")
   131  		// t.Logf("run produced invalid output (expected until #41724 merges): %q, expected %q",
   132  		// 	actualStdout.String(),
   133  		// 	"/bin/sleep cap_net_bind_service=eip")
   134  	} else {
   135  		// Shouldn't happen until fix is merged: https://github.com/moby/moby/pull/41724
   136  		t.Fatalf("run produced valid output (unexpected until #41724 merges): %q, expected %q",
   137  			actualStdout.String(),
   138  			"/bin/sleep cap_net_bind_service=eip")
   139  	}
   140  }