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 }