Repository navigation
fix(daemon): accept single-uid userns overflow-owned ancestors (#1830) - #2138
Merged
Merged
Conversation
Inside a 1:1 user namespace (podman --userns=keep-id, unshare -U --map-current-user), the root-owned ancestors /, /tmp appear owned by the kernel overflow uid; the daemon's ancestor-ownership walk refused every overflow-owned ancestor, making the daemon unusable in that legitimate setup. Tolerate an overflow-owned ancestor ONLY when /proc/self/uid_map is a single-uid map whose sole inside id is our euid AND /proc/sys/kernel/overflowuid is readable (never hardcoded; unreadable => no tolerance). No environment escape hatch. Group-writable overflow ancestor refused (host group unknown); world-writable overflow tolerated only with the sticky bit (the /tmp shape). The created/final/snapshot gates stay strict == geteuid(), so a host-squatted overflow-owned private directory is still refused; the tolerance only widens which ancestors the walk traverses. macOS byte-identical (overflow=-1). Co-Authored-By: Claude Fable 5.1 <[email protected]> Signed-off-by: Martin Vogel <[email protected]>
4 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Inside a single-uid user namespace (
unshare -U --map-current-user,podman --userns=keep-id), the root-owned top-level ancestors (/,/tmp) appear owned by the kernel overflow uid (nobody). The daemon's directory-security walk refused every overflow-owned ancestor, so it could not create its private runtime directory and refused to start in that legitimate setup.Fix (#1830)
Accept an overflow-owned ancestor only when
/proc/self/uid_mapis a single-uid map (exactly one line,count == 1,inside == euid) and/proc/sys/kernel/overflowuidis readable (the value is read from/proc, never hardcoded; unreadable ⇒ no tolerance). No environment escape hatch. Group-writable-overflow ancestors are refused (an unmapped owner's host group is unknowable); world-writable-overflow is tolerated only with the sticky bit (the/tmpshape).Why it's safe
The tolerance is confined to the ancestor walk (
posix_directory_parent_secure,posix_directory_transition_secure). The directories that actually hold data stay strict== geteuid(): the created-dir recheck (ipc.c:1687) and the final-dir gate (ipc.c:1714). These two euid gates are the security-critical backstop — a host-squatted, overflow-owned private directory is still refused there, so the overflow tolerance only widens which ancestors the walk may traverse, never the destination. In a single-uid namespaceuid_mapis write-once/immutable and no in-namespace principal can own or mutate an overflow-owned file, so an overflow-owned ancestor is exactly as safe as a root-owned one on the host.Verification
count != 1,inside != euid, and any second mapping line; a mapped-out foreign uid is refused even with tolerance ON.__linux__/proc path, plus a realunshare(CLONE_NEWUSER)end-to-end smoke (whitelisted-skip where userns is unavailable).src/daemon/ipc.c(+ test seams).Adversarially reviewed as a security-boundary change: no privilege-boundary fail-open found; the safety rests on the two
== geteuid()gates above staying strict.