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 7d08d84b03
(`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 <akihiro.suda.cz@hco.ntt.co.jp>
This commit is contained in:
Akihiro Suda 2024-03-14 13:49:35 +09:00
parent 979f03f9f6
commit 762ec4b60c
No known key found for this signature in database
GPG key ID: 49524C6F9F638F1A

View file

@ -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
}