From 762ec4b60ce1b337e64bc103d0166ed9b6bf1e99 Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Thu, 14 Mar 2024 13:49:35 +0900 Subject: [PATCH] plugin: fix mounting /etc/hosts when running in UserNS Fix `error mounting "/etc/hosts" to rootfs at "/etc/hosts": mount /etc/hosts:/etc/hosts (via /proc/self/fd/6), flags: 0x5021: operation not permitted`. This error was introduced in 7d08d84b039d2f4661a2242e765a141e65943920 (`dockerd-rootless.sh: set rootlesskit --state-dir=DIR`) that changed the filesystem of the state dir from /tmp to /run (in a typical setup). Fix issue 47248 Signed-off-by: Akihiro Suda --- plugin/v2/plugin_linux.go | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/plugin/v2/plugin_linux.go b/plugin/v2/plugin_linux.go index 82f973ffc9..746afde8d5 100644 --- a/plugin/v2/plugin_linux.go +++ b/plugin/v2/plugin_linux.go @@ -1,3 +1,6 @@ +// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16: +//go:build go1.19 + package v2 // import "github.com/docker/docker/plugin/v2" import ( @@ -6,7 +9,10 @@ import ( "runtime" "strings" + "github.com/containerd/containerd/pkg/userns" "github.com/docker/docker/api/types" + "github.com/docker/docker/internal/rootless/mountopts" + "github.com/docker/docker/internal/sliceutil" "github.com/docker/docker/oci" specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" @@ -136,5 +142,35 @@ func (p *Plugin) InitSpec(execRoot string) (*specs.Spec, error) { p.modifyRuntimeSpec(&s) } + // Rootless mode requires modifying the mount flags + // https://github.com/moby/moby/issues/47248#issuecomment-1927776700 + // https://github.com/moby/moby/pull/47558 + if userns.RunningInUserNS() { + for i := range s.Mounts { + m := &s.Mounts[i] + for _, o := range m.Options { + switch o { + case "bind", "rbind": + if _, err := os.Lstat(m.Source); err != nil { + if errors.Is(err, os.ErrNotExist) { + continue + } + return nil, err + } + // UnprivilegedMountFlags gets the set of mount flags that are set on the mount that contains the given + // path and are locked by CL_UNPRIVILEGED. This is necessary to ensure that + // bind-mounting "with options" will not fail with user namespaces, due to + // kernel restrictions that require user namespace mounts to preserve + // CL_UNPRIVILEGED locked flags. + unpriv, err := mountopts.UnprivilegedMountFlags(m.Source) + if err != nil { + return nil, errors.Wrapf(err, "failed to get unprivileged mount flags for %+v", m) + } + m.Options = sliceutil.Dedup(append(m.Options, unpriv...)) + } + } + } + } + return &s, nil }