fix: skip /tmp extraction when profiling libraries are installed#529
Conversation
I don't see this part ? |
sorry, I removed that part, I am not sure we want this |
|
Setting as draft until I get time to get back to this and fix some of the comments from Nicolas. |
When ddprof is installed as a package, skip writing executables and shared libraries to /tmp. Security scanners like CrowdStrike Falcon flag new executables in /tmp, and the extraction is pointless when the files already sit in standard system paths. The loader constructor tries dlopen with the bare library name before falling back to /tmp extraction. After a successful bare-name dlopen, it verifies the loaded library's build version matches via a new ddprof_profiling_version() symbol to prevent version mismatches between a stale system install and the injected library. Version macros (VER_MAJ/MIN/PATCH/REV) are now propagated to all profiling library targets so the version string is consistent across the loader, embedded lib, and shared lib. Based on original work by Xavier Roche <[email protected]>. Co-Authored-By: Xavier Roche <[email protected]> Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
26099e7 to
a95cde6
Compare
…alled lib Split the monolithic loader() constructor into three focused helpers: - try_load_installed_profiling_lib(): silent dlopen + version check - setup_ddprof_exe_for_installed_lib(): find ddprof via relative paths - load_embedded_profiling_lib(): extract lib+exe to /tmp Fix ensure_loader_symbols_promoted() to use dladdr() for the RTLD_NOLOAD call so it works on musl (which tracks libs by full path, not SONAME). Fix exe discovery when using an installed libdd_profiling-embedded.so: the standalone lib does not embed the ddprof binary, so the loader now searches for it relative to its own path: 1. <loader_dir>/../bin/ddprof (standard install layout) 2. <loader_dir>/ddprof (flat build/dev layout) with a fallback to extracting from the loader's own embedded data. Add loader_installed_lib-ut.sh to test both layout cases. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
|
this would require a documentation update once we merge |
dladdr lives in libdl.so. Like dlopen/dlsym, it may be absent when the loader is dlopen'd into a process that has not yet loaded libdl (e.g. Ubuntu 16 minimal environments), causing an "undefined symbol: dladdr" crash at load time. Add a weak declaration and NULL-guard every call site. Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This speeds up the install test (avoiding a copy of a large ddprof exe)
Adjust following comments from Nicolas in PR #529
This can be the case on old libc versions
| // non-NULL handle — installed library found and version matches | ||
| // NULL — library not found or version mismatch (fell back OK) | ||
| // (void *)-1 — version mismatch but dlclose failed; caller must abort | ||
| static void *try_load_installed_profiling_lib() { |
There was a problem hiding this comment.
After putting some more thoughts, I think that the strategy "dlopen lib, check version, dlclose if mismatch" is dangerous:
in LD_PRELOAD mode, dlopen will trigger start of dpprof and memory allocation profiling, I am not sure just dlclos'ing the lib is enough. I fear some stale state might be left.
Remove all dlclose usage from the loader constructor — it is unsafe this early and hard to ensure proper cleanup. On version mismatch, warn but proceed with the installed library. Restructure the loader flow to check for the ddprof executable (relative to the loader's path) before attempting to dlopen the installed libdd_profiling-embedded.so. This avoids loading a library we cannot safely unload if the exe turns out to be missing. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
68ebfa2 to
6282c69
Compare
|
thanks for adjusting! So simple warning for now, no dlclose 👍 |
|
/merge |
|
View all feedbacks in Devflow UI.
The expected merge time in
|
What does this PR do?
When ddprof is installed as a package, skip writing executables and shared libraries to /tmp. Security scanners like CrowdStrike Falcon flag new executables in /tmp, and the extraction is pointless when
the files already sit in standard system paths.
The loader constructor tries dlopen with the bare library name before falling back to /tmp extraction. After a successful bare-name dlopen, it verifies the loaded library's build version matches via a
new ddprof_profiling_version() symbol to prevent version mismatches between a stale system install and the injected library.
Version macros (VER_MAJ/MIN/PATCH/REV) are now propagated to all profiling library targets so the version string is consistent across the loader, embedded lib, and shared lib.
Two bugs affecting Alpine Linux (musl) are also fixed:
ensure_loader_symbols_promoted() failed on musl. The loader re-opens itself with RTLD_NOLOAD | RTLD_GLOBAL to promote ddprof_lib_state (initial-exec TLS) to global scope before loading the embedded .so.
On musl, RTLD_NOLOAD with a bare SONAME always fails because musl tracks loaded libraries by full path, not SONAME. Fixed by using dladdr() to obtain the loader's actual on-disk path at runtime.
ddprof binary not found when using an installed libdd_profiling-embedded.so. The standalone embedded lib does not contain the ddprof binary (profiler_exe_data() returns size=0), so the previous fallback
left DD_PROFILING_NATIVE_DDPROF_EXE unset. The loader now searches for ddprof relative to its own path: <loader_dir>/../bin/ddprof (package install layout) and <loader_dir>/ddprof (flat build layout),
falling back to extraction from the loader's own embedded data.
The loader() constructor is refactored into three helpers (try_load_installed_profiling_lib, setup_ddprof_exe_for_installed_lib, load_embedded_profiling_lib) and a new test (loader_installed_lib-ut.sh)
covers both path layouts.
Motivation
fix for the following issue
Additional Notes
This now requires the library + the executable to be installed
exe should be:
./../bin/How to test the change?
Describe here in detail how the change can be validated. This is a great section to call out specific tests you've added or improved, or to acknowledge code sections which are particularly difficult to test.