Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change private loader to use system dynamic loader for DR, clients, and private libraries #7312

Open
derekbruening opened this issue Mar 1, 2025 · 1 comment

Comments

@derekbruening
Copy link
Contributor

Separating out from #5437. Pasting context and proposed options from there:

Pasting from #5437 (comment):


Unfortunately glibc is going the direction of Android with Bionic with tight integration between the loader and libpthread with hardcoded, private dependences between them such that the loader cannot easily be replaced for private loading as it no longer uses clean public interfaces to load libc and libpthread. This is why Android support breaks with each release as they change the internal TLS layout: #3543, #3683.


And now glibc is causing the same type of problem: #5437, #6693, #6611, #6541, #5431, #7293. Relocation support also causes us headaches: #7120.

Pasting from #5437 (comment):


Summarizing the situation:

  • Hacky workaround for now

  • Long-term possible choices:

    A. Keep going with whatever tweaks/hacks are needed to keep the current DR-as-private-loader scheme working.

    B. Static PIC libc + libc++ with --wrap and don't support other libs unless user can find a static PIC version and link it with --wrap. This would work on Mac as well where private libs may never work well but is limiting to users on Linux where previously there was a lot of freedom in library use and many libraries "just worked" with no effort. This will be annoying to the DR repo's own tools which rely on dynamic compression libs, libunwind, etc. If we go this route, a bonus would be that a tool could make a single static lib with DR and itself and its deps for simplified deployment.

    C. Set up the private ld.so and client as though the kernel loaded them and let ld.so relocate and load everything else (as proposed at SIGFPE in private __libc_early_init in glibc 2.34+ SIGFPE in private __libc_early_init in glibc 2.34+ #5437 (comment)): or use ld.so to load DR as well which is even simpler. This feels less clean and transparent though than DR being the loader, and it is harder to intercept and isolate. This seems the most promising and as noted above may help Android as well but is a big refactor to how things are done and will likely encounter a bunch of issues even if the core setup is not too much code.

    D. Switch from glibc to musl: require clients to use musl if they use libc. We'd have to experiment to see whether musl is missing any key features in its libc that many clients rely on; and we'd have to see whether its pthreads has its own problems. Xref build fails on musl-libc based linux systems (for example alpine, void, sabotage) build fails on musl-libc based linux systems (for example alpine, void, sabotage) #1973 on building with a musl-based system.

    E. Don't support library usage at all in general: this may seem like a non-starter but the model of linking DR and a client into the app ends up with this restriction, though some library use is possible if carefully done: e.g., the STL from the app can be used with placement new, and maybe a separate libc++ copy with --wrap could be linked. The DR API does have a lot of resources in it. Most users end up wanting other libs though.

Note that Mac may never support private library copies due to how the system handles shared libraries: #1285.
And Windows private loader support has been difficult to maintain due to fewer devs working on Windows.
Switching to static libs plus DR-provided interfaces ("drwinapi" on Windows) and away from private libraries would be a more unified cross-platform approach, at a lost of freedom on Linux/Android.


Since option C of using the system loader for DR, clients, and private libraries may not be very hard to implement, despite it possibly not helping Windows and Mac, this issue covers trying that out.

#5437 (comment) proposes a complex scheme that keeps libdynamorio.so without an interpreter: but it would be simpler to have ld.so be libdynamorio.so's interpreter and handle its relocations.

  • Give libdynamorio.so an interpreter: ld-linux.so
  • Have libdynamorio.so export "malloc", etc. from the list in
    redirect_imports[] and rely on ELF namespace lookup ordering picking
    those first
    • But: what about a library with DF_SYMBOLIC, or dlopen w/o RTLD_GLOBAL?
  • Have libdynamorio.so require libdl.so and use dlopen to load
    the client(s)

The app will still be mapped by libdynamorio.so; libdynamorio.so will still
also map the app's ld.so, and execute every ld.so and app instruction from
the very start. There will still be two copies of ld.so and other
libraries used by both the client and the app. We rely on ELF namespace
ordering to redirect key functions like malloc for isolation.

This feels less clean and harder to intercept and isolate than when
libdynamorio.so is the loader: and we may not know until we try it whether
we lose more in isolation than we gain in maintainability.

derekbruening added a commit that referenced this issue Mar 10, 2025
Adds the client.exception test to the ignore list on Linux as the
Linux private loader on glibc 2.34+ fails to support C++ exceptions.

Long-term we should either officially drop C++ exception support and
remove this test, or add support (probably via #7312).

Issue: #7297
derekbruening added a commit that referenced this issue Mar 11, 2025
Adds the client.exception test to the ignore list on Linux as the
Linux private loader on glibc 2.34+ fails to support C++ exceptions.

Long-term we should either officially drop C++ exception support and
remove this test, or add support (probably via #7312).

Issue: #7297, #7270
@derekbruening
Copy link
Contributor Author

More reasons to abandon the current private loader:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant