Skip to content

Defer sidecar walks to the sysroot host fallback#118

Merged
jserv merged 1 commit into
sysprog21:mainfrom
Max042004:fix-sidecar-host-fallback
Jul 2, 2026
Merged

Defer sidecar walks to the sysroot host fallback#118
jserv merged 1 commit into
sysprog21:mainfrom
Max042004:fix-sidecar-host-fallback

Conversation

@Max042004

@Max042004 Max042004 commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Problem

On a case-insensitive sysroot (macOS default APFS, where the sidecar
case-folding layer is active), absolute guest paths that live outside the
sysroot became unreachable. proc_resolve_sysroot_path_flags documents the
contract: resolve inside the sysroot when the path exists there, otherwise
fall back to the literal host path so guests can still reach host resources
such as mktemp directories or /etc/resolv.conf. The sidecar walk vetoed
that fallback in two ways:

  • sidecar_translate_lookup_at anchored every absolute path at the sysroot
    root and returned ENOENT as soon as an intermediate component was missing
    there; when only the final component was missing it still rewrote the path
    to ${sysroot}${path}. Either way the resolver's host-literal decision was
    overridden.
  • Mutating syscalls (openat with O_CREAT, mkdirat, unlinkat,
    linkat, renameat) hit the same wall through sidecar_walk_parent_at,
    which hard-anchored the parent directory at the sysroot.

Symptom

All 27 failures in the test-matrix "musl dyn" coreutils suite on the
self-hosted runtime job (PR #91) and on any local run where the fixtures
live on a case-insensitive volume:

cat   [ FAIL ] (exit 1)   ... cat: /var/folders/.../hello.txt: No such file or directory
touch [ FAIL ] (got 1)    ... cannot touch '/var/folders/.../touched-1'
env   [ FAIL ] (got 127)  ... execve could not reach the host binary

Dynamic binaries run under --sysroot; macOS mktemp -d lives in
/var/folders/... and the sysroot only contains /var, so the walk
descended into ${sysroot}/var, failed at folders, and turned the
documented fallback into ENOENT. Static coreutils run without --sysroot
and passed, which is why only the dynamic suite failed.

Fix

Track whether the walk consulted an index mapping:

  • A walk that leaves the sysroot tree without touching a mapping returns
    "no translation" (0), so the resolver's fallback decision stands.
  • Beneath a mapped prefix the sysroot view stays authoritative: missing
    suffixes append literally and surface as ENOENT against the translated
    path (no index can exist under a missing directory).
  • An unmapped final component is claimed only if it actually exists in the
    sysroot, restoring the fallback for paths like /etc/resolv.conf whose
    parent exists in the sysroot but whose leaf does not.

sidecar_walk_parent_at now reports a parent that resolves outside the
sysroot as a distinct verdict, and all mutation entry points hand such paths
back as SIDECAR_NOT_HANDLED to the regular translation flow.

Validation

  • tests/test-matrix.sh elfuse-aarch64: 168 passed, 0 failed (was
    141/27); the remaining 4 skips are missing optional fixtures
    (base32/b2sum/numfmt applets, glibc dyn suite), unrelated to this bug.
  • New regression test test-sysroot-host-fallback (wired into
    make check): 7 cases covering reads through missing intermediates,
    create/write/unlink, mkdir/rmdir, rename on host paths, the
    missing-final-component fallback, and sysroot-over-host precedence.
    Without the fix six of the seven cases fail with ENOENT.
  • make check: all green (104 driver tests + host unit tests, 0 failed).
  • test-case-collision and test-case-collision-fallback (12/12 both):
    the sidecar's collision compensation is unaffected.

Summary by cubic

Defers sidecar path walks to the resolver’s host-literal fallback on case-insensitive sysroots so absolute guest paths outside the sysroot remain reachable. Restores access to host resources (e.g., mktemp dirs, /etc/resolv.conf) and fixes the “musl dyn” coreutils failures.

  • Bug Fixes
    • Lookup returns “no translation” if a walk leaves the sysroot without an index mapping; mapped prefixes stay authoritative and missing dirs surface ENOENT; unmapped final components are only claimed if they exist.
    • sidecar_walk_parent_at reports parents outside the sysroot; mutation syscalls (openat, mkdirat, unlinkat, linkat, renameat) return SIDECAR_NOT_HANDLED for the regular resolver.
    • Adds test-sysroot-host-fallback and wires it into make check; matrix now 168 passed, 0 failed (was 141/27).

Written for commit 1304c68. Summary will update on new commits.

Review in cubic

proc_resolve_sysroot_path_flags resolves an absolute guest path inside
the sysroot when it exists there and otherwise falls back to the
literal host path, so guests can reach host resources such as mktemp
directories or /etc/resolv.conf. On a case-insensitive sysroot the
sidecar case-folding walk vetoed that fallback: it anchored every
absolute path at the sysroot root and failed with ENOENT as soon as a
component was missing there, and when only the final component was
missing it still rewrote the path to ${sysroot}${path}, overriding the
resolver either way. Mutating syscalls hit the same wall through
sidecar_walk_parent_at, which hard-anchored the parent directory at
the sysroot.

This broke every file-touching coreutils invocation against a host
path in the test-matrix "musl dyn" suite (27 failures: cat/ls/stat/
cp/touch/... on the mktemp TEST_TMPDIR, plus env/nice/nohup/timeout
returning 127 because execve could not reach the host binary), since
dynamic binaries run under --sysroot and macOS mktemp lives in
/var/folders while the sysroot only contains /var.

Track whether the walk consulted an index mapping. A walk that leaves
the sysroot tree without one returns "no translation" so the
resolver's decision stands; beneath a mapped prefix the sysroot view
stays authoritative and missing suffixes surface as ENOENT against
the translated path. sidecar_walk_parent_at now reports a parent that
resolves outside the sysroot as a distinct verdict, and the mutation
entry points (openat, mkdirat, unlinkat, linkat, renameat) hand such
paths back as SIDECAR_NOT_HANDLED to the regular translation flow.

Add test-sysroot-host-fallback covering reads through missing
intermediates, creates/renames/mkdir/unlink on host paths, the
missing-final-component fallback, and sysroot-over-host precedence;
wire it into make check. Without the fix six of its seven cases fail
with ENOENT.
@Max042004 Max042004 force-pushed the fix-sidecar-host-fallback branch from 60f6165 to 1304c68 Compare July 2, 2026 13:01
@jserv jserv merged commit 4cd5745 into sysprog21:main Jul 2, 2026
4 checks passed
@jserv

jserv commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Thank @Max042004 for contributing!

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.

2 participants