Repository: moby/buildkit

Issue:
non-octal notation in `--chmod` option of `COPY` or `ADD` does not work as expected with capital X
### Contributing guidelines and issue reporting guide

- [x] I've read the [contributing guidelines](https://github.com/moby/buildkit/blob/master/.github/CONTRIBUTING.md) and wholeheartedly agree. I've also read the [issue reporting guide](https://github.com/moby/buildkit/blob/master/.github/issue_reporting_guide.md).

### Well-formed report checklist

- [x] I have found a bug that the documentation does not mention anything about my problem
- [x] I have found a bug that there are no open or closed issues that are related to my problem
- [x] I have provided version/information about my environment and done my best to provide a reproducer

### Description of bug

## Bug description

When using non-octal notation in `--chmod` option of `COPY` or `ADD` in a Dockerfile which starts with `# syntax=docker/dockerfile:labs`, the syntax doesn't work as expected.

Specifically, capital `X` is not interpreted correctly, from my experiments it looks like it's being ignored, e.g. `--chmod=u=rwX,go=rX` works exactly like `--chmod=u=rw,go=r`.

Moreover, the docker documentation at https://docs.docker.com/reference/dockerfile/#copy---chown---chmod states that

> Only octal notation is currently supported. Non-octal support is tracked in [moby/buildkit#1951](https://github.com/moby/buildkit/issues/1951).

Because of that there's unfortunately no way to know for sure whether the current implementation works like that on purpose, or not.

However, I don't think it's on purpose because:

* the capital X was directly mentioned in the original issue moby/buildkit#1951 as one of the motivations for adding support for non-octal notation
* the regular `chmod` command supports this and it's well documented how the non-octal notation should work in full, e.g. https://www.man7.org/linux/man-pages/man1/chmod.1.html and https://en.wikipedia.org/wiki/Chmod#Symbolic_modes

There has been 2 issues that are most related this bug:
* moby/buildkit#1951
* moby/buildkit#5611

However, they have been closed as "completed", with what seems like no resolution to this specific issue despite it being mentioned on both cases. It makes me wonder what should I expect of this feature, i.e. should I expect the non-octal flags to work like in `chmod` command? Or,  should I expect some subset of the features. If it's a subset, I wonder what is this expected subset.

## Reproduction

One can reproduce this issue by building the following Dockerfile,
e.g. with

```bash
docker build --no-cache --progress=plain -t testimage -f Dockerfile_copy_chmod_issue .
```

```Dockerfile
# syntax=docker/dockerfile:labs

FROM ubuntu:latest AS base
RUN touch /etc/apt/sources.list.d/custom.list
RUN ls -lah /etc/apt/sources.list.d

FROM ubuntu:latest AS final
RUN ls -lah /etc/apt/sources.list.d
COPY --from=base --chmod=u=rwX,go=rX /etc/apt/ /etc/apt/
RUN ls -lah /etc/apt/sources.list.d
RUN chmod -R u=rwX,go=rX /etc/apt
RUN ls -lah /etc/apt/sources.list.d
```

In the output, in the step after `COPY --from=base --chmod=u=rwX,go=rX /etc/apt/ /etc/apt/` step, one can see that the `x` bits are gone from the `/etc/apt/sources.list.d` directory, whereas they are there on the source directory. In this case the `x` bits remain on parent `/etc/apt` directory itself because it was not copied, only its contents were.

```text
#11 [final 4/6] RUN ls -lah /etc/apt/sources.list.d
#11 0.352 total 16K
#11 0.352 drw-r--r-- 1 root root 4.0K Mar 12 09:34 .
#11 0.352 drwxr-xr-x 1 root root 4.0K Jan 27 02:03 ..
#11 0.352 -rw-r--r-- 1 root root    0 Mar 12 09:34 custom.list
#11 0.352 -rw-r--r-- 1 root root 2.5K Jan 27 02:09 ubuntu.sources
#11 DONE 0.4s
```

Two steps later, after `RUN chmod -R u=rwX,go=rX /etc/apt` one can see in the output that the result of running `chmod` command with the same flags correctly sets the `x` bits on the directory, but not on files.

```text
#13 [final 6/6] RUN ls -lah /etc/apt/sources.list.d
#13 0.281 total 20K
#13 0.281 drwxr-xr-x 1 root root 4.0K Mar 12 09:34 .
#13 0.281 drwxr-xr-x 1 root root 4.0K Jan 27 02:03 ..
#13 0.281 -rw-r--r-- 1 root root    0 Mar 12 09:34 custom.list
#13 0.281 -rw-r--r-- 1 root root 2.5K Jan 27 02:09 ubuntu.sources
#13 DONE 0.3s
```

I'll subscribe to this issue and try to answer any questions as soon as possible. Thank you!

## Version information

```text
$ buildctl --version
buildctl: command not found

$ buildkitd version
buildkitd: command not found

$ docker buildx version
github.com/docker/buildx v0.21.1 7c2359c

$ docker buildx inspect
Name:          default
Driver:        docker
Last Activity: 2025-03-12 09:07:11 +0000 UTC

Nodes:
Name:             default
Endpoint:         default
Status:           running
BuildKit version: v0.20.0
Platforms:        linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/386
Labels:
 org.mobyproject.buildkit.worker.moby.host-gateway-ip: 172.17.0.1

$ docker version
Client: Docker Engine - Community
 Version:           28.0.1
 API version:       1.48
 Go version:        go1.23.6
 Git commit:        068a01e
 Built:             Wed Feb 26 10:41:08 2025
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          28.0.1
  API version:      1.48 (minimum version 1.24)
  Go version:       go1.23.6
  Git commit:       bbd0a17
  Built:            Wed Feb 26 10:41:08 2025
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.7.25
  GitCommit:        bcc810d6b9066471b0b6fa75f557a15a1cbf31bb
 nvidia:
  Version:          1.2.4
  GitCommit:        v1.2.4-0-g6c52b3f
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

$ docker info
Client: Docker Engine - Community
 Version:    28.0.1
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.21.1
    Path:     /usr/libexec/docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  v2.33.1
    Path:     /usr/libexec/docker/cli-plugins/docker-compose

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 2
 Server Version: 28.0.1
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Using metacopy: false
  Native Overlay Diff: true
  userxattr: false
 Logging Driver: json-file
 Cgroup Driver: systemd
 Cgroup Version: 2
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
 Swarm: inactive
 Runtimes: io.containerd.runc.v2 nvidia runc
 Default Runtime: nvidia
 Init Binary: docker-init
 containerd version: bcc810d6b9066471b0b6fa75f557a15a1cbf31bb
 runc version: v1.2.4-0-g6c52b3f
 init version: de40ad0
 Security Options:
  apparmor
  seccomp
   Profile: builtin
  cgroupns
 Kernel Version: 5.15.0-131-generic
 Operating System: Ubuntu 22.04.5 LTS
 OSType: linux
 Architecture: x86_64
 CPUs: 12
 Total Memory: 15.49GiB
 Name: name
 ID: de3ab65f-7db3-4c2a-b735-469747b4d5bf
 Docker Root Dir: /var/lib/docker
 Debug Mode: false
 Experimental: false
 Insecure Registries:
  ::1/128
  127.0.0.0/8
 Live Restore Enabled: false

```


Discussion:
@tonistiigi: Looks like the difference comes from changed meaning of `X`. In BSD and earlier POSIX `X` states that it should be ignored for other operators than `+`.

From `man chmod` on BSD/Darwin:

```
  X	     The execute/search	bits if	the file is a directory	or any
		     of	the execute/search bits	are set	in the	original  (un-
		     modified)	mode.	Operations  with the perm symbol ``X''
		     are only meaningful in conjunction	 with  the  op	symbol
		     ``+'', and	are ignored in all other cases.
```

From POSIX 2024

```
The X perm symbol was adopted from BSD-based systems because it provides commonly desired functionality when doing recursive (-R option) modifications. Similar functionality is not provided by the [find](https://pubs.opengroup.org/onlinepubs/9799919799/utilities/find.html) utility. Historical BSD versions of chmod, however, only supported X with op+; it has been extended in this volume of POSIX.1-2024 because it is also useful with op=. (It has also been added for op- even though it duplicates x, in this case, because it is intuitive and easier to explain.)
```

Looks linux doesn't have operator restrictions.

The library we use atm https://github.com/tonistiigi/dchapes-mode/ seems to have operator limitation and would need to be updated for current linux behavior.

To have the behavior you are looking for you should rewrite your command as

```
COPY --from=base --chmod=u=rw,u+X,go=r,go+X /etc/apt/ /etc/apt/
```

to make sure `+` operator is used.@mbdevpl: @tonistiigi Thank you so much for the explanation and a fix recommendation! I wasn't aware of the evolution of this feature.

Moving `X` from the `=` part to `+` part indeed makes the command behave as one would expect.

Below I'm pasting the working Dockerfile along with the last command output:

```Dockerfile
# syntax=docker/dockerfile:labs

FROM ubuntu:latest AS base
RUN touch /etc/apt/sources.list.d/custom.list
RUN ls -lah /etc/apt/sources.list.d

FROM ubuntu:latest AS final
RUN ls -lah /etc/apt/sources.list.d
COPY --from=base --chmod=u=rw,u+X,go=r,go+X /etc/apt/ /etc/apt/
RUN ls -lah /etc/apt/sources.list.d
```

The `x` bits on the folder are now set:

```text
#11 [final 4/4] RUN ls -lah /etc/apt/sources.list.d
#11 0.259 total 16K
#11 0.259 drwxr-xr-x 1 root root 4.0K Mar 14 05:46 .
#11 0.259 drwxr-xr-x 1 root root 4.0K Jan 27 02:03 ..
#11 0.259 -rw-r--r-- 1 root root    0 Mar 14 05:46 custom.list
#11 0.259 -rw-r--r-- 1 root root 2.5K Jan 27 02:09 ubuntu.sources
#11 DONE 0.3s
```

I'm not sure what next steps would be good for this issue here -- feel free to close it if you think it's now appropriate.

I very much hope that when this syntax lands in the main release, the exact supported syntax is explained hopefully with some example that include correct usage of `X`, as I think many of the users of the non-octal syntax would use it especially because of the `X`.@tonistiigi: > I'm not sure what next steps would be good for this issue here -- feel free to close it if you think it's now appropriate.

Added a patch in https://github.com/tonistiigi/dchapes-mode/pull/2 . We can leave this open until that lands in buildkit.

> I very much hope that when this syntax lands in the main release, 

It is already in `#syntax=docker/dockerfile:1.14` but we haven't updated the `latest` tag yet(probably will switch next week).

Solution patch:
diff --git a/.github/labeler.yml b/.github/labeler.yml
index 9904941b6..f0a6a0e7e 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -68,6 +68,14 @@ area/buildkitd:
   - changed-files:
       - any-glob-to-any-file: "cmd/buildkitd/**"
 
+# area:cdi
+area/cdi:
+  - changed-files:
+      - any-glob-to-any-file:
+          - "contrib/cdisetup/**"
+          - "docs/cdi.md"
+          - "solver/llbsolver/cdidevices/**"
+
 # area:dependencies
 area/dependencies:
   - changed-files:
diff --git a/.github/workflows/.test.yml b/.github/workflows/.test.yml
index 05f216985..586fc9b9c 100644
--- a/.github/workflows/.test.yml
+++ b/.github/workflows/.test.yml
@@ -1,6 +1,10 @@
 # reusable workflow
 name: .test
 
+# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
+permissions:
+  contents: read
+
 on:
   workflow_call:
     inputs:
diff --git a/.github/workflows/buildkit.yml b/.github/workflows/buildkit.yml
index c17f80e8e..4af1fd0be 100644
--- a/.github/workflows/buildkit.yml
+++ b/.github/workflows/buildkit.yml
@@ -4,6 +4,10 @@ concurrency:
   group: ${{ github.workflow }}-${{ github.ref }}
   cancel-in-progress: true
 
+# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
+permissions:
+  contents: read
+
 on:
   schedule:
     - cron: '0 10 * * *'
@@ -150,10 +154,10 @@ jobs:
   govulncheck:
     runs-on: ubuntu-24.04
     permissions:
+      # same as global permission
+      contents: read
       # required to write sarif report
       security-events: write
-      # required to check out the repository
-      contents: read
     steps:
       -
         name: Set up Docker Buildx
@@ -226,6 +230,8 @@ jobs:
     runs-on: ubuntu-24.04
     if: ${{ github.ref == 'refs/heads/master' && github.repository == 'moby/buildkit' }}
     permissions:
+      # same as global permission
+      contents: read
       # required to write sarif report
       security-events: write
     needs:
@@ -266,6 +272,9 @@ jobs:
 
   release:
     runs-on: ubuntu-24.04
+    permissions:
+      # required to create GitHub release
+      contents: write
     needs:
       - prepare
       - test
diff --git a/.github/workflows/buildx-image.yml b/.github/workflows/buildx-image.yml
index f3f00e3b9..a6c316517 100644
--- a/.github/workflows/buildx-image.yml
+++ b/.github/workflows/buildx-image.yml
@@ -13,6 +13,10 @@ concurrency:
   group: ${{ github.workflow }}-${{ github.ref }}
   cancel-in-progress: true
 
+# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
+permissions:
+  contents: read
+
 on:
   workflow_dispatch:
     inputs:
diff --git a/.github/workflows/dockerd.yml b/.github/workflows/dockerd.yml
index b323ac404..6d76fb26f 100644
--- a/.github/workflows/dockerd.yml
+++ b/.github/workflows/dockerd.yml
@@ -1,5 +1,9 @@
 name: dockerd
 
+# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
+permissions:
+  contents: read
+
 on:
   # TODO: add event to build on command in PR (e.g., /test-dockerd)
   workflow_dispatch:
diff --git a/.github/workflows/docs-upstream.yml b/.github/workflows/docs-upstream.yml
index 0c9d18e7d..4762d64c8 100644
--- a/.github/workflows/docs-upstream.yml
+++ b/.github/workflows/docs-upstream.yml
@@ -7,6 +7,10 @@ concurrency:
   group: ${{ github.workflow }}-${{ github.ref }}
   cancel-in-progress: true
 
+# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
+permissions:
+  contents: read
+
 on:
   push:
     branches:
diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml
index ff5ffece8..95e619cdd 100644
--- a/.github/workflows/frontend.yml
+++ b/.github/workflows/frontend.yml
@@ -4,6 +4,10 @@ concurrency:
   group: ${{ github.workflow }}-${{ github.ref }}
   cancel-in-progress: true
 
+# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
+permissions:
+  contents: read
+
 on:
   workflow_dispatch:
   push:
@@ -130,6 +134,8 @@ jobs:
     runs-on: ubuntu-24.04
     if: ${{ github.ref == 'refs/heads/master' && github.repository == 'moby/buildkit' }}
     permissions:
+      # same as global permission
+      contents: read
       # required to write sarif report
       security-events: write
     needs:
@@ -171,6 +177,9 @@ jobs:
   release:
     runs-on: ubuntu-24.04
     if: startsWith(github.ref, 'refs/tags/dockerfile')
+    permissions:
+      # required to create GitHub release
+      contents: write
     needs:
       - prepare
       - test
diff --git a/.github/workflows/test-os.yml b/.github/workflows/test-os.yml
index 101313020..dbc2ea586 100644
--- a/.github/workflows/test-os.yml
+++ b/.github/workflows/test-os.yml
@@ -4,6 +4,10 @@ concurrency:
   group: ${{ github.workflow }}-${{ github.ref }}
   cancel-in-progress: true
 
+# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
+permissions:
+  contents: read
+
 on:
   schedule:
     - cron: '0 10 * * *'
diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml
index 4bc88855e..a99017106 100644
--- a/.github/workflows/validate.yml
+++ b/.github/workflows/validate.yml
@@ -4,6 +4,10 @@ concurrency:
   group: ${{ github.workflow }}-${{ github.ref }}
   cancel-in-progress: true
 
+# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
+permissions:
+  contents: read
+
 on:
   workflow_dispatch:
   push:
diff --git a/Dockerfile b/Dockerfile
index f4057d957..eeb63cdd1 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,6 @@
 # syntax=docker/dockerfile-upstream:master
 
-ARG RUNC_VERSION=v1.2.5
+ARG RUNC_VERSION=v1.2.6
 ARG CONTAINERD_VERSION=v2.0.4
 # CONTAINERD_ALT_VERSION_... defines fallback containerd version for integration tests
 ARG CONTAINERD_ALT_VERSION_17=v1.7.25
diff --git a/cache/manager.go b/cache/manager.go
index dd99dd68d..6e7c0064e 100644
--- a/cache/manager.go
+++ b/cache/manager.go
@@ -3,6 +3,7 @@ package cache
 import (
 	"context"
 	"fmt"
+	"maps"
 	"sort"
 	"strings"
 	"sync"
@@ -15,7 +16,6 @@ import (
 	"github.com/containerd/containerd/v2/pkg/gc"
 	"github.com/containerd/containerd/v2/pkg/labels"
 	cerrdefs "github.com/containerd/errdefs"
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/moby/buildkit/cache/metadata"
 	"github.com/moby/buildkit/client"
 	"github.com/moby/buildkit/identity"
@@ -25,6 +25,7 @@ import (
 	"github.com/moby/buildkit/util/disk"
 	"github.com/moby/buildkit/util/flightcontrol"
 	"github.com/moby/buildkit/util/progress"
+	"github.com/moby/sys/user"
 	digest "github.com/opencontainers/go-digest"
 	imagespecidentity "github.com/opencontainers/image-spec/identity"
 	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
@@ -61,7 +62,7 @@ type Accessor interface {
 
 	New(ctx context.Context, parent ImmutableRef, s session.Group, opts ...RefOption) (MutableRef, error)
 	GetMutable(ctx context.Context, id string, opts ...RefOption) (MutableRef, error) // Rebase?
-	IdentityMapping() *idtools.IdentityMapping
+	IdentityMapping() *user.IdentityMapping
 	Merge(ctx context.Context, parents []ImmutableRef, pg progress.Controller, opts ...RefOption) (ImmutableRef, error)
 	Diff(ctx context.Context, lower, upper ImmutableRef, pg progress.Controller, opts ...RefOption) (ImmutableRef, error)
 }
@@ -337,7 +338,7 @@ func (cm *cacheManager) init(ctx context.Context) error {
 }
 
 // IdentityMapping returns the userns remapping used for refs
-func (cm *cacheManager) IdentityMapping() *idtools.IdentityMapping {
+func (cm *cacheManager) IdentityMapping() *user.IdentityMapping {
 	return cm.Snapshotter.IdentityMapping()
 }
 
@@ -742,9 +743,7 @@ func (cm *cacheManager) Merge(ctx context.Context, inputParents []ImmutableRef,
 		default:
 			parents.mergeParents = append(parents.mergeParents, parent.clone())
 		}
-		for dgst, handler := range parent.descHandlers {
-			dhs[dgst] = handler
-		}
+		maps.Copy(dhs, parent.descHandlers)
 	}
 
 	// On success, createMergeRef takes ownership of parents
@@ -868,9 +867,7 @@ func (cm *cacheManager) Diff(ctx context.Context, lower, upper ImmutableRef, pg
 		} else {
 			dps.upper = parent.clone()
 		}
-		for dgst, handler := range parent.descHandlers {
-			dhs[dgst] = handler
-		}
+		maps.Copy(dhs, parent.descHandlers)
 	}
 
 	// Check to see if lower is an ancestor of upper. If so, define the diff as a merge
diff --git a/cache/refs.go b/cache/refs.go
index 5f5692b42..8752ce1de 100644
--- a/cache/refs.go
+++ b/cache/refs.go
@@ -18,7 +18,6 @@ import (
 	"github.com/containerd/containerd/v2/core/snapshots"
 	"github.com/containerd/containerd/v2/pkg/labels"
 	cerrdefs "github.com/containerd/errdefs"
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/hashicorp/go-multierror"
 	"github.com/moby/buildkit/cache/config"
 	"github.com/moby/buildkit/identity"
@@ -32,13 +31,17 @@ import (
 	"github.com/moby/buildkit/util/overlay"
 	"github.com/moby/buildkit/util/progress"
 	rootlessmountopts "github.com/moby/buildkit/util/rootless/mountopts"
+	"github.com/moby/buildkit/util/tracing"
 	"github.com/moby/buildkit/util/winlayers"
 	"github.com/moby/sys/mountinfo"
+	"github.com/moby/sys/user"
 	"github.com/moby/sys/userns"
 	digest "github.com/opencontainers/go-digest"
 	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
+	"go.opentelemetry.io/otel/attribute"
+	"go.opentelemetry.io/otel/trace"
 	"golang.org/x/sync/errgroup"
 )
 
@@ -49,7 +52,7 @@ type Ref interface {
 	Mountable
 	RefMetadata
 	Release(context.Context) error
-	IdentityMapping() *idtools.IdentityMapping
+	IdentityMapping() *user.IdentityMapping
 	DescHandler(digest.Digest) *DescHandler
 }
 
@@ -310,7 +313,7 @@ func (cr *cacheRecord) isLazy(ctx context.Context) (bool, error) {
 	return false, nil
 }
 
-func (cr *cacheRecord) IdentityMapping() *idtools.IdentityMapping {
+func (cr *cacheRecord) IdentityMapping() *user.IdentityMapping {
 	return cr.cm.IdentityMapping()
 }
 
@@ -1308,6 +1311,11 @@ func (sr *immutableRef) unlazyLayer(ctx context.Context, dhs DescHandlers, pg pr
 		statusDone := pg.Status("extracting "+desc.Digest.String(), "extracting")
 		defer statusDone()
 	}
+	sp, ctx := tracing.StartSpan(ctx, "extract", trace.WithAttributes(
+		attribute.String("digest", desc.Digest.String()),
+		attribute.Int("size", int(desc.Size)),
+	))
+	defer sp.End()
 
 	key := fmt.Sprintf("extract-%s %s", identity.NewID(), sr.getChainID())
 
diff --git a/client/solve.go b/client/solve.go
index 57ee82d05..557c4886f 100644
--- a/client/solve.go
+++ b/client/solve.go
@@ -142,9 +142,7 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG
 		}
 
 		contentStores := map[string]content.Store{}
-		for key, store := range cacheOpt.contentStores {
-			contentStores[key] = store
-		}
+		maps.Copy(contentStores, cacheOpt.contentStores)
 		for key, store := range opt.OCIStores {
 			key2 := "oci:" + key
 			if _, ok := contentStores[key2]; ok {
@@ -361,7 +359,7 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG
 		}
 		for _, storePath := range storesToUpdate {
 			names := []ociindex.NameOrTag{ociindex.Tag("latest")}
-			if t, ok := res.ExporterResponse["image.name"]; ok {
+			if t, ok := res.ExporterResponse[exptypes.ExporterImageNameKey]; ok {
 				inp := strings.Split(t, ",")
 				names = make([]ociindex.NameOrTag, len(inp))
 				for i, n := range inp {
@@ -538,9 +536,7 @@ func parseCacheOptions(ctx context.Context, isGateway bool, opt SolveOpt) (*cach
 func prepareMounts(opt *SolveOpt) (map[string]fsutil.FS, error) {
 	// merge local mounts and fallback local directories together
 	mounts := make(map[string]fsutil.FS)
-	for k, mount := range opt.LocalMounts {
-		mounts[k] = mount
-	}
+	maps.Copy(mounts, opt.LocalMounts)
 	for k, dir := range opt.LocalDirs {
 		mount, err := fsutil.NewFS(dir)
 		if err != nil {
diff --git a/cmd/buildkitd/main_oci_worker.go b/cmd/buildkitd/main_oci_worker.go
index ec2f36e47..f31c5a04a 100644
--- a/cmd/buildkitd/main_oci_worker.go
+++ b/cmd/buildkitd/main_oci_worker.go
@@ -5,6 +5,7 @@ package main
 import (
 	"context"
 	"fmt"
+	"maps"
 	"os"
 	"os/exec"
 	"path/filepath"
@@ -190,9 +191,7 @@ func applyOCIFlags(c *cli.Context, cfg *config.Config) error {
 	if cfg.Workers.OCI.Labels == nil {
 		cfg.Workers.OCI.Labels = make(map[string]string)
 	}
-	for k, v := range labels {
-		cfg.Workers.OCI.Labels[k] = v
-	}
+	maps.Copy(cfg.Workers.OCI.Labels, labels)
 	if c.GlobalIsSet("oci-worker-snapshotter") {
 		cfg.Workers.OCI.Snapshotter = c.GlobalString("oci-worker-snapshotter")
 	}
diff --git a/cmd/buildkitd/util_linux.go b/cmd/buildkitd/util_linux.go
index 2fda61c91..3f18edf96 100644
--- a/cmd/buildkitd/util_linux.go
+++ b/cmd/buildkitd/util_linux.go
@@ -3,12 +3,12 @@ package main
 import (
 	"strings"
 
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/moby/buildkit/util/bklog"
+	"github.com/moby/sys/user"
 	"github.com/pkg/errors"
 )
 
-func parseIdentityMapping(str string) (*idtools.IdentityMapping, error) {
+func parseIdentityMapping(str string) (*user.IdentityMapping, error) {
 	if str == "" {
 		return nil, nil
 	}
@@ -22,7 +22,7 @@ func parseIdentityMapping(str string) (*idtools.IdentityMapping, error) {
 
 	bklog.L.Debugf("user namespaces: ID ranges will be mapped to subuid ranges of: %s", username)
 
-	mappings, err := idtools.LoadIdentityMapping(username)
+	mappings, err := user.LoadIdentityMapping(username)
 	if err != nil {
 		return nil, errors.Wrap(err, "failed to create ID mappings")
 	}
diff --git a/executor/containerdexecutor/executor.go b/executor/containerdexecutor/executor.go
index 366959f01..99540d7c6 100644
--- a/executor/containerdexecutor/executor.go
+++ b/executor/containerdexecutor/executor.go
@@ -154,7 +154,7 @@ func (w *containerdExecutor) Run(ctx context.Context, id string, root executor.M
 		defer releasers()
 	}
 
-	if err := w.ensureCWD(ctx, details, meta); err != nil {
+	if err := w.ensureCWD(details, meta); err != nil {
 		return nil, err
 	}
 
diff --git a/executor/containerdexecutor/executor_unix.go b/executor/containerdexecutor/executor_unix.go
index 2233909cd..5e3e2ecf5 100644
--- a/executor/containerdexecutor/executor_unix.go
+++ b/executor/containerdexecutor/executor_unix.go
@@ -11,7 +11,6 @@ import (
 	"github.com/containerd/containerd/v2/core/mount"
 	containerdoci "github.com/containerd/containerd/v2/pkg/oci"
 	"github.com/containerd/continuity/fs"
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/moby/buildkit/executor"
 	"github.com/moby/buildkit/executor/oci"
 	"github.com/moby/buildkit/snapshot"
@@ -19,6 +18,7 @@ import (
 	"github.com/moby/buildkit/util/bklog"
 	"github.com/moby/buildkit/util/network"
 	rootlessspecconv "github.com/moby/buildkit/util/rootless/specconv"
+	"github.com/moby/sys/user"
 	"github.com/opencontainers/runtime-spec/specs-go"
 	"github.com/pkg/errors"
 )
@@ -101,7 +101,7 @@ func (w *containerdExecutor) prepareExecutionEnv(ctx context.Context, rootMount
 	return resolvConf, hostsFile, releaseAll, nil
 }
 
-func (w *containerdExecutor) ensureCWD(_ context.Context, details *containerState, meta executor.Meta) error {
+func (w *containerdExecutor) ensureCWD(details *containerState, meta executor.Meta) error {
 	newp, err := fs.RootPath(details.rootfsPath, meta.Cwd)
 	if err != nil {
 		return errors.Wrapf(err, "working dir %s points to invalid target", newp)
@@ -112,13 +112,8 @@ func (w *containerdExecutor) ensureCWD(_ context.Context, details *containerStat
 		return err
 	}
 
-	identity := idtools.Identity{
-		UID: int(uid),
-		GID: int(gid),
-	}
-
 	if _, err := os.Stat(newp); err != nil {
-		if err := idtools.MkdirAllAndChown(newp, 0755, identity); err != nil {
+		if err := user.MkdirAllAndChown(newp, 0755, int(uid), int(gid)); err != nil {
 			return errors.Wrapf(err, "failed to create working directory %s", newp)
 		}
 	}
diff --git a/executor/containerdexecutor/executor_windows.go b/executor/containerdexecutor/executor_windows.go
index b09114deb..1145c2f25 100644
--- a/executor/containerdexecutor/executor_windows.go
+++ b/executor/containerdexecutor/executor_windows.go
@@ -8,13 +8,12 @@ import (
 	ctd "github.com/containerd/containerd/v2/client"
 	containerdoci "github.com/containerd/containerd/v2/pkg/oci"
 	"github.com/containerd/continuity/fs"
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/moby/buildkit/executor"
 	"github.com/moby/buildkit/executor/oci"
 	"github.com/moby/buildkit/snapshot"
 	"github.com/moby/buildkit/solver/pb"
 	"github.com/moby/buildkit/util/network"
-	"github.com/moby/buildkit/util/windows"
+	"github.com/moby/sys/user"
 	"github.com/opencontainers/runtime-spec/specs-go"
 	"github.com/pkg/errors"
 )
@@ -48,13 +47,7 @@ func (w *containerdExecutor) prepareExecutionEnv(ctx context.Context, rootMount
 	return "", "", releaseAll, nil
 }
 
-func (w *containerdExecutor) ensureCWD(ctx context.Context, details *containerState, meta executor.Meta) (err error) {
-	// TODO(gabriel-samfira): Use a snapshot?
-	identity, err := windows.ResolveUsernameToSID(ctx, w, details.rootMounts, meta.User)
-	if err != nil {
-		return errors.Wrap(err, "getting user SID")
-	}
-
+func (w *containerdExecutor) ensureCWD(details *containerState, meta executor.Meta) (err error) {
 	lm := snapshot.LocalMounterWithMounts(details.rootMounts)
 	rootfsPath, err := lm.Mount()
 	if err != nil {
@@ -68,7 +61,8 @@ func (w *containerdExecutor) ensureCWD(ctx context.Context, details *containerSt
 	}
 
 	if _, err := os.Stat(newp); err != nil {
-		if err := idtools.MkdirAllAndChown(newp, 0755, identity); err != nil {
+		// uid and gid are not used on windows.
+		if err := user.MkdirAllAndChown(newp, 0755, 0, 0); err != nil {
 			return errors.Wrapf(err, "failed to create working directory %s", newp)
 		}
 	}
diff --git a/executor/executor.go b/executor/executor.go
index d35e18af6..aa011e27d 100644
--- a/executor/executor.go
+++ b/executor/executor.go
@@ -7,9 +7,9 @@ import (
 	"syscall"
 
 	"github.com/containerd/containerd/v2/core/mount"
-	"github.com/docker/docker/pkg/idtools"
 	resourcestypes "github.com/moby/buildkit/executor/resources/types"
 	"github.com/moby/buildkit/solver/pb"
+	"github.com/moby/sys/user"
 )
 
 type Meta struct {
@@ -33,7 +33,7 @@ type Meta struct {
 
 type MountableRef interface {
 	Mount() ([]mount.Mount, func() error, error)
-	IdentityMapping() *idtools.IdentityMapping
+	IdentityMapping() *user.IdentityMapping
 }
 
 type Mountable interface {
diff --git a/executor/oci/hosts.go b/executor/oci/hosts.go
index cecaf11bf..895005ee2 100644
--- a/executor/oci/hosts.go
+++ b/executor/oci/hosts.go
@@ -7,15 +7,15 @@ import (
 	"os"
 	"path/filepath"
 
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/moby/buildkit/executor"
 	"github.com/moby/buildkit/identity"
+	"github.com/moby/sys/user"
 	"github.com/pkg/errors"
 )
 
 const defaultHostname = "buildkitsandbox"
 
-func GetHostsFile(ctx context.Context, stateDir string, extraHosts []executor.HostIP, idmap *idtools.IdentityMapping, hostname string) (string, func(), error) {
+func GetHostsFile(ctx context.Context, stateDir string, extraHosts []executor.HostIP, idmap *user.IdentityMapping, hostname string) (string, func(), error) {
 	if len(extraHosts) != 0 || hostname != defaultHostname {
 		return makeHostsFile(stateDir, extraHosts, idmap, hostname)
 	}
@@ -30,7 +30,7 @@ func GetHostsFile(ctx context.Context, stateDir string, extraHosts []executor.Ho
 	return filepath.Join(stateDir, "hosts"), func() {}, nil
 }
 
-func makeHostsFile(stateDir string, extraHosts []executor.HostIP, idmap *idtools.IdentityMapping, hostname string) (string, func(), error) {
+func makeHostsFile(stateDir string, extraHosts []executor.HostIP, idmap *user.IdentityMapping, hostname string) (string, func(), error) {
 	p := filepath.Join(stateDir, "hosts")
 	if len(extraHosts) != 0 || hostname != defaultHostname {
 		p += "." + identity.NewID()
@@ -60,8 +60,8 @@ func makeHostsFile(stateDir string, extraHosts []executor.HostIP, idmap *idtools
 	}
 
 	if idmap != nil {
-		root := idmap.RootPair()
-		if err := os.Chown(tmpPath, root.UID, root.GID); err != nil {
+		uid, gid := idmap.RootPair()
+		if err := os.Chown(tmpPath, uid, gid); err != nil {
 			return "", nil, errors.WithStack(err)
 		}
 	}
diff --git a/executor/oci/resolvconf.go b/executor/oci/resolvconf.go
index 7def36a6f..8354d101c 100644
--- a/executor/oci/resolvconf.go
+++ b/executor/oci/resolvconf.go
@@ -6,15 +6,17 @@ import (
 	"path/filepath"
 
 	"github.com/docker/docker/libnetwork/resolvconf"
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/moby/buildkit/solver/pb"
 	"github.com/moby/buildkit/util/flightcontrol"
+	"github.com/moby/sys/user"
 	"github.com/pkg/errors"
 )
 
-var g flightcontrol.Group[struct{}]
-var notFirstRun bool
-var lastNotEmpty bool
+var (
+	g            flightcontrol.Group[struct{}]
+	notFirstRun  bool
+	lastNotEmpty bool
+)
 
 // overridden by tests
 var resolvconfPath = func(netMode pb.NetMode) string {
@@ -36,7 +38,7 @@ type DNSConfig struct {
 	SearchDomains []string
 }
 
-func GetResolvConf(ctx context.Context, stateDir string, idmap *idtools.IdentityMapping, dns *DNSConfig, netMode pb.NetMode) (string, error) {
+func GetResolvConf(ctx context.Context, stateDir string, idmap *user.IdentityMapping, dns *DNSConfig, netMode pb.NetMode) (string, error) {
 	p := filepath.Join(stateDir, "resolv.conf")
 	if netMode == pb.NetMode_HOST {
 		p = filepath.Join(stateDir, "resolv-host.conf")
@@ -116,8 +118,8 @@ func GetResolvConf(ctx context.Context, stateDir string, idmap *idtools.Identity
 		}
 
 		if idmap != nil {
-			root := idmap.RootPair()
-			if err := os.Chown(tmpPath, root.UID, root.GID); err != nil {
+			uid, gid := idmap.RootPair()
+			if err := os.Chown(tmpPath, uid, gid); err != nil {
 				return struct{}{}, errors.WithStack(err)
 			}
 		}
diff --git a/executor/oci/spec.go b/executor/oci/spec.go
index e3887d9c4..2e90665d1 100644
--- a/executor/oci/spec.go
+++ b/executor/oci/spec.go
@@ -13,7 +13,6 @@ import (
 	"github.com/containerd/containerd/v2/core/mount"
 	"github.com/containerd/containerd/v2/pkg/namespaces"
 	"github.com/containerd/containerd/v2/pkg/oci"
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/mitchellh/hashstructure/v2"
 	"github.com/moby/buildkit/executor"
 	"github.com/moby/buildkit/snapshot"
@@ -22,6 +21,7 @@ import (
 	rootlessmountopts "github.com/moby/buildkit/util/rootless/mountopts"
 	"github.com/moby/buildkit/util/system"
 	traceexec "github.com/moby/buildkit/util/tracing/exec"
+	"github.com/moby/sys/user"
 	"github.com/moby/sys/userns"
 	specs "github.com/opencontainers/runtime-spec/specs-go"
 	"github.com/opencontainers/selinux/go-selinux"
@@ -61,7 +61,7 @@ func (pm ProcessMode) String() string {
 
 // GenerateSpec generates spec using containerd functionality.
 // opts are ignored for s.Process, s.Hostname, and s.Mounts .
-func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mount, id, resolvConf, hostsFile string, namespace network.Namespace, cgroupParent string, processMode ProcessMode, idmap *idtools.IdentityMapping, apparmorProfile string, selinuxB bool, tracingSocket string, cdiManager *cdidevices.Manager, opts ...oci.SpecOpts) (*specs.Spec, func(), error) {
+func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mount, id, resolvConf, hostsFile string, namespace network.Namespace, cgroupParent string, processMode ProcessMode, idmap *user.IdentityMapping, apparmorProfile string, selinuxB bool, tracingSocket string, cdiManager *cdidevices.Manager, opts ...oci.SpecOpts) (*specs.Spec, func(), error) {
 	c := &containers.Container{
 		ID: id,
 	}
diff --git a/executor/oci/spec_darwin.go b/executor/oci/spec_darwin.go
index ae609a216..15a4544ac 100644
--- a/executor/oci/spec_darwin.go
+++ b/executor/oci/spec_darwin.go
@@ -4,9 +4,9 @@ import (
 	"github.com/containerd/containerd/v2/core/mount"
 	"github.com/containerd/containerd/v2/pkg/oci"
 	"github.com/containerd/continuity/fs"
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/moby/buildkit/solver/llbsolver/cdidevices"
 	"github.com/moby/buildkit/solver/pb"
+	"github.com/moby/sys/user"
 	"github.com/opencontainers/runtime-spec/specs-go"
 	"github.com/pkg/errors"
 )
@@ -27,7 +27,7 @@ func generateProcessModeOpts(mode ProcessMode) ([]oci.SpecOpts, error) {
 	return nil, nil
 }
 
-func generateIDmapOpts(idmap *idtools.IdentityMapping) ([]oci.SpecOpts, error) {
+func generateIDmapOpts(idmap *user.IdentityMapping) ([]oci.SpecOpts, error) {
 	if idmap == nil {
 		return nil, nil
 	}
diff --git a/executor/oci/spec_freebsd.go b/executor/oci/spec_freebsd.go
index d1456a8ec..71efef5cf 100644
--- a/executor/oci/spec_freebsd.go
+++ b/executor/oci/spec_freebsd.go
@@ -4,9 +4,9 @@ import (
 	"github.com/containerd/containerd/v2/core/mount"
 	"github.com/containerd/containerd/v2/pkg/oci"
 	"github.com/containerd/continuity/fs"
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/moby/buildkit/solver/llbsolver/cdidevices"
 	"github.com/moby/buildkit/solver/pb"
+	"github.com/moby/sys/user"
 	specs "github.com/opencontainers/runtime-spec/specs-go"
 	"github.com/pkg/errors"
 )
@@ -35,7 +35,7 @@ func generateProcessModeOpts(mode ProcessMode) ([]oci.SpecOpts, error) {
 	return nil, nil
 }
 
-func generateIDmapOpts(idmap *idtools.IdentityMapping) ([]oci.SpecOpts, error) {
+func generateIDmapOpts(idmap *user.IdentityMapping) ([]oci.SpecOpts, error) {
 	if idmap == nil {
 		return nil, nil
 	}
diff --git a/executor/oci/spec_linux.go b/executor/oci/spec_linux.go
index 7b437c28b..2e80c8557 100644
--- a/executor/oci/spec_linux.go
+++ b/executor/oci/spec_linux.go
@@ -14,13 +14,13 @@ import (
 	"github.com/containerd/containerd/v2/pkg/oci"
 	cdseccomp "github.com/containerd/containerd/v2/pkg/seccomp"
 	"github.com/containerd/continuity/fs"
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/docker/docker/profiles/seccomp"
 	"github.com/moby/buildkit/snapshot"
 	"github.com/moby/buildkit/solver/llbsolver/cdidevices"
 	"github.com/moby/buildkit/solver/pb"
 	"github.com/moby/buildkit/util/bklog"
 	"github.com/moby/buildkit/util/entitlements/security"
+	"github.com/moby/sys/user"
 	specs "github.com/opencontainers/runtime-spec/specs-go"
 	selinux "github.com/opencontainers/selinux/go-selinux"
 	"github.com/opencontainers/selinux/go-selinux/label"
@@ -106,7 +106,7 @@ func generateProcessModeOpts(mode ProcessMode) ([]oci.SpecOpts, error) {
 	return nil, nil
 }
 
-func generateIDmapOpts(idmap *idtools.IdentityMapping) ([]oci.SpecOpts, error) {
+func generateIDmapOpts(idmap *user.IdentityMapping) ([]oci.SpecOpts, error) {
 	if idmap == nil {
 		return nil, nil
 	}
@@ -115,13 +115,13 @@ func generateIDmapOpts(idmap *idtools.IdentityMapping) ([]oci.SpecOpts, error) {
 	}, nil
 }
 
-func specMapping(s []idtools.IDMap) []specs.LinuxIDMapping {
+func specMapping(s []user.IDMap) []specs.LinuxIDMapping {
 	var ids []specs.LinuxIDMapping
 	for _, item := range s {
 		ids = append(ids, specs.LinuxIDMapping{
-			HostID:      uint32(item.HostID),
-			ContainerID: uint32(item.ContainerID),
-			Size:        uint32(item.Size),
+			HostID:      uint32(item.ParentID),
+			ContainerID: uint32(item.ID),
+			Size:        uint32(item.Count),
 		})
 	}
 	return ids
@@ -286,7 +286,7 @@ func cgroupV2NamespaceSupported() bool {
 }
 
 func sub(m mount.Mount, subPath string) (mount.Mount, func() error, error) {
-	var retries = 10
+	retries := 10
 	root := m.Source
 	for {
 		src, err := fs.RootPath(root, subPath)
diff --git a/executor/oci/spec_windows.go b/executor/oci/spec_windows.go
index bdd8757fb..3e28c2900 100644
--- a/executor/oci/spec_windows.go
+++ b/executor/oci/spec_windows.go
@@ -13,9 +13,9 @@ import (
 	"github.com/containerd/containerd/v2/core/mount"
 	"github.com/containerd/containerd/v2/pkg/oci"
 	"github.com/containerd/continuity/fs"
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/moby/buildkit/solver/llbsolver/cdidevices"
 	"github.com/moby/buildkit/solver/pb"
+	"github.com/moby/sys/user"
 	specs "github.com/opencontainers/runtime-spec/specs-go"
 	"github.com/pkg/errors"
 )
@@ -73,7 +73,7 @@ func generateProcessModeOpts(mode ProcessMode) ([]oci.SpecOpts, error) {
 	return nil, nil
 }
 
-func generateIDmapOpts(idmap *idtools.IdentityMapping) ([]oci.SpecOpts, error) {
+func generateIDmapOpts(idmap *user.IdentityMapping) ([]oci.SpecOpts, error) {
 	if idmap == nil {
 		return nil, nil
 	}
diff --git a/executor/runcexecutor/executor.go b/executor/runcexecutor/executor.go
index 1ca978bbb..cbc3f9eba 100644
--- a/executor/runcexecutor/executor.go
+++ b/executor/runcexecutor/executor.go
@@ -23,7 +23,6 @@ import (
 	containerdoci "github.com/containerd/containerd/v2/pkg/oci"
 	"github.com/containerd/continuity/fs"
 	runc "github.com/containerd/go-runc"
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/moby/buildkit/executor"
 	"github.com/moby/buildkit/executor/oci"
 	"github.com/moby/buildkit/executor/resources"
@@ -35,6 +34,7 @@ import (
 	"github.com/moby/buildkit/util/network"
 	rootlessspecconv "github.com/moby/buildkit/util/rootless/specconv"
 	"github.com/moby/buildkit/util/stack"
+	"github.com/moby/sys/user"
 	"github.com/opencontainers/runtime-spec/specs-go"
 	"github.com/pkg/errors"
 )
@@ -49,7 +49,7 @@ type Opt struct {
 	DefaultCgroupParent string
 	// ProcessMode
 	ProcessMode     oci.ProcessMode
-	IdentityMapping *idtools.IdentityMapping
+	IdentityMapping *user.IdentityMapping
 	// runc run --no-pivot (unrecommended)
 	NoPivot         bool
 	DNS             *oci.DNSConfig
@@ -70,7 +70,7 @@ type runcExecutor struct {
 	rootless         bool
 	networkProviders map[pb.NetMode]network.Provider
 	processMode      oci.ProcessMode
-	idmap            *idtools.IdentityMapping
+	idmap            *user.IdentityMapping
 	noPivot          bool
 	dns              *oci.DNSConfig
 	oomScoreAdj      *int
@@ -227,13 +227,13 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount,
 	}
 	defer os.RemoveAll(bundle)
 
-	identity := idtools.Identity{}
+	var rootUID, rootGID int
 	if w.idmap != nil {
-		identity = w.idmap.RootPair()
+		rootUID, rootGID = w.idmap.RootPair()
 	}
 
 	rootFSPath := filepath.Join(bundle, "rootfs")
-	if err := idtools.MkdirAllAndChown(rootFSPath, 0o700, identity); err != nil {
+	if err := user.MkdirAllAndChown(rootFSPath, 0o700, rootUID, rootGID); err != nil {
 		return nil, errors.WithStack(err)
 	}
 	if err := mount.All(rootMount, rootFSPath); err != nil {
@@ -260,12 +260,9 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount,
 		opts = append(opts, containerdoci.WithRootFSReadonly())
 	}
 
-	identity = idtools.Identity{
-		UID: int(uid),
-		GID: int(gid),
-	}
+	rootUID, rootGID = int(uid), int(gid)
 	if w.idmap != nil {
-		identity, err = w.idmap.ToHost(identity)
+		rootUID, rootGID, err = w.idmap.ToHost(rootUID, rootGID)
 		if err != nil {
 			return nil, err
 		}
@@ -287,7 +284,7 @@ func (w *runcExecutor) Run(ctx context.Context, id string, root executor.Mount,
 		return nil, errors.Wrapf(err, "working dir %s points to invalid target", newp)
 	}
 	if _, err := os.Stat(newp); err != nil {
-		if err := idtools.MkdirAllAndChown(newp, 0o755, identity); err != nil {
+		if err := user.MkdirAllAndChown(newp, 0o755, rootUID, rootGID); err != nil {
 			return nil, errors.Wrapf(err, "failed to create working directory %s", newp)
 		}
 	}
diff --git a/exporter/containerimage/export.go b/exporter/containerimage/export.go
index 7c4136b53..58d2623b4 100644
--- a/exporter/containerimage/export.go
+++ b/exporter/containerimage/export.go
@@ -149,6 +149,16 @@ func (e *imageExporter) Resolve(ctx context.Context, id int, opt map[string]stri
 			i.storeAllowIncomplete = b
 		case exptypes.OptKeyDanglingPrefix:
 			i.danglingPrefix = v
+		case exptypes.OptKeyDanglingEmptyOnly:
+			if v == "" {
+				i.danglingEmptyOnly = true
+				continue
+			}
+			b, err := strconv.ParseBool(v)
+			if err != nil {
+				return nil, errors.Wrapf(err, "non-bool value specified for %s", k)
+			}
+			i.danglingEmptyOnly = b
 		case exptypes.OptKeyNameCanonical:
 			if v == "" {
 				i.nameCanonical = true
@@ -183,6 +193,7 @@ type imageExporterInstance struct {
 	insecure             bool
 	nameCanonical        bool
 	danglingPrefix       string
+	danglingEmptyOnly    bool
 	meta                 map[string][]byte
 }
 
@@ -247,9 +258,14 @@ func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source
 	}
 
 	nameCanonical := e.nameCanonical
-	if e.opts.ImageName == "" && e.danglingPrefix != "" {
-		e.opts.ImageName = e.danglingPrefix + "@" + desc.Digest.String()
-		nameCanonical = false
+	if e.danglingPrefix != "" && (!e.danglingEmptyOnly || e.opts.ImageName == "") {
+		danglingImageName := e.danglingPrefix + "@" + desc.Digest.String()
+		if e.opts.ImageName != "" {
+			e.opts.ImageName += "," + danglingImageName
+		} else {
+			e.opts.ImageName = danglingImageName
+			nameCanonical = false
+		}
 	}
 
 	if e.opts.ImageName != "" {
@@ -274,7 +290,7 @@ func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source
 				}
 
 				sfx := []string{""}
-				if nameCanonical {
+				if nameCanonical && !strings.ContainsRune(targetName, '@') {
 					sfx = append(sfx, "@"+desc.Digest.String())
 				}
 				for _, sfx := range sfx {
@@ -344,7 +360,7 @@ func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source
 				}
 			}
 		}
-		resp["image.name"] = e.opts.ImageName
+		resp[exptypes.ExporterImageNameKey] = e.opts.ImageName
 	}
 
 	resp[exptypes.ExporterImageDigestKey] = desc.Digest.String()
diff --git a/exporter/containerimage/exptypes/keys.go b/exporter/containerimage/exptypes/keys.go
index 8eb2064e1..7cfa8dc02 100644
--- a/exporter/containerimage/exptypes/keys.go
+++ b/exporter/containerimage/exptypes/keys.go
@@ -26,11 +26,17 @@ var (
 	// Value: bool <true|false>
 	OptKeyUnpack ImageExporterOptKey = "unpack"
 
-	// Fallback image name prefix if image name isn't provided.
-	// If used, image will be named as <value>@<digest>
+	// Image name prefix to be used for tagging a dangling image.
+	// If used, image will be named as <value>@<digest> in addition
+	// to any other specified names.
 	// Value: string
 	OptKeyDanglingPrefix ImageExporterOptKey = "dangling-name-prefix"
 
+	// Only use the dangling image name as a fallback if image name isn't provided.
+	// Ignored if dangling-name-prefix is not set.
+	// Value: bool <true|false>
+	OptKeyDanglingEmptyOnly ImageExporterOptKey = "danging-name-empty-only"
+
 	// Creates additional image name with format <name>@<digest>
 	// Value: bool <true|false>
 	OptKeyNameCanonical ImageExporterOptKey = "name-canonical"
diff --git a/exporter/containerimage/exptypes/types.go b/exporter/containerimage/exptypes/types.go
index 056485b66..d7cc98b94 100644
--- a/exporter/containerimage/exptypes/types.go
+++ b/exporter/containerimage/exptypes/types.go
@@ -9,6 +9,7 @@ import (
 
 const (
 	ExporterConfigDigestKey      = "config.digest"
+	ExporterImageNameKey         = "image.name"
 	ExporterImageDigestKey       = "containerimage.digest"
 	ExporterImageConfigKey       = "containerimage.config"
 	ExporterImageConfigDigestKey = "containerimage.config.digest"
diff --git a/exporter/local/fs.go b/exporter/local/fs.go
index b565592d2..1985ed009 100644
--- a/exporter/local/fs.go
+++ b/exporter/local/fs.go
@@ -12,7 +12,6 @@ import (
 	"strings"
 	"time"
 
-	"github.com/docker/docker/pkg/idtools"
 	intoto "github.com/in-toto/in-toto-golang/in_toto"
 	"github.com/moby/buildkit/cache"
 	"github.com/moby/buildkit/exporter"
@@ -22,6 +21,7 @@ import (
 	"github.com/moby/buildkit/snapshot"
 	"github.com/moby/buildkit/solver/result"
 	"github.com/moby/buildkit/util/staticfs"
+	"github.com/moby/sys/user"
 	digest "github.com/opencontainers/go-digest"
 	"github.com/pkg/errors"
 	"github.com/tonistiigi/fsutil"
@@ -73,7 +73,7 @@ func CreateFS(ctx context.Context, sessionID string, k string, ref cache.Immutab
 	var cleanup func() error
 	var src string
 	var err error
-	var idmap *idtools.IdentityMapping
+	var idmap *user.IdentityMapping
 	if ref == nil {
 		src, err = os.MkdirTemp("", "buildkit")
 		if err != nil {
@@ -108,10 +108,7 @@ func CreateFS(ctx context.Context, sessionID string, k string, ref cache.Immutab
 	var idMapFunc func(p string, st *fstypes.Stat) fsutil.MapResult
 	if idmap != nil {
 		idMapFunc = func(p string, st *fstypes.Stat) fsutil.MapResult {
-			uid, gid, err := idmap.ToContainer(idtools.Identity{
-				UID: int(st.Uid),
-				GID: int(st.Gid),
-			})
+			uid, gid, err := idmap.ToContainer(int(st.Uid), int(st.Gid))
 			if err != nil {
 				return fsutil.MapResultExclude
 			}
diff --git a/exporter/oci/export.go b/exporter/oci/export.go
index 69eabfebb..3db1278fb 100644
--- a/exporter/oci/export.go
+++ b/exporter/oci/export.go
@@ -204,7 +204,7 @@ func (e *imageExporterInstance) Export(ctx context.Context, src *exporter.Source
 	}
 
 	if len(names) != 0 {
-		resp["image.name"] = strings.Join(names, ",")
+		resp[exptypes.ExporterImageNameKey] = strings.Join(names, ",")
 	}
 
 	expOpts := []archiveexporter.ExportOpt{archiveexporter.WithManifest(*desc, names...)}
@@ -298,7 +298,7 @@ func normalizedNames(name string) ([]string, error) {
 		return nil, nil
 	}
 	names := strings.Split(name, ",")
-	var tagNames = make([]string, len(names))
+	tagNames := make([]string, len(names))
 	for i, name := range names {
 		parsed, err := reference.ParseNormalizedNamed(name)
 		if err != nil {
diff --git a/frontend/dockerui/build.go b/frontend/dockerui/build.go
index 744aa692a..fe2dbd05d 100644
--- a/frontend/dockerui/build.go
+++ b/frontend/dockerui/build.go
@@ -62,18 +62,9 @@ func (bc *Client) Build(ctx context.Context, fn BuildFunc) (*ResultBuilder, erro
 				p = platforms.DefaultSpec()
 			}
 
-			// in certain conditions we allow input platform to be extended from base image
-			if p.OS == "windows" && img.OS == p.OS {
-				if p.OSVersion == "" && img.OSVersion != "" {
-					p.OSVersion = img.OSVersion
-				}
-				if p.OSFeatures == nil && len(img.OSFeatures) > 0 {
-					p.OSFeatures = slices.Clone(img.OSFeatures)
-				}
-			}
-
-			p = platforms.Normalize(p)
 			k := platforms.FormatAll(p)
+			p = extendWindowsPlatform(p, img.Platform)
+			p = platforms.Normalize(p)
 
 			if bc.MultiPlatformRequested {
 				res.AddRef(k, ref)
@@ -129,3 +120,16 @@ func (rb *ResultBuilder) EachPlatform(ctx context.Context, fn func(ctx context.C
 	}
 	return eg.Wait()
 }
+
+func extendWindowsPlatform(p, imgP ocispecs.Platform) ocispecs.Platform {
+	// in certain conditions we allow input platform to be extended from base image
+	if p.OS == "windows" && imgP.OS == p.OS {
+		if p.OSVersion == "" && imgP.OSVersion != "" {
+			p.OSVersion = imgP.OSVersion
+		}
+		if p.OSFeatures == nil && len(imgP.OSFeatures) > 0 {
+			p.OSFeatures = slices.Clone(imgP.OSFeatures)
+		}
+	}
+	return p
+}
diff --git a/frontend/gateway/gateway.go b/frontend/gateway/gateway.go
index be9f1e113..158e4ccfd 100644
--- a/frontend/gateway/gateway.go
+++ b/frontend/gateway/gateway.go
@@ -19,7 +19,6 @@ import (
 	"github.com/containerd/containerd/v2/core/mount"
 	"github.com/containerd/containerd/v2/defaults"
 	"github.com/distribution/reference"
-	"github.com/docker/docker/pkg/idtools"
 	apitypes "github.com/moby/buildkit/api/types"
 	"github.com/moby/buildkit/cache"
 	cacheutil "github.com/moby/buildkit/cache/util"
@@ -49,6 +48,7 @@ import (
 	"github.com/moby/buildkit/worker"
 	dockerspec "github.com/moby/docker-image-spec/specs-go/v1"
 	"github.com/moby/sys/signal"
+	"github.com/moby/sys/user"
 	digest "github.com/opencontainers/go-digest"
 	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
@@ -411,7 +411,7 @@ func (b *bindMount) Mount() ([]mount.Mount, func() error, error) {
 	}}, func() error { return nil }, nil
 }
 
-func (b *bindMount) IdentityMapping() *idtools.IdentityMapping {
+func (b *bindMount) IdentityMapping() *user.IdentityMapping {
 	return nil
 }
 
diff --git a/go.mod b/go.mod
index 8eccd8ecf..a83aba8a7 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
 module github.com/moby/buildkit
 
-go 1.22.0
+go 1.23.0
 
 require (
 	github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0
@@ -32,8 +32,8 @@ require (
 	github.com/containernetworking/plugins v1.5.1
 	github.com/coreos/go-systemd/v22 v22.5.0
 	github.com/distribution/reference v0.6.0
-	github.com/docker/cli v28.0.1+incompatible
-	github.com/docker/docker v28.0.1+incompatible
+	github.com/docker/cli v28.0.4+incompatible
+	github.com/docker/docker v28.0.4+incompatible
 	github.com/docker/go-connections v0.5.0
 	github.com/docker/go-units v0.5.0
 	github.com/gofrs/flock v0.12.1
@@ -53,11 +53,11 @@ require (
 	github.com/moby/sys/mountinfo v0.7.2
 	github.com/moby/sys/reexec v0.1.0
 	github.com/moby/sys/signal v0.7.1
-	github.com/moby/sys/user v0.3.0
+	github.com/moby/sys/user v0.4.0
 	github.com/moby/sys/userns v0.1.0
 	github.com/morikuni/aec v1.0.0
 	github.com/opencontainers/go-digest v1.0.0
-	github.com/opencontainers/image-spec v1.1.0
+	github.com/opencontainers/image-spec v1.1.1
 	github.com/opencontainers/runtime-spec v1.2.0
 	github.com/opencontainers/selinux v1.11.1
 	github.com/package-url/packageurl-go v0.1.1
@@ -71,8 +71,8 @@ require (
 	github.com/sirupsen/logrus v1.9.3
 	github.com/spdx/tools-golang v0.5.3
 	github.com/stretchr/testify v1.10.0
-	github.com/tonistiigi/dchapes-mode v0.0.0-20241001053921-ca0759fec205
-	github.com/tonistiigi/fsutil v0.0.0-20250227023350-13604323a291
+	github.com/tonistiigi/dchapes-mode v0.0.0-20250318174251-73d941a28323
+	github.com/tonistiigi/fsutil v0.0.0-20250318190121-d73a4b3b8a7e
 	github.com/tonistiigi/go-actions-cache v0.0.0-20250228231703-3e9a6642607f
 	github.com/tonistiigi/go-archvariant v1.0.0
 	github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4
@@ -108,7 +108,7 @@ require (
 	google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1
 	google.golang.org/protobuf v1.35.2
 	kernel.org/pub/linux/libs/security/libcap/cap v1.2.73
-	tags.cncf.io/container-device-interface v0.8.1
+	tags.cncf.io/container-device-interface v1.0.1
 )
 
 require (
@@ -143,7 +143,7 @@ require (
 	github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/dimchansky/utfbom v1.1.1 // indirect
-	github.com/docker/docker-credential-helpers v0.8.2 // indirect
+	github.com/docker/docker-credential-helpers v0.9.3 // indirect
 	github.com/docker/go-metrics v0.0.1 // indirect
 	github.com/felixge/fgprof v0.9.3 // indirect
 	github.com/felixge/httpsnoop v1.0.4 // indirect
@@ -151,7 +151,7 @@ require (
 	github.com/go-logr/logr v1.4.2 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
-	github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
+	github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
 	github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect
 	github.com/google/uuid v1.6.0 // indirect
@@ -183,7 +183,7 @@ require (
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 	kernel.org/pub/linux/libs/security/libcap/psx v1.2.73 // indirect
 	sigs.k8s.io/yaml v1.4.0 // indirect
-	tags.cncf.io/container-device-interface/specs-go v0.8.0 // indirect
+	tags.cncf.io/container-device-interface/specs-go v1.0.0 // indirect
 )
 
 exclude (
diff --git a/go.sum b/go.sum
index d605d1a9d..c54dd46a8 100644
--- a/go.sum
+++ b/go.sum
@@ -144,12 +144,12 @@ github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi
 github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
 github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
 github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
-github.com/docker/cli v28.0.1+incompatible h1:g0h5NQNda3/CxIsaZfH4Tyf6vpxFth7PYl3hgCPOKzs=
-github.com/docker/cli v28.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
-github.com/docker/docker v28.0.1+incompatible h1:FCHjSRdXhNRFjlHMTv4jUNlIBbTeRjrWfeFuJp7jpo0=
-github.com/docker/docker v28.0.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
-github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
+github.com/docker/cli v28.0.4+incompatible h1:pBJSJeNd9QeIWPjRcV91RVJihd/TXB77q1ef64XEu4A=
+github.com/docker/cli v28.0.4+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/docker v28.0.4+incompatible h1:JNNkBctYKurkw6FrHfKqY0nKIDf5nrbxjVBtS+cdcok=
+github.com/docker/docker v28.0.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
+github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
 github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
 github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
 github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
@@ -185,8 +185,8 @@ github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeH
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
-github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
-github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
+github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
+github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
@@ -250,8 +250,8 @@ github.com/in-toto/in-toto-golang v0.5.0/go.mod h1:/Rq0IZHLV7Ku5gielPT4wPHJfH1Gd
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
-github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs=
-github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw=
+github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
+github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
 github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
@@ -288,8 +288,8 @@ github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7z
 github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
 github.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0=
 github.com/moby/sys/signal v0.7.1/go.mod h1:Se1VGehYokAkrSQwL4tDzHvETwUZlnY7S5XtQ50mQp8=
-github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
-github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
+github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=
+github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
 github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
 github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -308,8 +308,8 @@ github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
 github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
 github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
-github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
-github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
+github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
+github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
 github.com/opencontainers/runtime-spec v1.0.3-0.20220825212826-86290f6a00fb/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
 github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk=
 github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
@@ -393,10 +393,10 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
 github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
 github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
-github.com/tonistiigi/dchapes-mode v0.0.0-20241001053921-ca0759fec205 h1:eUk79E1w8yMtXeHSzjKorxuC8qJOnyXQnLaJehxpJaI=
-github.com/tonistiigi/dchapes-mode v0.0.0-20241001053921-ca0759fec205/go.mod h1:3Iuxbr0P7D3zUzBMAZB+ois3h/et0shEz0qApgHYGpY=
-github.com/tonistiigi/fsutil v0.0.0-20250227023350-13604323a291 h1:1WRvmYdTkwjgFIlnOwo6Y15BMwQBUQT423y1zHad4Eo=
-github.com/tonistiigi/fsutil v0.0.0-20250227023350-13604323a291/go.mod h1:Dl/9oEjK7IqnjAm21Okx/XIxUCFJzvh+XdVHUlBwXTw=
+github.com/tonistiigi/dchapes-mode v0.0.0-20250318174251-73d941a28323 h1:r0p7fK56l8WPequOaR3i9LBqfPtEdXIQbUTzT55iqT4=
+github.com/tonistiigi/dchapes-mode v0.0.0-20250318174251-73d941a28323/go.mod h1:3Iuxbr0P7D3zUzBMAZB+ois3h/et0shEz0qApgHYGpY=
+github.com/tonistiigi/fsutil v0.0.0-20250318190121-d73a4b3b8a7e h1:AiXT0JHwQA52AEOVMsxRytSI9mdJSie5gUp6OQ1R8fU=
+github.com/tonistiigi/fsutil v0.0.0-20250318190121-d73a4b3b8a7e/go.mod h1:BKdcez7BiVtBvIcef90ZPc6ebqIWr4JWD7+EvLm6J98=
 github.com/tonistiigi/go-actions-cache v0.0.0-20250228231703-3e9a6642607f h1:q/SWz3Bz0KtAsqaBo73CHVXjaz5O8PDnmD2JHVhgYnE=
 github.com/tonistiigi/go-actions-cache v0.0.0-20250228231703-3e9a6642607f/go.mod h1:h0oRlVs3NoFIHysRQ4rU1+RG4QmU0M2JVSwTYrB4igk=
 github.com/tonistiigi/go-archvariant v1.0.0 h1:5LC1eDWiBNflnTF1prCiX09yfNHIxDC/aukdhCdTyb0=
@@ -590,7 +590,7 @@ kernel.org/pub/linux/libs/security/libcap/psx v1.2.73/go.mod h1:+l6Ee2F59XiJ2I6W
 sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
 sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
 sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
-tags.cncf.io/container-device-interface v0.8.1 h1:c0jN4Mt6781jD67NdPajmZlD1qrqQyov/Xfoab37lj0=
-tags.cncf.io/container-device-interface v0.8.1/go.mod h1:Apb7N4VdILW0EVdEMRYXIDVRZfNJZ+kmEUss2kRRQ6Y=
-tags.cncf.io/container-device-interface/specs-go v0.8.0 h1:QYGFzGxvYK/ZLMrjhvY0RjpUavIn4KcmRmVP/JjdBTA=
-tags.cncf.io/container-device-interface/specs-go v0.8.0/go.mod h1:BhJIkjjPh4qpys+qm4DAYtUyryaTDg9zris+AczXyws=
+tags.cncf.io/container-device-interface v1.0.1 h1:KqQDr4vIlxwfYh0Ed/uJGVgX+CHAkahrgabg6Q8GYxc=
+tags.cncf.io/container-device-interface v1.0.1/go.mod h1:JojJIOeW3hNbcnOH2q0NrWNha/JuHoDZcmYxAZwb2i0=
+tags.cncf.io/container-device-interface/specs-go v1.0.0 h1:8gLw29hH1ZQP9K1YtAzpvkHCjjyIxHZYzBAvlQ+0vD8=
+tags.cncf.io/container-device-interface/specs-go v1.0.0/go.mod h1:u86hoFWqnh3hWz3esofRFKbI261bUlvUfLKGrDhJkgQ=
diff --git a/hack/dockerfiles/lint.Dockerfile b/hack/dockerfiles/lint.Dockerfile
index 44c827b3b..627e6f569 100644
--- a/hack/dockerfiles/lint.Dockerfile
+++ b/hack/dockerfiles/lint.Dockerfile
@@ -4,7 +4,8 @@ ARG GO_VERSION=1.23
 ARG ALPINE_VERSION=3.21
 ARG XX_VERSION=1.6.1
 ARG PROTOLINT_VERSION=0.50.5
-ARG GOLANGCI_LINT_VERSION=1.61.0
+ARG GOLANGCI_LINT_VERSION=v1.61.0
+ARG GOLANGCI_FROM_SOURCE=false
 # v0.31 requires go1.24
 ARG GOPLS_VERSION=v0.30.0
 # GOPLS_ANALYZERS defines gopls analyzers to be run. disabled by default: deprecated unusedvariable simplifyrange
@@ -14,11 +15,27 @@ FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine${ALPINE_VERSION} AS g
 FROM --platform=$BUILDPLATFORM yoheimuta/protolint:${PROTOLINT_VERSION} AS protolint-base
 FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
 
+
+FROM golang-base AS golangci-build
+WORKDIR /src
+ARG GOLANGCI_LINT_VERSION
+ADD https://github.com/golangci/golangci-lint.git#${GOLANGCI_LINT_VERSION} .
+RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/ go mod download
+RUN --mount=type=cache,target=/go/pkg/mod --mount=type=cache,target=/root/.cache/ mkdir -p out && go build -o /out/golangci-lint ./cmd/golangci-lint
+
+
+FROM scratch AS golangci-binary-false
+FROM scratch AS golangci-binary-true
+COPY --from=golangci-build /out/golangci-lint golangci-lint
+FROM golangci-binary-${GOLANGCI_FROM_SOURCE} AS golangci-binary
+
 FROM golang-base AS base
 ENV GOFLAGS="-buildvcs=false"
-ARG GOLANGCI_LINT_VERSION
 RUN apk add --no-cache gcc musl-dev yamllint
-RUN wget -O- -nv https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v${GOLANGCI_LINT_VERSION}
+ARG GOLANGCI_LINT_VERSION
+ARG GOLANGCI_FROM_SOURCE
+COPY --link --from=golangci-binary / /usr/bin/
+RUN [ "${GOLANGCI_FROM_SOURCE}" = "true" ] && exit 0; wget -O- -nv https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s ${GOLANGCI_LINT_VERSION}
 COPY --link --from=protolint-base /usr/local/bin/protolint /usr/local/bin/protolint
 COPY --link --from=xx / /
 WORKDIR /go/src/github.com/moby/buildkit
@@ -34,11 +51,17 @@ RUN --mount=target=/go/src/github.com/moby/buildkit \
   touch /golangci-lint.done
   
 
-FROM base AS golangci-verify
+FROM base AS golangci-verify-false
 RUN --mount=target=/go/src/github.com/moby/buildkit \
   golangci-lint config verify && \
   touch /golangci-verify.done
 
+FROM scratch AS golangci-verify-true
+COPY <<EOF /golangci-verify.done
+EOF
+
+FROM golangci-verify-${GOLANGCI_FROM_SOURCE} AS golangci-verify
+
 FROM base AS yamllint
 RUN --mount=target=/go/src/github.com/moby/buildkit \
   yamllint -c .yamllint.yml --strict . && \
diff --git a/session/auth/authprovider/authprovider.go b/session/auth/authprovider/authprovider.go
index 0280e96dc..54e458e53 100644
--- a/session/auth/authprovider/authprovider.go
+++ b/session/auth/authprovider/authprovider.go
@@ -45,7 +45,7 @@ type DockerAuthProviderConfig struct {
 	TLSConfigs map[string]*AuthTLSConfig
 	// ExpireCachedAuth is a function that returns true auth config should be refreshed
 	// instead of using a pre-cached result.
-	// If nil then the cached result will expire after 10 minutes.
+	// If nil then the cached result will expire after 4 minutes and 50 seconds.
 	// The function is called with the time the cached auth config was created
 	// and the server URL the auth config is for.
 	ExpireCachedAuth func(created time.Time, serverURL string) bool
@@ -59,7 +59,8 @@ type authConfigCacheEntry struct {
 func NewDockerAuthProvider(cfg DockerAuthProviderConfig) session.Attachable {
 	if cfg.ExpireCachedAuth == nil {
 		cfg.ExpireCachedAuth = func(created time.Time, _ string) bool {
-			return time.Since(created) > 10*time.Minute
+			// Tokens for Google Artifact Registry via Workload Identity expire after 5 minutes.
+			return time.Since(created) > 4*time.Minute+50*time.Second
 		}
 	}
 	return &authProvider{
diff --git a/snapshot/containerd/snapshotter.go b/snapshot/containerd/snapshotter.go
index 12ff1b1da..50b818bb3 100644
--- a/snapshot/containerd/snapshotter.go
+++ b/snapshot/containerd/snapshotter.go
@@ -6,12 +6,12 @@ import (
 	"github.com/containerd/containerd/v2/core/mount"
 	"github.com/containerd/containerd/v2/core/snapshots"
 	"github.com/containerd/containerd/v2/pkg/namespaces"
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/moby/buildkit/snapshot"
+	"github.com/moby/sys/user"
 	"github.com/pkg/errors"
 )
 
-func NewSnapshotter(name string, snapshotter snapshots.Snapshotter, ns string, idmap *idtools.IdentityMapping) snapshot.Snapshotter {
+func NewSnapshotter(name string, snapshotter snapshots.Snapshotter, ns string, idmap *user.IdentityMapping) snapshot.Snapshotter {
 	return snapshot.FromContainerdSnapshotter(name, &nsSnapshotter{ns, snapshotter}, idmap)
 }
 
@@ -38,25 +38,31 @@ func (s *nsSnapshotter) Usage(ctx context.Context, key string) (snapshots.Usage,
 	ctx = namespaces.WithNamespace(ctx, s.ns)
 	return s.Snapshotter.Usage(ctx, key)
 }
+
 func (s *nsSnapshotter) Mounts(ctx context.Context, key string) ([]mount.Mount, error) {
 	ctx = namespaces.WithNamespace(ctx, s.ns)
 	return s.Snapshotter.Mounts(ctx, key)
 }
+
 func (s *nsSnapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) {
 	ctx = namespaces.WithNamespace(ctx, s.ns)
 	return s.Snapshotter.Prepare(ctx, key, parent, opts...)
 }
+
 func (s *nsSnapshotter) View(ctx context.Context, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) {
 	ctx = namespaces.WithNamespace(ctx, s.ns)
 	return s.Snapshotter.View(ctx, key, parent, opts...)
 }
+
 func (s *nsSnapshotter) Commit(ctx context.Context, name, key string, opts ...snapshots.Opt) error {
 	ctx = namespaces.WithNamespace(ctx, s.ns)
 	return s.Snapshotter.Commit(ctx, name, key, opts...)
 }
+
 func (s *nsSnapshotter) Remove(ctx context.Context, key string) error {
 	return errors.Errorf("calling snapshotter.Remove is forbidden")
 }
+
 func (s *nsSnapshotter) Walk(ctx context.Context, fn snapshots.WalkFunc, filters ...string) error {
 	ctx = namespaces.WithNamespace(ctx, s.ns)
 	return s.Snapshotter.Walk(ctx, fn, filters...)
diff --git a/snapshot/localmounter_windows.go b/snapshot/localmounter_windows.go
index 783545f22..0bb4df884 100644
--- a/snapshot/localmounter_windows.go
+++ b/snapshot/localmounter_windows.go
@@ -2,6 +2,8 @@ package snapshot
 
 import (
 	"os"
+	"strings"
+	"time"
 
 	"github.com/Microsoft/go-winio/pkg/bindfilter"
 	"github.com/containerd/containerd/v2/core/mount"
@@ -46,11 +48,15 @@ func (lm *localMounter) Mount() (string, error) {
 		// The Windows snapshotter does not have any notion of bind mounts. We emulate
 		// bind mounts here using the bind filter.
 		if err := bindfilter.ApplyFileBinding(dir, m.Source, m.ReadOnly()); err != nil {
-			return "", errors.Wrapf(err, "failed to mount %v: %+v", m, err)
+			return "", errors.Wrapf(err, "failed to mount %v", m)
 		}
 	} else {
-		if err := m.Mount(dir); err != nil {
-			return "", errors.Wrapf(err, "failed to mount %v: %+v", m, err)
+		// see https://github.com/moby/buildkit/issues/5807
+		// if it's a race condition issue, do max 2 retries with some backoff
+		// should adjust the retries if this persists but 1 retry
+		// seems to be enough.
+		if err := mountWithRetries(m, dir, 2); err != nil {
+			return "", errors.Wrapf(err, "failed to mount %v", m)
 		}
 	}
 
@@ -58,6 +64,27 @@ func (lm *localMounter) Mount() (string, error) {
 	return lm.target, nil
 }
 
+func mountWithRetries(m mount.Mount, dir string, retries int) error {
+	errStr := "cannot access the file because it is being used by another process"
+	backoff := 30 * time.Millisecond
+	var err error
+
+	for i := range retries + 1 {
+		// i = 0 is first call and not a retry
+		err = m.Mount(dir)
+		if err == nil || i == retries {
+			return err
+		}
+		if strings.Contains(err.Error(), errStr) {
+			time.Sleep(time.Duration(i+1) * backoff)
+		} else {
+			return err
+		}
+	}
+
+	return err
+}
+
 func (lm *localMounter) Unmount() error {
 	lm.mu.Lock()
 	defer lm.mu.Unlock()
diff --git a/snapshot/snapshotter.go b/snapshot/snapshotter.go
index fde9957fc..14ee0e3f9 100644
--- a/snapshot/snapshotter.go
+++ b/snapshot/snapshotter.go
@@ -8,8 +8,8 @@ import (
 
 	"github.com/containerd/containerd/v2/core/mount"
 	"github.com/containerd/containerd/v2/core/snapshots"
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/moby/buildkit/executor"
+	"github.com/moby/sys/user"
 	"github.com/moby/sys/userns"
 	"github.com/pkg/errors"
 )
@@ -30,17 +30,17 @@ type Snapshotter interface {
 	Remove(ctx context.Context, key string) error
 	Walk(ctx context.Context, fn snapshots.WalkFunc, filters ...string) error
 	Close() error
-	IdentityMapping() *idtools.IdentityMapping
+	IdentityMapping() *user.IdentityMapping
 }
 
-func FromContainerdSnapshotter(name string, s snapshots.Snapshotter, idmap *idtools.IdentityMapping) Snapshotter {
+func FromContainerdSnapshotter(name string, s snapshots.Snapshotter, idmap *user.IdentityMapping) Snapshotter {
 	return &fromContainerd{name: name, Snapshotter: s, idmap: idmap}
 }
 
 type fromContainerd struct {
 	name string
 	snapshots.Snapshotter
-	idmap *idtools.IdentityMapping
+	idmap *user.IdentityMapping
 }
 
 func (s *fromContainerd) Name() string {
@@ -59,6 +59,7 @@ func (s *fromContainerd) Prepare(ctx context.Context, key, parent string, opts .
 	_, err := s.Snapshotter.Prepare(ctx, key, parent, opts...)
 	return err
 }
+
 func (s *fromContainerd) View(ctx context.Context, key, parent string, opts ...snapshots.Opt) (Mountable, error) {
 	mounts, err := s.Snapshotter.View(ctx, key, parent, opts...)
 	if err != nil {
@@ -66,7 +67,8 @@ func (s *fromContainerd) View(ctx context.Context, key, parent string, opts ...s
 	}
 	return &staticMountable{mounts: mounts, idmap: s.idmap, id: key}, nil
 }
-func (s *fromContainerd) IdentityMapping() *idtools.IdentityMapping {
+
+func (s *fromContainerd) IdentityMapping() *user.IdentityMapping {
 	return s.idmap
 }
 
@@ -132,6 +134,7 @@ func (cs *containerdSnapshotter) Prepare(ctx context.Context, key, parent string
 	}
 	return cs.Mounts(ctx, key)
 }
+
 func (cs *containerdSnapshotter) View(ctx context.Context, key, parent string, opts ...snapshots.Opt) ([]mount.Mount, error) {
 	mf, err := cs.Snapshotter.View(ctx, key, parent, opts...)
 	if err != nil {
@@ -140,8 +143,10 @@ func (cs *containerdSnapshotter) View(ctx context.Context, key, parent string, o
 	return cs.returnMounts(mf)
 }
 
-var redirectDirOption string
-var redirectDirOptionOnce sync.Once
+var (
+	redirectDirOption     string
+	redirectDirOptionOnce sync.Once
+)
 
 func getRedirectDirOption() string {
 	redirectDirOptionOnce.Do(func() {
diff --git a/snapshot/staticmountable.go b/snapshot/staticmountable.go
index 098146824..65845667b 100644
--- a/snapshot/staticmountable.go
+++ b/snapshot/staticmountable.go
@@ -5,14 +5,14 @@ import (
 	"sync/atomic"
 
 	"github.com/containerd/containerd/v2/core/mount"
-	"github.com/docker/docker/pkg/idtools"
+	"github.com/moby/sys/user"
 )
 
 type staticMountable struct {
 	count  int32
 	id     string
 	mounts []mount.Mount
-	idmap  *idtools.IdentityMapping
+	idmap  *user.IdentityMapping
 }
 
 func (cm *staticMountable) Mount() ([]mount.Mount, func() error, error) {
@@ -36,6 +36,6 @@ func (cm *staticMountable) Mount() ([]mount.Mount, func() error, error) {
 	}, nil
 }
 
-func (cm *staticMountable) IdentityMapping() *idtools.IdentityMapping {
+func (cm *staticMountable) IdentityMapping() *user.IdentityMapping {
 	return cm.idmap
 }
diff --git a/solver/cachekey.go b/solver/cachekey.go
index 8c5ec92de..1f34467b8 100644
--- a/solver/cachekey.go
+++ b/solver/cachekey.go
@@ -1,6 +1,7 @@
 package solver
 
 import (
+	"maps"
 	"slices"
 	"sync"
 
@@ -101,9 +102,7 @@ func (ck *CacheKey) clone() *CacheKey {
 		output: ck.output,
 		ids:    make(map[*cacheManager]string, len(ck.ids)),
 	}
-	for cm, id := range ck.ids {
-		nk.ids[cm] = id
-	}
+	maps.Copy(nk.ids, ck.ids)
 	ck.mu.RUnlock()
 	return nk
 }
diff --git a/solver/jobs.go b/solver/jobs.go
index 6e3150420..030eef03c 100644
--- a/solver/jobs.go
+++ b/solver/jobs.go
@@ -3,6 +3,7 @@ package solver
 import (
 	"context"
 	"fmt"
+	"maps"
 	"sync"
 	"time"
 
@@ -568,9 +569,7 @@ func (jl *Solver) loadUnlocked(ctx context.Context, v, parent Vertex, j *Job, ca
 			}
 			parentState.childVtx[dgst] = struct{}{}
 
-			for id, c := range parentState.cache {
-				st.cache[id] = c
-			}
+			maps.Copy(st.cache, parentState.cache)
 		}
 	}
 
diff --git a/solver/llbsolver/cdidevices/manager.go b/solver/llbsolver/cdidevices/manager.go
index 673c823f2..274c6a40d 100644
--- a/solver/llbsolver/cdidevices/manager.go
+++ b/solver/llbsolver/cdidevices/manager.go
@@ -2,6 +2,7 @@ package cdidevices
 
 import (
 	"context"
+	"maps"
 	"strconv"
 	"strings"
 
@@ -268,13 +269,9 @@ func deviceAnnotations(dev *cdi.Device) map[string]string {
 	}
 	out := make(map[string]string)
 	// spec annotations
-	for k, v := range dev.GetSpec().Annotations {
-		out[k] = v
-	}
+	maps.Copy(out, dev.GetSpec().Annotations)
 	// device annotations
-	for k, v := range dev.Device.Annotations {
-		out[k] = v
-	}
+	maps.Copy(out, dev.Device.Annotations)
 	return out
 }
 
diff --git a/solver/llbsolver/file/backend.go b/solver/llbsolver/file/backend.go
index ad7ac8fd5..61550b84f 100644
--- a/solver/llbsolver/file/backend.go
+++ b/solver/llbsolver/file/backend.go
@@ -9,10 +9,10 @@ import (
 	"time"
 
 	"github.com/containerd/continuity/fs"
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/moby/buildkit/snapshot"
 	"github.com/moby/buildkit/solver/llbsolver/ops/fileoptypes"
 	"github.com/moby/buildkit/solver/pb"
+	"github.com/moby/sys/user"
 	"github.com/pkg/errors"
 	copy "github.com/tonistiigi/fsutil/copy"
 )
@@ -25,7 +25,7 @@ func timestampToTime(ts int64) *time.Time {
 	return &tm
 }
 
-func mkdir(d string, action *pb.FileActionMkDir, user *copy.User, idmap *idtools.IdentityMapping) (err error) {
+func mkdir(d string, action *pb.FileActionMkDir, user *copy.User, idmap *user.IdentityMapping) (err error) {
 	defer func() {
 		var osErr *os.PathError
 		if errors.As(err, &osErr) {
@@ -65,7 +65,7 @@ func mkdir(d string, action *pb.FileActionMkDir, user *copy.User, idmap *idtools
 	return nil
 }
 
-func symlink(d string, action *pb.FileActionSymlink, user *copy.User, idmap *idtools.IdentityMapping) (err error) {
+func symlink(d string, action *pb.FileActionSymlink, user *copy.User, idmap *user.IdentityMapping) (err error) {
 	defer func() {
 		var osErr *os.PathError
 		if errors.As(err, &osErr) {
@@ -99,7 +99,7 @@ func symlink(d string, action *pb.FileActionSymlink, user *copy.User, idmap *idt
 	return nil
 }
 
-func mkfile(d string, action *pb.FileActionMkFile, user *copy.User, idmap *idtools.IdentityMapping) (err error) {
+func mkfile(d string, action *pb.FileActionMkFile, user *copy.User, idmap *user.IdentityMapping) (err error) {
 	defer func() {
 		var osErr *os.PathError
 		if errors.As(err, &osErr) {
@@ -184,7 +184,7 @@ func rmPath(root, src string, allowNotFound bool) error {
 	return errors.WithStack(os.RemoveAll(p))
 }
 
-func docopy(ctx context.Context, src, dest string, action *pb.FileActionCopy, u *copy.User, idmap *idtools.IdentityMapping) (err error) {
+func docopy(ctx context.Context, src, dest string, action *pb.FileActionCopy, u *copy.User, idmap *user.IdentityMapping) (err error) {
 	srcPath := cleanPath(action.Src)
 	destPath := cleanPath(action.Dest)
 
diff --git a/solver/llbsolver/file/backend_unix.go b/solver/llbsolver/file/backend_unix.go
index f515d7db6..7014f7343 100644
--- a/solver/llbsolver/file/backend_unix.go
+++ b/solver/llbsolver/file/backend_unix.go
@@ -3,12 +3,12 @@
 package file
 
 import (
-	"github.com/docker/docker/pkg/idtools"
+	"github.com/moby/sys/user"
 	"github.com/pkg/errors"
 	copy "github.com/tonistiigi/fsutil/copy"
 )
 
-func mapUserToChowner(user *copy.User, idmap *idtools.IdentityMapping) (copy.Chowner, error) {
+func mapUserToChowner(user *copy.User, idmap *user.IdentityMapping) (copy.Chowner, error) {
 	if user == nil {
 		return func(old *copy.User) (*copy.User, error) {
 			if old == nil {
@@ -18,14 +18,11 @@ func mapUserToChowner(user *copy.User, idmap *idtools.IdentityMapping) (copy.Cho
 				old = &copy.User{} // root
 				// non-nil old is already mapped
 				if idmap != nil {
-					identity, err := idmap.ToHost(idtools.Identity{
-						UID: old.UID,
-						GID: old.GID,
-					})
+					uid, gid, err := idmap.ToHost(old.UID, old.GID)
 					if err != nil {
 						return nil, errors.WithStack(err)
 					}
-					return &copy.User{UID: identity.UID, GID: identity.GID}, nil
+					return &copy.User{UID: uid, GID: gid}, nil
 				}
 			}
 			return old, nil
@@ -33,15 +30,12 @@ func mapUserToChowner(user *copy.User, idmap *idtools.IdentityMapping) (copy.Cho
 	}
 	u := *user
 	if idmap != nil {
-		identity, err := idmap.ToHost(idtools.Identity{
-			UID: user.UID,
-			GID: user.GID,
-		})
+		uid, gid, err := idmap.ToHost(user.UID, user.GID)
 		if err != nil {
 			return nil, errors.WithStack(err)
 		}
-		u.UID = identity.UID
-		u.GID = identity.GID
+		u.UID = uid
+		u.GID = gid
 	}
 	return func(*copy.User) (*copy.User, error) {
 		return &u, nil
diff --git a/solver/llbsolver/file/backend_windows.go b/solver/llbsolver/file/backend_windows.go
index 70c1ba147..d35080be0 100644
--- a/solver/llbsolver/file/backend_windows.go
+++ b/solver/llbsolver/file/backend_windows.go
@@ -1,16 +1,17 @@
 package file
 
 import (
-	"github.com/docker/docker/pkg/idtools"
+	"github.com/moby/buildkit/util/windows"
+	"github.com/moby/sys/user"
 	copy "github.com/tonistiigi/fsutil/copy"
 )
 
-func mapUserToChowner(user *copy.User, _ *idtools.IdentityMapping) (copy.Chowner, error) {
+func mapUserToChowner(user *copy.User, _ *user.IdentityMapping) (copy.Chowner, error) {
 	if user == nil || user.SID == "" {
 		return func(old *copy.User) (*copy.User, error) {
 			if old == nil || old.SID == "" {
 				old = &copy.User{
-					SID: idtools.ContainerAdministratorSidString,
+					SID: windows.ContainerAdministratorSidString,
 				}
 			}
 			return old, nil
diff --git a/solver/llbsolver/file/unpack.go b/solver/llbsolver/file/unpack.go
index ff167e324..33bbd23af 100644
--- a/solver/llbsolver/file/unpack.go
+++ b/solver/llbsolver/file/unpack.go
@@ -9,10 +9,11 @@ import (
 	"github.com/docker/docker/pkg/archive"
 	"github.com/docker/docker/pkg/chrootarchive"
 	"github.com/docker/docker/pkg/idtools"
+	"github.com/moby/sys/user"
 	copy "github.com/tonistiigi/fsutil/copy"
 )
 
-func unpack(srcRoot string, src string, destRoot string, dest string, ch copy.Chowner, tm *time.Time, idmap *idtools.IdentityMapping) (bool, error) {
+func unpack(srcRoot string, src string, destRoot string, dest string, ch copy.Chowner, tm *time.Time, idmap *user.IdentityMapping) (bool, error) {
 	src, err := fs.RootPath(srcRoot, src)
 	if err != nil {
 		return false, err
@@ -39,7 +40,23 @@ func unpack(srcRoot string, src string, destRoot string, dest string, ch copy.Ch
 		BestEffortXattrs: true,
 	}
 	if idmap != nil {
-		opts.IDMap = *idmap
+		// TODO: chrootarchive should be moved into moby/sys like idtools
+		// was moved into moby/sys/user. This section can be removed
+		// when chrootarchive accepts moby/sys/user arguments.
+		for _, uid := range idmap.UIDMaps {
+			opts.IDMap.UIDMaps = append(opts.IDMap.UIDMaps, idtools.IDMap{
+				ContainerID: int(uid.ID),
+				HostID:      int(uid.ParentID),
+				Size:        int(uid.Count),
+			})
+		}
+		for _, gid := range idmap.GIDMaps {
+			opts.IDMap.GIDMaps = append(opts.IDMap.GIDMaps, idtools.IDMap{
+				ContainerID: int(gid.ID),
+				HostID:      int(gid.ParentID),
+				Size:        int(gid.Count),
+			})
+		}
 	}
 	return true, chrootarchive.Untar(file, dest, opts)
 }
diff --git a/solver/llbsolver/mounts/mount.go b/solver/llbsolver/mounts/mount.go
index 92b103458..93d97a907 100644
--- a/solver/llbsolver/mounts/mount.go
+++ b/solver/llbsolver/mounts/mount.go
@@ -9,10 +9,7 @@ import (
 	"sync"
 	"time"
 
-	"github.com/moby/buildkit/util/bklog"
-
 	"github.com/containerd/containerd/v2/core/mount"
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/moby/buildkit/cache"
 	"github.com/moby/buildkit/client"
 	"github.com/moby/buildkit/identity"
@@ -21,8 +18,10 @@ import (
 	"github.com/moby/buildkit/session/sshforward"
 	"github.com/moby/buildkit/snapshot"
 	"github.com/moby/buildkit/solver/pb"
+	"github.com/moby/buildkit/util/bklog"
 	"github.com/moby/buildkit/util/grpcerrors"
 	"github.com/moby/locker"
+	"github.com/moby/sys/user"
 	"github.com/moby/sys/userns"
 	"github.com/pkg/errors"
 	"google.golang.org/grpc/codes"
@@ -187,7 +186,7 @@ func (mm *MountManager) getSSHMountable(ctx context.Context, m *pb.Mount, g sess
 type sshMount struct {
 	mount  *pb.Mount
 	caller session.Caller
-	idmap  *idtools.IdentityMapping
+	idmap  *user.IdentityMapping
 }
 
 func (sm *sshMount) Mount(ctx context.Context, readonly bool, g session.Group) (snapshot.Mountable, error) {
@@ -196,7 +195,7 @@ func (sm *sshMount) Mount(ctx context.Context, readonly bool, g session.Group) (
 
 type sshMountInstance struct {
 	sm    *sshMount
-	idmap *idtools.IdentityMapping
+	idmap *user.IdentityMapping
 }
 
 func (sm *sshMountInstance) Mount() ([]mount.Mount, func() error, error) {
@@ -206,16 +205,12 @@ func (sm *sshMountInstance) Mount() ([]mount.Mount, func() error, error) {
 	gid := int(sm.sm.mount.SSHOpt.Gid)
 
 	if sm.idmap != nil {
-		identity, err := sm.idmap.ToHost(idtools.Identity{
-			UID: uid,
-			GID: gid,
-		})
+		var err error
+		uid, gid, err = sm.idmap.ToHost(uid, gid)
 		if err != nil {
 			cancel(err)
 			return nil, nil, err
 		}
-		uid = identity.UID
-		gid = identity.GID
 	}
 
 	sock, cleanup, err := sshforward.MountSSHSocket(ctx, sm.sm.caller, sshforward.SocketOpt{
@@ -244,7 +239,7 @@ func (sm *sshMountInstance) Mount() ([]mount.Mount, func() error, error) {
 	}}, release, nil
 }
 
-func (sm *sshMountInstance) IdentityMapping() *idtools.IdentityMapping {
+func (sm *sshMountInstance) IdentityMapping() *user.IdentityMapping {
 	return sm.idmap
 }
 
@@ -278,7 +273,7 @@ func (mm *MountManager) getSecretMountable(ctx context.Context, m *pb.Mount, g s
 type secretMount struct {
 	mount *pb.Mount
 	data  []byte
-	idmap *idtools.IdentityMapping
+	idmap *user.IdentityMapping
 }
 
 func (sm *secretMount) Mount(ctx context.Context, readonly bool, g session.Group) (snapshot.Mountable, error) {
@@ -288,7 +283,7 @@ func (sm *secretMount) Mount(ctx context.Context, readonly bool, g session.Group
 type secretMountInstance struct {
 	sm    *secretMount
 	root  string
-	idmap *idtools.IdentityMapping
+	idmap *user.IdentityMapping
 }
 
 func (sm *secretMountInstance) Mount() ([]mount.Mount, func() error, error) {
@@ -344,16 +339,11 @@ func (sm *secretMountInstance) Mount() ([]mount.Mount, func() error, error) {
 	gid := int(sm.sm.mount.SecretOpt.Gid)
 
 	if sm.idmap != nil {
-		identity, err := sm.idmap.ToHost(idtools.Identity{
-			UID: uid,
-			GID: gid,
-		})
+		uid, gid, err = sm.idmap.ToHost(uid, gid)
 		if err != nil {
 			cleanup()
 			return nil, nil, err
 		}
-		uid = identity.UID
-		gid = identity.GID
 	}
 
 	if err := os.Chown(fp, uid, gid); err != nil {
@@ -373,7 +363,7 @@ func (sm *secretMountInstance) Mount() ([]mount.Mount, func() error, error) {
 	}}, cleanup, nil
 }
 
-func (sm *secretMountInstance) IdentityMapping() *idtools.IdentityMapping {
+func (sm *secretMountInstance) IdentityMapping() *user.IdentityMapping {
 	return sm.idmap
 }
 
@@ -396,12 +386,12 @@ func (mm *MountManager) MountableSSH(ctx context.Context, m *pb.Mount, g session
 	return mm.getSSHMountable(ctx, m, g)
 }
 
-func newTmpfs(idmap *idtools.IdentityMapping, opt *pb.TmpfsOpt) cache.Mountable {
+func newTmpfs(idmap *user.IdentityMapping, opt *pb.TmpfsOpt) cache.Mountable {
 	return &tmpfs{idmap: idmap, opt: opt}
 }
 
 type tmpfs struct {
-	idmap *idtools.IdentityMapping
+	idmap *user.IdentityMapping
 	opt   *pb.TmpfsOpt
 }
 
@@ -411,7 +401,7 @@ func (f *tmpfs) Mount(ctx context.Context, readonly bool, g session.Group) (snap
 
 type tmpfsMount struct {
 	readonly bool
-	idmap    *idtools.IdentityMapping
+	idmap    *user.IdentityMapping
 	opt      *pb.TmpfsOpt
 }
 
@@ -432,7 +422,7 @@ func (m *tmpfsMount) Mount() ([]mount.Mount, func() error, error) {
 	}}, func() error { return nil }, nil
 }
 
-func (m *tmpfsMount) IdentityMapping() *idtools.IdentityMapping {
+func (m *tmpfsMount) IdentityMapping() *user.IdentityMapping {
 	return m.idmap
 }
 
diff --git a/solver/llbsolver/ops/exec_binfmt.go b/solver/llbsolver/ops/exec_binfmt.go
index 9b410d4b8..6b9f82463 100644
--- a/solver/llbsolver/ops/exec_binfmt.go
+++ b/solver/llbsolver/ops/exec_binfmt.go
@@ -9,11 +9,11 @@ import (
 
 	"github.com/containerd/containerd/v2/core/mount"
 	"github.com/containerd/platforms"
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/moby/buildkit/snapshot"
 	"github.com/moby/buildkit/solver/pb"
 	"github.com/moby/buildkit/util/archutil"
 	"github.com/moby/buildkit/util/bklog"
+	"github.com/moby/sys/user"
 	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 	copy "github.com/tonistiigi/fsutil/copy"
@@ -33,7 +33,7 @@ var qemuArchMap = map[string]string{
 
 type emulator struct {
 	path  string
-	idmap *idtools.IdentityMapping
+	idmap *user.IdentityMapping
 }
 
 func (e *emulator) Mount(ctx context.Context, readonly bool) (snapshot.Mountable, error) {
@@ -42,7 +42,7 @@ func (e *emulator) Mount(ctx context.Context, readonly bool) (snapshot.Mountable
 
 type staticEmulatorMount struct {
 	path  string
-	idmap *idtools.IdentityMapping
+	idmap *user.IdentityMapping
 }
 
 func (m *staticEmulatorMount) Mount() ([]mount.Mount, func() error, error) {
@@ -59,9 +59,7 @@ func (m *staticEmulatorMount) Mount() ([]mount.Mount, func() error, error) {
 
 	var uid, gid int
 	if m.idmap != nil {
-		root := m.idmap.RootPair()
-		uid = root.UID
-		gid = root.GID
+		uid, gid = m.idmap.RootPair()
 	}
 	if err := copy.Copy(context.TODO(), filepath.Dir(m.path), filepath.Base(m.path), tmpdir, qemuMountName, func(ci *copy.CopyInfo) {
 		m := 0555
@@ -80,7 +78,7 @@ func (m *staticEmulatorMount) Mount() ([]mount.Mount, func() error, error) {
 		}, nil
 }
 
-func (m *staticEmulatorMount) IdentityMapping() *idtools.IdentityMapping {
+func (m *staticEmulatorMount) IdentityMapping() *user.IdentityMapping {
 	return m.idmap
 }
 
diff --git a/solver/llbsolver/ops/user_windows.go b/solver/llbsolver/ops/user_windows.go
index 1164a8fdb..732b340f3 100644
--- a/solver/llbsolver/ops/user_windows.go
+++ b/solver/llbsolver/ops/user_windows.go
@@ -3,7 +3,6 @@ package ops
 import (
 	"context"
 
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/moby/buildkit/snapshot"
 	"github.com/moby/buildkit/solver/pb"
 	"github.com/moby/buildkit/util/windows"
@@ -35,14 +34,14 @@ func readUser(chopt *pb.ChownOpt, mu, _ snapshot.Mountable, worker worker.Worker
 				return nil, err
 			}
 			defer release()
-			ident, err := windows.ResolveUsernameToSID(context.Background(), worker.Executor(), rootMounts, u.ByName.Name)
+			sid, err := windows.ResolveUsernameToSID(context.Background(), worker.Executor(), rootMounts, u.ByName.Name)
 			if err != nil {
 				return nil, err
 			}
-			return &copy.User{SID: ident.SID}, nil
+			return &copy.User{SID: sid}, nil
 		default:
-			return &copy.User{SID: idtools.ContainerAdministratorSidString}, nil
+			return &copy.User{SID: windows.ContainerAdministratorSidString}, nil
 		}
 	}
-	return &copy.User{SID: idtools.ContainerAdministratorSidString}, nil
+	return &copy.User{SID: windows.ContainerAdministratorSidString}, nil
 }
diff --git a/solver/llbsolver/vertex.go b/solver/llbsolver/vertex.go
index d2973d9dd..c80345403 100644
--- a/solver/llbsolver/vertex.go
+++ b/solver/llbsolver/vertex.go
@@ -136,6 +136,11 @@ func ValidateEntitlements(ent entitlements.Set, cdiManager *cdidevices.Manager)
 
 				var allowedDevices []*pb.CDIDevice
 				var nonAliasedDevices []*pb.CDIDevice
+				for _, d := range cdiManager.ListDevices() {
+					if d.OnDemand && d.AutoAllow {
+						allowedDevices = append(allowedDevices, &pb.CDIDevice{Name: d.Name})
+					}
+				}
 				if cfg != nil {
 					for _, d := range op.Exec.CdiDevices {
 						if newName, ok := cfg.Devices[d.Name]; ok && newName != "" {
diff --git a/source/git/source.go b/source/git/source.go
index db07e7788..acba38551 100644
--- a/source/git/source.go
+++ b/source/git/source.go
@@ -641,9 +641,9 @@ func (gs *gitSourceHandler) Snapshot(ctx context.Context, g session.Group) (out
 	}
 
 	if idmap := mount.IdentityMapping(); idmap != nil {
-		u := idmap.RootPair()
+		uid, gid := idmap.RootPair()
 		err := filepath.WalkDir(gitDir, func(p string, _ os.DirEntry, _ error) error {
-			return os.Lchown(p, u.UID, u.GID)
+			return os.Lchown(p, uid, gid)
 		})
 		if err != nil {
 			return nil, errors.Wrap(err, "failed to remap git checkout")
@@ -749,10 +749,12 @@ func getDefaultBranch(ctx context.Context, git *gitutil.GitCLI, remoteURL string
 	return ss[0][1], nil
 }
 
-const keyGitRemote = "git-remote"
-const gitRemoteIndex = keyGitRemote + "::"
-const keyGitSnapshot = "git-snapshot"
-const gitSnapshotIndex = keyGitSnapshot + "::"
+const (
+	keyGitRemote     = "git-remote"
+	gitRemoteIndex   = keyGitRemote + "::"
+	keyGitSnapshot   = "git-snapshot"
+	gitSnapshotIndex = keyGitSnapshot + "::"
+)
 
 func search(ctx context.Context, store cache.MetadataStore, key string, idx string) ([]cacheRefMetadata, error) {
 	var results []cacheRefMetadata
diff --git a/source/http/source.go b/source/http/source.go
index 130339fcc..819a71812 100644
--- a/source/http/source.go
+++ b/source/http/source.go
@@ -19,7 +19,6 @@ import (
 	"strings"
 	"time"
 
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/moby/buildkit/cache"
 	"github.com/moby/buildkit/session"
 	"github.com/moby/buildkit/session/secrets"
@@ -399,15 +398,10 @@ func (hs *httpSourceHandler) save(ctx context.Context, resp *http.Response, s se
 	uid := hs.src.UID
 	gid := hs.src.GID
 	if idmap := mount.IdentityMapping(); idmap != nil {
-		identity, err := idmap.ToHost(idtools.Identity{
-			UID: int(uid),
-			GID: int(gid),
-		})
+		uid, gid, err = idmap.ToHost(int(uid), int(gid))
 		if err != nil {
 			return nil, "", err
 		}
-		uid = identity.UID
-		gid = identity.GID
 	}
 
 	if gid != 0 || uid != 0 {
@@ -523,7 +517,6 @@ func (hs *httpSourceHandler) newHTTPRequest(ctx context.Context, g session.Group
 
 			return nil
 		})
-
 		if err != nil {
 			return nil, errors.Wrapf(err, "failed to retrieve HTTP auth secret %s", hs.src.AuthHeaderSecret)
 		}
@@ -572,9 +565,11 @@ type cacheRefMetadata struct {
 	cache.RefMetadata
 }
 
-const keyHTTPChecksum = "http.checksum"
-const keyETag = "etag"
-const keyModTime = "http.modtime"
+const (
+	keyHTTPChecksum = "http.checksum"
+	keyETag         = "etag"
+	keyModTime      = "http.modtime"
+)
 
 func (md cacheRefMetadata) getHTTPChecksum() digest.Digest {
 	return digest.Digest(md.GetString(keyHTTPChecksum))
diff --git a/source/local/source.go b/source/local/source.go
index 28a6f7aff..5f6485a66 100644
--- a/source/local/source.go
+++ b/source/local/source.go
@@ -7,11 +7,6 @@ import (
 	"strings"
 	"time"
 
-	"github.com/moby/buildkit/solver/pb"
-	srctypes "github.com/moby/buildkit/source/types"
-	"github.com/moby/buildkit/util/bklog"
-
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/moby/buildkit/cache"
 	"github.com/moby/buildkit/cache/contenthash"
 	"github.com/moby/buildkit/client"
@@ -19,8 +14,12 @@ import (
 	"github.com/moby/buildkit/session/filesync"
 	"github.com/moby/buildkit/snapshot"
 	"github.com/moby/buildkit/solver"
+	"github.com/moby/buildkit/solver/pb"
 	"github.com/moby/buildkit/source"
+	srctypes "github.com/moby/buildkit/source/types"
+	"github.com/moby/buildkit/util/bklog"
 	"github.com/moby/buildkit/util/progress"
+	"github.com/moby/sys/user"
 	digest "github.com/opencontainers/go-digest"
 	"github.com/pkg/errors"
 	"github.com/tonistiigi/fsutil"
@@ -248,15 +247,12 @@ func (ls *localSourceHandler) snapshot(ctx context.Context, caller session.Calle
 
 	if idmap := mount.IdentityMapping(); idmap != nil {
 		opt.Filter = func(p string, stat *fstypes.Stat) bool {
-			identity, err := idmap.ToHost(idtools.Identity{
-				UID: int(stat.Uid),
-				GID: int(stat.Gid),
-			})
+			uid, gid, err := idmap.ToHost(int(stat.Uid), int(stat.Gid))
 			if err != nil {
 				return false
 			}
-			stat.Uid = uint32(identity.UID)
-			stat.Gid = uint32(identity.GID)
+			stat.Uid = uint32(uid)
+			stat.Gid = uint32(gid)
 			return true
 		}
 	}
@@ -319,7 +315,7 @@ func newProgressHandler(ctx context.Context, id string) func(int, bool) {
 
 type cacheUpdater struct {
 	contenthash.CacheContext
-	idmap *idtools.IdentityMapping
+	idmap *user.IdentityMapping
 }
 
 func (cu *cacheUpdater) MarkSupported(bool) {
@@ -329,8 +325,10 @@ func (cu *cacheUpdater) ContentHasher() fsutil.ContentHasher {
 	return contenthash.NewFromStat
 }
 
-const keySharedKey = "local.sharedKey"
-const sharedKeyIndex = keySharedKey + ":"
+const (
+	keySharedKey   = "local.sharedKey"
+	sharedKeyIndex = keySharedKey + ":"
+)
 
 func searchSharedKey(ctx context.Context, store cache.MetadataStore, k string) ([]cacheRefMetadata, error) {
 	var results []cacheRefMetadata
diff --git a/util/system/getuserinfo/userinfo_windows.go b/util/system/getuserinfo/userinfo_windows.go
index 3c00bfb1b..08f7a1021 100644
--- a/util/system/getuserinfo/userinfo_windows.go
+++ b/util/system/getuserinfo/userinfo_windows.go
@@ -7,7 +7,6 @@ import (
 
 	"golang.org/x/sys/windows"
 
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/moby/sys/reexec"
 )
 
@@ -31,9 +30,10 @@ func userInfoMain() {
 		os.Exit(3)
 	}
 
-	ident := idtools.Identity{
-		SID: sid.String(),
+	var ident struct {
+		SID string
 	}
+	ident.SID = sid.String()
 
 	asJSON, err := json.Marshal(ident)
 	if err != nil {
diff --git a/util/windows/util_windows.go b/util/windows/util_windows.go
index 997c19f32..f5f6fefa5 100644
--- a/util/windows/util_windows.go
+++ b/util/windows/util_windows.go
@@ -8,20 +8,28 @@ import (
 	"syscall"
 
 	"github.com/containerd/containerd/v2/core/mount"
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/moby/buildkit/executor"
 	"github.com/moby/buildkit/snapshot"
+	"github.com/moby/sys/user"
 	"github.com/pkg/errors"
 )
 
-func ResolveUsernameToSID(ctx context.Context, exec executor.Executor, rootMount []mount.Mount, userName string) (idtools.Identity, error) {
+// Constants for well-known SIDs in the Windows container.
+// These are currently undocumented.
+// See https://github.com/moby/buildkit/pull/5791#discussion_r1976652227 for more information.
+const (
+	ContainerAdministratorSidString = "S-1-5-93-2-1"
+	ContainerUserSidString          = "S-1-5-93-2-2"
+)
+
+func ResolveUsernameToSID(ctx context.Context, exec executor.Executor, rootMount []mount.Mount, userName string) (string, error) {
 	// This is a shortcut in case the user is one of the builtin users that should exist
 	// in any WCOW container. While these users do exist in containers, they don't exist on the
 	// host. We check them before trying to look them up using LookupSID().
 	if strings.EqualFold(userName, "ContainerAdministrator") || userName == "" {
-		return idtools.Identity{SID: idtools.ContainerAdministratorSidString}, nil
+		return ContainerAdministratorSidString, nil
 	} else if strings.EqualFold(userName, "ContainerUser") {
-		return idtools.Identity{SID: idtools.ContainerUserSidString}, nil
+		return ContainerUserSidString, nil
 	}
 
 	// We might have a SID set as username. There is no guarantee that this SID will exist
@@ -29,7 +37,7 @@ func ResolveUsernameToSID(ctx context.Context, exec executor.Executor, rootMount
 	// that the user has made sure it does map to an identity inside the container.
 	if strings.HasPrefix(strings.ToLower(userName), "s-") {
 		if _, err := syscall.StringToSid(userName); err == nil {
-			return idtools.Identity{SID: userName}, nil
+			return userName, nil
 		}
 	}
 
@@ -44,7 +52,7 @@ func ResolveUsernameToSID(ctx context.Context, exec executor.Executor, rootMount
 		if accountType == syscall.SidTypeAlias || accountType == syscall.SidTypeWellKnownGroup {
 			sidAsString, err := sid.String()
 			if err == nil {
-				return idtools.Identity{SID: sidAsString}, nil
+				return sidAsString, nil
 			}
 		}
 	}
@@ -66,16 +74,18 @@ func ResolveUsernameToSID(ctx context.Context, exec executor.Executor, rootMount
 	// TODO(gsamfira): Should we use a snapshot of the rootMount?
 	ident, err := GetUserIdentFromContainer(ctx, exec, rootMount, userName)
 	if err != nil {
-		return idtools.Identity{}, errors.Wrap(err, "getting account SID from container")
+		return "", errors.Wrap(err, "getting account SID from container")
 	}
 	return ident, nil
 }
 
-func GetUserIdentFromContainer(ctx context.Context, exec executor.Executor, rootMounts []mount.Mount, userName string) (idtools.Identity, error) {
-	var ident idtools.Identity
+func GetUserIdentFromContainer(ctx context.Context, exec executor.Executor, rootMounts []mount.Mount, userName string) (string, error) {
+	var ident struct {
+		SID string
+	}
 
 	if len(rootMounts) > 1 {
-		return ident, errors.Errorf("unexpected number of root mounts: %d", len(rootMounts))
+		return "", errors.Errorf("unexpected number of root mounts: %d", len(rootMounts))
 	}
 
 	stdout := &bytesReadWriteCloser{
@@ -100,15 +110,15 @@ func GetUserIdentFromContainer(ctx context.Context, exec executor.Executor, root
 	}
 
 	if _, err := exec.Run(ctx, "", newStubMountable(rootMounts), nil, procInfo, nil); err != nil {
-		return ident, errors.Wrap(err, "executing command")
+		return "", errors.Wrap(err, "executing command")
 	}
 
 	data := stdout.bw.Bytes()
 	if err := json.Unmarshal(data, &ident); err != nil {
-		return ident, errors.Wrap(err, "reading user info")
+		return "", errors.Wrap(err, "reading user info")
 	}
 
-	return ident, nil
+	return ident.SID, nil
 }
 
 type bytesReadWriteCloser struct {
@@ -138,7 +148,8 @@ func (m *snapshotMountable) Mount() ([]mount.Mount, func() error, error) {
 	cleanup := func() error { return nil }
 	return m.m, cleanup, nil
 }
-func (m *snapshotMountable) IdentityMapping() *idtools.IdentityMapping {
+
+func (m *snapshotMountable) IdentityMapping() *user.IdentityMapping {
 	return nil
 }
 
diff --git a/vendor/github.com/docker/cli/cli/config/config.go b/vendor/github.com/docker/cli/cli/config/config.go
index 910b3c006..cbb34486a 100644
--- a/vendor/github.com/docker/cli/cli/config/config.go
+++ b/vendor/github.com/docker/cli/cli/config/config.go
@@ -58,7 +58,7 @@ func resetConfigDir() {
 // getHomeDir is a copy of [pkg/homedir.Get] to prevent adding docker/docker
 // as dependency for consumers that only need to read the config-file.
 //
-// [pkg/homedir.Get]: https://pkg.go.dev/github.com/docker/docker@v26.1.4+incompatible/pkg/homedir#Get
+// [pkg/homedir.Get]: https://pkg.go.dev/github.com/docker/docker@v28.0.3+incompatible/pkg/homedir#Get
 func getHomeDir() string {
 	home, _ := os.UserHomeDir()
 	if home == "" && runtime.GOOS != "windows" {
@@ -69,6 +69,11 @@ func getHomeDir() string {
 	return home
 }
 
+// Provider defines an interface for providing the CLI config.
+type Provider interface {
+	ConfigFile() *configfile.ConfigFile
+}
+
 // Dir returns the directory the configuration file is stored in
 func Dir() string {
 	initConfigDir.Do(func() {
diff --git a/vendor/github.com/docker/docker-credential-helpers/client/command.go b/vendor/github.com/docker/docker-credential-helpers/client/command.go
index 1936234be..93863480b 100644
--- a/vendor/github.com/docker/docker-credential-helpers/client/command.go
+++ b/vendor/github.com/docker/docker-credential-helpers/client/command.go
@@ -15,27 +15,30 @@ type Program interface {
 // ProgramFunc is a type of function that initializes programs based on arguments.
 type ProgramFunc func(args ...string) Program
 
-// NewShellProgramFunc creates programs that are executed in a Shell.
-func NewShellProgramFunc(name string) ProgramFunc {
-	return NewShellProgramFuncWithEnv(name, nil)
+// NewShellProgramFunc creates a [ProgramFunc] to run command in a [Shell].
+func NewShellProgramFunc(command string) ProgramFunc {
+	return func(args ...string) Program {
+		return createProgramCmdRedirectErr(command, args, nil)
+	}
 }
 
-// NewShellProgramFuncWithEnv creates programs that are executed in a Shell with environment variables
-func NewShellProgramFuncWithEnv(name string, env *map[string]string) ProgramFunc {
+// NewShellProgramFuncWithEnv creates a [ProgramFunc] tu run command
+// in a [Shell] with the given environment variables.
+func NewShellProgramFuncWithEnv(command string, env *map[string]string) ProgramFunc {
 	return func(args ...string) Program {
-		return &Shell{cmd: createProgramCmdRedirectErr(name, args, env)}
+		return createProgramCmdRedirectErr(command, args, env)
 	}
 }
 
-func createProgramCmdRedirectErr(commandName string, args []string, env *map[string]string) *exec.Cmd {
-	programCmd := exec.Command(commandName, args...)
+func createProgramCmdRedirectErr(command string, args []string, env *map[string]string) *Shell {
+	ec := exec.Command(command, args...)
 	if env != nil {
 		for k, v := range *env {
-			programCmd.Env = append(programCmd.Environ(), k+"="+v)
+			ec.Env = append(ec.Environ(), k+"="+v)
 		}
 	}
-	programCmd.Stderr = os.Stderr
-	return programCmd
+	ec.Stderr = os.Stderr
+	return &Shell{cmd: ec}
 }
 
 // Shell invokes shell commands to talk with a remote credentials-helper.
diff --git a/vendor/github.com/docker/docker/libnetwork/resolvconf/resolvconf.go b/vendor/github.com/docker/docker/libnetwork/resolvconf/resolvconf.go
index 4805b0ead..3be2bff6c 100644
--- a/vendor/github.com/docker/docker/libnetwork/resolvconf/resolvconf.go
+++ b/vendor/github.com/docker/docker/libnetwork/resolvconf/resolvconf.go
@@ -5,7 +5,6 @@ import (
 	"bytes"
 	"net/netip"
 	"os"
-	"strings"
 
 	"github.com/docker/docker/libnetwork/internal/resolvconf"
 	"github.com/opencontainers/go-digest"
@@ -127,31 +126,33 @@ func GetOptions(resolvConf []byte) []string {
 //
 // Note that the resolv.conf file is written, but the hash file is not.
 func Build(path string, nameservers, dnsSearch, dnsOptions []string) (*File, error) {
-	content := bytes.NewBuffer(nil)
-	if len(dnsSearch) > 0 {
-		if searchString := strings.Join(dnsSearch, " "); strings.Trim(searchString, " ") != "." {
-			if _, err := content.WriteString("search " + searchString + "\n"); err != nil {
-				return nil, err
-			}
-		}
-	}
-	for _, dns := range nameservers {
-		if _, err := content.WriteString("nameserver " + dns + "\n"); err != nil {
+	var ns []netip.Addr
+	for _, addr := range nameservers {
+		ipAddr, err := netip.ParseAddr(addr)
+		if err != nil {
 			return nil, err
 		}
+		ns = append(ns, ipAddr)
 	}
-	if len(dnsOptions) > 0 {
-		if optsString := strings.Join(dnsOptions, " "); strings.Trim(optsString, " ") != "" {
-			if _, err := content.WriteString("options " + optsString + "\n"); err != nil {
-				return nil, err
-			}
-		}
+	rc := resolvconf.ResolvConf{}
+	rc.OverrideNameServers(ns)
+	rc.OverrideSearch(dnsSearch)
+	rc.OverrideOptions(dnsOptions)
+
+	content, err := rc.Generate(false)
+	if err != nil {
+		return nil, err
 	}
 
-	if err := os.WriteFile(path, content.Bytes(), 0o644); err != nil {
+	// Write the resolv.conf file - it's bind-mounted into the container, so can't
+	// move a temp file into place, just have to truncate and write it.
+	//
+	// TODO(thaJeztah): the Build function is currently only used by BuildKit, which only uses "File.Content", and doesn't require the file to be written.
+	if err := os.WriteFile(path, content, 0o644); err != nil {
 		return nil, err
 	}
 
-	hash := digest.FromBytes(content.Bytes())
-	return &File{Content: content.Bytes(), Hash: []byte(hash)}, nil
+	// TODO(thaJeztah): the Build function is currently only used by BuildKit, which does not use the Hash
+	hash := digest.FromBytes(content)
+	return &File{Content: content, Hash: []byte(hash)}, nil
 }
diff --git a/vendor/github.com/docker/docker/pkg/archive/archive.go b/vendor/github.com/docker/docker/pkg/archive/archive.go
index b05780406..9bbb11c19 100644
--- a/vendor/github.com/docker/docker/pkg/archive/archive.go
+++ b/vendor/github.com/docker/docker/pkg/archive/archive.go
@@ -236,11 +236,9 @@ func (r *readCloserWrapper) Close() error {
 	return nil
 }
 
-var (
-	bufioReader32KPool = &sync.Pool{
-		New: func() interface{} { return bufio.NewReaderSize(nil, 32*1024) },
-	}
-)
+var bufioReader32KPool = &sync.Pool{
+	New: func() interface{} { return bufio.NewReaderSize(nil, 32*1024) },
+}
 
 type bufferedReader struct {
 	buf *bufio.Reader
@@ -252,17 +250,17 @@ func newBufferedReader(r io.Reader) *bufferedReader {
 	return &bufferedReader{buf}
 }
 
-func (r *bufferedReader) Read(p []byte) (n int, err error) {
+func (r *bufferedReader) Read(p []byte) (int, error) {
 	if r.buf == nil {
 		return 0, io.EOF
 	}
-	n, err = r.buf.Read(p)
+	n, err := r.buf.Read(p)
 	if err == io.EOF {
 		r.buf.Reset(nil)
 		bufioReader32KPool.Put(r.buf)
 		r.buf = nil
 	}
-	return
+	return n, err
 }
 
 func (r *bufferedReader) Peek(n int) ([]byte, error) {
@@ -428,7 +426,7 @@ func ReplaceFileTarWrapper(inputTarStream io.ReadCloser, mods map[string]TarModi
 					pipeWriter.CloseWithError(err)
 					return
 				}
-				if _, err := copyWithBuffer(tarWriter, tarReader); err != nil {
+				if err := copyWithBuffer(tarWriter, tarReader); err != nil {
 					pipeWriter.CloseWithError(err)
 					return
 				}
@@ -731,7 +729,7 @@ func (ta *tarAppender) addTarFile(path, name string) error {
 			return err
 		}
 
-		_, err = copyWithBuffer(ta.TarWriter, file)
+		err = copyWithBuffer(ta.TarWriter, file)
 		file.Close()
 		if err != nil {
 			return err
@@ -778,11 +776,11 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, o
 		if err != nil {
 			return err
 		}
-		if _, err := copyWithBuffer(file, reader); err != nil {
-			file.Close()
+		if err := copyWithBuffer(file, reader); err != nil {
+			_ = file.Close()
 			return err
 		}
-		file.Close()
+		_ = file.Close()
 
 	case tar.TypeBlock, tar.TypeChar:
 		if inUserns { // cannot create devices in a userns
@@ -1438,7 +1436,7 @@ func (archiver *Archiver) CopyFileWithTar(src, dst string) (err error) {
 			if err := tw.WriteHeader(hdr); err != nil {
 				return err
 			}
-			if _, err := copyWithBuffer(tw, srcF); err != nil {
+			if err := copyWithBuffer(tw, srcF); err != nil {
 				return err
 			}
 			return nil
diff --git a/vendor/github.com/docker/docker/pkg/archive/archive_linux.go b/vendor/github.com/docker/docker/pkg/archive/archive_linux.go
index 631d2e3c5..7b6c3e02b 100644
--- a/vendor/github.com/docker/docker/pkg/archive/archive_linux.go
+++ b/vendor/github.com/docker/docker/pkg/archive/archive_linux.go
@@ -20,7 +20,7 @@ func getWhiteoutConverter(format WhiteoutFormat) tarWhiteoutConverter {
 
 type overlayWhiteoutConverter struct{}
 
-func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os.FileInfo) (wo *tar.Header, err error) {
+func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os.FileInfo) (wo *tar.Header, _ error) {
 	// convert whiteouts to AUFS format
 	if fi.Mode()&os.ModeCharDevice != 0 && hdr.Devmajor == 0 && hdr.Devminor == 0 {
 		// we just rename the file and make it normal
@@ -31,38 +31,41 @@ func (overlayWhiteoutConverter) ConvertWrite(hdr *tar.Header, path string, fi os
 		hdr.Size = 0
 	}
 
-	if fi.Mode()&os.ModeDir != 0 {
-		opaqueXattrName := "trusted.overlay.opaque"
-		if userns.RunningInUserNS() {
-			opaqueXattrName = "user.overlay.opaque"
-		}
+	if fi.Mode()&os.ModeDir == 0 {
+		// FIXME(thaJeztah): return a sentinel error instead of nil, nil
+		return nil, nil
+	}
 
-		// convert opaque dirs to AUFS format by writing an empty file with the prefix
-		opaque, err := lgetxattr(path, opaqueXattrName)
-		if err != nil {
-			return nil, err
-		}
-		if len(opaque) == 1 && opaque[0] == 'y' {
-			delete(hdr.PAXRecords, paxSchilyXattr+opaqueXattrName)
-
-			// create a header for the whiteout file
-			// it should inherit some properties from the parent, but be a regular file
-			wo = &tar.Header{
-				Typeflag:   tar.TypeReg,
-				Mode:       hdr.Mode & int64(os.ModePerm),
-				Name:       filepath.Join(hdr.Name, WhiteoutOpaqueDir), // #nosec G305 -- An archive is being created, not extracted.
-				Size:       0,
-				Uid:        hdr.Uid,
-				Uname:      hdr.Uname,
-				Gid:        hdr.Gid,
-				Gname:      hdr.Gname,
-				AccessTime: hdr.AccessTime,
-				ChangeTime: hdr.ChangeTime,
-			}
-		}
+	opaqueXattrName := "trusted.overlay.opaque"
+	if userns.RunningInUserNS() {
+		opaqueXattrName = "user.overlay.opaque"
 	}
 
-	return
+	// convert opaque dirs to AUFS format by writing an empty file with the prefix
+	opaque, err := lgetxattr(path, opaqueXattrName)
+	if err != nil {
+		return nil, err
+	}
+	if len(opaque) != 1 || opaque[0] != 'y' {
+		// FIXME(thaJeztah): return a sentinel error instead of nil, nil
+		return nil, nil
+	}
+	delete(hdr.PAXRecords, paxSchilyXattr+opaqueXattrName)
+
+	// create a header for the whiteout file
+	// it should inherit some properties from the parent, but be a regular file
+	return &tar.Header{
+		Typeflag:   tar.TypeReg,
+		Mode:       hdr.Mode & int64(os.ModePerm),
+		Name:       filepath.Join(hdr.Name, WhiteoutOpaqueDir), // #nosec G305 -- An archive is being created, not extracted.
+		Size:       0,
+		Uid:        hdr.Uid,
+		Uname:      hdr.Uname,
+		Gid:        hdr.Gid,
+		Gname:      hdr.Gname,
+		AccessTime: hdr.AccessTime,
+		ChangeTime: hdr.ChangeTime,
+	}, nil
 }
 
 func (c overlayWhiteoutConverter) ConvertRead(hdr *tar.Header, path string) (bool, error) {
diff --git a/vendor/github.com/docker/docker/pkg/archive/archive_unix.go b/vendor/github.com/docker/docker/pkg/archive/archive_unix.go
index 9c70d1789..bc6b25ae0 100644
--- a/vendor/github.com/docker/docker/pkg/archive/archive_unix.go
+++ b/vendor/github.com/docker/docker/pkg/archive/archive_unix.go
@@ -73,14 +73,13 @@ func statUnix(fi os.FileInfo, hdr *tar.Header) error {
 	return nil
 }
 
-func getInodeFromStat(stat interface{}) (inode uint64, err error) {
+func getInodeFromStat(stat interface{}) (uint64, error) {
 	s, ok := stat.(*syscall.Stat_t)
-
-	if ok {
-		inode = s.Ino
+	if !ok {
+		// FIXME(thaJeztah): this should likely return an error; see https://github.com/moby/moby/pull/49493#discussion_r1979152897
+		return 0, nil
 	}
-
-	return
+	return s.Ino, nil
 }
 
 func getFileUIDGID(stat interface{}) (idtools.Identity, error) {
diff --git a/vendor/github.com/docker/docker/pkg/archive/archive_windows.go b/vendor/github.com/docker/docker/pkg/archive/archive_windows.go
index 031608162..fd2546eab 100644
--- a/vendor/github.com/docker/docker/pkg/archive/archive_windows.go
+++ b/vendor/github.com/docker/docker/pkg/archive/archive_windows.go
@@ -48,9 +48,9 @@ func setHeaderForSpecialDevice(hdr *tar.Header, name string, stat interface{}) (
 	return
 }
 
-func getInodeFromStat(stat interface{}) (inode uint64, err error) {
+func getInodeFromStat(stat interface{}) (uint64, error) {
 	// do nothing. no notion of Inode in stat on Windows
-	return
+	return 0, nil
 }
 
 // handleTarTypeBlockCharFifo is an OS-specific helper function used by
diff --git a/vendor/github.com/docker/docker/pkg/archive/changes.go b/vendor/github.com/docker/docker/pkg/archive/changes.go
index 79c810a68..1c0509d03 100644
--- a/vendor/github.com/docker/docker/pkg/archive/changes.go
+++ b/vendor/github.com/docker/docker/pkg/archive/changes.go
@@ -83,7 +83,7 @@ func aufsMetadataSkip(path string) (skip bool, err error) {
 	if err != nil {
 		skip = true
 	}
-	return
+	return skip, err
 }
 
 func aufsDeletedFile(root, path string, fi os.FileInfo) (string, error) {
diff --git a/vendor/github.com/docker/docker/pkg/archive/copy.go b/vendor/github.com/docker/docker/pkg/archive/copy.go
index cddf18ecd..cae0173de 100644
--- a/vendor/github.com/docker/docker/pkg/archive/copy.go
+++ b/vendor/github.com/docker/docker/pkg/archive/copy.go
@@ -25,11 +25,11 @@ var copyPool = sync.Pool{
 	New: func() interface{} { s := make([]byte, 32*1024); return &s },
 }
 
-func copyWithBuffer(dst io.Writer, src io.Reader) (written int64, err error) {
+func copyWithBuffer(dst io.Writer, src io.Reader) error {
 	buf := copyPool.Get().(*[]byte)
-	written, err = io.CopyBuffer(dst, src, *buf)
+	_, err := io.CopyBuffer(dst, src, *buf)
 	copyPool.Put(buf)
-	return
+	return err
 }
 
 // PreserveTrailingDotOrSeparator returns the given cleaned path (after
@@ -105,13 +105,13 @@ func TarResource(sourceInfo CopyInfo) (content io.ReadCloser, err error) {
 
 // TarResourceRebase is like TarResource but renames the first path element of
 // items in the resulting tar archive to match the given rebaseName if not "".
-func TarResourceRebase(sourcePath, rebaseName string) (content io.ReadCloser, err error) {
+func TarResourceRebase(sourcePath, rebaseName string) (content io.ReadCloser, _ error) {
 	sourcePath = normalizePath(sourcePath)
-	if _, err = os.Lstat(sourcePath); err != nil {
+	if _, err := os.Lstat(sourcePath); err != nil {
 		// Catches the case where the source does not exist or is not a
 		// directory if asserted to be a directory, as this also causes an
 		// error.
-		return
+		return nil, err
 	}
 
 	// Separate the source path between its directory and
@@ -442,11 +442,12 @@ func CopyTo(content io.Reader, srcInfo CopyInfo, dstPath string) error {
 // whether to follow symbol link or not, if followLink is true, resolvedPath will return
 // link target of any symbol link file, else it will only resolve symlink of directory
 // but return symbol link file itself without resolving.
-func ResolveHostSourcePath(path string, followLink bool) (resolvedPath, rebaseName string, err error) {
+func ResolveHostSourcePath(path string, followLink bool) (resolvedPath, rebaseName string, _ error) {
 	if followLink {
+		var err error
 		resolvedPath, err = filepath.EvalSymlinks(path)
 		if err != nil {
-			return
+			return "", "", err
 		}
 
 		resolvedPath, rebaseName = GetRebaseName(path, resolvedPath)
@@ -454,10 +455,9 @@ func ResolveHostSourcePath(path string, followLink bool) (resolvedPath, rebaseNa
 		dirPath, basePath := filepath.Split(path)
 
 		// if not follow symbol link, then resolve symbol link of parent dir
-		var resolvedDirPath string
-		resolvedDirPath, err = filepath.EvalSymlinks(dirPath)
+		resolvedDirPath, err := filepath.EvalSymlinks(dirPath)
 		if err != nil {
-			return
+			return "", "", err
 		}
 		// resolvedDirPath will have been cleaned (no trailing path separators) so
 		// we can manually join it with the base path element.
diff --git a/vendor/github.com/docker/docker/pkg/archive/time_nonwindows.go b/vendor/github.com/docker/docker/pkg/archive/time_nonwindows.go
index 8ce83bd0b..5bfdfa2f1 100644
--- a/vendor/github.com/docker/docker/pkg/archive/time_nonwindows.go
+++ b/vendor/github.com/docker/docker/pkg/archive/time_nonwindows.go
@@ -17,12 +17,13 @@ func chtimes(name string, atime time.Time, mtime time.Time) error {
 	return os.Chtimes(name, atime, mtime)
 }
 
-func timeToTimespec(time time.Time) (ts unix.Timespec) {
+func timeToTimespec(time time.Time) unix.Timespec {
 	if time.IsZero() {
 		// Return UTIME_OMIT special value
-		ts.Sec = 0
-		ts.Nsec = (1 << 30) - 2
-		return
+		return unix.Timespec{
+			Sec:  0,
+			Nsec: (1 << 30) - 2,
+		}
 	}
 	return unix.NsecToTimespec(time.UnixNano())
 }
diff --git a/vendor/github.com/docker/docker/pkg/archive/wrap.go b/vendor/github.com/docker/docker/pkg/archive/wrap.go
index 903befd76..f8a97254e 100644
--- a/vendor/github.com/docker/docker/pkg/archive/wrap.go
+++ b/vendor/github.com/docker/docker/pkg/archive/wrap.go
@@ -45,8 +45,8 @@ func Generate(input ...string) (io.Reader, error) {
 	return buf, nil
 }
 
-func parseStringPairs(input ...string) (output [][2]string) {
-	output = make([][2]string, 0, len(input)/2+1)
+func parseStringPairs(input ...string) [][2]string {
+	output := make([][2]string, 0, len(input)/2+1)
 	for i := 0; i < len(input); i += 2 {
 		var pair [2]string
 		pair[0] = input[i]
@@ -55,5 +55,5 @@ func parseStringPairs(input ...string) (output [][2]string) {
 		}
 		output = append(output, pair)
 	}
-	return
+	return output
 }
diff --git a/vendor/github.com/docker/docker/pkg/atomicwriter/atomicwriter.go b/vendor/github.com/docker/docker/pkg/atomicwriter/atomicwriter.go
index cbbe835bb..e8aa78071 100644
--- a/vendor/github.com/docker/docker/pkg/atomicwriter/atomicwriter.go
+++ b/vendor/github.com/docker/docker/pkg/atomicwriter/atomicwriter.go
@@ -1,22 +1,81 @@
 package atomicwriter
 
 import (
+	"errors"
+	"fmt"
 	"io"
 	"os"
 	"path/filepath"
 )
 
+func validateDestination(fileName string) error {
+	if fileName == "" {
+		return errors.New("file name is empty")
+	}
+
+	// Deliberately using Lstat here to match the behavior of [os.Rename],
+	// which is used when completing the write and does not resolve symlinks.
+	//
+	// TODO(thaJeztah): decide whether we want to disallow symlinks or to follow them.
+	if fi, err := os.Lstat(fileName); err != nil {
+		if !os.IsNotExist(err) {
+			return fmt.Errorf("failed to stat output path: %w", err)
+		}
+	} else if err := validateFileMode(fi.Mode()); err != nil {
+		return err
+	}
+	if dir := filepath.Dir(fileName); dir != "" && dir != "." {
+		if _, err := os.Stat(dir); errors.Is(err, os.ErrNotExist) {
+			return fmt.Errorf("invalid file path: %w", err)
+		}
+	}
+	return nil
+}
+
+func validateFileMode(mode os.FileMode) error {
+	switch {
+	case mode.IsRegular():
+		return nil // Regular file
+	case mode&os.ModeDir != 0:
+		return errors.New("cannot write to a directory")
+	// TODO(thaJeztah): decide whether we want to disallow symlinks or to follow them.
+	// case mode&os.ModeSymlink != 0:
+	// 	return errors.New("cannot write to a symbolic link directly")
+	case mode&os.ModeNamedPipe != 0:
+		return errors.New("cannot write to a named pipe (FIFO)")
+	case mode&os.ModeSocket != 0:
+		return errors.New("cannot write to a socket")
+	case mode&os.ModeDevice != 0:
+		if mode&os.ModeCharDevice != 0 {
+			return errors.New("cannot write to a character device file")
+		}
+		return errors.New("cannot write to a block device file")
+	case mode&os.ModeSetuid != 0:
+		return errors.New("cannot write to a setuid file")
+	case mode&os.ModeSetgid != 0:
+		return errors.New("cannot write to a setgid file")
+	case mode&os.ModeSticky != 0:
+		return errors.New("cannot write to a sticky bit file")
+	default:
+		// Unknown file mode; let's assume it works
+		return nil
+	}
+}
+
 // New returns a WriteCloser so that writing to it writes to a
 // temporary file and closing it atomically changes the temporary file to
 // destination path. Writing and closing concurrently is not allowed.
 // NOTE: umask is not considered for the file's permissions.
 func New(filename string, perm os.FileMode) (io.WriteCloser, error) {
-	f, err := os.CreateTemp(filepath.Dir(filename), ".tmp-"+filepath.Base(filename))
+	if err := validateDestination(filename); err != nil {
+		return nil, err
+	}
+	abspath, err := filepath.Abs(filename)
 	if err != nil {
 		return nil, err
 	}
 
-	abspath, err := filepath.Abs(filename)
+	f, err := os.CreateTemp(filepath.Dir(abspath), ".tmp-"+filepath.Base(filename))
 	if err != nil {
 		return nil, err
 	}
@@ -49,10 +108,12 @@ type atomicFileWriter struct {
 	f        *os.File
 	fn       string
 	writeErr error
+	written  bool
 	perm     os.FileMode
 }
 
 func (w *atomicFileWriter) Write(dt []byte) (int, error) {
+	w.written = true
 	n, err := w.f.Write(dt)
 	if err != nil {
 		w.writeErr = err
@@ -62,12 +123,12 @@ func (w *atomicFileWriter) Write(dt []byte) (int, error) {
 
 func (w *atomicFileWriter) Close() (retErr error) {
 	defer func() {
-		if retErr != nil || w.writeErr != nil {
-			os.Remove(w.f.Name())
+		if err := os.Remove(w.f.Name()); !errors.Is(err, os.ErrNotExist) && retErr == nil {
+			retErr = err
 		}
 	}()
 	if err := w.f.Sync(); err != nil {
-		w.f.Close()
+		_ = w.f.Close()
 		return err
 	}
 	if err := w.f.Close(); err != nil {
@@ -76,7 +137,7 @@ func (w *atomicFileWriter) Close() (retErr error) {
 	if err := os.Chmod(w.f.Name(), w.perm); err != nil {
 		return err
 	}
-	if w.writeErr == nil {
+	if w.writeErr == nil && w.written {
 		return os.Rename(w.f.Name(), w.fn)
 	}
 	return nil
diff --git a/vendor/github.com/docker/docker/pkg/chrootarchive/diff_unix.go b/vendor/github.com/docker/docker/pkg/chrootarchive/diff_unix.go
index e214e9a3d..be1110dcc 100644
--- a/vendor/github.com/docker/docker/pkg/chrootarchive/diff_unix.go
+++ b/vendor/github.com/docker/docker/pkg/chrootarchive/diff_unix.go
@@ -13,7 +13,7 @@ import (
 // applyLayerHandler parses a diff in the standard layer format from `layer`, and
 // applies it to the directory `dest`. Returns the size in bytes of the
 // contents of the layer.
-func applyLayerHandler(dest string, layer io.Reader, options *archive.TarOptions, decompress bool) (size int64, err error) {
+func applyLayerHandler(dest string, layer io.Reader, options *archive.TarOptions, decompress bool) (size int64, _ error) {
 	if decompress {
 		decompressed, err := archive.DecompressStream(layer)
 		if err != nil {
diff --git a/vendor/github.com/golang-jwt/jwt/v5/README.md b/vendor/github.com/golang-jwt/jwt/v5/README.md
index 964598a31..0bb636f22 100644
--- a/vendor/github.com/golang-jwt/jwt/v5/README.md
+++ b/vendor/github.com/golang-jwt/jwt/v5/README.md
@@ -10,11 +10,11 @@ implementation of [JSON Web
 Tokens](https://datatracker.ietf.org/doc/html/rfc7519).
 
 Starting with [v4.0.0](https://github.com/golang-jwt/jwt/releases/tag/v4.0.0)
-this project adds Go module support, but maintains backwards compatibility with
+this project adds Go module support, but maintains backward compatibility with
 older `v3.x.y` tags and upstream `github.com/dgrijalva/jwt-go`. See the
 [`MIGRATION_GUIDE.md`](./MIGRATION_GUIDE.md) for more information. Version
 v5.0.0 introduces major improvements to the validation of tokens, but is not
-entirely backwards compatible. 
+entirely backward compatible. 
 
 > After the original author of the library suggested migrating the maintenance
 > of `jwt-go`, a dedicated team of open source maintainers decided to clone the
@@ -24,7 +24,7 @@ entirely backwards compatible.
 
 
 **SECURITY NOTICE:** Some older versions of Go have a security issue in the
-crypto/elliptic. Recommendation is to upgrade to at least 1.15 See issue
+crypto/elliptic. The recommendation is to upgrade to at least 1.15 See issue
 [dgrijalva/jwt-go#216](https://github.com/dgrijalva/jwt-go/issues/216) for more
 detail.
 
@@ -32,7 +32,7 @@ detail.
 what you
 expect](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/).
 This library attempts to make it easy to do the right thing by requiring key
-types match the expected alg, but you should take the extra step to verify it in
+types to match the expected alg, but you should take the extra step to verify it in
 your usage.  See the examples provided.
 
 ### Supported Go versions
@@ -41,7 +41,7 @@ Our support of Go versions is aligned with Go's [version release
 policy](https://golang.org/doc/devel/release#policy). So we will support a major
 version of Go until there are two newer major releases. We no longer support
 building jwt-go with unsupported Go versions, as these contain security
-vulnerabilities which will not be fixed.
+vulnerabilities that will not be fixed.
 
 ## What the heck is a JWT?
 
@@ -117,7 +117,7 @@ notable differences:
 
 This library is considered production ready.  Feedback and feature requests are
 appreciated.  The API should be considered stable.  There should be very few
-backwards-incompatible changes outside of major version updates (and only with
+backward-incompatible changes outside of major version updates (and only with
 good reason).
 
 This project uses [Semantic Versioning 2.0.0](http://semver.org).  Accepted pull
@@ -125,8 +125,8 @@ requests will land on `main`.  Periodically, versions will be tagged from
 `main`.  You can find all the releases on [the project releases
 page](https://github.com/golang-jwt/jwt/releases).
 
-**BREAKING CHANGES:*** A full list of breaking changes is available in
-`VERSION_HISTORY.md`.  See `MIGRATION_GUIDE.md` for more information on updating
+**BREAKING CHANGES:** A full list of breaking changes is available in
+`VERSION_HISTORY.md`.  See [`MIGRATION_GUIDE.md`](./MIGRATION_GUIDE.md) for more information on updating
 your code.
 
 ## Extensions
diff --git a/vendor/github.com/golang-jwt/jwt/v5/SECURITY.md b/vendor/github.com/golang-jwt/jwt/v5/SECURITY.md
index b08402c34..2740597f1 100644
--- a/vendor/github.com/golang-jwt/jwt/v5/SECURITY.md
+++ b/vendor/github.com/golang-jwt/jwt/v5/SECURITY.md
@@ -2,11 +2,11 @@
 
 ## Supported Versions
 
-As of February 2022 (and until this document is updated), the latest version `v4` is supported.
+As of November 2024 (and until this document is updated), the latest version `v5` is supported. In critical cases, we might supply back-ported patches for `v4`.
 
 ## Reporting a Vulnerability
 
-If you think you found a vulnerability, and even if you are not sure, please report it to jwt-go-security@googlegroups.com or one of the other [golang-jwt maintainers](https://github.com/orgs/golang-jwt/people). Please try be explicit, describe steps to reproduce the security issue with code example(s).
+If you think you found a vulnerability, and even if you are not sure, please report it a [GitHub Security Advisory](https://github.com/golang-jwt/jwt/security/advisories/new). Please try be explicit, describe steps to reproduce the security issue with code example(s).
 
 You will receive a response within a timely manner. If the issue is confirmed, we will do our best to release a patch as soon as possible given the complexity of the problem.
 
diff --git a/vendor/github.com/golang-jwt/jwt/v5/parser.go b/vendor/github.com/golang-jwt/jwt/v5/parser.go
index ecf99af78..054c7eb6f 100644
--- a/vendor/github.com/golang-jwt/jwt/v5/parser.go
+++ b/vendor/github.com/golang-jwt/jwt/v5/parser.go
@@ -8,6 +8,8 @@ import (
 	"strings"
 )
 
+const tokenDelimiter = "."
+
 type Parser struct {
 	// If populated, only these methods will be considered valid.
 	validMethods []string
@@ -136,9 +138,10 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf
 // It's only ever useful in cases where you know the signature is valid (since it has already
 // been or will be checked elsewhere in the stack) and you want to extract values from it.
 func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) {
-	parts = strings.Split(tokenString, ".")
-	if len(parts) != 3 {
-		return nil, parts, newError("token contains an invalid number of segments", ErrTokenMalformed)
+	var ok bool
+	parts, ok = splitToken(tokenString)
+	if !ok {
+		return nil, nil, newError("token contains an invalid number of segments", ErrTokenMalformed)
 	}
 
 	token = &Token{Raw: tokenString}
@@ -196,6 +199,33 @@ func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Toke
 	return token, parts, nil
 }
 
+// splitToken splits a token string into three parts: header, claims, and signature. It will only
+// return true if the token contains exactly two delimiters and three parts. In all other cases, it
+// will return nil parts and false.
+func splitToken(token string) ([]string, bool) {
+	parts := make([]string, 3)
+	header, remain, ok := strings.Cut(token, tokenDelimiter)
+	if !ok {
+		return nil, false
+	}
+	parts[0] = header
+	claims, remain, ok := strings.Cut(remain, tokenDelimiter)
+	if !ok {
+		return nil, false
+	}
+	parts[1] = claims
+	// One more cut to ensure the signature is the last part of the token and there are no more
+	// delimiters. This avoids an issue where malicious input could contain additional delimiters
+	// causing unecessary overhead parsing tokens.
+	signature, _, unexpected := strings.Cut(remain, tokenDelimiter)
+	if unexpected {
+		return nil, false
+	}
+	parts[2] = signature
+
+	return parts, true
+}
+
 // DecodeSegment decodes a JWT specific base64url encoding. This function will
 // take into account whether the [Parser] is configured with additional options,
 // such as [WithStrictDecoding] or [WithPaddingAllowed].
diff --git a/vendor/github.com/golang-jwt/jwt/v5/token.go b/vendor/github.com/golang-jwt/jwt/v5/token.go
index 352873a2d..9c7f4ab01 100644
--- a/vendor/github.com/golang-jwt/jwt/v5/token.go
+++ b/vendor/github.com/golang-jwt/jwt/v5/token.go
@@ -75,7 +75,7 @@ func (t *Token) SignedString(key interface{}) (string, error) {
 }
 
 // SigningString generates the signing string.  This is the most expensive part
-// of the whole deal.  Unless you need this for something special, just go
+// of the whole deal. Unless you need this for something special, just go
 // straight for the SignedString.
 func (t *Token) SigningString() (string, error) {
 	h, err := json.Marshal(t.Header)
diff --git a/vendor/github.com/moby/sys/user/idtools.go b/vendor/github.com/moby/sys/user/idtools.go
new file mode 100644
index 000000000..595b7a927
--- /dev/null
+++ b/vendor/github.com/moby/sys/user/idtools.go
@@ -0,0 +1,141 @@
+package user
+
+import (
+	"fmt"
+	"os"
+)
+
+// MkdirOpt is a type for options to pass to Mkdir calls
+type MkdirOpt func(*mkdirOptions)
+
+type mkdirOptions struct {
+	onlyNew bool
+}
+
+// WithOnlyNew is an option for MkdirAllAndChown that will only change ownership and permissions
+// on newly created directories.  If the directory already exists, it will not be modified
+func WithOnlyNew(o *mkdirOptions) {
+	o.onlyNew = true
+}
+
+// MkdirAllAndChown creates a directory (include any along the path) and then modifies
+// ownership to the requested uid/gid.  By default, if the directory already exists, this
+// function will still change ownership and permissions. If WithOnlyNew is passed as an
+// option, then only the newly created directories will have ownership and permissions changed.
+func MkdirAllAndChown(path string, mode os.FileMode, uid, gid int, opts ...MkdirOpt) error {
+	var options mkdirOptions
+	for _, opt := range opts {
+		opt(&options)
+	}
+
+	return mkdirAs(path, mode, uid, gid, true, options.onlyNew)
+}
+
+// MkdirAndChown creates a directory and then modifies ownership to the requested uid/gid.
+// By default, if the directory already exists, this function still changes ownership and permissions.
+// If WithOnlyNew is passed as an option, then only the newly created directory will have ownership
+// and permissions changed.
+// Note that unlike os.Mkdir(), this function does not return IsExist error
+// in case path already exists.
+func MkdirAndChown(path string, mode os.FileMode, uid, gid int, opts ...MkdirOpt) error {
+	var options mkdirOptions
+	for _, opt := range opts {
+		opt(&options)
+	}
+	return mkdirAs(path, mode, uid, gid, false, options.onlyNew)
+}
+
+// getRootUIDGID retrieves the remapped root uid/gid pair from the set of maps.
+// If the maps are empty, then the root uid/gid will default to "real" 0/0
+func getRootUIDGID(uidMap, gidMap []IDMap) (int, int, error) {
+	uid, err := toHost(0, uidMap)
+	if err != nil {
+		return -1, -1, err
+	}
+	gid, err := toHost(0, gidMap)
+	if err != nil {
+		return -1, -1, err
+	}
+	return uid, gid, nil
+}
+
+// toContainer takes an id mapping, and uses it to translate a
+// host ID to the remapped ID. If no map is provided, then the translation
+// assumes a 1-to-1 mapping and returns the passed in id
+func toContainer(hostID int, idMap []IDMap) (int, error) {
+	if idMap == nil {
+		return hostID, nil
+	}
+	for _, m := range idMap {
+		if (int64(hostID) >= m.ParentID) && (int64(hostID) <= (m.ParentID + m.Count - 1)) {
+			contID := int(m.ID + (int64(hostID) - m.ParentID))
+			return contID, nil
+		}
+	}
+	return -1, fmt.Errorf("host ID %d cannot be mapped to a container ID", hostID)
+}
+
+// toHost takes an id mapping and a remapped ID, and translates the
+// ID to the mapped host ID. If no map is provided, then the translation
+// assumes a 1-to-1 mapping and returns the passed in id #
+func toHost(contID int, idMap []IDMap) (int, error) {
+	if idMap == nil {
+		return contID, nil
+	}
+	for _, m := range idMap {
+		if (int64(contID) >= m.ID) && (int64(contID) <= (m.ID + m.Count - 1)) {
+			hostID := int(m.ParentID + (int64(contID) - m.ID))
+			return hostID, nil
+		}
+	}
+	return -1, fmt.Errorf("container ID %d cannot be mapped to a host ID", contID)
+}
+
+// IdentityMapping contains a mappings of UIDs and GIDs.
+// The zero value represents an empty mapping.
+type IdentityMapping struct {
+	UIDMaps []IDMap `json:"UIDMaps"`
+	GIDMaps []IDMap `json:"GIDMaps"`
+}
+
+// RootPair returns a uid and gid pair for the root user. The error is ignored
+// because a root user always exists, and the defaults are correct when the uid
+// and gid maps are empty.
+func (i IdentityMapping) RootPair() (int, int) {
+	uid, gid, _ := getRootUIDGID(i.UIDMaps, i.GIDMaps)
+	return uid, gid
+}
+
+// ToHost returns the host UID and GID for the container uid, gid.
+// Remapping is only performed if the ids aren't already the remapped root ids
+func (i IdentityMapping) ToHost(uid, gid int) (int, int, error) {
+	var err error
+	ruid, rgid := i.RootPair()
+
+	if uid != ruid {
+		ruid, err = toHost(uid, i.UIDMaps)
+		if err != nil {
+			return ruid, rgid, err
+		}
+	}
+
+	if gid != rgid {
+		rgid, err = toHost(gid, i.GIDMaps)
+	}
+	return ruid, rgid, err
+}
+
+// ToContainer returns the container UID and GID for the host uid and gid
+func (i IdentityMapping) ToContainer(uid, gid int) (int, int, error) {
+	ruid, err := toContainer(uid, i.UIDMaps)
+	if err != nil {
+		return -1, -1, err
+	}
+	rgid, err := toContainer(gid, i.GIDMaps)
+	return ruid, rgid, err
+}
+
+// Empty returns true if there are no id mappings
+func (i IdentityMapping) Empty() bool {
+	return len(i.UIDMaps) == 0 && len(i.GIDMaps) == 0
+}
diff --git a/vendor/github.com/moby/sys/user/idtools_unix.go b/vendor/github.com/moby/sys/user/idtools_unix.go
new file mode 100644
index 000000000..4e39d2446
--- /dev/null
+++ b/vendor/github.com/moby/sys/user/idtools_unix.go
@@ -0,0 +1,143 @@
+//go:build !windows
+
+package user
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"strconv"
+	"syscall"
+)
+
+func mkdirAs(path string, mode os.FileMode, uid, gid int, mkAll, onlyNew bool) error {
+	path, err := filepath.Abs(path)
+	if err != nil {
+		return err
+	}
+
+	stat, err := os.Stat(path)
+	if err == nil {
+		if !stat.IsDir() {
+			return &os.PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR}
+		}
+		if onlyNew {
+			return nil
+		}
+
+		// short-circuit -- we were called with an existing directory and chown was requested
+		return setPermissions(path, mode, uid, gid, stat)
+	}
+
+	// make an array containing the original path asked for, plus (for mkAll == true)
+	// all path components leading up to the complete path that don't exist before we MkdirAll
+	// so that we can chown all of them properly at the end.  If onlyNew is true, we won't
+	// chown the full directory path if it exists
+	var paths []string
+	if os.IsNotExist(err) {
+		paths = append(paths, path)
+	}
+
+	if mkAll {
+		// walk back to "/" looking for directories which do not exist
+		// and add them to the paths array for chown after creation
+		dirPath := path
+		for {
+			dirPath = filepath.Dir(dirPath)
+			if dirPath == "/" {
+				break
+			}
+			if _, err = os.Stat(dirPath); os.IsNotExist(err) {
+				paths = append(paths, dirPath)
+			}
+		}
+		if err = os.MkdirAll(path, mode); err != nil {
+			return err
+		}
+	} else if err = os.Mkdir(path, mode); err != nil {
+		return err
+	}
+	// even if it existed, we will chown the requested path + any subpaths that
+	// didn't exist when we called MkdirAll
+	for _, pathComponent := range paths {
+		if err = setPermissions(pathComponent, mode, uid, gid, nil); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// setPermissions performs a chown/chmod only if the uid/gid don't match what's requested
+// Normally a Chown is a no-op if uid/gid match, but in some cases this can still cause an error, e.g. if the
+// dir is on an NFS share, so don't call chown unless we absolutely must.
+// Likewise for setting permissions.
+func setPermissions(p string, mode os.FileMode, uid, gid int, stat os.FileInfo) error {
+	if stat == nil {
+		var err error
+		stat, err = os.Stat(p)
+		if err != nil {
+			return err
+		}
+	}
+	if stat.Mode().Perm() != mode.Perm() {
+		if err := os.Chmod(p, mode.Perm()); err != nil {
+			return err
+		}
+	}
+	ssi := stat.Sys().(*syscall.Stat_t)
+	if ssi.Uid == uint32(uid) && ssi.Gid == uint32(gid) {
+		return nil
+	}
+	return os.Chown(p, uid, gid)
+}
+
+// LoadIdentityMapping takes a requested username and
+// using the data from /etc/sub{uid,gid} ranges, creates the
+// proper uid and gid remapping ranges for that user/group pair
+func LoadIdentityMapping(name string) (IdentityMapping, error) {
+	// TODO: Consider adding support for calling out to "getent"
+	usr, err := LookupUser(name)
+	if err != nil {
+		return IdentityMapping{}, fmt.Errorf("could not get user for username %s: %w", name, err)
+	}
+
+	subuidRanges, err := lookupSubRangesFile("/etc/subuid", usr)
+	if err != nil {
+		return IdentityMapping{}, err
+	}
+	subgidRanges, err := lookupSubRangesFile("/etc/subgid", usr)
+	if err != nil {
+		return IdentityMapping{}, err
+	}
+
+	return IdentityMapping{
+		UIDMaps: subuidRanges,
+		GIDMaps: subgidRanges,
+	}, nil
+}
+
+func lookupSubRangesFile(path string, usr User) ([]IDMap, error) {
+	uidstr := strconv.Itoa(usr.Uid)
+	rangeList, err := ParseSubIDFileFilter(path, func(sid SubID) bool {
+		return sid.Name == usr.Name || sid.Name == uidstr
+	})
+	if err != nil {
+		return nil, err
+	}
+	if len(rangeList) == 0 {
+		return nil, fmt.Errorf("no subuid ranges found for user %q", usr.Name)
+	}
+
+	idMap := []IDMap{}
+
+	var containerID int64
+	for _, idrange := range rangeList {
+		idMap = append(idMap, IDMap{
+			ID:       containerID,
+			ParentID: idrange.SubID,
+			Count:    idrange.Count,
+		})
+		containerID = containerID + idrange.Count
+	}
+	return idMap, nil
+}
diff --git a/vendor/github.com/moby/sys/user/idtools_windows.go b/vendor/github.com/moby/sys/user/idtools_windows.go
new file mode 100644
index 000000000..9de730caf
--- /dev/null
+++ b/vendor/github.com/moby/sys/user/idtools_windows.go
@@ -0,0 +1,13 @@
+package user
+
+import (
+	"os"
+)
+
+// This is currently a wrapper around [os.MkdirAll] since currently
+// permissions aren't set through this path, the identity isn't utilized.
+// Ownership is handled elsewhere, but in the future could be support here
+// too.
+func mkdirAs(path string, _ os.FileMode, _, _ int, _, _ bool) error {
+	return os.MkdirAll(path, 0)
+}
diff --git a/vendor/github.com/opencontainers/image-spec/specs-go/version.go b/vendor/github.com/opencontainers/image-spec/specs-go/version.go
index 7069ae44d..c3897c7ca 100644
--- a/vendor/github.com/opencontainers/image-spec/specs-go/version.go
+++ b/vendor/github.com/opencontainers/image-spec/specs-go/version.go
@@ -22,7 +22,7 @@ const (
 	// VersionMinor is for functionality in a backwards-compatible manner
 	VersionMinor = 1
 	// VersionPatch is for backwards-compatible bug fixes
-	VersionPatch = 0
+	VersionPatch = 1
 
 	// VersionDev indicates development branch. Releases will be empty string.
 	VersionDev = ""
diff --git a/vendor/github.com/tonistiigi/dchapes-mode/mode.go b/vendor/github.com/tonistiigi/dchapes-mode/mode.go
index 01d3444f9..a53aa7d0f 100644
--- a/vendor/github.com/tonistiigi/dchapes-mode/mode.go
+++ b/vendor/github.com/tonistiigi/dchapes-mode/mode.go
@@ -262,8 +262,10 @@ func ParseWithUmask(s string, umask uint) (Set, error) {
 			case 'w':
 				perm |= iWUser | iWGroup | iWOther
 			case 'X':
-				if op == '+' {
+				if op != '-' {
 					permX = iXUser | iXGroup | iXOther
+				} else {
+					perm |= iXUser | iXGroup | iXOther
 				}
 			case 'x':
 				perm |= iXUser | iXGroup | iXOther
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 6c204246c..79cdbb2d3 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -486,14 +486,14 @@ github.com/dimchansky/utfbom
 # github.com/distribution/reference v0.6.0
 ## explicit; go 1.20
 github.com/distribution/reference
-# github.com/docker/cli v28.0.1+incompatible
+# github.com/docker/cli v28.0.4+incompatible
 ## explicit
 github.com/docker/cli/cli/config
 github.com/docker/cli/cli/config/configfile
 github.com/docker/cli/cli/config/credentials
 github.com/docker/cli/cli/config/types
 github.com/docker/cli/cli/connhelper/commandconn
-# github.com/docker/docker v28.0.1+incompatible
+# github.com/docker/docker v28.0.4+incompatible
 ## explicit
 github.com/docker/docker/internal/mounttree
 github.com/docker/docker/internal/unshare
@@ -504,8 +504,8 @@ github.com/docker/docker/pkg/atomicwriter
 github.com/docker/docker/pkg/chrootarchive
 github.com/docker/docker/pkg/idtools
 github.com/docker/docker/profiles/seccomp
-# github.com/docker/docker-credential-helpers v0.8.2
-## explicit; go 1.19
+# github.com/docker/docker-credential-helpers v0.9.3
+## explicit; go 1.21
 github.com/docker/docker-credential-helpers/client
 github.com/docker/docker-credential-helpers/credentials
 # github.com/docker/go-connections v0.5.0
@@ -539,7 +539,7 @@ github.com/gofrs/flock
 # github.com/gogo/protobuf v1.3.2
 ## explicit; go 1.15
 github.com/gogo/protobuf/proto
-# github.com/golang-jwt/jwt/v5 v5.2.1
+# github.com/golang-jwt/jwt/v5 v5.2.2
 ## explicit; go 1.18
 github.com/golang-jwt/jwt/v5
 # github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da
@@ -648,7 +648,7 @@ github.com/moby/sys/sequential
 # github.com/moby/sys/signal v0.7.1
 ## explicit; go 1.17
 github.com/moby/sys/signal
-# github.com/moby/sys/user v0.3.0
+# github.com/moby/sys/user v0.4.0
 ## explicit; go 1.17
 github.com/moby/sys/user
 # github.com/moby/sys/userns v0.1.0
@@ -663,7 +663,7 @@ github.com/munnerz/goautoneg
 # github.com/opencontainers/go-digest v1.0.0
 ## explicit; go 1.13
 github.com/opencontainers/go-digest
-# github.com/opencontainers/image-spec v1.1.0
+# github.com/opencontainers/image-spec v1.1.1
 ## explicit; go 1.18
 github.com/opencontainers/image-spec/identity
 github.com/opencontainers/image-spec/specs-go
@@ -774,10 +774,10 @@ github.com/stretchr/testify/require
 # github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635
 ## explicit
 github.com/syndtr/gocapability/capability
-# github.com/tonistiigi/dchapes-mode v0.0.0-20241001053921-ca0759fec205
+# github.com/tonistiigi/dchapes-mode v0.0.0-20250318174251-73d941a28323
 ## explicit; go 1.21
 github.com/tonistiigi/dchapes-mode
-# github.com/tonistiigi/fsutil v0.0.0-20250227023350-13604323a291
+# github.com/tonistiigi/fsutil v0.0.0-20250318190121-d73a4b3b8a7e
 ## explicit; go 1.21
 github.com/tonistiigi/fsutil
 github.com/tonistiigi/fsutil/copy
@@ -1121,12 +1121,12 @@ kernel.org/pub/linux/libs/security/libcap/psx
 ## explicit; go 1.12
 sigs.k8s.io/yaml
 sigs.k8s.io/yaml/goyaml.v2
-# tags.cncf.io/container-device-interface v0.8.1
+# tags.cncf.io/container-device-interface v1.0.1
 ## explicit; go 1.20
 tags.cncf.io/container-device-interface/internal/validation
 tags.cncf.io/container-device-interface/internal/validation/k8s
 tags.cncf.io/container-device-interface/pkg/cdi
 tags.cncf.io/container-device-interface/pkg/parser
-# tags.cncf.io/container-device-interface/specs-go v0.8.0
+# tags.cncf.io/container-device-interface/specs-go v1.0.0
 ## explicit; go 1.19
 tags.cncf.io/container-device-interface/specs-go
diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/annotations.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/annotations.go
index a38b0f1bc..a596c610b 100644
--- a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/annotations.go
+++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/annotations.go
@@ -71,7 +71,7 @@ func ParseAnnotations(annotations map[string]string) ([]string, []string, error)
 			continue
 		}
 		for _, d := range strings.Split(value, ",") {
-			if !IsQualifiedName(d) {
+			if !parser.IsQualifiedName(d) {
 				return nil, nil, fmt.Errorf("invalid CDI device name %q", d)
 			}
 			devices = append(devices, d)
@@ -130,7 +130,7 @@ func AnnotationKey(pluginName, deviceID string) (string, error) {
 func AnnotationValue(devices []string) (string, error) {
 	value, sep := "", ""
 	for _, d := range devices {
-		if _, _, _, err := ParseQualifiedName(d); err != nil {
+		if _, _, _, err := parser.ParseQualifiedName(d); err != nil {
 			return "", err
 		}
 		value += sep + d
diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache.go
index 9afa4b182..7095f27da 100644
--- a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache.go
+++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache.go
@@ -22,6 +22,7 @@ import (
 	"io/fs"
 	"os"
 	"path/filepath"
+	"runtime"
 	"sort"
 	"strings"
 	"sync"
@@ -116,7 +117,7 @@ func (c *Cache) configure(options ...Option) {
 		c.watch.setup(c.specDirs, c.dirErrors)
 		c.watch.start(&c.Mutex, c.refresh, c.dirErrors)
 	}
-	c.refresh()
+	_ = c.refresh() // we record but ignore errors
 }
 
 // Refresh rescans the CDI Spec directories and refreshes the Cache.
@@ -222,7 +223,8 @@ func (c *Cache) refreshIfRequired(force bool) (bool, error) {
 
 // InjectDevices injects the given qualified devices to an OCI Spec. It
 // returns any unresolvable devices and an error if injection fails for
-// any of the devices.
+// any of the devices. Might trigger a cache refresh, in which case any
+// errors encountered can be obtained using GetErrors().
 func (c *Cache) InjectDevices(ociSpec *oci.Spec, devices ...string) ([]string, error) {
 	var unresolved []string
 
@@ -233,7 +235,7 @@ func (c *Cache) InjectDevices(ociSpec *oci.Spec, devices ...string) ([]string, e
 	c.Lock()
 	defer c.Unlock()
 
-	c.refreshIfRequired(false)
+	_, _ = c.refreshIfRequired(false) // we record but ignore errors
 
 	edits := &ContainerEdits{}
 	specs := map[*Spec]struct{}{}
@@ -335,24 +337,27 @@ func (c *Cache) RemoveSpec(name string) error {
 	return err
 }
 
-// GetDevice returns the cached device for the given qualified name.
+// GetDevice returns the cached device for the given qualified name. Might trigger
+// a cache refresh, in which case any errors encountered can be obtained using
+// GetErrors().
 func (c *Cache) GetDevice(device string) *Device {
 	c.Lock()
 	defer c.Unlock()
 
-	c.refreshIfRequired(false)
+	_, _ = c.refreshIfRequired(false) // we record but ignore errors
 
 	return c.devices[device]
 }
 
-// ListDevices lists all cached devices by qualified name.
+// ListDevices lists all cached devices by qualified name. Might trigger a cache
+// refresh, in which case any errors encountered can be obtained using GetErrors().
 func (c *Cache) ListDevices() []string {
 	var devices []string
 
 	c.Lock()
 	defer c.Unlock()
 
-	c.refreshIfRequired(false)
+	_, _ = c.refreshIfRequired(false) // we record but ignore errors
 
 	for name := range c.devices {
 		devices = append(devices, name)
@@ -362,14 +367,15 @@ func (c *Cache) ListDevices() []string {
 	return devices
 }
 
-// ListVendors lists all vendors known to the cache.
+// ListVendors lists all vendors known to the cache. Might trigger a cache refresh,
+// in which case any errors encountered can be obtained using GetErrors().
 func (c *Cache) ListVendors() []string {
 	var vendors []string
 
 	c.Lock()
 	defer c.Unlock()
 
-	c.refreshIfRequired(false)
+	_, _ = c.refreshIfRequired(false) // we record but ignore errors
 
 	for vendor := range c.specs {
 		vendors = append(vendors, vendor)
@@ -379,7 +385,8 @@ func (c *Cache) ListVendors() []string {
 	return vendors
 }
 
-// ListClasses lists all device classes known to the cache.
+// ListClasses lists all device classes known to the cache. Might trigger a cache
+// refresh, in which case any errors encountered can be obtained using GetErrors().
 func (c *Cache) ListClasses() []string {
 	var (
 		cmap    = map[string]struct{}{}
@@ -389,7 +396,7 @@ func (c *Cache) ListClasses() []string {
 	c.Lock()
 	defer c.Unlock()
 
-	c.refreshIfRequired(false)
+	_, _ = c.refreshIfRequired(false) // we record but ignore errors
 
 	for _, specs := range c.specs {
 		for _, spec := range specs {
@@ -404,12 +411,13 @@ func (c *Cache) ListClasses() []string {
 	return classes
 }
 
-// GetVendorSpecs returns all specs for the given vendor.
+// GetVendorSpecs returns all specs for the given vendor. Might trigger a cache
+// refresh, in which case any errors encountered can be obtained using GetErrors().
 func (c *Cache) GetVendorSpecs(vendor string) []*Spec {
 	c.Lock()
 	defer c.Unlock()
 
-	c.refreshIfRequired(false)
+	_, _ = c.refreshIfRequired(false) // we record but ignore errors
 
 	return c.specs[vendor]
 }
@@ -522,6 +530,13 @@ func (w *watch) watch(fsw *fsnotify.Watcher, m *sync.Mutex, refresh func() error
 	if watch == nil {
 		return
 	}
+
+	eventMask := fsnotify.Rename | fsnotify.Remove | fsnotify.Write
+	// On macOS, we also need to watch for Create events.
+	if runtime.GOOS == "darwin" {
+		eventMask |= fsnotify.Create
+	}
+
 	for {
 		select {
 		case event, ok := <-watch.Events:
@@ -529,10 +544,10 @@ func (w *watch) watch(fsw *fsnotify.Watcher, m *sync.Mutex, refresh func() error
 				return
 			}
 
-			if (event.Op & (fsnotify.Rename | fsnotify.Remove | fsnotify.Write)) == 0 {
+			if (event.Op & eventMask) == 0 {
 				continue
 			}
-			if event.Op == fsnotify.Write {
+			if event.Op == fsnotify.Write || event.Op == fsnotify.Create {
 				if ext := filepath.Ext(event.Name); ext != ".json" && ext != ".yaml" {
 					continue
 				}
@@ -544,7 +559,7 @@ func (w *watch) watch(fsw *fsnotify.Watcher, m *sync.Mutex, refresh func() error
 			} else {
 				w.update(dirErrors)
 			}
-			refresh()
+			_ = refresh()
 			m.Unlock()
 
 		case _, ok := <-watch.Errors:
diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/container-edits.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/container-edits.go
index 70791666c..4744eff8f 100644
--- a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/container-edits.go
+++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/container-edits.go
@@ -26,7 +26,7 @@ import (
 
 	oci "github.com/opencontainers/runtime-spec/specs-go"
 	ocigen "github.com/opencontainers/runtime-tools/generate"
-	"tags.cncf.io/container-device-interface/specs-go"
+	cdi "tags.cncf.io/container-device-interface/specs-go"
 )
 
 const (
@@ -64,7 +64,7 @@ var (
 // to all OCI Specs where at least one devices from the CDI Spec
 // is injected.
 type ContainerEdits struct {
-	*specs.ContainerEdits
+	*cdi.ContainerEdits
 }
 
 // Apply edits to the given OCI Spec. Updates the OCI Spec in place.
@@ -205,7 +205,7 @@ func (e *ContainerEdits) Append(o *ContainerEdits) *ContainerEdits {
 		e = &ContainerEdits{}
 	}
 	if e.ContainerEdits == nil {
-		e.ContainerEdits = &specs.ContainerEdits{}
+		e.ContainerEdits = &cdi.ContainerEdits{}
 	}
 
 	e.Env = append(e.Env, o.Env...)
@@ -259,7 +259,7 @@ func ValidateEnv(env []string) error {
 
 // DeviceNode is a CDI Spec DeviceNode wrapper, used for validating DeviceNodes.
 type DeviceNode struct {
-	*specs.DeviceNode
+	*cdi.DeviceNode
 }
 
 // Validate a CDI Spec DeviceNode.
@@ -289,7 +289,7 @@ func (d *DeviceNode) Validate() error {
 
 // Hook is a CDI Spec Hook wrapper, used for validating hooks.
 type Hook struct {
-	*specs.Hook
+	*cdi.Hook
 }
 
 // Validate a hook.
@@ -308,7 +308,7 @@ func (h *Hook) Validate() error {
 
 // Mount is a CDI Mount wrapper, used for validating mounts.
 type Mount struct {
-	*specs.Mount
+	*cdi.Mount
 }
 
 // Validate a mount.
@@ -325,13 +325,13 @@ func (m *Mount) Validate() error {
 // IntelRdt is a CDI IntelRdt wrapper.
 // This is used for validation and conversion to OCI specifications.
 type IntelRdt struct {
-	*specs.IntelRdt
+	*cdi.IntelRdt
 }
 
 // ValidateIntelRdt validates the IntelRdt configuration.
 //
 // Deprecated: ValidateIntelRdt is deprecated use IntelRdt.Validate() instead.
-func ValidateIntelRdt(i *specs.IntelRdt) error {
+func ValidateIntelRdt(i *cdi.IntelRdt) error {
 	return (&IntelRdt{i}).Validate()
 }
 
@@ -355,7 +355,7 @@ func ensureOCIHooks(spec *oci.Spec) {
 func sortMounts(specgen *ocigen.Generator) {
 	mounts := specgen.Mounts()
 	specgen.ClearMounts()
-	sort.Sort(orderedMounts(mounts))
+	sort.Stable(orderedMounts(mounts))
 	specgen.Config.Mounts = mounts
 }
 
@@ -375,14 +375,7 @@ func (m orderedMounts) Len() int {
 // mount indexed by parameter 1 is less than that of the mount indexed by
 // parameter 2. Used in sorting.
 func (m orderedMounts) Less(i, j int) bool {
-	ip, jp := m.parts(i), m.parts(j)
-	if ip < jp {
-		return true
-	}
-	if jp < ip {
-		return false
-	}
-	return m[i].Destination < m[j].Destination
+	return m.parts(i) < m.parts(j)
 }
 
 // Swap swaps two items in an array of mounts. Used in sorting
diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/device.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/device.go
index 00be48dd5..2e5fa57f4 100644
--- a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/device.go
+++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/device.go
@@ -67,7 +67,7 @@ func (d *Device) edits() *ContainerEdits {
 
 // Validate the device.
 func (d *Device) validate() error {
-	if err := ValidateDeviceName(d.Name); err != nil {
+	if err := parser.ValidateDeviceName(d.Name); err != nil {
 		return err
 	}
 	name := d.Name
diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/doc.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/doc.go
index 0ea071455..d00e0d339 100644
--- a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/doc.go
+++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/doc.go
@@ -35,25 +35,11 @@
 // available and instantiated the first time it is referenced directly
 // or indirectly. The most frequently used cache functions are available
 // as identically named package level functions which operate on the
-// default cache instance. Moreover, the registry also operates on the
-// same default cache. We plan to deprecate the registry and eventually
-// remove it in a future release.
-//
-// # CDI Registry
-//
-// Note: the Registry and its related interfaces are deprecated and will
-// be removed in a future version. Please use the default cache and its
-// related package-level function instead.
-//
-// The primary interface to interact with CDI devices is the Registry. It
-// is essentially a cache of all Specs and devices discovered in standard
-// CDI directories on the host. The registry has two main functionality,
-// injecting devices into an OCI Spec and refreshing the cache of CDI
-// Specs and devices.
+// default cache instance.
 //
 // # Device Injection
 //
-// Using the Registry one can inject CDI devices into a container with code
+// Using the Cache one can inject CDI devices into a container with code
 // similar to the following snippet:
 //
 //	import (
@@ -63,13 +49,14 @@
 //	    log "github.com/sirupsen/logrus"
 //
 //	    "tags.cncf.io/container-device-interface/pkg/cdi"
-//	    oci "github.com/opencontainers/runtime-spec/specs-go"
+//	    "github.com/opencontainers/runtime-spec/specs-go"
 //	)
 //
-//	func injectCDIDevices(spec *oci.Spec, devices []string) error {
+//	func injectCDIDevices(spec *specs.Spec, devices []string) error {
 //	    log.Debug("pristine OCI Spec: %s", dumpSpec(spec))
 //
-//	    unresolved, err := cdi.GetRegistry().InjectDevices(spec, devices)
+//	    cache := cdi.GetDefaultCache()
+//	    unresolved, err := cache.InjectDevices(spec, devices)
 //	    if err != nil {
 //	        return fmt.Errorf("CDI device injection failed: %w", err)
 //	    }
@@ -106,17 +93,17 @@
 //	    log "github.com/sirupsen/logrus"
 //
 //	    "tags.cncf.io/container-device-interface/pkg/cdi"
-//	    oci "github.com/opencontainers/runtime-spec/specs-go"
+//	    "github.com/opencontainers/runtime-spec/specs-go"
 //	)
 //
-//	func injectCDIDevices(spec *oci.Spec, devices []string) error {
-//	    registry := cdi.GetRegistry()
+//	func injectCDIDevices(spec *specs.Spec, devices []string) error {
+//	    cache := cdi.GetDefaultCache()
 //
-//	    if err := registry.Refresh(); err != nil {
+//	    if err := cache.Refresh(); err != nil {
 //	        // Note:
 //	        //   It is up to the implementation to decide whether
 //	        //   to abort injection on errors. A failed Refresh()
-//	        //   does not necessarily render the registry unusable.
+//	        //   does not necessarily render the cache unusable.
 //	        //   For instance, a parse error in a Spec file for
 //	        //   vendor A does not have any effect on devices of
 //	        //   vendor B...
@@ -125,7 +112,7 @@
 //
 //	    log.Debug("pristine OCI Spec: %s", dumpSpec(spec))
 //
-//	    unresolved, err := registry.InjectDevices(spec, devices)
+//	    unresolved, err := cache.InjectDevices(spec, devices)
 //	    if err != nil {
 //	        return fmt.Errorf("CDI device injection failed: %w", err)
 //	    }
@@ -192,7 +179,7 @@
 // )
 //
 //	func generateDeviceSpecs() error {
-//	    registry := cdi.GetRegistry()
+//	    cache := specs.GetDefaultCache()
 //	    spec := &specs.Spec{
 //	        Version: specs.CurrentVersion,
 //	        Kind:    vendor+"/"+class,
@@ -210,7 +197,7 @@
 //	        return fmt.Errorf("failed to generate Spec name: %w", err)
 //	    }
 //
-//	    return registry.SpecDB().WriteSpec(spec, specName)
+//	    return cache.WriteSpec(spec, specName)
 //	}
 //
 // Similarly, generating and later cleaning up transient Spec files can be
@@ -229,7 +216,7 @@
 // )
 //
 //	func generateTransientSpec(ctr Container) error {
-//	    registry := cdi.GetRegistry()
+//	    cache := specs.GetDefaultCache()
 //	    devices := getContainerDevs(ctr, vendor, class)
 //	    spec := &specs.Spec{
 //	        Version: specs.CurrentVersion,
@@ -257,21 +244,21 @@
 //	        return fmt.Errorf("failed to generate Spec name: %w", err)
 //	    }
 //
-//	    return registry.SpecDB().WriteSpec(spec, specName)
+//	    return cache.WriteSpec(spec, specName)
 //	}
 //
 //	func removeTransientSpec(ctr Container) error {
-//	    registry := cdi.GetRegistry()
+//	    cache := specs.GetDefaultCache()
 //	    transientID := getSomeSufficientlyUniqueIDForContainer(ctr)
 //	    specName := cdi.GenerateNameForTransientSpec(vendor, class, transientID)
 //
-//	    return registry.SpecDB().RemoveSpec(specName)
+//	    return cache.RemoveSpec(specName)
 //	}
 //
 // # CDI Spec Validation
 //
 // This package performs both syntactic and semantic validation of CDI
-// Spec file data when a Spec file is loaded via the registry or using
+// Spec file data when a Spec file is loaded via the cache or using
 // the ReadSpec API function. As part of the semantic verification, the
 // Spec file is verified against the CDI Spec JSON validation schema.
 //
diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/qualified-device.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/qualified-device.go
deleted file mode 100644
index 0bdfdc166..000000000
--- a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/qualified-device.go
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
-   Copyright © 2021 The CDI Authors
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-package cdi
-
-import (
-	"tags.cncf.io/container-device-interface/pkg/parser"
-)
-
-// QualifiedName returns the qualified name for a device.
-// The syntax for a qualified device names is
-//
-//	"<vendor>/<class>=<name>".
-//
-// A valid vendor and class name may contain the following runes:
-//
-//	'A'-'Z', 'a'-'z', '0'-'9', '.', '-', '_'.
-//
-// A valid device name may contain the following runes:
-//
-//	'A'-'Z', 'a'-'z', '0'-'9', '-', '_', '.', ':'
-//
-// Deprecated: use parser.QualifiedName instead
-func QualifiedName(vendor, class, name string) string {
-	return parser.QualifiedName(vendor, class, name)
-}
-
-// IsQualifiedName tests if a device name is qualified.
-//
-// Deprecated: use parser.IsQualifiedName instead
-func IsQualifiedName(device string) bool {
-	return parser.IsQualifiedName(device)
-}
-
-// ParseQualifiedName splits a qualified name into device vendor, class,
-// and name. If the device fails to parse as a qualified name, or if any
-// of the split components fail to pass syntax validation, vendor and
-// class are returned as empty, together with the verbatim input as the
-// name and an error describing the reason for failure.
-//
-// Deprecated: use parser.ParseQualifiedName instead
-func ParseQualifiedName(device string) (string, string, string, error) {
-	return parser.ParseQualifiedName(device)
-}
-
-// ParseDevice tries to split a device name into vendor, class, and name.
-// If this fails, for instance in the case of unqualified device names,
-// ParseDevice returns an empty vendor and class together with name set
-// to the verbatim input.
-//
-// Deprecated: use parser.ParseDevice instead
-func ParseDevice(device string) (string, string, string) {
-	return parser.ParseDevice(device)
-}
-
-// ParseQualifier splits a device qualifier into vendor and class.
-// The syntax for a device qualifier is
-//
-//	"<vendor>/<class>"
-//
-// If parsing fails, an empty vendor and the class set to the
-// verbatim input is returned.
-//
-// Deprecated: use parser.ParseQualifier instead
-func ParseQualifier(kind string) (string, string) {
-	return parser.ParseQualifier(kind)
-}
-
-// ValidateVendorName checks the validity of a vendor name.
-// A vendor name may contain the following ASCII characters:
-//   - upper- and lowercase letters ('A'-'Z', 'a'-'z')
-//   - digits ('0'-'9')
-//   - underscore, dash, and dot ('_', '-', and '.')
-//
-// Deprecated: use parser.ValidateVendorName instead
-func ValidateVendorName(vendor string) error {
-	return parser.ValidateVendorName(vendor)
-}
-
-// ValidateClassName checks the validity of class name.
-// A class name may contain the following ASCII characters:
-//   - upper- and lowercase letters ('A'-'Z', 'a'-'z')
-//   - digits ('0'-'9')
-//   - underscore, dash, and dot ('_', '-', and '.')
-//
-// Deprecated: use parser.ValidateClassName instead
-func ValidateClassName(class string) error {
-	return parser.ValidateClassName(class)
-}
-
-// ValidateDeviceName checks the validity of a device name.
-// A device name may contain the following ASCII characters:
-//   - upper- and lowercase letters ('A'-'Z', 'a'-'z')
-//   - digits ('0'-'9')
-//   - underscore, dash, dot, colon ('_', '-', '.', ':')
-//
-// Deprecated: use parser.ValidateDeviceName instead
-func ValidateDeviceName(name string) error {
-	return parser.ValidateDeviceName(name)
-}
diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/registry.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/registry.go
deleted file mode 100644
index 3113a05a2..000000000
--- a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/registry.go
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
-   Copyright © 2021 The CDI Authors
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-*/
-
-package cdi
-
-import (
-	"sync"
-
-	oci "github.com/opencontainers/runtime-spec/specs-go"
-	cdi "tags.cncf.io/container-device-interface/specs-go"
-)
-
-// Registry keeps a cache of all CDI Specs installed or generated on
-// the host. Registry is the primary interface clients should use to
-// interact with CDI.
-//
-// The most commonly used Registry functions are for refreshing the
-// registry and injecting CDI devices into an OCI Spec.
-//
-// Deprecated: Registry is deprecated and will be removed in a future
-// version. Please update your code to use the corresponding package-
-// level functions Configure(), Refresh(), InjectDevices(), GetErrors(),
-// and GetDefaultCache().
-type Registry interface {
-	RegistryResolver
-	RegistryRefresher
-	DeviceDB() RegistryDeviceDB
-	SpecDB() RegistrySpecDB
-}
-
-// RegistryRefresher is the registry interface for refreshing the
-// cache of CDI Specs and devices.
-//
-// Configure reconfigures the registry with the given options.
-//
-// Refresh rescans all CDI Spec directories and updates the
-// state of the cache to reflect any changes. It returns any
-// errors encountered during the refresh.
-//
-// GetErrors returns all errors encountered for any of the scanned
-// Spec files during the last cache refresh.
-//
-// GetSpecDirectories returns the set up CDI Spec directories
-// currently in use. The directories are returned in the scan
-// order of Refresh().
-//
-// GetSpecDirErrors returns any errors related to the configured
-// Spec directories.
-//
-// Deprecated: RegistryRefresher is deprecated and will be removed
-// in a future version. Please use the default cache and its related
-// package-level functions instead.
-type RegistryRefresher interface {
-	Configure(...Option) error
-	Refresh() error
-	GetErrors() map[string][]error
-	GetSpecDirectories() []string
-	GetSpecDirErrors() map[string]error
-}
-
-// RegistryResolver is the registry interface for injecting CDI
-// devices into an OCI Spec.
-//
-// InjectDevices takes an OCI Spec and injects into it a set of
-// CDI devices given by qualified name. It returns the names of
-// any unresolved devices and an error if injection fails.
-//
-// Deprecated: RegistryRefresher is deprecated and will be removed
-// in a future version. Please use the default cache and its related
-// package-level functions instead.
-type RegistryResolver interface {
-	InjectDevices(spec *oci.Spec, device ...string) (unresolved []string, err error)
-}
-
-// RegistryDeviceDB is the registry interface for querying devices.
-//
-// GetDevice returns the CDI device for the given qualified name. If
-// the device is not GetDevice returns nil.
-//
-// ListDevices returns a slice with the names of qualified device
-// known. The returned slice is sorted.
-//
-// Deprecated: RegistryDeviceDB is deprecated and will be removed
-// in a future version. Please use the default cache and its related
-// package-level functions instead.
-// and will be removed in a future version. Please use the default
-// cache and its related package-level functions instead.
-type RegistryDeviceDB interface {
-	GetDevice(device string) *Device
-	ListDevices() []string
-}
-
-// RegistrySpecDB is the registry interface for querying CDI Specs.
-//
-// ListVendors returns a slice with all vendors known. The returned
-// slice is sorted.
-//
-// ListClasses returns a slice with all classes known. The returned
-// slice is sorted.
-//
-// GetVendorSpecs returns a slice of all Specs for the vendor.
-//
-// GetSpecErrors returns any errors for the Spec encountered during
-// the last cache refresh.
-//
-// WriteSpec writes the Spec with the given content and name to the
-// last Spec directory.
-//
-// Deprecated: RegistrySpecDB is deprecated and will be removed
-// in a future version. Please use the default cache and its related
-// package-level functions instead.
-type RegistrySpecDB interface {
-	ListVendors() []string
-	ListClasses() []string
-	GetVendorSpecs(vendor string) []*Spec
-	GetSpecErrors(*Spec) []error
-	WriteSpec(raw *cdi.Spec, name string) error
-	RemoveSpec(name string) error
-}
-
-type registry struct {
-	*Cache
-}
-
-var _ Registry = &registry{}
-
-var (
-	reg      *registry
-	initOnce sync.Once
-)
-
-// GetRegistry returns the CDI registry. If any options are given, those
-// are applied to the registry.
-//
-// Deprecated: GetRegistry is deprecated and will be removed in a future
-// version. Please use the default cache and its related package-level
-// functions instead.
-func GetRegistry(options ...Option) Registry {
-	initOnce.Do(func() {
-		reg = &registry{GetDefaultCache()}
-	})
-	if len(options) > 0 {
-		// We don't care about errors here
-		_ = reg.Configure(options...)
-	}
-	return reg
-}
-
-// DeviceDB returns the registry interface for querying devices.
-//
-// Deprecated: DeviceDB is deprecated and will be removed in a future
-// version. Please use the default cache and its related package-level
-// functions instead.
-func (r *registry) DeviceDB() RegistryDeviceDB {
-	return r
-}
-
-// SpecDB returns the registry interface for querying Specs.
-//
-// Deprecated: SpecDB is deprecated and will be removed in a future
-// version. Please use the default cache and its related package-level
-// functions instead.
-func (r *registry) SpecDB() RegistrySpecDB {
-	return r
-}
diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/spec-dirs.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/spec-dirs.go
index 09005d690..b192f962c 100644
--- a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/spec-dirs.go
+++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/spec-dirs.go
@@ -35,8 +35,7 @@ var (
 	// While altering this variable changes the package defaults,
 	// the preferred way of overriding the default directories is
 	// to use a WithSpecDirs options. Otherwise the change is only
-	// effective if it takes place before creating the Registry or
-	// other Cache instances.
+	// effective if it takes place before creating the cache instance.
 	DefaultSpecDirs = []string{DefaultStaticDir, DefaultDynamicDir}
 	// ErrStopScan can be returned from a ScanSpecFunc to stop the scan.
 	ErrStopScan = errors.New("stop Spec scan")
diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/spec.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/spec.go
index 1a0a662b8..8d295a83f 100644
--- a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/spec.go
+++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/spec.go
@@ -25,9 +25,11 @@ import (
 	"sync"
 
 	oci "github.com/opencontainers/runtime-spec/specs-go"
+	orderedyaml "gopkg.in/yaml.v3"
 	"sigs.k8s.io/yaml"
 
 	"tags.cncf.io/container-device-interface/internal/validation"
+	"tags.cncf.io/container-device-interface/pkg/parser"
 	cdi "tags.cncf.io/container-device-interface/specs-go"
 )
 
@@ -36,9 +38,13 @@ const (
 	defaultSpecExt = ".yaml"
 )
 
+type validator interface {
+	Validate(*cdi.Spec) error
+}
+
 var (
 	// Externally set CDI Spec validation function.
-	specValidator func(*cdi.Spec) error
+	specValidator validator
 	validatorLock sync.RWMutex
 )
 
@@ -105,7 +111,7 @@ func newSpec(raw *cdi.Spec, path string, priority int) (*Spec, error) {
 		spec.path += defaultSpecExt
 	}
 
-	spec.vendor, spec.class = ParseQualifier(spec.Kind)
+	spec.vendor, spec.class = parser.ParseQualifier(spec.Kind)
 
 	if spec.devices, err = spec.validate(); err != nil {
 		return nil, fmt.Errorf("invalid CDI Spec: %w", err)
@@ -130,7 +136,7 @@ func (s *Spec) write(overwrite bool) error {
 	}
 
 	if filepath.Ext(s.path) == ".yaml" {
-		data, err = yaml.Marshal(s.Spec)
+		data, err = orderedyaml.Marshal(s.Spec)
 		data = append([]byte("---\n"), data...)
 	} else {
 		data, err = json.Marshal(s.Spec)
@@ -200,24 +206,21 @@ func (s *Spec) edits() *ContainerEdits {
 	return &ContainerEdits{&s.ContainerEdits}
 }
 
+// MinimumRequiredVersion determines the minimum spec version for the input spec.
+// Deprecated: use cdi.MinimumRequiredVersion instead
+func MinimumRequiredVersion(spec *cdi.Spec) (string, error) {
+	return cdi.MinimumRequiredVersion(spec)
+}
+
 // Validate the Spec.
 func (s *Spec) validate() (map[string]*Device, error) {
-	if err := validateVersion(s.Version); err != nil {
+	if err := cdi.ValidateVersion(s.Spec); err != nil {
 		return nil, err
 	}
-
-	minVersion, err := MinimumRequiredVersion(s.Spec)
-	if err != nil {
-		return nil, fmt.Errorf("could not determine minimum required version: %v", err)
-	}
-	if newVersion(minVersion).IsGreaterThan(newVersion(s.Version)) {
-		return nil, fmt.Errorf("the spec version must be at least v%v", minVersion)
-	}
-
-	if err := ValidateVendorName(s.vendor); err != nil {
+	if err := parser.ValidateVendorName(s.vendor); err != nil {
 		return nil, err
 	}
-	if err := ValidateClassName(s.class); err != nil {
+	if err := parser.ValidateClassName(s.class); err != nil {
 		return nil, err
 	}
 	if err := validation.ValidateSpecAnnotations(s.Kind, s.Annotations); err != nil {
@@ -238,17 +241,11 @@ func (s *Spec) validate() (map[string]*Device, error) {
 		}
 		devices[d.Name] = dev
 	}
-
-	return devices, nil
-}
-
-// validateVersion checks whether the specified spec version is supported.
-func validateVersion(version string) error {
-	if !validSpecVersions.isValidVersion(version) {
-		return fmt.Errorf("invalid version %q", version)
+	if len(devices) == 0 {
+		return nil, fmt.Errorf("invalid spec, no devices")
 	}
 
-	return nil
+	return devices, nil
 }
 
 // ParseSpec parses CDI Spec data into a raw CDI Spec.
@@ -264,13 +261,13 @@ func ParseSpec(data []byte) (*cdi.Spec, error) {
 // SetSpecValidator sets a CDI Spec validator function. This function
 // is used for extra CDI Spec content validation whenever a Spec file
 // loaded (using ReadSpec() or written (using WriteSpec()).
-func SetSpecValidator(fn func(*cdi.Spec) error) {
+func SetSpecValidator(v validator) {
 	validatorLock.Lock()
 	defer validatorLock.Unlock()
-	specValidator = fn
+	specValidator = v
 }
 
-// validateSpec validates the Spec using the extneral validator.
+// validateSpec validates the Spec using the external validator.
 func validateSpec(raw *cdi.Spec) error {
 	validatorLock.RLock()
 	defer validatorLock.RUnlock()
@@ -278,7 +275,7 @@ func validateSpec(raw *cdi.Spec) error {
 	if specValidator == nil {
 		return nil
 	}
-	err := specValidator(raw)
+	err := specValidator.Validate(raw)
 	if err != nil {
 		return fmt.Errorf("Spec validation failed: %w", err)
 	}
@@ -328,7 +325,7 @@ func GenerateTransientSpecName(vendor, class, transientID string) string {
 // the Spec does not contain a valid vendor or class, it returns
 // an empty name and a non-nil error.
 func GenerateNameForSpec(raw *cdi.Spec) (string, error) {
-	vendor, class := ParseQualifier(raw.Kind)
+	vendor, class := parser.ParseQualifier(raw.Kind)
 	if vendor == "" {
 		return "", fmt.Errorf("invalid vendor/class %q in Spec", raw.Kind)
 	}
@@ -342,7 +339,7 @@ func GenerateNameForSpec(raw *cdi.Spec) (string, error) {
 // If the Spec does not contain a valid vendor or class, it returns an
 // an empty name and a non-nil error.
 func GenerateNameForTransientSpec(raw *cdi.Spec, transientID string) (string, error) {
-	vendor, class := ParseQualifier(raw.Kind)
+	vendor, class := parser.ParseQualifier(raw.Kind)
 	if vendor == "" {
 		return "", fmt.Errorf("invalid vendor/class %q in Spec", raw.Kind)
 	}
diff --git a/vendor/tags.cncf.io/container-device-interface/specs-go/config.go b/vendor/tags.cncf.io/container-device-interface/specs-go/config.go
index d6d6302ff..f28657b86 100644
--- a/vendor/tags.cncf.io/container-device-interface/specs-go/config.go
+++ b/vendor/tags.cncf.io/container-device-interface/specs-go/config.go
@@ -2,72 +2,71 @@ package specs
 
 import "os"
 
-// CurrentVersion is the current version of the Spec.
-const CurrentVersion = "0.8.0"
-
 // Spec is the base configuration for CDI
 type Spec struct {
-	Version string `json:"cdiVersion"`
-	Kind    string `json:"kind"`
+	Version string `json:"cdiVersion" yaml:"cdiVersion"`
+	Kind    string `json:"kind"       yaml:"kind"`
 	// Annotations add meta information per CDI spec. Note these are CDI-specific and do not affect container metadata.
-	Annotations    map[string]string `json:"annotations,omitempty"`
-	Devices        []Device          `json:"devices"`
-	ContainerEdits ContainerEdits    `json:"containerEdits,omitempty"`
+	// Added in v0.6.0.
+	Annotations    map[string]string `json:"annotations,omitempty"    yaml:"annotations,omitempty"`
+	Devices        []Device          `json:"devices"                  yaml:"devices"`
+	ContainerEdits ContainerEdits    `json:"containerEdits,omitempty" yaml:"containerEdits,omitempty"`
 }
 
 // Device is a "Device" a container runtime can add to a container
 type Device struct {
-	Name string `json:"name"`
+	Name string `json:"name" yaml:"name"`
 	// Annotations add meta information per device. Note these are CDI-specific and do not affect container metadata.
-	Annotations    map[string]string `json:"annotations,omitempty"`
-	ContainerEdits ContainerEdits    `json:"containerEdits"`
+	// Added in v0.6.0.
+	Annotations    map[string]string `json:"annotations,omitempty" yaml:"annotations,omitempty"`
+	ContainerEdits ContainerEdits    `json:"containerEdits"        yaml:"containerEdits"`
 }
 
 // ContainerEdits are edits a container runtime must make to the OCI spec to expose the device.
 type ContainerEdits struct {
-	Env            []string      `json:"env,omitempty"`
-	DeviceNodes    []*DeviceNode `json:"deviceNodes,omitempty"`
-	Hooks          []*Hook       `json:"hooks,omitempty"`
-	Mounts         []*Mount      `json:"mounts,omitempty"`
-	IntelRdt       *IntelRdt     `json:"intelRdt,omitempty"`
-	AdditionalGIDs []uint32      `json:"additionalGids,omitempty"`
+	Env            []string      `json:"env,omitempty"            yaml:"env,omitempty"`
+	DeviceNodes    []*DeviceNode `json:"deviceNodes,omitempty"    yaml:"deviceNodes,omitempty"`
+	Hooks          []*Hook       `json:"hooks,omitempty"          yaml:"hooks,omitempty"`
+	Mounts         []*Mount      `json:"mounts,omitempty"         yaml:"mounts,omitempty"`
+	IntelRdt       *IntelRdt     `json:"intelRdt,omitempty"       yaml:"intelRdt,omitempty"`       // Added in v0.7.0
+	AdditionalGIDs []uint32      `json:"additionalGids,omitempty" yaml:"additionalGids,omitempty"` // Added in v0.7.0
 }
 
 // DeviceNode represents a device node that needs to be added to the OCI spec.
 type DeviceNode struct {
-	Path        string       `json:"path"`
-	HostPath    string       `json:"hostPath,omitempty"`
-	Type        string       `json:"type,omitempty"`
-	Major       int64        `json:"major,omitempty"`
-	Minor       int64        `json:"minor,omitempty"`
-	FileMode    *os.FileMode `json:"fileMode,omitempty"`
-	Permissions string       `json:"permissions,omitempty"`
-	UID         *uint32      `json:"uid,omitempty"`
-	GID         *uint32      `json:"gid,omitempty"`
+	Path        string       `json:"path"                  yaml:"path"`
+	HostPath    string       `json:"hostPath,omitempty"    yaml:"hostPath,omitempty"` // Added in v0.5.0
+	Type        string       `json:"type,omitempty"        yaml:"type,omitempty"`
+	Major       int64        `json:"major,omitempty"       yaml:"major,omitempty"`
+	Minor       int64        `json:"minor,omitempty"       yaml:"minor,omitempty"`
+	FileMode    *os.FileMode `json:"fileMode,omitempty"    yaml:"fileMode,omitempty"`
+	Permissions string       `json:"permissions,omitempty" yaml:"permissions,omitempty"`
+	UID         *uint32      `json:"uid,omitempty"         yaml:"uid,omitempty"`
+	GID         *uint32      `json:"gid,omitempty"         yaml:"gid,omitempty"`
 }
 
 // Mount represents a mount that needs to be added to the OCI spec.
 type Mount struct {
-	HostPath      string   `json:"hostPath"`
-	ContainerPath string   `json:"containerPath"`
-	Options       []string `json:"options,omitempty"`
-	Type          string   `json:"type,omitempty"`
+	HostPath      string   `json:"hostPath"          yaml:"hostPath"`
+	ContainerPath string   `json:"containerPath"     yaml:"containerPath"`
+	Options       []string `json:"options,omitempty" yaml:"options,omitempty"`
+	Type          string   `json:"type,omitempty"    yaml:"type,omitempty"` // Added in v0.4.0
 }
 
 // Hook represents a hook that needs to be added to the OCI spec.
 type Hook struct {
-	HookName string   `json:"hookName"`
-	Path     string   `json:"path"`
-	Args     []string `json:"args,omitempty"`
-	Env      []string `json:"env,omitempty"`
-	Timeout  *int     `json:"timeout,omitempty"`
+	HookName string   `json:"hookName"          yaml:"hookName"`
+	Path     string   `json:"path"              yaml:"path"`
+	Args     []string `json:"args,omitempty"    yaml:"args,omitempty"`
+	Env      []string `json:"env,omitempty"     yaml:"env,omitempty"`
+	Timeout  *int     `json:"timeout,omitempty" yaml:"timeout,omitempty"`
 }
 
 // IntelRdt describes the Linux IntelRdt parameters to set in the OCI spec.
 type IntelRdt struct {
-	ClosID        string `json:"closID,omitempty"`
-	L3CacheSchema string `json:"l3CacheSchema,omitempty"`
-	MemBwSchema   string `json:"memBwSchema,omitempty"`
-	EnableCMT     bool   `json:"enableCMT,omitempty"`
-	EnableMBM     bool   `json:"enableMBM,omitempty"`
+	ClosID        string `json:"closID,omitempty"        yaml:"closID,omitempty"`
+	L3CacheSchema string `json:"l3CacheSchema,omitempty" yaml:"l3CacheSchema,omitempty"`
+	MemBwSchema   string `json:"memBwSchema,omitempty"   yaml:"memBwSchema,omitempty"`
+	EnableCMT     bool   `json:"enableCMT,omitempty"     yaml:"enableCMT,omitempty"`
+	EnableMBM     bool   `json:"enableMBM,omitempty"     yaml:"enableMBM,omitempty"`
 }
diff --git a/vendor/tags.cncf.io/container-device-interface/specs-go/oci.go b/vendor/tags.cncf.io/container-device-interface/specs-go/oci.go
deleted file mode 100644
index ce485cb23..000000000
--- a/vendor/tags.cncf.io/container-device-interface/specs-go/oci.go
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
-Copyright © 2021 The CDI Authors
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-	http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package specs
-
-import "errors"
-
-// errDeprecated is returned for the ToOCI functions below.
-// This should provide better guidance for user when migrating from the API
-// below to the APIs provided in the cdi package.
-var errDeprecated = errors.New("deprecated; Use cdi package functions instead")
-
-// ToOCI returns the opencontainers runtime Spec Hook for this Hook.
-//
-// Deprecated: This function has been moved to tags.cncf.io/container-device-interface/pkg/cdi.Hook.toOCI
-// and made private.
-func (h *Hook) ToOCI() error {
-	return errDeprecated
-}
-
-// ToOCI returns the opencontainers runtime Spec Mount for this Mount.
-//
-// Deprecated: This function has been moved to tags.cncf.io/container-device-interface/pkg/cdi.Mount.toOCI
-// and made private.
-func (m *Mount) ToOCI() error {
-	return errDeprecated
-}
-
-// ToOCI returns the opencontainers runtime Spec LinuxDevice for this DeviceNode.
-//
-// Deprecated: This function has been moved to tags.cncf.io/container-device-interface/pkg/cdi.DeviceNode.toOCI
-// and made private.
-func (d *DeviceNode) ToOCI() error {
-	return errDeprecated
-}
-
-// ToOCI returns the opencontainers runtime Spec LinuxIntelRdt for this IntelRdt config.
-//
-// Deprecated: This function has been moved to tags.cncf.io/container-device-interface/pkg/cdi.IntelRdt.toOCI
-// and made private.
-func (i *IntelRdt) ToOCI() error {
-	return errDeprecated
-}
diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/version.go b/vendor/tags.cncf.io/container-device-interface/specs-go/version.go
similarity index 69%
rename from vendor/tags.cncf.io/container-device-interface/pkg/cdi/version.go
rename to vendor/tags.cncf.io/container-device-interface/specs-go/version.go
index 9ca912671..002e03505 100644
--- a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/version.go
+++ b/vendor/tags.cncf.io/container-device-interface/specs-go/version.go
@@ -14,20 +14,18 @@
    limitations under the License.
 */
 
-package cdi
+package specs
 
 import (
+	"fmt"
 	"strings"
 
 	"golang.org/x/mod/semver"
-
-	"tags.cncf.io/container-device-interface/pkg/parser"
-	cdi "tags.cncf.io/container-device-interface/specs-go"
 )
 
 const (
-	// CurrentVersion is the current version of the CDI Spec.
-	CurrentVersion = cdi.CurrentVersion
+	// CurrentVersion is the current version of the Spec.
+	CurrentVersion = "1.0.0"
 
 	// vCurrent is the current version as a semver-comparable type
 	vCurrent version = "v" + CurrentVersion
@@ -41,6 +39,7 @@ const (
 	v060 version = "v0.6.0"
 	v070 version = "v0.7.0"
 	v080 version = "v0.8.0"
+	v100 version = "v1.0.0"
 
 	// vEarliest is the earliest supported version of the CDI specification
 	vEarliest version = v030
@@ -58,10 +57,29 @@ var validSpecVersions = requiredVersionMap{
 	v060: requiresV060,
 	v070: requiresV070,
 	v080: requiresV080,
+	v100: requiresV100,
+}
+
+// ValidateVersion checks whether the specified spec version is valid.
+// In addition to checking whether the spec version is in the set of known versions,
+// the spec is inspected to determine whether the features used are available in specified
+// version.
+func ValidateVersion(spec *Spec) error {
+	if !validSpecVersions.isValidVersion(spec.Version) {
+		return fmt.Errorf("invalid version %q", spec.Version)
+	}
+	minVersion, err := MinimumRequiredVersion(spec)
+	if err != nil {
+		return fmt.Errorf("could not determine minimum required version: %w", err)
+	}
+	if newVersion(minVersion).isGreaterThan(newVersion(spec.Version)) {
+		return fmt.Errorf("the spec version must be at least v%v", minVersion)
+	}
+	return nil
 }
 
 // MinimumRequiredVersion determines the minimum spec version for the input spec.
-func MinimumRequiredVersion(spec *cdi.Spec) (string, error) {
+func MinimumRequiredVersion(spec *Spec) (string, error) {
 	minVersion := validSpecVersions.requiredVersion(spec)
 	return minVersion.String(), nil
 }
@@ -80,17 +98,17 @@ func (v version) String() string {
 	return strings.TrimPrefix(string(v), "v")
 }
 
-// IsGreaterThan checks with a version is greater than the specified version.
-func (v version) IsGreaterThan(o version) bool {
+// isGreaterThan checks with a version is greater than the specified version.
+func (v version) isGreaterThan(o version) bool {
 	return semver.Compare(string(v), string(o)) > 0
 }
 
-// IsLatest checks whether the version is the latest supported version
-func (v version) IsLatest() bool {
+// isLatest checks whether the version is the latest supported version
+func (v version) isLatest() bool {
 	return v == vCurrent
 }
 
-type requiredFunc func(*cdi.Spec) bool
+type requiredFunc func(*Spec) bool
 
 type requiredVersionMap map[version]requiredFunc
 
@@ -103,18 +121,18 @@ func (r requiredVersionMap) isValidVersion(specVersion string) bool {
 }
 
 // requiredVersion returns the minimum version required for the given spec
-func (r requiredVersionMap) requiredVersion(spec *cdi.Spec) version {
+func (r requiredVersionMap) requiredVersion(spec *Spec) version {
 	minVersion := vEarliest
 
 	for v, isRequired := range validSpecVersions {
 		if isRequired == nil {
 			continue
 		}
-		if isRequired(spec) && v.IsGreaterThan(minVersion) {
+		if isRequired(spec) && v.isGreaterThan(minVersion) {
 			minVersion = v
 		}
 		// If we have already detected the latest version then no later version could be detected
-		if minVersion.IsLatest() {
+		if minVersion.isLatest() {
 			break
 		}
 	}
@@ -122,15 +140,22 @@ func (r requiredVersionMap) requiredVersion(spec *cdi.Spec) version {
 	return minVersion
 }
 
+// requiresV100 returns true if the spec uses v1.0.0 features.
+// Since the v1.0.0 spec bump was due to moving the minimum version checks to
+// the spec package, there are no explicit spec changes.
+func requiresV100(_ *Spec) bool {
+	return false
+}
+
 // requiresV080 returns true if the spec uses v0.8.0 features.
 // Since the v0.8.0 spec bump was due to the removed .ToOCI functions on the
-// spec types, there are explicit spec changes.
-func requiresV080(_ *cdi.Spec) bool {
+// spec types, there are no explicit spec changes.
+func requiresV080(_ *Spec) bool {
 	return false
 }
 
 // requiresV070 returns true if the spec uses v0.7.0 features
-func requiresV070(spec *cdi.Spec) bool {
+func requiresV070(spec *Spec) bool {
 	if spec.ContainerEdits.IntelRdt != nil {
 		return true
 	}
@@ -153,7 +178,7 @@ func requiresV070(spec *cdi.Spec) bool {
 }
 
 // requiresV060 returns true if the spec uses v0.6.0 features
-func requiresV060(spec *cdi.Spec) bool {
+func requiresV060(spec *Spec) bool {
 	// The v0.6.0 spec allows annotations to be specified at a spec level
 	for range spec.Annotations {
 		return true
@@ -167,23 +192,20 @@ func requiresV060(spec *cdi.Spec) bool {
 	}
 
 	// The v0.6.0 spec allows dots "." in Kind name label (class)
-	vendor, class := parser.ParseQualifier(spec.Kind)
-	if vendor != "" {
-		if strings.ContainsRune(class, '.') {
-			return true
-		}
+	if !strings.Contains(spec.Kind, "/") {
+		return false
 	}
-
-	return false
+	class := strings.SplitN(spec.Kind, "/", 2)[1]
+	return strings.Contains(class, ".")
 }
 
 // requiresV050 returns true if the spec uses v0.5.0 features
-func requiresV050(spec *cdi.Spec) bool {
-	var edits []*cdi.ContainerEdits
+func requiresV050(spec *Spec) bool {
+	var edits []*ContainerEdits
 
 	for _, d := range spec.Devices {
-		// The v0.5.0 spec allowed device names to start with a digit instead of requiring a letter
-		if len(d.Name) > 0 && !parser.IsLetter(rune(d.Name[0])) {
+		// The v0.5.0 spec allowed device name to start with a digit
+		if len(d.Name) > 0 && '0' <= d.Name[0] && d.Name[0] <= '9' {
 			return true
 		}
 		edits = append(edits, &d.ContainerEdits)
@@ -202,8 +224,8 @@ func requiresV050(spec *cdi.Spec) bool {
 }
 
 // requiresV040 returns true if the spec uses v0.4.0 features
-func requiresV040(spec *cdi.Spec) bool {
-	var edits []*cdi.ContainerEdits
+func requiresV040(spec *Spec) bool {
+	var edits []*ContainerEdits
 
 	for _, d := range spec.Devices {
 		edits = append(edits, &d.ContainerEdits)
diff --git a/worker/base/worker.go b/worker/base/worker.go
index 4e3357c78..0329c2888 100644
--- a/worker/base/worker.go
+++ b/worker/base/worker.go
@@ -13,7 +13,6 @@ import (
 	"github.com/containerd/containerd/v2/core/remotes/docker"
 	"github.com/containerd/containerd/v2/pkg/gc"
 	"github.com/containerd/platforms"
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/hashicorp/go-multierror"
 	"github.com/moby/buildkit/cache"
 	"github.com/moby/buildkit/cache/metadata"
@@ -48,6 +47,7 @@ import (
 	"github.com/moby/buildkit/util/network"
 	"github.com/moby/buildkit/util/progress"
 	"github.com/moby/buildkit/util/progress/controller"
+	"github.com/moby/sys/user"
 	digest "github.com/opencontainers/go-digest"
 	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
@@ -76,7 +76,7 @@ type WorkerOpt struct {
 	Differ           diff.Comparer
 	ImageStore       images.Store // optional
 	RegistryHosts    docker.RegistryHosts
-	IdentityMapping  *idtools.IdentityMapping
+	IdentityMapping  *user.IdentityMapping
 	LeaseManager     *leaseutil.Manager
 	GarbageCollect   func(context.Context) (gc.Stats, error)
 	ParallelismSem   *semaphore.Weighted
diff --git a/worker/containerd/containerd.go b/worker/containerd/containerd.go
index c6a5b1e05..0d34fe9b4 100644
--- a/worker/containerd/containerd.go
+++ b/worker/containerd/containerd.go
@@ -2,6 +2,7 @@ package containerd
 
 import (
 	"context"
+	"maps"
 	"os"
 	"path/filepath"
 	"strconv"
@@ -100,9 +101,7 @@ func newContainerd(client *ctd.Client, workerOpts WorkerOptions) (base.WorkerOpt
 	}
 	xlabels[wlabel.ContainerdNamespace] = workerOpts.Namespace
 	xlabels[wlabel.ContainerdUUID] = serverInfo.UUID
-	for k, v := range workerOpts.Labels {
-		xlabels[k] = v
-	}
+	maps.Copy(xlabels, workerOpts.Labels)
 
 	lm := leaseutil.WithNamespace(client.LeasesService(), workerOpts.Namespace)
 
diff --git a/worker/runc/runc.go b/worker/runc/runc.go
index 1626530d5..ededdc3cc 100644
--- a/worker/runc/runc.go
+++ b/worker/runc/runc.go
@@ -4,6 +4,7 @@ package runc
 
 import (
 	"context"
+	"maps"
 	"os"
 	"path/filepath"
 	"strconv"
@@ -14,7 +15,6 @@ import (
 	"github.com/containerd/containerd/v2/plugins/content/local"
 	"github.com/containerd/containerd/v2/plugins/diff/walking"
 	"github.com/containerd/platforms"
-	"github.com/docker/docker/pkg/idtools"
 	"github.com/moby/buildkit/cache"
 	"github.com/moby/buildkit/cache/metadata"
 	"github.com/moby/buildkit/executor/oci"
@@ -27,6 +27,7 @@ import (
 	"github.com/moby/buildkit/util/winlayers"
 	"github.com/moby/buildkit/worker/base"
 	wlabel "github.com/moby/buildkit/worker/label"
+	"github.com/moby/sys/user"
 	ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
 	bolt "go.etcd.io/bbolt"
 	"golang.org/x/sync/semaphore"
@@ -39,7 +40,7 @@ type SnapshotterFactory struct {
 }
 
 // NewWorkerOpt creates a WorkerOpt.
-func NewWorkerOpt(root string, snFactory SnapshotterFactory, rootless bool, processMode oci.ProcessMode, labels map[string]string, idmap *idtools.IdentityMapping, nopt netproviders.Opt, dns *oci.DNSConfig, binary, apparmorProfile string, selinux bool, parallelismSem *semaphore.Weighted, traceSocket, defaultCgroupParent string, cdiManager *cdidevices.Manager) (base.WorkerOpt, error) {
+func NewWorkerOpt(root string, snFactory SnapshotterFactory, rootless bool, processMode oci.ProcessMode, labels map[string]string, idmap *user.IdentityMapping, nopt netproviders.Opt, dns *oci.DNSConfig, binary, apparmorProfile string, selinux bool, parallelismSem *semaphore.Weighted, traceSocket, defaultCgroupParent string, cdiManager *cdidevices.Manager) (base.WorkerOpt, error) {
 	var opt base.WorkerOpt
 	name := "runc-" + snFactory.Name
 	root = filepath.Join(root, name)
@@ -128,9 +129,7 @@ func NewWorkerOpt(root string, snFactory SnapshotterFactory, rootless bool, proc
 		xlabels[wlabel.ApparmorProfile] = apparmorProfile
 	}
 
-	for k, v := range labels {
-		xlabels[k] = v
-	}
+	maps.Copy(xlabels, labels)
 	lm := leaseutil.WithNamespace(ctdmetadata.NewLeaseManager(mdb), "buildkit")
 	snap := containerdsnapshot.NewSnapshotter(snFactory.Name, mdb.Snapshotter(snFactory.Name), "buildkit", idmap)
 	if err := cache.MigrateV2(



Test patch:
diff --git a/client/client_test.go b/client/client_test.go
index badac0b0a..ccfd94959 100644
--- a/client/client_test.go
+++ b/client/client_test.go
@@ -1229,8 +1229,8 @@ func testFrontendImageNaming(t *testing.T, sb integration.Sandbox) {
 			// Nothing to check
 		},
 		ExporterDocker: func(out, imageName string, exporterResponse map[string]string) {
-			require.Contains(t, exporterResponse, "image.name")
-			require.Equal(t, exporterResponse["image.name"], "docker.io/library/"+imageName)
+			require.Contains(t, exporterResponse, exptypes.ExporterImageNameKey)
+			require.Equal(t, exporterResponse[exptypes.ExporterImageNameKey], "docker.io/library/"+imageName)
 
 			dt, err := os.ReadFile(out)
 			require.NoError(t, err)
@@ -1257,8 +1257,8 @@ func testFrontendImageNaming(t *testing.T, sb integration.Sandbox) {
 			require.Equal(t, imageName, dockerMfst[0].RepoTags[0])
 		},
 		ExporterImage: func(_, imageName string, exporterResponse map[string]string) {
-			require.Contains(t, exporterResponse, "image.name")
-			require.Equal(t, exporterResponse["image.name"], imageName)
+			require.Contains(t, exporterResponse, exptypes.ExporterImageNameKey)
+			require.Equal(t, exporterResponse[exptypes.ExporterImageNameKey], imageName)
 
 			// check if we can pull (requires containerd)
 			cdAddress := sb.ContainerdAddress()
@@ -1782,10 +1782,11 @@ func testFileOpCopyChmodText(t *testing.T, sb integration.Sandbox) {
 		{"file", "f4", "u+rw,g+r,o-x,o+w"},
 		{"dir", "d1", "a+X"},
 		{"dir", "d2", "g+rw,o+rw"},
+		{"dir", "d3", "u=rwX,go=rX"},
 	}
 
 	st := llb.Image("alpine").
-		Run(llb.Shlex(`sh -c "mkdir /input && touch /input/file && mkdir /input/dir && chmod 0400 /input/dir && mkdir /expected"`))
+		Run(llb.Shlex(`sh -c "mkdir /input && touch /input/file && mkdir /input/dir && chmod 0500 /input/dir && mkdir /expected"`))
 
 	for _, tc := range tcases {
 		st = st.Run(llb.Shlex(`sh -c "cp -a /input/` + tc.src + ` /expected/` + tc.dest + ` && chmod ` + tc.mode + ` /expected/` + tc.dest + `"`))
@@ -3291,9 +3292,9 @@ func testMultipleExporters(t *testing.T, sb integration.Sandbox) {
 	require.NoError(t, err)
 
 	if workers.IsTestDockerd() {
-		require.Equal(t, resp.ExporterResponse["image.name"], target1+","+target2)
+		require.Equal(t, resp.ExporterResponse[exptypes.ExporterImageNameKey], target1+","+target2)
 	} else {
-		require.Equal(t, resp.ExporterResponse["image.name"], target2)
+		require.Equal(t, resp.ExporterResponse[exptypes.ExporterImageNameKey], target2)
 	}
 	require.FileExists(t, filepath.Join(destDir, "out.tar"))
 	require.FileExists(t, filepath.Join(destDir, "out2.tar"))
diff --git a/cmd/buildctl/build_test.go b/cmd/buildctl/build_test.go
index 6bb791077..76d072de4 100644
--- a/cmd/buildctl/build_test.go
+++ b/cmd/buildctl/build_test.go
@@ -144,8 +144,8 @@ func testBuildMetadataFile(t *testing.T, sb integration.Sandbox) {
 	err = json.Unmarshal(metadataBytes, &metadata)
 	require.NoError(t, err)
 
-	require.Contains(t, metadata, "image.name")
-	require.Equal(t, imageName, metadata["image.name"])
+	require.Contains(t, metadata, exptypes.ExporterImageNameKey)
+	require.Equal(t, imageName, metadata[exptypes.ExporterImageNameKey])
 
 	require.Contains(t, metadata, exptypes.ExporterImageDigestKey)
 	digest := metadata[exptypes.ExporterImageDigestKey]
diff --git a/util/testutil/integration/run.go b/util/testutil/integration/run.go
index c087c7cb6..fefbb167c 100644
--- a/util/testutil/integration/run.go
+++ b/util/testutil/integration/run.go
@@ -360,55 +360,97 @@ func lazyMirrorRunnerFunc(t *testing.T, images map[string]string) func() string
 	var mirror string
 	return func() string {
 		once.Do(func() {
-			host, cleanup, err := runMirror(t, images)
+			m, err := RunMirror()
 			require.NoError(t, err)
-			t.Cleanup(func() { _ = cleanup() })
-			mirror = host
+			require.NoError(t, m.AddImages(t, images))
+			t.Cleanup(func() { _ = m.Close() })
+			mirror = m.Host
 		})
 		return mirror
 	}
 }
 
-func runMirror(t *testing.T, mirroredImages map[string]string) (host string, _ func() error, err error) {
-	mirrorDir := os.Getenv("BUILDKIT_REGISTRY_MIRROR_DIR")
+type Mirror struct {
+	Host    string
+	dir     string
+	cleanup func() error
+}
 
-	var lock *flock.Flock
-	if mirrorDir != "" {
-		if err := os.MkdirAll(mirrorDir, 0700); err != nil {
-			return "", nil, err
-		}
-		lock = flock.New(filepath.Join(mirrorDir, "lock"))
-		if err := lock.Lock(); err != nil {
-			return "", nil, err
+func (m *Mirror) lock() (*flock.Flock, error) {
+	if m.dir == "" {
+		return nil, nil
+	}
+	if err := os.MkdirAll(m.dir, 0700); err != nil {
+		return nil, err
+	}
+	lock := flock.New(filepath.Join(m.dir, "lock"))
+	if err := lock.Lock(); err != nil {
+		return nil, err
+	}
+	return lock, nil
+}
+
+func (m *Mirror) Close() error {
+	if m.cleanup != nil {
+		return m.cleanup()
+	}
+	return nil
+}
+
+func (m *Mirror) AddImages(t *testing.T, images map[string]string) (err error) {
+	lock, err := m.lock()
+	if err != nil {
+		return err
+	}
+	defer func() {
+		if lock != nil {
+			lock.Unlock()
 		}
-		defer func() {
-			if err != nil {
-				lock.Unlock()
-			}
-		}()
+	}()
+
+	if err := copyImagesLocal(t, m.Host, images); err != nil {
+		return err
+	}
+	return nil
+}
+
+func RunMirror() (_ *Mirror, err error) {
+	mirrorDir := os.Getenv("BUILDKIT_REGISTRY_MIRROR_DIR")
+
+	m := &Mirror{
+		dir: mirrorDir,
 	}
 
-	mirror, cleanup, err := NewRegistry(mirrorDir)
+	lock, err := m.lock()
 	if err != nil {
-		return "", nil, err
+		return nil, err
 	}
 	defer func() {
 		if err != nil {
-			cleanup()
+			lock.Unlock()
 		}
 	}()
 
-	if err := copyImagesLocal(t, mirror, mirroredImages); err != nil {
-		return "", nil, err
+	host, cleanup, err := NewRegistry(mirrorDir)
+	if err != nil {
+		return nil, err
 	}
+	defer func() {
+		if err != nil {
+			cleanup()
+		}
+	}()
+
+	m.Host = host
+	m.cleanup = cleanup
 
-	if mirrorDir != "" {
+	if lock != nil {
 		if err := lock.Unlock(); err != nil {
-			return "", nil, err
+			return nil, err
 		}
 	}
 
-	return mirror, cleanup, err
+	return m, err
 }
 
 type matrixValue struct {
diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache_test_darwin.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache_test_darwin.go
new file mode 100644
index 000000000..b09ea6ff9
--- /dev/null
+++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache_test_darwin.go
@@ -0,0 +1,26 @@
+//go:build darwin
+// +build darwin
+
+/*
+   Copyright © 2021 The CDI Authors
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package cdi
+
+import "syscall"
+
+func osSync() {
+	_ = syscall.Sync()
+}
diff --git a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache_test_unix.go b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache_test_unix.go
index 0ee5fb86f..b7c44129f 100644
--- a/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache_test_unix.go
+++ b/vendor/tags.cncf.io/container-device-interface/pkg/cdi/cache_test_unix.go
@@ -1,5 +1,5 @@
-//go:build !windows
-// +build !windows
+//go:build !windows && !darwin
+// +build !windows,!darwin
 
 /*
    Copyright © 2021 The CDI Authors
diff --git a/worker/containerd/containerd_test.go b/worker/containerd/containerd_test.go
index f8e7cbae1..04db1b3db 100644
--- a/worker/containerd/containerd_test.go
+++ b/worker/containerd/containerd_test.go
@@ -14,6 +14,11 @@ import (
 	"github.com/stretchr/testify/require"
 )
 
+func TestMain(m *testing.M) {
+	defer tests.RunMirror()()
+	m.Run()
+}
+
 func init() {
 	workers.InitContainerdWorker()
 }
diff --git a/worker/runc/runc_test.go b/worker/runc/runc_test.go
index ea58b90d4..82b4c40f5 100644
--- a/worker/runc/runc_test.go
+++ b/worker/runc/runc_test.go
@@ -27,6 +27,11 @@ import (
 	"github.com/stretchr/testify/require"
 )
 
+func TestMain(m *testing.M) {
+	defer tests.RunMirror()()
+	m.Run()
+}
+
 func newWorkerOpt(t *testing.T, processMode oci.ProcessMode) base.WorkerOpt {
 	tmpdir := t.TempDir()
 
diff --git a/worker/tests/common.go b/worker/tests/common.go
index 07efebb55..85ac3c24c 100644
--- a/worker/tests/common.go
+++ b/worker/tests/common.go
@@ -4,6 +4,7 @@ import (
 	"bytes"
 	"context"
 	"io"
+	"sync"
 	"testing"
 	"time"
 
@@ -14,14 +15,38 @@ import (
 	"github.com/moby/buildkit/session"
 	"github.com/moby/buildkit/snapshot"
 	"github.com/moby/buildkit/source/containerimage"
+	"github.com/moby/buildkit/util/testutil/integration"
 	"github.com/moby/buildkit/worker/base"
 	"github.com/pkg/errors"
 	"github.com/stretchr/testify/require"
 	"golang.org/x/sync/errgroup"
 )
 
+var mirrorOnce sync.Once
+var mirror *integration.Mirror
+var mirrorMu sync.Mutex
+
+func RunMirror() func() error {
+	mirrorOnce.Do(func() {
+		m, err := integration.RunMirror()
+		if err != nil {
+			panic(err)
+		}
+		mirror = m
+	})
+	return func() error { return mirror.Close() }
+}
+
+func mirrorBusybox(t *testing.T) string {
+	mirrorMu.Lock()
+	defer mirrorMu.Unlock()
+	require.NotNil(t, mirror, "mirror must be initialized")
+	require.NoError(t, mirror.AddImages(t, integration.OfficialImages("busybox:latest")))
+	return mirror.Host + "/library/busybox:latest"
+}
+
 func NewBusyboxSourceSnapshot(ctx context.Context, t *testing.T, w *base.Worker, sm *session.Manager) cache.ImmutableRef {
-	img, err := containerimage.NewImageIdentifier("docker.io/library/busybox:latest")
+	img, err := containerimage.NewImageIdentifier(mirrorBusybox(t))
 	require.NoError(t, err)
 	src, err := w.SourceManager.Resolve(ctx, img, sm, nil)
 	require.NoError(t, err)