From 1ba5aa43f3af34a6df851c3093c2eb2ccf85ae1e Mon Sep 17 00:00:00 2001 From: "Jonathan A. Sternberg" Date: Thu, 27 Feb 2025 19:15:11 -0600 Subject: [PATCH] vendor: switch from idtools to moby/sys/user Convert usages of `github.com/docker/docker/pkg/idtools` to `github.com/moby/sys/user` in order to break the dependency between buildkit and docker. Signed-off-by: Jonathan A. Sternberg --- cache/manager.go | 6 +- cache/refs.go | 6 +- cmd/buildkitd/util_linux.go | 6 +- executor/containerdexecutor/executor.go | 2 +- executor/containerdexecutor/executor_unix.go | 11 +- .../containerdexecutor/executor_windows.go | 14 +- executor/executor.go | 4 +- executor/oci/hosts.go | 10 +- executor/oci/resolvconf.go | 16 +- executor/oci/spec.go | 4 +- executor/oci/spec_darwin.go | 4 +- executor/oci/spec_freebsd.go | 4 +- executor/oci/spec_linux.go | 14 +- executor/oci/spec_windows.go | 4 +- executor/runcexecutor/executor.go | 21 ++- exporter/local/fs.go | 9 +- frontend/gateway/gateway.go | 4 +- go.mod | 2 +- go.sum | 4 +- snapshot/containerd/snapshotter.go | 10 +- snapshot/snapshotter.go | 19 ++- snapshot/staticmountable.go | 6 +- solver/llbsolver/file/backend.go | 10 +- solver/llbsolver/file/backend_unix.go | 20 +-- solver/llbsolver/file/backend_windows.go | 7 +- solver/llbsolver/file/unpack.go | 21 ++- solver/llbsolver/mounts/mount.go | 40 ++--- solver/llbsolver/ops/exec_binfmt.go | 12 +- solver/llbsolver/ops/user_windows.go | 9 +- source/git/source.go | 14 +- source/http/source.go | 17 +-- source/local/source.go | 26 ++-- util/system/getuserinfo/userinfo_windows.go | 6 +- util/windows/util_windows.go | 36 +++-- vendor/github.com/moby/sys/user/idtools.go | 141 +++++++++++++++++ .../github.com/moby/sys/user/idtools_unix.go | 143 ++++++++++++++++++ .../moby/sys/user/idtools_windows.go | 13 ++ vendor/modules.txt | 2 +- worker/base/worker.go | 4 +- worker/runc/runc.go | 4 +- 40 files changed, 500 insertions(+), 205 deletions(-) create mode 100644 vendor/github.com/moby/sys/user/idtools.go create mode 100644 vendor/github.com/moby/sys/user/idtools_unix.go create mode 100644 vendor/github.com/moby/sys/user/idtools_windows.go diff --git a/cache/manager.go b/cache/manager.go index f5af2c6a97d2..fd3a109fa1b2 100644 --- a/cache/manager.go +++ b/cache/manager.go @@ -15,7 +15,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 +24,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 +61,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 +337,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() } diff --git a/cache/refs.go b/cache/refs.go index aa2b3f380984..b781fa40ed81 100644 --- a/cache/refs.go +++ b/cache/refs.go @@ -17,7 +17,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" @@ -33,6 +32,7 @@ import ( rootlessmountopts "github.com/moby/buildkit/util/rootless/mountopts" "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" @@ -48,7 +48,7 @@ type Ref interface { Mountable RefMetadata Release(context.Context) error - IdentityMapping() *idtools.IdentityMapping + IdentityMapping() *user.IdentityMapping DescHandler(digest.Digest) *DescHandler } @@ -309,7 +309,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() } diff --git a/cmd/buildkitd/util_linux.go b/cmd/buildkitd/util_linux.go index 2fda61c91d40..3f18edf96367 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 366959f01492..99540d7c629e 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 2233909cdff5..5e3e2ecf54bc 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 b09114deb432..1145c2f25261 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 d35e18af6513..aa011e27d700 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 e27d13ccd380..23e3fd555244 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 7def36a6f495..8354d101ccc5 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 e3887d9c4127..2e90665d1bf8 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 ae609a216bce..15a4544ac3af 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 d1456a8eca53..71efef5cf0c5 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 7b437c28b8b0..2e80c8557e7c 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 bdd8757fb04d..3e28c29003fd 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 1ca978bbb75f..cbc3f9ebadfd 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/local/fs.go b/exporter/local/fs.go index b565592d2300..1985ed0096dc 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/frontend/gateway/gateway.go b/frontend/gateway/gateway.go index 19edcd84f10e..ec437ddbbce8 100644 --- a/frontend/gateway/gateway.go +++ b/frontend/gateway/gateway.go @@ -18,7 +18,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" @@ -48,6 +47,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" @@ -412,7 +412,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 479b9c30cd77..53b5b4da2607 100644 --- a/go.mod +++ b/go.mod @@ -53,7 +53,7 @@ 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.3.1-0.20250227193707-71f0c5ead442 github.com/moby/sys/userns v0.1.0 github.com/morikuni/aec v1.0.0 github.com/opencontainers/go-digest v1.0.0 diff --git a/go.sum b/go.sum index 98d55401a175..f1b0f709fe8a 100644 --- a/go.sum +++ b/go.sum @@ -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.3.1-0.20250227193707-71f0c5ead442 h1:1sbX2CeW23ljS5+eKSeIzU5XJk3RTZITcZcJJ0fDQBc= +github.com/moby/sys/user v0.3.1-0.20250227193707-71f0c5ead442/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= diff --git a/snapshot/containerd/snapshotter.go b/snapshot/containerd/snapshotter.go index 12ff1b1dad74..50b818bb370d 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/snapshotter.go b/snapshot/snapshotter.go index fde9957fce06..14ee0e3f9e6c 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 098146824a61..65845667b92c 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/llbsolver/file/backend.go b/solver/llbsolver/file/backend.go index 465cfe67aeee..939a8454cd87 100644 --- a/solver/llbsolver/file/backend.go +++ b/solver/llbsolver/file/backend.go @@ -10,11 +10,11 @@ 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/buildkit/util/system" + "github.com/moby/sys/user" "github.com/pkg/errors" copy "github.com/tonistiigi/fsutil/copy" ) @@ -27,7 +27,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) { @@ -67,7 +67,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) { @@ -101,7 +101,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) { @@ -189,7 +189,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, err := cleanPath(action.Src) if err != nil { return errors.Wrap(err, "cleaning source path") diff --git a/solver/llbsolver/file/backend_unix.go b/solver/llbsolver/file/backend_unix.go index f515d7db62f3..7014f73433b3 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 = ©.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 ©.User{UID: identity.UID, GID: identity.GID}, nil + return ©.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 70c1ba1475a0..d35080be083c 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 = ©.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 ff167e324de0..33bbd23aff1a 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 92b103458f3c..93d97a907d22 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 9b410d4b8f5b..6b9f8246399b 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 1164a8fdb4a6..732b340f3e4f 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 ©.User{SID: ident.SID}, nil + return ©.User{SID: sid}, nil default: - return ©.User{SID: idtools.ContainerAdministratorSidString}, nil + return ©.User{SID: windows.ContainerAdministratorSidString}, nil } } - return ©.User{SID: idtools.ContainerAdministratorSidString}, nil + return ©.User{SID: windows.ContainerAdministratorSidString}, nil } diff --git a/source/git/source.go b/source/git/source.go index 12b381196b06..37da0de9d6d6 100644 --- a/source/git/source.go +++ b/source/git/source.go @@ -635,9 +635,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") @@ -743,10 +743,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 130339fcc0e9..819a71812d33 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 28a6f7affd4f..5f6485a66e06 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 3c00bfb1bf3c..08f7a1021953 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 997c19f32b63..19293a3cd02c 100644 --- a/util/windows/util_windows.go +++ b/util/windows/util_windows.go @@ -8,20 +8,25 @@ 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) { +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 +34,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 +49,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 +71,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 +107,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 +145,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/moby/sys/user/idtools.go b/vendor/github.com/moby/sys/user/idtools.go new file mode 100644 index 000000000000..595b7a927263 --- /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 000000000000..4e39d2446b23 --- /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 000000000000..9de730cafbe0 --- /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/modules.txt b/vendor/modules.txt index 1508768c22bb..9d4f39628791 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -651,7 +651,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.3.1-0.20250227193707-71f0c5ead442 ## explicit; go 1.17 github.com/moby/sys/user # github.com/moby/sys/userns v0.1.0 diff --git a/worker/base/worker.go b/worker/base/worker.go index c1569cd98a1e..d34ec57da8da 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/runc/runc.go b/worker/runc/runc.go index 1626530d5e7f..7d97aed2985d 100644 --- a/worker/runc/runc.go +++ b/worker/runc/runc.go @@ -14,7 +14,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 +26,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 +39,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)