Linux: ancestor walk fails unconditionally in Docker userns-remap containers (single-uid mapping, / owned by nobody/65534)
Version
Would affect any version from v0.10.0 onward (the daemon coordination layer). Not currently installed — cannot run due to this issue.
Platform
Linux (x64): Docker Desktop 29.x on Windows 11 WSL2, container running Debian 13 (trixie), kernel 6.18.35.2-microsoft-standard-WSL2
Install channel
Binary (attempted previously with v0.10.6; same issue expected on v0.10.8)
What happened, and what did you expect?
Every cbm process exits immediately with secure CLI coordination could not be created (endpoint). The ancestor walk rejects every possible directory path because no ancestor directory from /home/kirocrew to / is owned by uid 0 or uid 1000 — they are all owned by uid 65534 (nobody).
Expected: cbm should be able to run in a standard Docker container that uses user namespace remapping (a single-uid mapping), which is a common production Docker security pattern.
Root cause
Docker's userns-remap feature (or equivalently, Podman's rootless mode) creates a user namespace where only a single uid is mapped:
# /proc/self/uid_map
1000 1000 1
This means:
- The process runs as uid 1000 (kirocrew)
- uid 0 does not exist inside the container namespace
- All filesystem objects owned by uids outside the mapped range appear as
nobody (65534) per kernel overflow behavior
The directory ownership chain:
mode=755 owner=65534:65534 / ← nobody (unmapped host root)
mode=755 owner=65534:65534 /home ← nobody
mode=700 owner=1000:1000 /home/kirocrew ← ✅ current user
mode=1777 owner=65534:65534 /tmp ← nobody (not uid 0!)
The ancestor walk (posix_directory_parent_secure) requires each ancestor to be owned by either:
- The current process euid (1000), OR
- uid 0 (root)
Neither condition is satisfiable for /, /home, or /tmp because:
- uid 0 doesn't exist in the namespace (no mapping)
- These directories show owner uid 65534 (the kernel's overflow uid for unmapped uids)
The /tmp sticky-bit special case also fails: it requires root-owned (uid 0) + sticky, but /tmp is uid 65534 + sticky.
CBM_RUNTIME_DIR (added in v0.10.5 for #1672) cannot help because any path ultimately traverses / or /home, both of which are uid 65534.
Reproduction
- Run any Docker container with a single-uid user namespace mapping:
# docker-compose.yml or docker run equivalent
# The container uses userns-remap or is started with --userns=host
# with a USER directive that maps only one uid
- Verify the uid_map:
cat /proc/self/uid_map → shows 1000 1000 1
- Verify
/ ownership: stat -c '%u' / → shows 65534
- Attempt to run any cbm command → fails at ancestor walk
Suggested fix
When the process detects it is running inside a user namespace with a restricted uid_map (single-uid or no uid-0 mapping), the ancestor walk should relax its ownership requirement for ancestors that show the overflow uid (65534/nobody). Specifically:
- Detect userns: read
/proc/self/uid_map — if uid 0 is not mapped (or maps to an unprivileged host uid), the container has no real root.
- Relax ancestor check: in this case, accept ancestors owned by the overflow uid (65534) as equivalent to "owned by the host root that we cannot see". The security guarantee (no local user can swap a path component) is maintained because the container is already isolated — no other uid can exist to attack the path.
- Keep strict checks for the private directory itself (
CBM_RUNTIME_DIR, CBM_CACHE_DIR) — these must still be owned by the process euid (1000).
Alternative: provide a CBM_SKIP_ANCESTOR_WALK=1 escape hatch for container environments where the operator accepts the risk, similar to how git provides safe.directory for ownership mismatches.
Related issues
Environment details
OS: Debian GNU/Linux 13 (trixie)
Kernel: 6.18.35.2-microsoft-standard-WSL2
Container runtime: Docker Desktop (overlay2)
uid_map: 1000 1000 1
gid_map: 1000 1000 1
Process: uid=1000(kirocrew) gid=1000(kirocrew)
Linux: ancestor walk fails unconditionally in Docker userns-remap containers (single-uid mapping,
/owned by nobody/65534)Version
Would affect any version from v0.10.0 onward (the daemon coordination layer). Not currently installed — cannot run due to this issue.
Platform
Linux (x64): Docker Desktop 29.x on Windows 11 WSL2, container running Debian 13 (trixie), kernel 6.18.35.2-microsoft-standard-WSL2
Install channel
Binary (attempted previously with v0.10.6; same issue expected on v0.10.8)
What happened, and what did you expect?
Every cbm process exits immediately with
secure CLI coordination could not be created (endpoint). The ancestor walk rejects every possible directory path because no ancestor directory from/home/kirocrewto/is owned by uid 0 or uid 1000 — they are all owned by uid 65534 (nobody).Expected: cbm should be able to run in a standard Docker container that uses user namespace remapping (a single-uid mapping), which is a common production Docker security pattern.
Root cause
Docker's
userns-remapfeature (or equivalently, Podman's rootless mode) creates a user namespace where only a single uid is mapped:This means:
nobody(65534) per kernel overflow behaviorThe directory ownership chain:
The ancestor walk (
posix_directory_parent_secure) requires each ancestor to be owned by either:Neither condition is satisfiable for
/,/home, or/tmpbecause:The
/tmpsticky-bit special case also fails: it requires root-owned (uid 0) + sticky, but/tmpis uid 65534 + sticky.CBM_RUNTIME_DIR(added in v0.10.5 for #1672) cannot help because any path ultimately traverses/or/home, both of which are uid 65534.Reproduction
cat /proc/self/uid_map→ shows1000 1000 1/ownership:stat -c '%u' /→ shows65534Suggested fix
When the process detects it is running inside a user namespace with a restricted uid_map (single-uid or no uid-0 mapping), the ancestor walk should relax its ownership requirement for ancestors that show the overflow uid (65534/nobody). Specifically:
/proc/self/uid_map— if uid 0 is not mapped (or maps to an unprivileged host uid), the container has no real root.CBM_RUNTIME_DIR,CBM_CACHE_DIR) — these must still be owned by the process euid (1000).Alternative: provide a
CBM_SKIP_ANCESTOR_WALK=1escape hatch for container environments where the operator accepts the risk, similar to howgitprovidessafe.directoryfor ownership mismatches.Related issues
CBM_RUNTIME_DIR)Environment details