Port osbuild/images v0.33.0 with dot-notation to composer
Update the osbuild/images to the version which introduces "dot notation" for distro release versions. - Replace all uses of distroregistry by distrofactory. - Delete local version of reporegistry and use the one from the osbuild/images. - Weldr: unify `createWeldrAPI()` and `createWeldrAPI2()` into a single `createTestWeldrAPI()` function`. - store/fixture: rework fixtures to allow overriding the host distro name and host architecture name. A cleanup function to restore the host distro and arch names is always part of the fixture struct. - Delete `distro_mock` package, since it is no longer used. - Bump the required version of osbuild to 98, because the OSCAP customization is using the 'compress_results' stage option, which is not available in older versions of osbuild. Signed-off-by: Tomáš Hozza <thozza@redhat.com>
This commit is contained in:
parent
f6ff8c40dd
commit
625b1578fa
1166 changed files with 154457 additions and 5508 deletions
311
vendor/github.com/containers/storage/userns.go
generated
vendored
Normal file
311
vendor/github.com/containers/storage/userns.go
generated
vendored
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
drivers "github.com/containers/storage/drivers"
|
||||
"github.com/containers/storage/pkg/idtools"
|
||||
"github.com/containers/storage/pkg/unshare"
|
||||
"github.com/containers/storage/types"
|
||||
libcontainerUser "github.com/opencontainers/runc/libcontainer/user"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// getAdditionalSubIDs looks up the additional IDs configured for
|
||||
// the specified user.
|
||||
// The argument USERNAME is ignored for rootless users, as it is not
|
||||
// possible to use an arbitrary entry in /etc/sub*id.
|
||||
// Differently, if the username is not specified for root users, a
|
||||
// default name is used.
|
||||
func getAdditionalSubIDs(username string) (*idSet, *idSet, error) {
|
||||
var uids, gids *idSet
|
||||
|
||||
if unshare.IsRootless() {
|
||||
username = os.Getenv("USER")
|
||||
if username == "" {
|
||||
var id string
|
||||
if os.Geteuid() == 0 {
|
||||
id = strconv.Itoa(unshare.GetRootlessUID())
|
||||
} else {
|
||||
id = strconv.Itoa(os.Geteuid())
|
||||
}
|
||||
userID, err := user.LookupId(id)
|
||||
if err == nil {
|
||||
username = userID.Username
|
||||
}
|
||||
}
|
||||
} else if username == "" {
|
||||
username = RootAutoUserNsUser
|
||||
}
|
||||
mappings, err := idtools.NewIDMappings(username, username)
|
||||
if err != nil {
|
||||
logrus.Errorf("Cannot find mappings for user %q: %v", username, err)
|
||||
} else {
|
||||
uids = getHostIDs(mappings.UIDs())
|
||||
gids = getHostIDs(mappings.GIDs())
|
||||
}
|
||||
return uids, gids, nil
|
||||
}
|
||||
|
||||
// getAvailableIDs returns the list of ranges that are usable by the current user.
|
||||
// When running as root, it looks up the additional IDs assigned to the specified user.
|
||||
// When running as rootless, the mappings assigned to the unprivileged user are converted
|
||||
// to the IDs inside of the initial rootless user namespace.
|
||||
func (s *store) getAvailableIDs() (*idSet, *idSet, error) {
|
||||
if s.additionalUIDs == nil {
|
||||
uids, gids, err := getAdditionalSubIDs(s.autoUsernsUser)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// Store the result so we don't need to look it up again next time
|
||||
s.additionalUIDs, s.additionalGIDs = uids, gids
|
||||
}
|
||||
|
||||
if !unshare.IsRootless() {
|
||||
// No mapping to inner namespace needed
|
||||
return s.additionalUIDs, s.additionalGIDs, nil
|
||||
}
|
||||
|
||||
// We are already inside of the rootless user namespace.
|
||||
// We need to remap the configured mappings to what is available
|
||||
// inside of the rootless userns.
|
||||
u := newIDSet([]interval{{start: 1, end: s.additionalUIDs.size() + 1}})
|
||||
g := newIDSet([]interval{{start: 1, end: s.additionalGIDs.size() + 1}})
|
||||
return u, g, nil
|
||||
}
|
||||
|
||||
// nobodyUser returns the UID and GID of the "nobody" user. Hardcode its value
|
||||
// for simplicity.
|
||||
const nobodyUser = 65534
|
||||
|
||||
// parseMountedFiles returns the maximum UID and GID found in the /etc/passwd and
|
||||
// /etc/group files.
|
||||
func parseMountedFiles(containerMount, passwdFile, groupFile string) uint32 {
|
||||
if passwdFile == "" {
|
||||
passwdFile = filepath.Join(containerMount, "etc/passwd")
|
||||
}
|
||||
if groupFile == "" {
|
||||
groupFile = filepath.Join(groupFile, "etc/group")
|
||||
}
|
||||
|
||||
size := 0
|
||||
|
||||
users, err := libcontainerUser.ParsePasswdFile(passwdFile)
|
||||
if err == nil {
|
||||
for _, u := range users {
|
||||
// Skip the "nobody" user otherwise we end up with 65536
|
||||
// ids with most images
|
||||
if u.Name == "nobody" {
|
||||
continue
|
||||
}
|
||||
if u.Uid > size && u.Uid != nobodyUser {
|
||||
size = u.Uid
|
||||
}
|
||||
if u.Gid > size && u.Gid != nobodyUser {
|
||||
size = u.Gid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
groups, err := libcontainerUser.ParseGroupFile(groupFile)
|
||||
if err == nil {
|
||||
for _, g := range groups {
|
||||
if g.Name == "nobody" {
|
||||
continue
|
||||
}
|
||||
if g.Gid > size && g.Gid != nobodyUser {
|
||||
size = g.Gid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return uint32(size)
|
||||
}
|
||||
|
||||
// getMaxSizeFromImage returns the maximum ID used by the specified image.
|
||||
// On entry, rlstore must be locked for writing, and lstores must be locked for reading.
|
||||
func (s *store) getMaxSizeFromImage(image *Image, rlstore rwLayerStore, lstores []roLayerStore, passwdFile, groupFile string) (_ uint32, retErr error) {
|
||||
layerStores := append([]roLayerStore{rlstore}, lstores...)
|
||||
|
||||
size := uint32(0)
|
||||
|
||||
var topLayer *Layer
|
||||
layerName := image.TopLayer
|
||||
outer:
|
||||
for {
|
||||
for _, ls := range layerStores {
|
||||
layer, err := ls.Get(layerName)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if image.TopLayer == layerName {
|
||||
topLayer = layer
|
||||
}
|
||||
for _, uid := range layer.UIDs {
|
||||
if uid >= size {
|
||||
size = uid + 1
|
||||
}
|
||||
}
|
||||
for _, gid := range layer.GIDs {
|
||||
if gid >= size {
|
||||
size = gid + 1
|
||||
}
|
||||
}
|
||||
layerName = layer.Parent
|
||||
if layerName == "" {
|
||||
break outer
|
||||
}
|
||||
continue outer
|
||||
}
|
||||
return 0, fmt.Errorf("cannot find layer %q", layerName)
|
||||
}
|
||||
|
||||
layerOptions := &LayerOptions{
|
||||
IDMappingOptions: types.IDMappingOptions{
|
||||
HostUIDMapping: true,
|
||||
HostGIDMapping: true,
|
||||
UIDMap: nil,
|
||||
GIDMap: nil,
|
||||
},
|
||||
}
|
||||
|
||||
// We need to create a temporary layer so we can mount it and lookup the
|
||||
// maximum IDs used.
|
||||
clayer, _, err := rlstore.create("", topLayer, nil, "", nil, layerOptions, false, nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer func() {
|
||||
if err2 := rlstore.Delete(clayer.ID); err2 != nil {
|
||||
if retErr == nil {
|
||||
retErr = fmt.Errorf("deleting temporary layer %#v: %w", clayer.ID, err2)
|
||||
} else {
|
||||
logrus.Errorf("Error deleting temporary layer %#v: %v", clayer.ID, err2)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
mountOptions := drivers.MountOpts{
|
||||
MountLabel: "",
|
||||
UidMaps: nil,
|
||||
GidMaps: nil,
|
||||
Options: nil,
|
||||
}
|
||||
|
||||
mountpoint, err := rlstore.Mount(clayer.ID, mountOptions)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer func() {
|
||||
if _, err2 := rlstore.unmount(clayer.ID, true, false); err2 != nil {
|
||||
if retErr == nil {
|
||||
retErr = fmt.Errorf("unmounting temporary layer %#v: %w", clayer.ID, err2)
|
||||
} else {
|
||||
logrus.Errorf("Error unmounting temporary layer %#v: %v", clayer.ID, err2)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
userFilesSize := parseMountedFiles(mountpoint, passwdFile, groupFile)
|
||||
if userFilesSize > size {
|
||||
size = userFilesSize
|
||||
}
|
||||
|
||||
return size, nil
|
||||
}
|
||||
|
||||
// getAutoUserNS creates an automatic user namespace
|
||||
// If image != nil, On entry, rlstore must be locked for writing, and lstores must be locked for reading.
|
||||
func (s *store) getAutoUserNS(options *types.AutoUserNsOptions, image *Image, rlstore rwLayerStore, lstores []roLayerStore) ([]idtools.IDMap, []idtools.IDMap, error) {
|
||||
requestedSize := uint32(0)
|
||||
initialSize := uint32(1)
|
||||
if options.Size > 0 {
|
||||
requestedSize = options.Size
|
||||
}
|
||||
if options.InitialSize > 0 {
|
||||
initialSize = options.InitialSize
|
||||
}
|
||||
|
||||
availableUIDs, availableGIDs, err := s.getAvailableIDs()
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("cannot read mappings: %w", err)
|
||||
}
|
||||
|
||||
// Look at every container that is using a user namespace and store
|
||||
// the intervals that are already used.
|
||||
containers, err := s.Containers()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
var usedUIDs, usedGIDs []idtools.IDMap
|
||||
for _, c := range containers {
|
||||
usedUIDs = append(usedUIDs, c.UIDMap...)
|
||||
usedGIDs = append(usedGIDs, c.GIDMap...)
|
||||
}
|
||||
|
||||
size := requestedSize
|
||||
|
||||
// If there is no requestedSize, lookup the maximum used IDs in the layers
|
||||
// metadata. Make sure the size is at least s.autoNsMinSize and it is not
|
||||
// bigger than s.autoNsMaxSize.
|
||||
// This is a best effort heuristic.
|
||||
if requestedSize == 0 {
|
||||
size = initialSize
|
||||
if s.autoNsMinSize > size {
|
||||
size = s.autoNsMinSize
|
||||
}
|
||||
if image != nil {
|
||||
sizeFromImage, err := s.getMaxSizeFromImage(image, rlstore, lstores, options.PasswdFile, options.GroupFile)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if sizeFromImage > size {
|
||||
size = sizeFromImage
|
||||
}
|
||||
}
|
||||
if s.autoNsMaxSize > 0 && size > s.autoNsMaxSize {
|
||||
return nil, nil, fmt.Errorf("the container needs a user namespace with size %v that is bigger than the maximum value allowed with userns=auto %v", size, s.autoNsMaxSize)
|
||||
}
|
||||
}
|
||||
|
||||
return getAutoUserNSIDMappings(
|
||||
int(size),
|
||||
availableUIDs, availableGIDs,
|
||||
usedUIDs, usedGIDs,
|
||||
options.AdditionalUIDMappings, options.AdditionalGIDMappings,
|
||||
)
|
||||
}
|
||||
|
||||
// getAutoUserNSIDMappings computes the user/group id mappings for the automatic user namespace.
|
||||
func getAutoUserNSIDMappings(
|
||||
size int,
|
||||
availableUIDs, availableGIDs *idSet,
|
||||
usedUIDMappings, usedGIDMappings, additionalUIDMappings, additionalGIDMappings []idtools.IDMap,
|
||||
) ([]idtools.IDMap, []idtools.IDMap, error) {
|
||||
usedUIDs := getHostIDs(append(usedUIDMappings, additionalUIDMappings...))
|
||||
usedGIDs := getHostIDs(append(usedGIDMappings, additionalGIDMappings...))
|
||||
|
||||
// Exclude additional uids and gids from requested range.
|
||||
targetIDs := newIDSet([]interval{{start: 0, end: size}})
|
||||
requestedContainerUIDs := targetIDs.subtract(getContainerIDs(additionalUIDMappings))
|
||||
requestedContainerGIDs := targetIDs.subtract(getContainerIDs(additionalGIDMappings))
|
||||
|
||||
// Make sure the specified additional IDs are not used as part of the automatic
|
||||
// mapping
|
||||
availableUIDs, err := availableUIDs.subtract(usedUIDs).findAvailable(requestedContainerUIDs.size())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
availableGIDs, err = availableGIDs.subtract(usedGIDs).findAvailable(requestedContainerGIDs.size())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
uidMap := append(availableUIDs.zip(requestedContainerUIDs), additionalUIDMappings...)
|
||||
gidMap := append(availableGIDs.zip(requestedContainerGIDs), additionalGIDMappings...)
|
||||
return uidMap, gidMap, nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue