From 78e61af47a3f5d539b405b39a7230c99369639bc Mon Sep 17 00:00:00 2001 From: Phil Estes Date: Mon, 10 Sep 2018 15:34:25 -0400 Subject: [PATCH] Add With-helper for supplemental gid support Can be used to conform to Docker engine behavior of adding additional GIDs to spec when found in /etc/group of image filesystem Signed-off-by: Phil Estes --- oci/spec_opts.go | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/oci/spec_opts.go b/oci/spec_opts.go index 47ffd8c9f..973ac7e15 100644 --- a/oci/spec_opts.go +++ b/oci/spec_opts.go @@ -634,6 +634,66 @@ func WithUsername(username string) SpecOpts { } } +// WithAdditionalGIDs sets the OCI spec's additionalGids array to any additional groups listed +// for a particular user in the /etc/groups file of the image's root filesystem +func WithAdditionalGIDs(username string) SpecOpts { + return func(ctx context.Context, client Client, c *containers.Container, s *Spec) (err error) { + setProcess(s) + if c.Snapshotter == "" && c.SnapshotKey == "" { + if !isRootfsAbs(s.Root.Path) { + return errors.Errorf("rootfs absolute path is required") + } + gids, err := getSupplementalGroupsFromPath(s.Root.Path, func(g user.Group) bool { + // we only want supplemental groups + if g.Name == username { + return false + } + for _, entry := range g.List { + if entry == username { + return true + } + } + return false + }) + if err != nil { + return err + } + s.Process.User.AdditionalGids = gids + return nil + } + if c.Snapshotter == "" { + return errors.Errorf("no snapshotter set for container") + } + if c.SnapshotKey == "" { + return errors.Errorf("rootfs snapshot not created for container") + } + snapshotter := client.SnapshotService(c.Snapshotter) + mounts, err := snapshotter.Mounts(ctx, c.SnapshotKey) + if err != nil { + return err + } + return mount.WithTempMount(ctx, mounts, func(root string) error { + gids, err := getSupplementalGroupsFromPath(root, func(g user.Group) bool { + // we only want supplemental groups + if g.Name == username { + return false + } + for _, entry := range g.List { + if entry == username { + return true + } + } + return false + }) + if err != nil { + return err + } + s.Process.User.AdditionalGids = gids + return nil + }) + } +} + // WithCapabilities sets Linux capabilities on the process func WithCapabilities(caps []string) SpecOpts { return func(_ context.Context, _ Client, _ *containers.Container, s *Spec) error { @@ -715,6 +775,26 @@ func getGIDFromPath(root string, filter func(user.Group) bool) (gid uint32, err return uint32(g.Gid), nil } +func getSupplementalGroupsFromPath(root string, filter func(user.Group) bool) ([]uint32, error) { + gpath, err := fs.RootPath(root, "/etc/group") + if err != nil { + return []uint32{}, err + } + groups, err := user.ParseGroupFileFilter(gpath, filter) + if err != nil { + return []uint32{}, err + } + if len(groups) == 0 { + // if there are no additional groups; just return an empty set + return []uint32{}, nil + } + addlGids := []uint32{} + for _, grp := range groups { + addlGids = append(addlGids, uint32(grp.Gid)) + } + return addlGids, nil +} + func isRootfsAbs(root string) bool { return filepath.IsAbs(root) }