Skip to content

Search the calling image's RUNPATH for dlopen from loaded code - #4

Open
Nikita-prog-art wants to merge 1 commit into
pg83:mainfrom
Nikita-prog-art:dlopen-caller-runpath
Open

Search the calling image's RUNPATH for dlopen from loaded code#4
Nikita-prog-art wants to merge 1 commit into
pg83:mainfrom
Nikita-prog-art:dlopen-caller-runpath

Conversation

@Nikita-prog-art

Copy link
Copy Markdown

Problem

glibc resolves a bare dlopen name through the calling object's DT_RUNPATH (or its DT_RPATH when it carries no RUNPATH). SoLo consulted the requester's paths only while resolving that image's own DT_NEEDED entries, so a dlopen issued by loaded code could not reach a sibling through $ORIGIN.

On WSL2 this breaks dzn: the D3D12 runtime loads libigd12umd64.so from the kernel-provided absolute path, and that image then dlopens libigd12um64xel.so by bare name from its own directory. The load previously required DL_ELF_LIBRARY_PATH pointed at the Intel driver directory. Two details made it worse: the UMD imports dlopen@GLIBC_2.2.5, which was not in the shim table and fell through to the raw stub, skipping the glibc-semantics wrapper entirely.

Fix

  • sh_glibc_dlopen / sh_glibc_dlmopen are now noinline boundary entries that capture __builtin_return_address(0); the new stub_dlopen_fromElfImage::loadElfFrom path maps that address to the issuing image via Loader::findImageByAddress and threads it into Loader::load.
  • resolvePath takes the dlopen caller and uses it for the rpath/runPath slots in glibc's order (DT_RPATH before LD_LIBRARY_PATH when the caller has no RUNPATH, DT_RUNPATH after it), falling back to the in-flight requester for DT_NEEDED resolution.
  • dlopen@GLIBC_2.2.5 is registered in the shim table next to GLIBC_2.34.

Test

The smoke test builds a host DSO with -Wl,-rpath,'$ORIGIN/runpath' — and an old-dtags DT_RPATH variant — that dlopens a sibling by bare name from a directory no other search path carries, so the load succeeds only through the caller's path. Both checks fail with caller DT_RUNPATH lookup failed / caller DT_RPATH lookup failed before the fix.

Verification

  • ./build test passes on Debian (host gcc 14.2); the new checks fail when the loader change is reverted.
  • The WSL2 dzn demo (./build vulkan, --driver dzn_icd.json) now runs with an empty environment: no DL_ELF_LIBRARY_PATH, no LD_LIBRARY_PATH — the UMD resolves through its caller's RUNPATH and the WSL client libraries through /etc/ld.so.cache.

glibc resolves a bare dlopen name through the calling object's
DT_RUNPATH (or its DT_RPATH when it carries no RUNPATH). SoLo
consulted the requester's paths only while resolving its DT_NEEDED
entries, so a dlopen issued by loaded code could not reach a sibling
through $ORIGIN. On WSL2, dzn's D3D12 UMD fails to load its
libigd12um64xel.so exactly this way and previously required
DL_ELF_LIBRARY_PATH pointed at the driver directory.

Map the glibc-boundary caller's return address to the issuing image,
thread it into Loader::load, and let resolvePath use it for the
rpath/runPath slots, in glibc's order. Register dlopen@GLIBC_2.2.5 in
the shim table as well: pre-2.34 importers previously fell through to
the raw stub and skipped the caller plumbing.

The smoke test builds a host DSO with -rpath '$ORIGIN/runpath' - and
an old-dtags DT_RPATH variant - that dlopens a sibling by bare name
from a directory no other search path carries, so the load succeeds
only through the caller's path.
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.

1 participant