Skip to content

fix(cli): trust root-owned per-user /home entries during activation walk - #2309

Open
BumaldaOverTheWater94 wants to merge 2 commits into
DeusData:mainfrom
BumaldaOverTheWater94:fix/home-user-symlink-alias
Open

BumaldaOverTheWater94 wants to merge 2 commits into
DeusData:mainfrom
BumaldaOverTheWater94:fix/home-user-symlink-alias

Conversation

@BumaldaOverTheWater94

Copy link
Copy Markdown

Fixes #2306

Linux install failed with activation transaction I/O failed when /home is a real directory but /home/<user> is a root-owned symlink (for example /home/alice -> /local/home/alice). The #2175 alias handling only covers /home itself being a symlink.

activation_posix_walk_path() now also resolves /home/<name> (Linux only), but only when all of these hold:

  • /home is a root-owned directory that isn't group- or world-writable
  • the entry is a root-owned symlink
  • it resolves to a directory owned by root or the current user

Arbitrary user-owned symlinks are still rejected by the O_NOFOLLOW walk.

Verification (AL2023 x86_64, gcc 11.5, /home/$USER is a root-owned symlink to /local/home/$USER). I ran install -y --force --skip-config --dir=$HOME_SANDBOX/bin with a sandbox HOME/CBM_CACHE_DIR under /home/$USER:

  • main @ same base: error: failed to stage install candidate: activation transaction I/O failed, rc=1
  • this branch: Install complete, rc=0
  • scripts/test.sh suites: 8175 passed, 0 failed, 8 skipped (143 suites)
  • clang-format 20 --dry-run --Werror: clean. clang-tidy and cppcheck weren't available locally.

No unit test is included: the case needs a root-owned symlink under /home, which the existing fixtures can't create without root.

Written with Claude Code (AI-assisted), on behalf of the account owner, who is accountable for the change.

@github-actions

Copy link
Copy Markdown

Thanks for opening this — it has been seen, and it is queued.

This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence.

Current review status: working through a backlog. 0.9.1-rc.1 is out, so the release freeze that held reviews is over — but it left a large queue of open pull requests behind it, and we are reading through them oldest-first. The background is in discussion #1144.

What that means for this PR, concretely:

  • It will not be closed for inactivity. No stale bot touches pull requests here.
  • It may still sit a while before a human reads it. That is on us, not on you.
  • Older PRs are read first, so a recent one is not being skipped — it is behind a queue.

Things that will genuinely speed it up whenever review does happen:

  • Keep it rebased on main — the tree is moving quickly right now, and a conflicting branch cannot be reviewed as the diff you intended.
  • Get CI green, or say which failures you believe are pre-existing.
  • Keep the change to one claim. Bundled features and refactors get split before they get merged, which costs you a round trip.
  • Every commit needs a sign-off (git commit -s) — CI enforces DCO.

If this fixes a bug, a reproduction we can run is worth more than a description of the symptom.

Thanks for contributing, and sorry in advance for the wait.

@DeusData DeusData left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thank you for #2306 — a root-owned /home/<name> symlink is a common Linux layout, and the check you added is narrow in the right way: only root can create or change that entry, so another user cannot race the lstat and realpath window, and every component of the resolved path is still walked with O_NOFOLLOW.

Three things before it merges:

  1. Memory-core lint. The lint job is red because raw allocator use grew in src/cli/activation_transaction.c (80 to 82). Building the mapped path in a stack buffer and returning activation_string_copy(buf) keeps the count flat, and callers still free() it as before.
  2. A test. This loosens a security check, so it needs one that fails without the change. Either a test seam that swaps the /home prefix and the uid checks, or a Linux container test that runs as root, would do.
  3. Consider folding it into the existing /home alias loop (the #2175 branch), which does almost the same walk. Note one deliberate difference to keep visible: the alias branch requires a root-owned target, while this one also accepts a target owned by the current user. That is reasonable, and worth one comment saying so.

Thank you again.

Managed Linux hosts keep /home a real directory and point /home/<user>
at another tree (e.g. /local/home/<user>). The O_NOFOLLOW walk rejected
that entry and install failed with 'activation transaction I/O failed'.

Resolve /home/<name> only when /home is root-owned and not group/world
writable, the entry is a root-owned symlink, and it resolves to a
directory owned by root or the current user. Arbitrary user-owned
symlinks are still rejected.

Fixes DeusData#2306

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: BumaldaOverTheWater94 <83429948+BumaldaOverTheWater94@users.noreply.github.com>
Address review on DeusData#2309:
- Fold the /home/<name> handling into the existing DeusData#2175 alias loop via a
  shared activation_alias_map() that builds the mapped path in a stack
  buffer and returns activation_string_copy(); raw allocator sites in
  activation_transaction.c drop from 80 to 78 (baseline lowered).
- Comment the deliberate difference: the per-user entry may resolve to a
  directory owned by the current account, the whole-alias case may not.
- Add cbm_activation_transaction_set_home_root_for_testing() (test seams
  only) and a Linux test that fails without the per-user branch.

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Glen Ko <gleko@amazon.com>

This branch has not been deployed

No deployments
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.

Linux install fails when $HOME is a root-owned symlink under /home (activation transaction I/O failed)

2 participants