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

[sanitizer_common] Add experimental flag to tweak dlopen(<main program>) #71715

Merged
merged 6 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler-rt/lib/sanitizer_common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ set(SANITIZER_NOLIBC_SOURCES
set(SANITIZER_LIBCDEP_SOURCES
sanitizer_common_libcdep.cpp
sanitizer_allocator_checks.cpp
sanitizer_dl.cpp
sanitizer_linux_libcdep.cpp
sanitizer_mac_libcdep.cpp
sanitizer_posix_libcdep.cpp
Expand Down Expand Up @@ -139,6 +140,7 @@ set(SANITIZER_IMPL_HEADERS
sanitizer_deadlock_detector_interface.h
sanitizer_dense_map.h
sanitizer_dense_map_info.h
sanitizer_dl.h
sanitizer_errno.h
sanitizer_errno_codes.h
sanitizer_file.h
Expand Down
36 changes: 33 additions & 3 deletions compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,17 @@
// COMMON_INTERCEPTOR_STRERROR
//===----------------------------------------------------------------------===//

#include <stdarg.h>

#include "interception/interception.h"
#include "sanitizer_addrhashmap.h"
#include "sanitizer_dl.h"
#include "sanitizer_errno.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_platform_interceptors.h"
#include "sanitizer_symbolizer.h"
#include "sanitizer_tls_get_addr.h"

#include <stdarg.h>

#if SANITIZER_INTERCEPTOR_HOOKS
#define CALL_WEAK_INTERCEPTOR_HOOK(f, ...) f(__VA_ARGS__);
#define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) \
Expand Down Expand Up @@ -6307,7 +6308,36 @@ INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) {
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) {
COMMON_INTERCEPTOR_READ_STRING(ctx, filename, 0);

# if !SANITIZER_DYNAMIC
vitalybuka marked this conversation as resolved.
Show resolved Hide resolved
// We care about a very specific use-case: dladdr on
// statically-linked ASan may return <main program>
// instead of the library.
// We therefore only take effect if the sanitizer is statically
// linked, and we don't bother canonicalizing paths because
// dladdr should return the same address both times (we assume
// the user did not canonicalize the result from dladdr).
if (common_flags()->test_only_replace_dlopen_main_program) {
VPrintf(1, "dlopen interceptor: filename: %s\n", filename);

const char *SelfFName = DladdrSelfFName();
VPrintf(1, "dlopen interceptor: DladdrSelfFName: %p %s\n",
(void *)SelfFName, SelfFName);

if (internal_strcmp(SelfFName, filename) == 0) {
// It's possible they copied the string from dladdr, so
// we do a string comparison rather than pointer comparison.
VPrintf(1, "dlopen interceptor: replacing %s because it matches %s\n",
filename, SelfFName);
filename = (char *)0; // RTLD_DEFAULT
}
}
# endif // !SANITIZER_DYNAMIC
}

void *res = COMMON_INTERCEPTOR_DLOPEN(filename, flag);
Symbolizer::GetOrInit()->InvalidateModuleList();
COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res);
Expand Down
35 changes: 35 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_dl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//===-- sanitizer_dl.cpp --------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file has helper functions that depend on libc's dynamic loading
// introspection.
//
//===----------------------------------------------------------------------===//

#include "sanitizer_dl.h"

#include <dlfcn.h>

#include "sanitizer_common/sanitizer_platform.h"

namespace __sanitizer {
extern const char *SanitizerToolName;

const char *DladdrSelfFName(void) {
#if SANITIZER_GLIBC
Dl_info info;
int ret = dladdr((void *)&SanitizerToolName, &info);
if (ret) {
return info.dli_fname;
}
#endif

return nullptr;
}

} // namespace __sanitizer
26 changes: 26 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_dl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//===-- sanitizer_dl.h ----------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file has helper functions that depend on libc's dynamic loading
// introspection.
//
//===----------------------------------------------------------------------===//

#ifndef SANITIZER_DL_H
#define SANITIZER_DL_H

namespace __sanitizer {

// Returns the path to the shared object or - in the case of statically linked
// sanitizers
// - the main program itself, that contains the sanitizer.
const char* DladdrSelfFName(void);

} // namespace __sanitizer

#endif // SANITIZER_DL_H
6 changes: 6 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
Original file line number Diff line number Diff line change
Expand Up @@ -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)")
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Test 'test_only_replace_dlopen_main_program' flag

// RUN: %clangxx %s -pie -fPIE -o %t
// RUN: env %tool_options='test_only_replace_dlopen_main_program=true' %run %t
// RUN: env %tool_options='test_only_replace_dlopen_main_program=false' not %run %t

// dladdr is 'nonstandard GNU extensions that are also present on Solaris'
// REQUIRES: glibc

// Does not intercept dlopen
// UNSUPPORTED: hwasan, lsan, ubsan

// Flag has no effect with dynamic runtime
// UNSUPPORTED: asan-dynamic-runtime

#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>

// We can't use the address of 'main' (error: ISO C++ does not allow 'main' to be used by a program [-Werror,-Wmain]')
// so we add this function.
__attribute__((noinline, no_sanitize("address"))) void foo() {
printf("Hello World!\n");
}

int main(int argc, char *argv[]) {
foo();

// "If filename is NULL, then the returned handle is for the main program."
void *correct_handle = dlopen(NULL, RTLD_LAZY);
printf("dlopen(NULL,...): %p\n", correct_handle);

Dl_info info;
if (dladdr((void *)&foo, &info) == 0) {
printf("dladdr failed\n");
return 1;
}
printf("dladdr(&foo): %s\n", info.dli_fname);
void *test_handle = dlopen(info.dli_fname, RTLD_LAZY);
printf("dlopen(%s,...): %p\n", info.dli_fname, test_handle);

if (test_handle != correct_handle) {
printf("Error: handles do not match\n");
return 1;
}

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ source_set("sources") {
"sanitizer_deadlock_detector_interface.h",
"sanitizer_dense_map.h",
"sanitizer_dense_map_info.h",
"sanitizer_dl.cpp",
"sanitizer_dl.h",
"sanitizer_errno.cpp",
"sanitizer_errno.h",
"sanitizer_errno_codes.h",
Expand Down