[compiler-rt] r209427 - [ASan/Win] Use the new function interception approach to handle function wrappers too; wrap strlen() in DLLs
Timur Iskhodzhanov
timurrrr at google.com
Thu May 22 05:03:40 PDT 2014
Author: timurrrr
Date: Thu May 22 07:03:40 2014
New Revision: 209427
URL: http://llvm.org/viewvc/llvm-project?rev=209427&view=rev
Log:
[ASan/Win] Use the new function interception approach to handle function wrappers too; wrap strlen() in DLLs
Reviewed at http://reviews.llvm.org/D3871
Added:
compiler-rt/trunk/test/asan/TestCases/Windows/dll_intercept_strlen.cc
Modified:
compiler-rt/trunk/lib/asan/asan_dll_thunk.cc
compiler-rt/trunk/lib/interception/interception.h
compiler-rt/trunk/test/asan/TestCases/Windows/dll_malloc_left_oob.cc
compiler-rt/trunk/test/asan/TestCases/Windows/dll_malloc_uaf.cc
Modified: compiler-rt/trunk/lib/asan/asan_dll_thunk.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_dll_thunk.cc?rev=209427&r1=209426&r2=209427&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_dll_thunk.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_dll_thunk.cc Thu May 22 07:03:40 2014
@@ -22,7 +22,7 @@
#ifdef ASAN_DLL_THUNK
#include "sanitizer_common/sanitizer_interception.h"
-// ----------------- Helper functions and macros --------------------- {{{1
+// ---------- Function interception helper functions and macros ----------- {{{1
extern "C" {
void *__stdcall GetModuleHandleA(const char *module_name);
void *__stdcall GetProcAddress(void *module, const char *proc_name);
@@ -36,68 +36,125 @@ static void *getRealProcAddressOrDie(con
return ret;
}
+// We need to intercept some functions (e.g. ASan interface, memory allocator --
+// let's call them "hooks") exported by the DLL thunk and forward the hooks to
+// the runtime in the main module.
+// However, we don't want to keep two lists of these hooks.
+// To avoid that, the list of hooks should be defined using the
+// INTERCEPT_WHEN_POSSIBLE macro. Then, all these hooks can be intercepted
+// at once by calling INTERCEPT_HOOKS().
+
+// Use macro+template magic to automatically generate the list of hooks.
+// Each hook at line LINE defines a template class with a static
+// FunctionInterceptor<LINE>::Execute() method intercepting the hook.
+// The default implementation of FunctionInterceptor<LINE> is to call
+// the Execute() method corresponding to the previous line.
+template<int LINE>
+struct FunctionInterceptor {
+ static void Execute() { FunctionInterceptor<LINE-1>::Execute(); }
+};
+
+// There shouldn't be any hooks with negative definition line number.
+template<>
+struct FunctionInterceptor<0> {
+ static void Execute() {}
+};
+
+#define INTERCEPT_WHEN_POSSIBLE(main_function, dll_function) \
+ template<> struct FunctionInterceptor<__LINE__> { \
+ static void Execute() { \
+ void *wrapper = getRealProcAddressOrDie(main_function); \
+ if (!__interception::OverrideFunction((uptr)dll_function, \
+ (uptr)wrapper, 0)) \
+ abort(); \
+ FunctionInterceptor<__LINE__-1>::Execute(); \
+ } \
+ };
+
+// Special case of hooks -- ASan own interface functions. Those are only called
+// after __asan_init, thus an empty implementation is sufficient.
+#define INTERFACE_FUNCTION(name) \
+ extern "C" void name() { __debugbreak(); } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name)
+
+// INTERCEPT_HOOKS must be used after the last INTERCEPT_WHEN_POSSIBLE.
+#define INTERCEPT_HOOKS FunctionInterceptor<__LINE__>::Execute
+
+static void InterceptHooks();
+// }}}
+
+// ---------- Function wrapping helpers ----------------------------------- {{{1
#define WRAP_V_V(name) \
extern "C" void name() { \
typedef void (*fntype)(); \
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
fn(); \
- }
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
#define WRAP_V_W(name) \
extern "C" void name(void *arg) { \
typedef void (*fntype)(void *arg); \
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
fn(arg); \
- }
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
#define WRAP_V_WW(name) \
extern "C" void name(void *arg1, void *arg2) { \
typedef void (*fntype)(void *, void *); \
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
fn(arg1, arg2); \
- }
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
#define WRAP_V_WWW(name) \
extern "C" void name(void *arg1, void *arg2, void *arg3) { \
typedef void *(*fntype)(void *, void *, void *); \
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
fn(arg1, arg2, arg3); \
- }
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
#define WRAP_W_V(name) \
extern "C" void *name() { \
typedef void *(*fntype)(); \
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
return fn(); \
- }
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
#define WRAP_W_W(name) \
extern "C" void *name(void *arg) { \
typedef void *(*fntype)(void *arg); \
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
return fn(arg); \
- }
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
#define WRAP_W_WW(name) \
extern "C" void *name(void *arg1, void *arg2) { \
typedef void *(*fntype)(void *, void *); \
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
return fn(arg1, arg2); \
- }
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
#define WRAP_W_WWW(name) \
extern "C" void *name(void *arg1, void *arg2, void *arg3) { \
typedef void *(*fntype)(void *, void *, void *); \
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
return fn(arg1, arg2, arg3); \
- }
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
#define WRAP_W_WWWW(name) \
extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \
typedef void *(*fntype)(void *, void *, void *, void *); \
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
return fn(arg1, arg2, arg3, arg4); \
- }
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
#define WRAP_W_WWWWW(name) \
extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
@@ -105,7 +162,8 @@ static void *getRealProcAddressOrDie(con
typedef void *(*fntype)(void *, void *, void *, void *, void *); \
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
return fn(arg1, arg2, arg3, arg4, arg5); \
- }
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
#define WRAP_W_WWWWWW(name) \
extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
@@ -113,48 +171,8 @@ static void *getRealProcAddressOrDie(con
typedef void *(*fntype)(void *, void *, void *, void *, void *, void *); \
static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
return fn(arg1, arg2, arg3, arg4, arg5, arg6); \
- }
-// }}}
-
-// --------- Interface interception helper functions and macros ----------- {{{1
-// We need to intercept the ASan interface exported by the DLL thunk and forward
-// all the functions to the runtime in the main module.
-// However, we don't want to keep two lists of interface functions.
-// To avoid that, the list of interface functions should be defined using the
-// INTERFACE_FUNCTION macro. Then, all the interface can be intercepted at once
-// by calling INTERCEPT_ASAN_INTERFACE().
-
-// Use macro+template magic to automatically generate the list of interface
-// functions. Each interface function at line LINE defines a template class
-// with a static InterfaceInteceptor<LINE>::Execute() method intercepting the
-// function. The default implementation of InterfaceInteceptor<LINE> is to call
-// the Execute() method corresponding to the previous line.
-template<int LINE>
-struct InterfaceInteceptor {
- static void Execute() { InterfaceInteceptor<LINE-1>::Execute(); }
-};
-
-// There shouldn't be any interface function with negative line number.
-template<>
-struct InterfaceInteceptor<0> {
- static void Execute() {}
-};
-
-#define INTERFACE_FUNCTION(name) \
- extern "C" void name() { __debugbreak(); } \
- template<> struct InterfaceInteceptor<__LINE__> { \
- static void Execute() { \
- void *wrapper = getRealProcAddressOrDie(#name); \
- if (!__interception::OverrideFunction((uptr)name, (uptr)wrapper, 0)) \
- abort(); \
- InterfaceInteceptor<__LINE__-1>::Execute(); \
- } \
- };
-
-// INTERCEPT_ASAN_INTERFACE must be used after the last INTERFACE_FUNCTION.
-#define INTERCEPT_ASAN_INTERFACE InterfaceInteceptor<__LINE__>::Execute
-
-static void InterceptASanInterface();
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, name);
// }}}
// ----------------- ASan own interface functions --------------------
@@ -178,7 +196,7 @@ extern "C" {
__asan_option_detect_stack_use_after_return =
(__asan_should_detect_stack_use_after_return() != 0);
- InterceptASanInterface();
+ InterceptHooks();
}
}
@@ -266,8 +284,14 @@ WRAP_W_W(_expand_dbg)
// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc).
-void InterceptASanInterface() {
- INTERCEPT_ASAN_INTERFACE();
+// strlen is an intrinsic function, so we must specify its exact return and
+// parameter types to avoid a compiler error.
+extern "C" unsigned strlen(const char *s);
+INTERCEPT_WHEN_POSSIBLE(WRAPPER_NAME(strlen), strlen);
+
+// Must be at the end of the file due to the way INTERCEPT_HOOKS is defined.
+void InterceptHooks() {
+ INTERCEPT_HOOKS();
}
#endif // ASAN_DLL_THUNK
Modified: compiler-rt/trunk/lib/interception/interception.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/interception/interception.h?rev=209427&r1=209426&r2=209427&view=diff
==============================================================================
--- compiler-rt/trunk/lib/interception/interception.h (original)
+++ compiler-rt/trunk/lib/interception/interception.h Thu May 22 07:03:40 2014
@@ -127,9 +127,9 @@ const interpose_substitution substitutio
# define WRAPPER_NAME(x) #x
# define INTERCEPTOR_ATTRIBUTE
# else // Static CRT
-# define WRAP(x) wrap_##x
-# define WRAPPER_NAME(x) "wrap_"#x
-# define INTERCEPTOR_ATTRIBUTE
+# define WRAP(x) __asan_wrap_##x
+# define WRAPPER_NAME(x) "__asan_wrap_"#x
+# define INTERCEPTOR_ATTRIBUTE __declspec(dllexport)
# endif
# define DECLARE_WRAPPER(ret_type, func, ...) \
extern "C" ret_type func(__VA_ARGS__);
Added: compiler-rt/trunk/test/asan/TestCases/Windows/dll_intercept_strlen.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Windows/dll_intercept_strlen.cc?rev=209427&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/Windows/dll_intercept_strlen.cc (added)
+++ compiler-rt/trunk/test/asan/TestCases/Windows/dll_intercept_strlen.cc Thu May 22 07:03:40 2014
@@ -0,0 +1,29 @@
+// RUN: %clangxx_asan -O0 %p/dll_host.cc -Fe%t
+// RUN: %clangxx_asan -LD -O0 %s -Fe%t.dll
+// FIXME: 'cat' is needed due to PR19744.
+// RUN: not %run %t %t.dll 2>&1 | cat | FileCheck %s
+
+#include <stdio.h>
+#include <string.h>
+
+extern "C" __declspec(dllexport)
+int test_function() {
+ char str[] = "Hello!";
+ if (6 != strlen(str))
+ return 1;
+ printf("Initial test OK\n");
+ fflush(0);
+// CHECK: Initial test OK
+
+ str[6] = '!'; // Removes '\0' at the end!
+ int len = strlen(str);
+// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
+// FIXME: Should be READ of size 1, see issue 155.
+// CHECK: READ of size {{[0-9]+}} at [[ADDR]] thread T0
+// CHECK-NEXT: {{#0 .*}}strlen
+// CHECK-NEXT: {{#1 .* test_function .*}}dll_intercept_strlen.cc:[[@LINE-5]]
+//
+// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame
+// CHECK-NEXT: test_function {{.*}}dll_intercept_strlen.cc:
+ return len > 42;
+}
Modified: compiler-rt/trunk/test/asan/TestCases/Windows/dll_malloc_left_oob.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Windows/dll_malloc_left_oob.cc?rev=209427&r1=209426&r2=209427&view=diff
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/Windows/dll_malloc_left_oob.cc (original)
+++ compiler-rt/trunk/test/asan/TestCases/Windows/dll_malloc_left_oob.cc Thu May 22 07:03:40 2014
@@ -15,8 +15,8 @@ int test_function() {
//
// CHECK: [[ADDR]] is located 1 bytes to the left of 42-byte region
// CHECK-LABEL: allocated by thread T0 here:
-// CHECK: malloc
-// CHECK: test_function {{.*}}dll_malloc_left_oob.cc:[[@LINE-10]]
+// CHECK-NEXT: malloc
+// CHECK-NEXT: test_function {{.*}}dll_malloc_left_oob.cc:[[@LINE-10]]
// CHECK-NEXT: main {{.*}}dll_host.cc
// CHECK-LABEL: SUMMARY
free(buffer);
Modified: compiler-rt/trunk/test/asan/TestCases/Windows/dll_malloc_uaf.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Windows/dll_malloc_uaf.cc?rev=209427&r1=209426&r2=209427&view=diff
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/Windows/dll_malloc_uaf.cc (original)
+++ compiler-rt/trunk/test/asan/TestCases/Windows/dll_malloc_uaf.cc Thu May 22 07:03:40 2014
@@ -17,13 +17,13 @@ int test_function() {
//
// CHECK: [[ADDR]] is located 0 bytes inside of 42-byte region
// CHECK-LABEL: freed by thread T0 here:
-// CHECK: free
-// CHECK: test_function {{.*}}dll_malloc_uaf.cc:[[@LINE-10]]
+// CHECK-NEXT: free
+// CHECK-NEXT: test_function {{.*}}dll_malloc_uaf.cc:[[@LINE-10]]
// CHECK-NEXT: main {{.*}}dll_host
//
// CHECK-LABEL: previously allocated by thread T0 here:
-// CHECK: malloc
-// CHECK: test_function {{.*}}dll_malloc_uaf.cc:[[@LINE-16]]
+// CHECK-NEXT: malloc
+// CHECK-NEXT: test_function {{.*}}dll_malloc_uaf.cc:[[@LINE-16]]
// CHECK-NEXT: main {{.*}}dll_host
return 0;
}
More information about the llvm-commits
mailing list