From 22c277ca9815315a525407135a7410fda96de1d3 Mon Sep 17 00:00:00 2001 From: weiyucheng123 Date: Thu, 11 Dec 2025 19:17:42 +0800 Subject: [PATCH] cri Fix userns with Dockerfile VOLUME mounts --- ...userns-with-Dockerfile-VOLUME-mounts.patch | 104 ++++++++++++++++++ k3s-containerd.spec | 9 +- 2 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 0013-cri-Fix-userns-with-Dockerfile-VOLUME-mounts.patch diff --git a/0013-cri-Fix-userns-with-Dockerfile-VOLUME-mounts.patch b/0013-cri-Fix-userns-with-Dockerfile-VOLUME-mounts.patch new file mode 100644 index 0000000..443cab4 --- /dev/null +++ b/0013-cri-Fix-userns-with-Dockerfile-VOLUME-mounts.patch @@ -0,0 +1,104 @@ +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 13eedaf..1cb9999 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 ++} ++ + func getTempDir() string { + if xdg := os.Getenv("XDG_RUNTIME_DIR"); xdg != "" { + return xdg +diff --git a/pkg/cri/opts/container.go b/pkg/cri/opts/container.go +index 984ce8b..6efd69e 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.25.1 + diff --git a/k3s-containerd.spec b/k3s-containerd.spec index 219baaf..79c8b2e 100644 --- a/k3s-containerd.spec +++ b/k3s-containerd.spec @@ -3,7 +3,7 @@ %global version_suffix k3s1 Version: 1.6.6 Name: k3s-containerd -Release: 15 +Release: 16 Summary: An industry-standard container runtime License: Apache-2.0 URL: https://github.com/k3s-io/containerd @@ -21,6 +21,7 @@ Patch0009: 0009-fix-CVE-2024-25621.patch Patch0010: 0010-fix-CVE-2025-64329.patch Patch0011: 0011-client-fix-returned-error-in-the-defer-function.patch Patch0012: 0012-Fix-ctr-snapshot-mount-produce-invalid-mount-command.patch +Patch0013: 0013-cri-Fix-userns-with-Dockerfile-VOLUME-mounts.patch BuildRequires: golang glibc-static make btrfs-progs-devel @@ -81,6 +82,12 @@ cp -rf %{_builddir}/containerd-%{version}-%{version_suffix}/. %{buildroot}%{_lib %changelog +* Thu Dec 11 2025 weiyucheng - 1.6.6-16 +- Type:bugfix +- CVE:NA +- SUG:NA +- DESC: cri Fix userns with Dockerfile VOLUME mounts + * Thu Dec 11 2025 weiyucheng - 1.6.6-15 - Type:bugfix - CVE:NA -- Gitee