From b5e6c8fcd329954f6a61272371e3adebe49d053d Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 22 Mar 2026 10:32:13 +0000 Subject: [PATCH] Fix rootless Podman lchown EINVAL by ensuring uidmap and fresh service MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- infra/start.sh | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/infra/start.sh b/infra/start.sh index d5275d8..6c62396 100755 --- a/infra/start.sh +++ b/infra/start.sh @@ -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 - 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; } + +# 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}" & +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; } # ── Build images ─────────────────────────────────────────────────────────────── make -C "$SCRIPT_DIR" build