fix: tell the confined semantic provider where its libraries are - #6
Merged
Merged
Conversation
rust-analyzer under confinement died with status 127 before its first
byte of LSP:
/module/rust-analyzer: error while loading shared libraries:
librustc_driver-<hash>.so: cannot open shared object file
It was read as the seccomp filter for a day, and it is not: no SIGSYS,
nothing in ausearch, and cargo running fine beside it under the same
profile.
The cause is RUNPATH. Every binary rustup installs carries
`RUNPATH: [$ORIGIN/../lib]`, and $ORIGIN is the directory the *loader*
finds the binary in — not the one it was installed in. `foreign::establish`
mounts a foreign program's own directory at `/module`, so a rust-analyzer
living in <toolchain>/bin is executed as `/module/rust-analyzer` and looks
for librustc_driver in `/lib`. Cargo never meets it: `cargo` needs no
librustc_driver, and the rustc it starts is started at its own absolute
path, where $ORIGIN still means what it was linked to mean.
So the directory RUNPATH meant is named outright, derived from where the
binary really is — no hash, no version, no toolchain name — and only when
it exists. Not a widening: it is inside the toolchain `readable()` already
grants read-only, a grant keeps its absolute path inside the root
filesystem, and an LD_LIBRARY_PATH entry naming something nobody granted
names something that is not there.
Reproduced physically without a confinement, by hardlinking this
container's rustc into another directory so its $ORIGIN is wrong: status
127 with that exact message, and `rustc --version` with LD_LIBRARY_PATH
set to <toolchain>/lib.
The regression test asserts the property the change controls — what
environment reaches whoever starts the process — through a spawner that
records and refuses. The confinement itself cannot be built here, and a
test that claimed otherwise would be claiming to have proven the thing
that was broken.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013VYCpUvjbzH1vPoCh4L4fh
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.
rust-analyzer under confinement died with status 127 before its first byte of LSP:
It was read as the seccomp filter for a day, and it is not: no SIGSYS, nothing in ausearch, and cargo running fine beside it under the same profile.
The cause is RUNPATH. Every binary rustup installs carries
RUNPATH: [$ORIGIN/../lib], and $ORIGIN is the directory the loader finds the binary in — not the one it was installed in.foreign::establishmounts a foreign program's own directory at/module, so a rust-analyzer living in /bin is executed as/module/rust-analyzerand looks for librustc_driver in/lib. Cargo never meets it:cargoneeds no librustc_driver, and the rustc it starts is started at its own absolute path, where $ORIGIN still means what it was linked to mean.So the directory RUNPATH meant is named outright, derived from where the binary really is — no hash, no version, no toolchain name — and only when it exists. Not a widening: it is inside the toolchain
readable()already grants read-only, a grant keeps its absolute path inside the root filesystem, and an LD_LIBRARY_PATH entry naming something nobody granted names something that is not there.Reproduced physically without a confinement, by hardlinking this container's rustc into another directory so its $ORIGIN is wrong: status 127 with that exact message, and
rustc --versionwith LD_LIBRARY_PATH set to /lib.The regression test asserts the property the change controls — what environment reaches whoever starts the process — through a spawner that records and refuses. The confinement itself cannot be built here, and a test that claimed otherwise would be claiming to have proven the thing that was broken.
Claude-Session: https://claude.ai/code/session_013VYCpUvjbzH1vPoCh4L4fh