diff --git a/hack/dind b/hack/dind index 087270a7a8..04bf6aaf92 100755 --- a/hack/dind +++ b/hack/dind @@ -37,6 +37,10 @@ if [ -f /sys/fs/cgroup/cgroup.controllers ]; then > /sys/fs/cgroup/cgroup.subtree_control fi +# Change mount propagation to shared to make the environment more similar to a +# modern Linux system, e.g. with SystemD as PID 1. +mount --make-rshared / + if [ $# -gt 0 ]; then exec "$@" fi diff --git a/hack/dind-systemd b/hack/dind-systemd index 27e07badd3..5ab0d25fc1 100755 --- a/hack/dind-systemd +++ b/hack/dind-systemd @@ -13,6 +13,11 @@ if [ ! -t 0 ]; then exit 1 fi +# Change mount propagation to shared, which SystemD PID 1 would normally do +# itself when started by the kernel. SystemD skips that when it detects it is +# running in a container. +mount --make-rshared / + env > /etc/docker-entrypoint-env cat > /etc/systemd/system/docker-entrypoint.target << EOF diff --git a/integration/container/mounts_linux_test.go b/integration/container/mounts_linux_test.go index 3c7aabda24..f45e4f785b 100644 --- a/integration/container/mounts_linux_test.go +++ b/integration/container/mounts_linux_test.go @@ -391,3 +391,38 @@ func TestContainerVolumesMountedAsSlave(t *testing.T) { t.Fatal(err) } } + +// Regression test for #38995 and #43390. +func TestContainerCopyLeaksMounts(t *testing.T) { + defer setupTest(t)() + + bindMount := mounttypes.Mount{ + Type: mounttypes.TypeBind, + Source: "/var", + Target: "/hostvar", + BindOptions: &mounttypes.BindOptions{ + Propagation: mounttypes.PropagationRSlave, + }, + } + + ctx := context.Background() + client := testEnv.APIClient() + cid := container.Run(ctx, t, client, container.WithMount(bindMount), container.WithCmd("sleep", "120s")) + + getMounts := func() string { + t.Helper() + res, err := container.Exec(ctx, client, cid, []string{"cat", "/proc/self/mountinfo"}) + assert.NilError(t, err) + assert.Equal(t, res.ExitCode, 0) + return res.Stdout() + } + + mountsBefore := getMounts() + + _, _, err := client.CopyFromContainer(ctx, cid, "/etc/passwd") + assert.NilError(t, err) + + mountsAfter := getMounts() + + assert.Equal(t, mountsBefore, mountsAfter) +}