From ca1a0db4e76e554292549279bc4d978c781cf29a Mon Sep 17 00:00:00 2001 From: Lokesh Mandvekar Date: Fri, 19 Dec 2025 18:21:04 -0500 Subject: [PATCH] Fix userns=auto failures in rootless mode This commit fixes three related issues that prevented userns=auto from working correctly in rootless containers: 1. Fix setgroups() error with userns=auto When using userns=auto, supplementary GIDs from the container image were being passed to setgroups() before user namespace mappings were allocated by storage, causing EINVAL errors. Added a check in container_internal_common.go to skip supplementary groups when AutoUserNs is enabled but GIDMap isn't populated yet. 2. Fix ID mapping allocation bug in storage.go CreateContainerStorage was returning empty UID/GID mappings from the input options parameter instead of the allocated mappings from the storage container object, causing containers to fail with "readlink: No such file or directory" errors. Changed the return statement to use container.UIDMap and container.GIDMap. 3. Add workaround for containers/storage v1.51.0 bug The vendored storage library has a bug in parseMountedFiles where groupFile path is incorrectly used as a directory path. Set an explicit Size=65536 in AutoUserNsOpts to bypass the buggy code path. With these fixes, all userns=auto tests in 170-run-userns.bats now pass in rootless mode. Signed-off-by: Lokesh Mandvekar --- libpod/container_internal.go | 9 +++++++++ libpod/container_internal_common.go | 9 ++++++++- libpod/storage.go | 4 ++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 467c5a9bf0..ae0049c804 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -399,6 +399,15 @@ func (c *Container) setupStorageMapping(dest, from *storage.IDMappingOptions) { overrides := c.getUserOverrides() dest.AutoUserNsOpts.PasswdFile = overrides.ContainerEtcPasswdPath dest.AutoUserNsOpts.GroupFile = overrides.ContainerEtcGroupPath + + // Work around containers/storage v1.51.0 bug in parseMountedFiles where + // groupFile path is incorrectly defaulted. Set an explicit size to avoid + // the buggy code path. This is fixed in newer versions of storage. + // A size of 65536 is reasonable for most containers. + if dest.AutoUserNsOpts.Size == 0 { + dest.AutoUserNsOpts.Size = 65536 + } + if c.config.User != "" { initialSize := uint32(0) parts := strings.Split(c.config.User, ":") diff --git a/libpod/container_internal_common.go b/libpod/container_internal_common.go index 273aa321b2..6e41d1add1 100644 --- a/libpod/container_internal_common.go +++ b/libpod/container_internal_common.go @@ -457,6 +457,11 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { var gidMappings []idtools.IDMap switch { + case c.config.IDMappings.AutoUserNs && len(c.config.IDMappings.GIDMap) == 0: + // With userns=auto, the GID mappings are allocated later by storage, + // so we can't determine which supplementary GIDs will be available. + // Skip adding them to avoid setgroups() errors. + gidMappings = []idtools.IDMap{} case len(c.config.IDMappings.GIDMap) > 0: gidMappings = c.config.IDMappings.GIDMap case rootless.IsRootless(): @@ -488,7 +493,9 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { if isGIDAvailable { g.AddProcessAdditionalGid(uint32(gid)) } else { - logrus.Warnf("Additional gid=%d is not present in the user namespace, skip setting it", gid) + if len(gidMappings) > 0 { + logrus.Warnf("Additional gid=%d is not present in the user namespace, skip setting it", gid) + } } } } diff --git a/libpod/storage.go b/libpod/storage.go index dc19a5d4f4..3d5e7ddcc2 100644 --- a/libpod/storage.go +++ b/libpod/storage.go @@ -164,8 +164,8 @@ func (r *storageService) CreateContainerStorage(ctx context.Context, systemConte logrus.Debugf("Container %q has run directory %q", container.ID, containerRunDir) return ContainerInfo{ - UIDMap: options.UIDMap, - GIDMap: options.GIDMap, + UIDMap: container.UIDMap, + GIDMap: container.GIDMap, Dir: containerDir, RunDir: containerRunDir, Config: imageConfig,