Skip to content

fix: tell the confined semantic provider where its libraries are - #6

Merged
CesarManzoCode merged 1 commit into
mainfrom
claude/rust-analyzer-lib-path-fix-pa2v3n
Aug 30, 2026
Merged

fix: tell the confined semantic provider where its libraries are#6
CesarManzoCode merged 1 commit into
mainfrom
claude/rust-analyzer-lib-path-fix-pa2v3n

Conversation

@CesarManzoCode

Copy link
Copy Markdown
Owner

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 /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 /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

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
@CesarManzoCode
CesarManzoCode merged commit 098c80e into main Aug 30, 2026
1 check failed
@CesarManzoCode
CesarManzoCode deleted the claude/rust-analyzer-lib-path-fix-pa2v3n branch September 5, 2026 03:02
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