c8d: Handle userns properly
**- What I did**

Remapped the GID/UID when a snapshot is created if the daemon is started with `--userns-remap`. This implementation differs from the graph driver one slightly. With graph drivers the files/directories are chown'ed when the image is downloaded and the contents extracted. Basically, with graph drivers we remap on pull and with containerd we remap on run.

Note: with this change builds still fail, my guess is because buildkit still mounts the roots in normal mode, I'll continue looking but I think we can merge this one, I am pretty sure some changes in buildkit are needed:

```console
$ docker build -t userns . 
[+] Building 1.7s (6/6) FINISHED                                                                                                                               docker:local
 => [internal] load build definition from dd                                                                                                                           0.0s
 => => transferring dockerfile: 71B                                                                                                                                    0.0s
 => [internal] load .dockerignore                                                                                                                                      0.0s
 => => transferring context: 2B                                                                                                                                        0.0s
 => [internal] load metadata for docker.io/library/debian:bullseye-slim                                                                                                1.3s
 => [auth] library/debian:pull token for registry-1.docker.io                                                                                                          0.0s
 => CACHED [1/2] FROM docker.io/library/debian:bullseye-slim@sha256:61386e11b5256efa33823cbfafd668dd651dbce810b24a8fb7b2e32fa7f65a85                                   0.0s
 => => resolve docker.io/library/debian:bullseye-slim@sha256:61386e11b5256efa33823cbfafd668dd651dbce810b24a8fb7b2e32fa7f65a85                                          0.0s
 => ERROR [2/2] RUN touch testa                                                                                                                                        0.3s
------
 > [2/2] RUN touch testa:
0.287 runc run failed: unable to start container process: error during container init: error mounting "/tmp/root/165536.165536/buildkit/executor/hosts.iv21cdui6qvdwqel9cdo93spo" to rootfs at "/etc/hosts": open /tmp/root/165536.165536/buildkit/executor/7yecjv2i25qdu44khgx41b450/rootfs/etc/hosts: permission denied
------
dd:2
--------------------
   1 |     FROM debian:bullseye-slim
   2 | >>> RUN touch testa
   3 |     
--------------------
ERROR: failed to solve: process "/bin/sh -c touch testa" did not complete successfully: exit code: 1
```

**- How I did it**

**- How to verify it**

`TestDaemonUserNamespaceRootSetting` should not fail any more
 
```console
$ make DOCKER_GRAPHDRIVER=overlayfs TEST_FILTER=TestDaemonUserNamespaceRootSetting TEST_INTEGRATION_USE_SNAPSHOTTER=1 test-integration
```

**- Description for the changelog**
<!--
Write a short (one line) summary that describes the changes in this
pull request for inclusion in the changelog:
-->


**- A picture of a cute animal (not mandatory but encouraged)**

daemon/containerd/image_snapshot.go
package containerd

import (
	"context"
	"fmt"

	"github.com/containerd/containerd"
	cerrdefs "github.com/containerd/containerd/errdefs"
	containerdimages "github.com/containerd/containerd/images"
	"github.com/containerd/containerd/leases"
	"github.com/containerd/containerd/platforms"
	"github.com/containerd/containerd/snapshots"
	"github.com/docker/docker/errdefs"
	"github.com/opencontainers/image-spec/identity"
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/pkg/errors"
)

