From 83a30084b2482fc55746b567a56064c6b21c6cd2 Mon Sep 17 00:00:00 2001 From: dongyuzhen Date: Tue, 23 Sep 2025 10:10:02 +0800 Subject: [PATCH] fix userns with Dockerfile VOLUME mounts that need copy --- containerd.spec | 8 +- git-commit | 2 +- ...userns-with-Dockerfile-VOLUME-mounts.patch | 103 ++++++++++++++++++ series.conf | 1 + 4 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 patch/0047-containerd-cri-Fix-userns-with-Dockerfile-VOLUME-mounts.patch diff --git a/containerd.spec b/containerd.spec index 1eb94b1..87a460c 100644 --- a/containerd.spec +++ b/containerd.spec @@ -2,7 +2,7 @@ %global debug_package %{nil} Version: 1.6.22 Name: containerd -Release: 23 +Release: 24 Summary: An industry-standard container runtime License: ASL 2.0 URL: https://containerd.io @@ -68,6 +68,12 @@ install -D -p -m 0644 %{S:7} %{buildroot}%{_sysconfdir}/containerd/config.toml %exclude %{_bindir}/containerd-stress %changelog +* Tue Sep 23 2025 dongyuzhen - 1.6.22-24 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:fix userns with Dockerfile VOLUME mounts that need copy + * Mon Aug 25 2025 Yu Peng - 1.6.22-23 - Type:bugfix - ID:NA diff --git a/git-commit b/git-commit index 4cdbc79..5a79cf6 100644 --- a/git-commit +++ b/git-commit @@ -1 +1 @@ -505c543740cc9cd666836e5c541d60d5296fa6ee +09eaedc738251fa31ef7e06d71b8de78176c6ec7 diff --git a/patch/0047-containerd-cri-Fix-userns-with-Dockerfile-VOLUME-mounts.patch b/patch/0047-containerd-cri-Fix-userns-with-Dockerfile-VOLUME-mounts.patch new file mode 100644 index 0000000..77a967d --- /dev/null +++ b/patch/0047-containerd-cri-Fix-userns-with-Dockerfile-VOLUME-mounts.patch @@ -0,0 +1,103 @@ +From aaa965608d565cd2212be215198483f3a7c79bd8 Mon Sep 17 00:00:00 2001 +From: Rodrigo Campos +Date: Tue, 19 Aug 2025 12:36:07 +0200 +Subject: [PATCH] cri: Fix userns with Dockerfile VOLUME mounts that need copy + +If a Dockerfile is using a `VOLUME` directive and the directory exists +in the rootfs, like in this example: + + FROM docker.io/library/alpine:latest + VOLUME [ "/run" ] + +The alpine container image already contains a "/run" directory. This +will force the code in WithVolumes() to copy its content to the new +volume created for the VOLUME directive. This copies the content as well +as the ownership. + +However, as we perform the mounts from the host POV without being inside +a userns, the idmap option will just shift the IDs in ways that will +screw up the ownerships when copied. We should only use the idmap option +when running the container inside a userns, so the ownerships are fine +(the userns will do a shift and the idmap another, to make it all seem +as if there was no UID/GID shift in the first place). + +This PR does just that, remove the idmap option from mounts so we copy +the files without any ID transformations. It's simpler and easier to +reason about if we just don't mount with the idmap option here: all +files are copied just fine without ID transformations and ID +transformation is applied via the idmap option at mount time when +running the pod. + +Also, note that `VOLUME` directives that refer to directories that don't +exist on the rootfs work fine (`VOLUME [ "/rata" ]` for example), as +there is no copy done in that case so the permissions weren't changed. + +Signed-off-by: Rodrigo Campos +--- + mount/temp.go | 27 +++++++++++++++++++++++++++ + pkg/cri/opts/container.go | 5 +++++ + 2 files changed, 32 insertions(+) + +diff --git a/mount/temp.go b/mount/temp.go +index 889d49c1a..407a746cd 100644 +--- a/mount/temp.go ++++ b/mount/temp.go +@@ -20,6 +20,7 @@ import ( + "context" + "fmt" + "os" ++ "strings" + + "github.com/containerd/containerd/log" + ) +@@ -67,6 +68,32 @@ func WithTempMount(ctx context.Context, mounts []Mount, f func(root string) erro + return nil + } + ++// RemoveIDMapOption copies and removes the uidmap/gidmap options on any of the mounts using it. ++func RemoveIDMapOption(mounts []Mount) []Mount { ++ var out []Mount ++ for i, m := range mounts { ++ for j, opt := range m.Options { ++ if strings.HasPrefix(opt, "uidmap") || strings.HasPrefix(opt, "gidmap") { ++ if out == nil { ++ out = copyMounts(mounts) ++ } ++ out[i].Options = append(out[i].Options[:j], out[i].Options[j+1:]...) ++ } ++ } ++ } ++ if out != nil { ++ return out ++ } ++ return mounts ++} ++ ++// copyMounts creates a copy of the original slice to allow for modification and not altering the original ++func copyMounts(in []Mount) []Mount { ++ out := make([]Mount, len(in)) ++ copy(out, in) ++ return out ++} ++ + // WithReadonlyTempMount mounts the provided mounts to a temp dir as readonly, + // and pass the temp dir to f. The mounts are valid during the call to the f. + // Finally we will unmount and remove the temp dir regardless of the result of f. +diff --git a/pkg/cri/opts/container.go b/pkg/cri/opts/container.go +index 5ea1b8739..5ad353f6d 100644 +--- a/pkg/cri/opts/container.go ++++ b/pkg/cri/opts/container.go +@@ -75,6 +75,11 @@ func WithVolumes(volumeMounts map[string]string) containerd.NewContainerOpts { + mounts[0].Options = append(mounts[0].Options, "ro") + } + ++ // Always copy files without UID/GID transformations. ++ // The ID transformations are only needed when running inside a userns, that is not ++ // the case here. ++ mounts = mount.RemoveIDMapOption(mounts) ++ + root, err := os.MkdirTemp("", "ctd-volume") + if err != nil { + return err +-- +2.33.0 diff --git a/series.conf b/series.conf index 2cd35fd..9892463 100644 --- a/series.conf +++ b/series.conf @@ -43,3 +43,4 @@ patch/0043-containerd-delete-task-asynchronously-to-avoid-conta.patch patch/0044-containerd-fix-dead-loop.patch patch/0045-containerd-remove-limitnofile-from-containerd-service.patch patch/0046-containerd-Fix-ctr-snapshot-mount-produce-invalid-mount-command.patch +patch/0047-containerd-cri-Fix-userns-with-Dockerfile-VOLUME-mounts.patch -- Gitee