Fix rootless Podman lchown EINVAL by ensuring uidmap and fresh service

Two root causes for "invalid argument" when chowning non-root UIDs/GIDs
in image layers:

1. Missing uidmap package: without setuid newuidmap/newgidmap binaries,
   Podman can only map a single UID (0 → current user) in the user
   namespace.  Any layer file owned by gid=42 (shadow) or similar then
   has no mapping and lchown returns EINVAL.  Now install uidmap if absent.

2. Stale Podman service: a service started before subuid/subgid entries
   existed silently keeps the single-UID mapping for its lifetime even
   after the entries are added and podman system migrate is run.  Now
   always kill and restart the service on each start.sh run so it always
   reads the current subuid/subgid configuration.

https://claude.ai/code/session_01FKCW3FDjNFj6jve4niMFXH
This commit is contained in:
Claude 2026-03-22 10:32:13 +00:00
parent b64195c58a
commit b5e6c8fcd3
No known key found for this signature in database

View file

@ -59,6 +59,16 @@ EOF
echo "[hiy] Generated proxy/caddy.json for ${DOMAIN_SUFFIX}"
# ── Ensure newuidmap/newgidmap setuid binaries are present ────────────────────
# These binaries (from the 'uidmap' package) allow rootless Podman to map a
# full range of UIDs/GIDs in user namespaces. Without them Podman can only
# map UID 0 → the calling user and any layer file owned by a non-zero UID/GID
# (e.g. gid=42 for /etc/shadow) will cause an "invalid argument" lchown error.
if ! command -v newuidmap &>/dev/null; then
echo "[hiy] Installing uidmap (provides newuidmap/newgidmap)…"
sudo apt-get install -y uidmap
fi
# ── Ensure subuid/subgid entries exist for rootless Podman ────────────────────
# Rootless Podman maps UIDs/GIDs inside containers using subordinate ID ranges
# from /etc/subuid and /etc/subgid. Without a sufficient range, pulling or
@ -72,7 +82,7 @@ fi
if ! grep -q "^${_HIY_USER}:" /etc/subgid 2>/dev/null; then
echo "${_HIY_USER}:100000:65536" | sudo tee -a /etc/subgid > /dev/null
fi
# Always migrate so Podman storage reflects the current subuid/subgid mappings.
# Migrate storage so Podman picks up the current subuid/subgid mappings.
podman system migrate
# ── Allow rootless processes to bind ports 80/443 ─────────────────────────────
@ -102,16 +112,25 @@ export XDG_RUNTIME_DIR="$_HIY_XDG"
PODMAN_SOCK="${_HIY_XDG}/podman.sock"
export PODMAN_SOCK
export DOCKER_HOST="unix://${PODMAN_SOCK}"
if [ ! -S "$PODMAN_SOCK" ]; then
# Always (re)start the Podman socket service so it reflects the current
# subuid/subgid configuration. A stale service started before the entries
# existed will silently fall back to single-UID mapping and cause lchown
# failures when extracting image layers that contain non-root UIDs/GIDs.
if [ -S "$PODMAN_SOCK" ]; then
echo "[hiy] Restarting Podman socket service (refreshing user namespace config)…"
pkill -f "podman system service.*${PODMAN_SOCK}" 2>/dev/null || true
# Give the process a moment to exit and release the socket.
sleep 1
rm -f "$PODMAN_SOCK"
fi
echo "[hiy] Starting Podman socket via podman system service…"
podman system service --time=0 "unix://${PODMAN_SOCK}" &
# Wait up to 5 s for the socket to appear
for i in 1 2 3 4 5; do
[ -S "$PODMAN_SOCK" ] && break
sleep 1
done
[ -S "$PODMAN_SOCK" ] || { echo "ERROR: Podman socket did not appear"; exit 1; }
fi
# ── Build images ───────────────────────────────────────────────────────────────
make -C "$SCRIPT_DIR" build