| package container |
| |
| import ( |
| "bytes" |
| "os" |
| "path/filepath" |
| "testing" |
| |
| mounttypes "github.com/moby/moby/api/types/mount" |
| "github.com/moby/moby/client" |
| "github.com/moby/moby/v2/integration/internal/build" |
| "github.com/moby/moby/v2/integration/internal/container" |
| "github.com/moby/moby/v2/internal/testutil" |
| "github.com/moby/moby/v2/internal/testutil/fakecontext" |
| "gotest.tools/v3/assert" |
| "gotest.tools/v3/skip" |
| ) |
| |
| // TestCopyWithAbsoluteSymlinkedMountTarget was introduced as a regression test |
| // for https://github.com/moby/moby/issues/52653. |
| // |
| // The security fix in GHSA-vp62-88p7-qqf5 switched openContainerFS to use |
| // os.Root for the mount-destination operations. |
| // os.Root refuses to follow absolute symlinks, but distro images commonly ship |
| // /var/run as an absolute symlink to /run. |
| // As a result, any container with a bind mount whose target traversed such a |
| // symlink (e.g. -v /host/sock:/var/run/docker.sock) made `docker cp` fail. |
| func TestCopyWithAbsoluteSymlinkedMountTarget(t *testing.T) { |
| skip.If(t, testEnv.DaemonInfo.OSType != "linux") |
| ctx := setupTest(t) |
| apiClient := testEnv.APIClient() |
| |
| // Build an image with an absolute in-container symlink along the mount |
| // target path. |
| // Stock distro images expose this shape via /var/run -> /run, but we set |
| // up our own /sockets -> /root pair so the test does not depend on any |
| // particular base image's layout. |
| buildCtx := fakecontext.New(t, "", |
| fakecontext.WithDockerfile(`FROM busybox |
| RUN touch /root/nil && ln -s /root /sockets |
| `), |
| ) |
| defer buildCtx.Close() |
| imgID := build.Do(ctx, t, apiClient, buildCtx, client.ImageBuildOptions{}) |
| |
| // Use testutil.TempDir so the rootless daemon can access the bind-mount |
| // source: t.TempDir() creates a 0700 parent that the fake-root user |
| // cannot stat. |
| srcDir := testutil.TempDir(t) |
| assert.NilError(t, os.WriteFile(filepath.Join(srcDir, "sock"), nil, 0o644)) |
| |
| cid := container.Create(ctx, t, apiClient, |
| container.WithImage(imgID), |
| container.WithMount(mounttypes.Mount{ |
| Type: mounttypes.TypeBind, |
| Source: filepath.Join(srcDir, "sock"), |
| Target: "/sockets/docker.sock", |
| }), |
| ) |
| |
| _, err := apiClient.CopyToContainer(ctx, cid, client.CopyToContainerOptions{ |
| DestinationPath: "/sockets/", |
| Content: bytes.NewReader(nil), |
| }) |
| assert.NilError(t, err) |
| } |