[compiler-rt] [sanitizer_common] Add experimental flag to tweak dlopen(<main program>) (PR #71715)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 8 10:07:16 PST 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-compiler-rt-sanitizer
Author: Thurston Dang (thurstond)
<details>
<summary>Changes</summary>
This introduces an experimental flag 'test_only_replace_dlopen_main_program'.
When enabled, this will replace dlopen(<main program,...> with dlopen(NULL,...),
which is the correct way to get a handle to the main program.
This can be useful when ASan is statically linked, since dladdr((void*)pthread_join)
or similar will return the path to the main program.
Note that dlopen(<main program>,...) never ends well:
- PIE in recent glibc versions (glibc bugzilla 24323), or non-PIE: return an error
- PIE in current GRTE and older glibc: attempt to load the main program
again, leading to reinitializing ASan and failing to remap the shadow
memory.
---
Full diff: https://github.com/llvm/llvm-project/pull/71715.diff
2 Files Affected:
- (modified) compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc (+29-1)
- (modified) compiler-rt/lib/sanitizer_common/sanitizer_flags.inc (+6)
``````````diff
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
index 80efaf54a0607f6..0f7d9da9d148443 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -6304,10 +6304,38 @@ INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) {
#endif
#if SANITIZER_INTERCEPT_DLOPEN_DLCLOSE
+// Returns 1 if key is a suffix of str, 0 otherwise
+static int internal_strcmp_suffix(const char *key, const char *str) {
+ if (!key || !str)
+ return 0;
+
+ if (internal_strlen(key) > internal_strlen(str))
+ return 0;
+
+ return !internal_strcmp(str + internal_strlen(str) - internal_strlen(key),
+ key);
+}
+
+# if SANITIZER_GLIBC
+extern char *__progname;
+# endif
+
INTERCEPTOR(void*, dlopen, const char *filename, int flag) {
void *ctx;
COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlopen, filename, flag);
- if (filename) COMMON_INTERCEPTOR_READ_STRING(ctx, filename, 0);
+
+ if (filename) {
+# if SANITIZER_GLIBC
+ if (common_flags()->test_only_replace_dlopen_main_program &&
+ internal_strcmp_suffix(__progname, filename)) {
+ VPrintf(1, "dlopen interceptor: replacing %s because it matches %s\n",
+ filename, __progname);
+ filename = (char *)0; // RTLD_DEFAULT
+ }
+# endif
+ COMMON_INTERCEPTOR_READ_STRING(ctx, filename, 0);
+ }
+
void *res = COMMON_INTERCEPTOR_DLOPEN(filename, flag);
Symbolizer::GetOrInit()->InvalidateModuleList();
COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res);
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc b/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
index 6148ae56067cae0..949bdbd148b6b89 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
@@ -269,3 +269,9 @@ COMMON_FLAG(bool, detect_write_exec, false,
COMMON_FLAG(bool, test_only_emulate_no_memorymap, false,
"TEST ONLY fail to read memory mappings to emulate sanitized "
"\"init\"")
+// With static linking, dladdr((void*)pthread_join) or similar will return the
+// path to the main program. This flag will replace dlopen(<main program,...>
+// with dlopen(NULL,...), which is the correct way to get a handle to the main
+// program.
+COMMON_FLAG(bool, test_only_replace_dlopen_main_program, false,
+ "TEST ONLY replace dlopen(<main program>,...) with dlopen(NULL)")
``````````
</details>
https://github.com/llvm/llvm-project/pull/71715
More information about the llvm-commits
mailing list