Skip to content

fix(entrypoint): chown $DEVA_HOME itself after UID remap - #507

Merged
lroolle merged 1 commit into
mainfrom
fix/home-chown-506
Jul 28, 2026
Merged

fix(entrypoint): chown $DEVA_HOME itself after UID remap#507
lroolle merged 1 commit into
mainfrom
fix/home-chown-506

Conversation

@lroolle

@lroolle lroolle commented Jul 28, 2026

Copy link
Copy Markdown
Member

Close #506

usermod's implicit home-tree chown walks live host mounts and chowns the top-level dir last; a mid-walk abort (rc=12, passwd already updated) leaves /home/deva at the build UID, mode 750, untraversable for the remapped user -> env: 'claude': Permission denied. Whitelist chown (7511464) never covered $DEVA_HOME itself; latent since 5807889.

One line of substance: explicit non-recursive chown of $DEVA_HOME after the usermod block, using the adapted DEVA_UID so the usermod-failed-outright variant stays consistent too.

Verified by fault injection (usermod stub: passwd updated, chown skipped, exit 12):

  • unpatched + stub -> home stays build-UID, exec denied (reproduces the field failure)
  • patched + stub -> home at target UID, claude --version launches
  • normal runs unaffected

Forensics in docs/devlog/20260728-home-dir-chown-race.org.

🤖 Generated with Claude Code

usermod -u implicitly chowns the home tree, and shadow's chown_tree
chowns the top-level dir LAST. When the walk crosses live host mounts
inside home, a transient error aborts the tree chown with rc=12 while
passwd is already updated: the user becomes the host UID but /home/deva
stays at the build UID with noble's HOME_MODE 750 -- untraversable, so
every launch dies with "env: 'claude': Permission denied".

The 7511464 whitelist chowns subdirs but never $DEVA_HOME itself;
latent since 5807889 dropped the recursive home chown. Intermittent by
nature: only bites when the walk races writes on the shared mounts.

Chown the home dir explicitly, non-recursively, with the adapted
DEVA_UID -- correct for both the half-succeeded and the failed-outright
usermod variants.

Verified by fault injection: a usermod stub that updates passwd, skips
the chown, and exits 12 reproduces the brick unpatched and comes out
clean patched.

Close #506
Copilot AI review requested due to automatic review settings July 28, 2026 10:06
@claude-yolo

claude-yolo Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Claude encountered an error after 1s —— View job


I'll analyze this and get back to you.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes an intermittent container startup failure where a UID remap can leave $DEVA_HOME (/home/deva) owned by the build-time UID (with default mode 0750), making the remapped user unable to traverse their own home directory and causing env: 'claude': Permission denied. The change ensures the home directory itself is explicitly chowned (non-recursively) after the usermod UID remap logic, covering the “usermod partially succeeded” (rc=12) scenario described in #506.

Changes:

  • Add an explicit, non-recursive chown "$DEVA_UID:$DEVA_GID" "$DEVA_HOME" after the usermod block in setup_nonroot_user() to repair ownership even if usermod’s implicit tree chown aborts mid-walk.
  • Add a detailed devlog entry documenting the failure mode, reproduction, and rationale.
  • Document the fix in DEV-LOGS.md and CHANGELOG.md.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
docker-entrypoint.sh Adds explicit non-recursive chown of $DEVA_HOME after UID remap to prevent home traversal breakage when usermod chown_tree aborts.
docs/devlog/20260728-home-dir-chown-race.org Forensics and rationale for the failure mode and the chosen minimal fix.
DEV-LOGS.md Index entry summarizing the incident, fix, and remaining gap (no entrypoint test coverage).
CHANGELOG.md Records the fix under Unreleased “Fixed” with user-facing symptom and root cause.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0a8365bee2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docker-entrypoint.sh
# build-time UID with mode 750, so the remapped user cannot even
# traverse into its own home ("env: 'claude': Permission denied").
# Chown the home dir itself explicitly, non-recursively.
chown "$DEVA_UID:$DEVA_GID" "$DEVA_HOME" 2>/dev/null || true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Run the home-directory repair on every entrypoint invocation

On a newly created persistent container, deva.sh starts the detached PID 1 entrypoint, sleeps only 0.3 seconds, and then invokes this entrypoint again with docker exec (deva.sh lines 4233, 4259, and 4287). Since usermod updates passwd before completing its potentially slow home-tree walk, the exec invocation can observe current_uid == DEVA_UID, skip this entire conditional, and reach the agent while PID 1 is still walking and /home/deva remains owned by the build UID. The same intermittent env: 'claude': Permission denied can therefore survive this fix; run the non-recursive home-directory ownership repair on every invocation after any UID adaptation, rather than only when that invocation detects a UID change.

Useful? React with 👍 / 👎.

@lroolle
lroolle merged commit b7d810c into main Jul 28, 2026
7 of 8 checks passed
@lroolle
lroolle deleted the fix/home-chown-506 branch July 28, 2026 10:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

entrypoint: home dir left at build UID when usermod tree chown aborts

2 participants