Browse code

test: Add a test for userns remapped daemon commit

The files in an image created by a commit should have the right uid and gid set

Signed-off-by: Djordje Lukic <djordje.lukic@docker.com>

Djordje Lukic authored on 2023/11/08 18:17:58
Showing 3 changed files
... ...
@@ -1,12 +1,14 @@
1 1
 package image // import "github.com/docker/docker/integration/image"
2 2
 
3 3
 import (
4
+	"context"
4 5
 	"strings"
5 6
 	"testing"
6 7
 
7 8
 	containertypes "github.com/docker/docker/api/types/container"
8 9
 	"github.com/docker/docker/api/types/versions"
9 10
 	"github.com/docker/docker/integration/internal/container"
11
+	"github.com/docker/docker/testutil/daemon"
10 12
 	"gotest.tools/v3/assert"
11 13
 	is "gotest.tools/v3/assert/cmp"
12 14
 	"gotest.tools/v3/skip"
... ...
@@ -47,3 +49,26 @@ func TestCommitInheritsEnv(t *testing.T) {
47 47
 	expectedEnv2 := []string{"PATH=/usr/bin:/bin"}
48 48
 	assert.Check(t, is.DeepEqual(expectedEnv2, image2.Config.Env))
49 49
 }
50
+
51
+// Verify that files created are owned by the remapped user even after a commit
52
+func TestUsernsCommit(t *testing.T) {
53
+	skip.If(t, testEnv.DaemonInfo.OSType != "linux")
54
+	skip.If(t, testEnv.IsRemoteDaemon())
55
+	skip.If(t, !testEnv.IsUserNamespaceInKernel())
56
+	skip.If(t, testEnv.IsRootless())
57
+
58
+	ctx := context.Background()
59
+	dUserRemap := daemon.New(t, daemon.WithUserNsRemap("default"))
60
+	dUserRemap.StartWithBusybox(ctx, t)
61
+	clientUserRemap := dUserRemap.NewClientT(t)
62
+	defer clientUserRemap.Close()
63
+
64
+	container.Run(ctx, t, clientUserRemap, container.WithName(t.Name()), container.WithImage("busybox"), container.WithCmd("sh", "-c", "echo hello world > /hello.txt && chown 1000:1000 /hello.txt"))
65
+	img, err := clientUserRemap.ContainerCommit(ctx, t.Name(), containertypes.CommitOptions{})
66
+	assert.NilError(t, err)
67
+
68
+	res := container.RunAttach(ctx, t, clientUserRemap, container.WithImage(img.ID), container.WithCmd("sh", "-c", "stat -c %u:%g /hello.txt"))
69
+	assert.Check(t, is.Equal(res.ExitCode, 0))
70
+	assert.Check(t, is.Equal(res.Stderr.String(), ""))
71
+	assert.Assert(t, is.Equal(strings.TrimSpace(res.Stdout.String()), "1000:1000"))
72
+}
... ...
@@ -83,6 +83,7 @@ type Daemon struct {
83 83
 	args                       []string
84 84
 	extraEnv                   []string
85 85
 	containerdSocket           string
86
+	usernsRemap                string
86 87
 	rootlessUser               *user.User
87 88
 	rootlessXDGRuntimeDir      string
88 89
 
... ...
@@ -457,6 +458,10 @@ func (d *Daemon) StartWithLogFile(out *os.File, providedArgs ...string) error {
457 457
 		d.args = append(d.args, "--containerd", d.containerdSocket)
458 458
 	}
459 459
 
460
+	if d.usernsRemap != "" {
461
+		d.args = append(d.args, "--userns-remap", d.usernsRemap)
462
+	}
463
+
460 464
 	if d.defaultCgroupNamespaceMode != "" {
461 465
 		d.args = append(d.args, "--default-cgroupns-mode", d.defaultCgroupNamespaceMode)
462 466
 	}
... ...
@@ -19,6 +19,12 @@ func WithContainerdSocket(socket string) Option {
19 19
 	}
20 20
 }
21 21
 
22
+func WithUserNsRemap(remap string) Option {
23
+	return func(d *Daemon) {
24
+		d.usernsRemap = remap
25
+	}
26
+}
27
+
22 28
 // WithDefaultCgroupNamespaceMode sets the default cgroup namespace mode for the daemon
23 29
 func WithDefaultCgroupNamespaceMode(mode string) Option {
24 30
 	return func(d *Daemon) {