// PrepareSnapshot prepares a snapshot from a parent image for a container
func (i *ImageService) PrepareSnapshot(ctx context.Context, id string, parentImage string, platform *ocispec.Platform) error {
	var parentSnapshot string
	if parentImage != "" {
		img, err := i.resolveImage(ctx, parentImage)
		if err != nil {
			return err
		}

		cs := i.client.ContentStore()

		matcher := platforms.Default()
		if platform != nil {
			matcher = platforms.Only(*platform)
		}

		platformImg := containerd.NewImageWithPlatform(i.client, img, matcher)
		unpacked, err := platformImg.IsUnpacked(ctx, i.snapshotter)
		if err != nil {
			return err
		}

		if !unpacked {
			if err := platformImg.Unpack(ctx, i.snapshotter); err != nil {
				return err
			}
		}

		desc, err := containerdimages.Config(ctx, cs, img.Target, matcher)
		if err != nil {
			return err
		}

		diffIDs, err := containerdimages.RootFS(ctx, cs, desc)
		if err != nil {
			return err
		}

		parentSnapshot = identity.ChainID(diffIDs).String()
	}

	// Add a lease so that containerd doesn't garbage collect our snapshot
	ls := i.client.LeasesService()
	lease, err := ls.Create(ctx, leases.WithID(id))
	if err != nil {
		return err
	}

	if err := ls.AddResource(ctx, lease, leases.Resource{
		ID:   id,
		Type: "snapshots/" + i.StorageDriver(),
	}); err != nil {
		return err
	}

	s := i.client.SnapshotService(i.StorageDriver())
	_, err = s.Prepare(ctx, id, parentSnapshot)
	return err
}

// calculateSnapshotParentUsage returns the usage of all ancestors of the
// provided snapshot. It doesn't include the size of the snapshot itself.
func calculateSnapshotParentUsage(ctx context.Context, snapshotter snapshots.Snapshotter, snapshotID string) (snapshots.Usage, error) {
	info, err := snapshotter.Stat(ctx, snapshotID)
	if err != nil {
		if cerrdefs.IsNotFound(err) {
			return snapshots.Usage{}, errdefs.NotFound(err)
		}
		return snapshots.Usage{}, errdefs.System(errors.Wrapf(err, "snapshotter.Stat failed for %s", snapshotID))
	}
	if info.Parent == "" {
		return snapshots.Usage{}, errdefs.NotFound(fmt.Errorf("snapshot %s has no parent", snapshotID))
	}

	return calculateSnapshotTotalUsage(ctx, snapshotter, info.Parent)
}

// calculateSnapshotTotalUsage returns the total usage of that snapshot
// including all of its ancestors.
func calculateSnapshotTotalUsage(ctx context.Context, snapshotter snapshots.Snapshotter, snapshotID string) (snapshots.Usage, error) {
	var total snapshots.Usage
	next := snapshotID

	for next != "" {
		usage, err := snapshotter.Usage(ctx, next)
		if err != nil {
			if cerrdefs.IsNotFound(err) {
				return total, errdefs.NotFound(errors.Wrapf(err, "non-existing ancestor of %s", snapshotID))
			}
			return total, errdefs.System(errors.Wrapf(err, "snapshotter.Usage failed for %s", next))
		}
		total.Size += usage.Size
		total.Inodes += usage.Inodes

		info, err := snapshotter.Stat(ctx, next)
		if err != nil {
			return total, errdefs.System(errors.Wrapf(err, "snapshotter.Stat failed for %s", next))
		}
		next = info.Parent
	}
	return total, nil
}

package containerd

import (
	"context"
	"fmt"

	"github.com/containerd/containerd"
	cerrdefs "github.com/containerd/containerd/errdefs"
	containerdimages "github.com/containerd/containerd/images"
	"github.com/containerd/containerd/leases"
	"github.com/containerd/containerd/platforms"
	"github.com/containerd/containerd/snapshots"
	"github.com/docker/docker/errdefs"
	"github.com/opencontainers/image-spec/identity"
	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
	"github.com/pkg/errors"
)

const remapSuffix = "-remap"

