From ebf0cad69d4b051b9320bfe6dab6eda3a1322fdf Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Sat, 18 Jul 2026 10:43:05 +0900 Subject: [PATCH] init: do not chdir into initfs prefix after switch_root The restored switch_root chdir set init's CWD to /scheme/initfs on the live image. login later restricts its namespace to DEFAULT_SCHEMES (no 'initfs' scheme) via mkns/setns; the inherited /scheme/initfs CWD fd then becomes unresolvable. Because relibc resolves paths through the CWD fd (AT_REDOX_CWD_FD), every subsequent file op in login hangs -- notably Command::spawn() loading the login shell binary never returns, so the shell never starts. Leaving the CWD inherited (as before the chdir was added) keeps spawn working across the login namespace switch; getcwd() in /usr binaries works without the chdir. Reverts the CWD half of 521c6ffe; the init-diag cleanup from that commit is retained. --- init/src/main.rs | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/init/src/main.rs b/init/src/main.rs index e99c584b74..94162e61d3 100644 --- a/init/src/main.rs +++ b/init/src/main.rs @@ -54,21 +54,15 @@ impl InitConfig { fn switch_root(unit_store: &mut UnitStore, config: &mut InitConfig, prefix: &Path, etcdir: &Path) { status_ok(&format!("switchroot to {} {}", prefix.display(), etcdir.display())); - // Point init's working directory at a valid directory in the new root so - // daemons spawned afterwards don't inherit an invalid CWD (via - // AT_REDOX_CWD_FD). Without this, getcwd() fails in /usr binaries — e.g. - // the 00_base-env `zsh -c` setup printed "zsh: Failed to get current - // directory: path invalid" and then hung, so init (which waits on that - // oneshot) never reached the login stack. The switch is logical (no - // chroot) and `prefix` (e.g. "/usr") is not itself a directory, so try the - // plausible roots in order and keep the first that works. - let cwd_candidates = [prefix.to_path_buf(), std::path::PathBuf::from("/")]; - if !cwd_candidates - .iter() - .any(|cand| std::env::set_current_dir(cand).is_ok()) - { - init_warn("failed to establish a valid working directory after switch_root"); - } + // NOTE: Do NOT chdir into `prefix` here. On the live image `prefix` is + // `/scheme/initfs`, and `login` later restricts its namespace to + // DEFAULT_SCHEMES (which does not include `initfs`) via mkns/setns. Any CWD + // inherited from init that lives on a scheme absent from that restricted + // namespace becomes unresolvable, and because relibc resolves paths through + // the CWD fd (AT_REDOX_CWD_FD), *all* subsequent file operations in login — + // including `Command::spawn()` loading the shell binary — then hang. Leaving + // the CWD as inherited keeps process spawning working after the login + // namespace switch. (getcwd() in /usr binaries works without this chdir.) config .envs