From ad6ed082c4cfb10a4aa70a2893988fcdac2b10c3 Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Wed, 1 Mar 2023 14:34:09 +0900 Subject: [PATCH] Fix `operation not permitted` with systemd-homed Fix issue 2056 Note: in addition to this PR, the subid ranges in`/etc/subuid` and `/etc/subgid` have to begin from 524288 e.g., ``` test:524288:65536 ``` Otherwise running most images will fail with `value too large for defined data type` ```console $ ./nerdctl run -it --rm alpine:3.17.0 docker.io/library/alpine:3.17.0: resolved |++++++++++++++++++++++++++++++++++++++| index-sha256:8914eb54f968791faf6a8638949e480fef81e697984fba772b3976835194c6d4: done |++++++++++++++++++++++++++++++++++++++| manifest-sha256:c0d488a800e4127c334ad20d61d7bc21b4097540327217dfab52262adc02380c: waiting |--------------------------------------| config-sha256:49176f190c7e9cdb51ac85ab6c6d5e4512352218190cd69b08e6fd803ffbf3da: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:c158987b05517b6f2c5913f3acef1f2182a32345a304fe357e3ace5fadcad715: downloading |+++++++++++++++++++++++---------------| 2.0 MiB/3.2 MiB elapsed: 10.4s total: 2.0 Mi (197.1 KiB/s) FATA[0010] failed to extract layer sha256:ded7a220bb058e28ee3254fbba04ca90b679070424424761a53a043b93b612bf: mount callback failed on /var/lib/containerd/tmpmounts/containerd-mount762573051: failed to Lchown "/var/lib/containerd/tmpmounts/containerd-mount762573051/etc/shadow" for UID 0, GID 42: lchown /var/lib/containerd/tmpmounts/containerd-mount762573051/etc/shadow: value too large for defined data type: unknown ``` Signed-off-by: Akihiro Suda --- cmd/nerdctl/container_run_mount.go | 20 ++++++++++++++++++++ pkg/mountutil/mountutil.go | 2 +- pkg/mountutil/mountutil_freebsd.go | 2 +- pkg/mountutil/mountutil_linux.go | 4 ++-- pkg/mountutil/mountutil_windows.go | 2 +- 5 files changed, 25 insertions(+), 5 deletions(-) diff --git a/cmd/nerdctl/container_run_mount.go b/cmd/nerdctl/container_run_mount.go index e2c026e06cd..373e30307aa 100644 --- a/cmd/nerdctl/container_run_mount.go +++ b/cmd/nerdctl/container_run_mount.go @@ -29,6 +29,7 @@ import ( "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/mount" "github.com/containerd/containerd/oci" + "github.com/containerd/containerd/pkg/userns" "github.com/containerd/continuity/fs" "github.com/containerd/nerdctl/pkg/api/types" "github.com/containerd/nerdctl/pkg/idgen" @@ -189,6 +190,25 @@ func generateMountOpts(ctx context.Context, cmd *cobra.Command, client *containe return nil, nil, nil, err } } + } else if runtime.GOOS == "linux" { + defer unmounter(tempDir) + for _, m := range mounts { + m := m + if m.Type == "bind" && userns.RunningInUserNS() { + // For https://github.com/containerd/nerdctl/issues/2056 + unpriv, err := mountutil.UnprivilegedMountFlags(m.Source) + if err != nil { + return nil, nil, nil, err + } + m.Options = strutil.DedupeStrSlice(append(m.Options, unpriv...)) + } + if err := m.Mount(tempDir); err != nil { + if rmErr := s.Remove(ctx, tempDir); rmErr != nil && !errdefs.IsNotFound(rmErr) { + return nil, nil, nil, rmErr + } + return nil, nil, nil, fmt.Errorf("failed to mount %+v on %q: %w", m, tempDir, err) + } + } } else { defer unmounter(tempDir) if err := mount.All(mounts, tempDir); err != nil { diff --git a/pkg/mountutil/mountutil.go b/pkg/mountutil/mountutil.go index 4fefe5d533b..8d42fd099b5 100644 --- a/pkg/mountutil/mountutil.go +++ b/pkg/mountutil/mountutil.go @@ -144,7 +144,7 @@ func ProcessFlagV(s string, volStore volumestore.VolumeStore) (*Processed, error Options: options, } if userns.RunningInUserNS() { - unpriv, err := getUnprivilegedMountFlags(src) + unpriv, err := UnprivilegedMountFlags(src) if err != nil { return nil, err } diff --git a/pkg/mountutil/mountutil_freebsd.go b/pkg/mountutil/mountutil_freebsd.go index 6a29dcbe08b..76766d6a3db 100644 --- a/pkg/mountutil/mountutil_freebsd.go +++ b/pkg/mountutil/mountutil_freebsd.go @@ -26,7 +26,7 @@ import ( "github.com/sirupsen/logrus" ) -func getUnprivilegedMountFlags(path string) ([]string, error) { +func UnprivilegedMountFlags(path string) ([]string, error) { m := []string{} return m, nil } diff --git a/pkg/mountutil/mountutil_linux.go b/pkg/mountutil/mountutil_linux.go index 0c9b42adf2c..0b7d0936544 100644 --- a/pkg/mountutil/mountutil_linux.go +++ b/pkg/mountutil/mountutil_linux.go @@ -43,14 +43,14 @@ import ( NOTICE: https://github.com/moby/moby/blob/v20.10.5/NOTICE */ -// getUnprivilegedMountFlags is from https://github.com/moby/moby/blob/v20.10.5/daemon/oci_linux.go#L420-L450 +// UnprivilegedMountFlags is from https://github.com/moby/moby/blob/v20.10.5/daemon/oci_linux.go#L420-L450 // // Get 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. -func getUnprivilegedMountFlags(path string) ([]string, error) { +func UnprivilegedMountFlags(path string) ([]string, error) { var statfs unix.Statfs_t if err := unix.Statfs(path, &statfs); err != nil { return nil, err diff --git a/pkg/mountutil/mountutil_windows.go b/pkg/mountutil/mountutil_windows.go index 12a157fe6dc..3867b8d10fc 100644 --- a/pkg/mountutil/mountutil_windows.go +++ b/pkg/mountutil/mountutil_windows.go @@ -26,7 +26,7 @@ import ( "github.com/sirupsen/logrus" ) -func getUnprivilegedMountFlags(path string) ([]string, error) { +func UnprivilegedMountFlags(path string) ([]string, error) { m := []string{} return m, nil }