// PrepareSnapshot prepares a snapshot from a parent image for a container
func (i *ImageService) PrepareSnapshot(ctx context.Context, id string, parentImage string, platform *ocispec.Platform) error {
	var parentSnapshot string
	if parentImage != "" {
		img, err := i.resolveImage(ctx, parentImage)
		if err != nil {
			return err
		}

		cs := i.client.ContentStore()

		matcher := platforms.Default()
		if platform != nil {
			matcher = platforms.Only(*platform)
		}

		platformImg := containerd.NewImageWithPlatform(i.client, img, matcher)
		unpacked, err := platformImg.IsUnpacked(ctx, i.snapshotter)
		if err != nil {
			return err
		}

		if !unpacked {
			if err := platformImg.Unpack(ctx, i.snapshotter); err != nil {
				return err
			}
		}

		desc, err := containerdimages.Config(ctx, cs, img.Target, matcher)
		if err != nil {
			return err
		}

		diffIDs, err := containerdimages.RootFS(ctx, cs, desc)
		if err != nil {
			return err
		}

		parentSnapshot = identity.ChainID(diffIDs).String()
	}

	// Add a lease so that containerd doesn't garbage collect our snapshot
	ls := i.client.LeasesService()
	lease, err := ls.Create(ctx, leases.WithID(id))
	if err != nil {
		return err
	}
	if err := ls.AddResource(ctx, lease, leases.Resource{
		ID:   id,
		Type: "snapshots/" + i.StorageDriver(),
	}); err != nil {
		return err
	}

	snapshotter := i.client.SnapshotService(i.StorageDriver())

	if !i.idMapping.Empty() {
		return i.remapSnapshot(ctx, snapshotter, id, parentSnapshot, lease)
	}

	_, err = snapshotter.Prepare(ctx, id, parentSnapshot)
	return err
}

// calculateSnapshotParentUsage returns the usage of all ancestors of the
// provided snapshot. It doesn't include the size of the snapshot itself.
func calculateSnapshotParentUsage(ctx context.Context, snapshotter snapshots.Snapshotter, snapshotID string) (snapshots.Usage, error) {
	info, err := snapshotter.Stat(ctx, snapshotID)
	if err != nil {
		if cerrdefs.IsNotFound(err) {
			return snapshots.Usage{}, errdefs.NotFound(err)
		}
		return snapshots.Usage{}, errdefs.System(errors.Wrapf(err, "snapshotter.Stat failed for %s", snapshotID))
	}
	if info.Parent == "" {
		return snapshots.Usage{}, errdefs.NotFound(fmt.Errorf("snapshot %s has no parent", snapshotID))
	}

	return calculateSnapshotTotalUsage(ctx, snapshotter, info.Parent)
}

// calculateSnapshotTotalUsage returns the total usage of that snapshot
// including all of its ancestors.
func calculateSnapshotTotalUsage(ctx context.Context, snapshotter snapshots.Snapshotter, snapshotID string) (snapshots.Usage, error) {
	var total snapshots.Usage
	next := snapshotID

	for next != "" {
		usage, err := snapshotter.Usage(ctx, next)
		if err != nil {
			if cerrdefs.IsNotFound(err) {
				return total, errdefs.NotFound(errors.Wrapf(err, "non-existing ancestor of %s", snapshotID))
			}
			return total, errdefs.System(errors.Wrapf(err, "snapshotter.Usage failed for %s", next))
		}
		total.Size += usage.Size
		total.Inodes += usage.Inodes

		info, err := snapshotter.Stat(ctx, next)
		if err != nil {
			return total, errdefs.System(errors.Wrapf(err, "snapshotter.Stat failed for %s", next))
		}
		next = info.Parent
	}
	return total, nil
}

Ohman, changes look good, but I'm just looking at this part again, and this _could be_ a potential foot-gun if either a linter, or some "helpful" contribution fixes "unhandled error" here;

```suggestion

	if i.idMapping.Empty() {
		if _, err := snapshotter.Prepare(ctx, id, parentSnapshot); err != nil {
			return err
		}
	}

	return i.remapSnapshot(ctx, snapshotter, id, parentSnapshot, lease)
```


The above would break this code (which would _hopefully_ be caught in CI.

Do you think it's worth to be defensive here, and to reverse the order?

```suggestion

	if !i.idMapping.Empty() {
		return i.remapSnapshot(ctx, snapshotter, id, parentSnapshot, lease)
	}

	_, err = snapshotter.Prepare(ctx, id, parentSnapshot)
	return err
```

