diff options
-rw-r--r-- | include/sanitizer/common_interface_defs.h | 11 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_common_interceptors.inc | 54 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_flags.inc | 2 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_platform_interceptors.h | 1 | ||||
-rw-r--r-- | test/asan/TestCases/memmem_test.cc | 21 | ||||
-rw-r--r-- | test/sanitizer_common/TestCases/Linux/weak_hook_test.cc | 82 |
6 files changed, 169 insertions, 2 deletions
diff --git a/include/sanitizer/common_interface_defs.h b/include/sanitizer/common_interface_defs.h index 7aa58e986..1c90a60d7 100644 --- a/include/sanitizer/common_interface_defs.h +++ b/include/sanitizer/common_interface_defs.h @@ -131,8 +131,19 @@ extern "C" { const void *s2, size_t n, int result); void __sanitizer_weak_hook_strncmp(void *called_pc, const char *s1, const char *s2, size_t n, int result); + void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1, + const char *s2, size_t n, int result); void __sanitizer_weak_hook_strcmp(void *called_pc, const char *s1, const char *s2, int result); + void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1, + const char *s2, int result); + void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1, + const char *s2, char *result); + void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1, + const char *s2, char *result); + void __sanitizer_weak_hook_memmem(void *called_pc, + const void *s1, size_t len1, + const void *s2, size_t len2, void *result); // Prints stack traces for all live heap allocations ordered by total // allocation size until `top_percent` of total live heap is shown. diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 955950538..c95b3580a 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -326,6 +326,9 @@ static inline int CharCaseCmp(unsigned char c1, unsigned char c2) { return c1_low - c2_low; } +DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcasecmp, uptr called_pc, + const char *s1, const char *s2, int result) + INTERCEPTOR(int, strcasecmp, const char *s1, const char *s2) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, strcasecmp, s1, s2); @@ -338,9 +341,16 @@ INTERCEPTOR(int, strcasecmp, const char *s1, const char *s2) { } COMMON_INTERCEPTOR_READ_STRING(ctx, s1, i + 1); COMMON_INTERCEPTOR_READ_STRING(ctx, s2, i + 1); - return CharCaseCmp(c1, c2); + int result = CharCaseCmp(c1, c2); + CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcasecmp, GET_CALLER_PC(), + s1, s2, result); + return result; } +DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncasecmp, uptr called_pc, + const char *s1, const char *s2, uptr n, + int result) + INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, SIZE_T n) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, strncasecmp, s1, s2, n); @@ -353,7 +363,10 @@ INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, SIZE_T n) { } COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, n)); COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, n)); - return CharCaseCmp(c1, c2); + int result = CharCaseCmp(c1, c2); + CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncasecmp, GET_CALLER_PC(), + s1, s2, n, result); + return result; } #define INIT_STRCASECMP COMMON_INTERCEPT_FUNCTION(strcasecmp) @@ -375,6 +388,10 @@ static inline void StrstrCheck(void *ctx, char *r, const char *s1, #endif #if SANITIZER_INTERCEPT_STRSTR + +DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strstr, uptr called_pc, + const char *s1, const char *s2, char *result); + INTERCEPTOR(char*, strstr, const char *s1, const char *s2) { if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) return internal_strstr(s1, s2); @@ -383,6 +400,8 @@ INTERCEPTOR(char*, strstr, const char *s1, const char *s2) { char *r = REAL(strstr)(s1, s2); if (common_flags()->intercept_strstr) StrstrCheck(ctx, r, s1, s2); + CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strstr, GET_CALLER_PC(), s1, + s2, r); return r; } @@ -392,12 +411,18 @@ INTERCEPTOR(char*, strstr, const char *s1, const char *s2) { #endif #if SANITIZER_INTERCEPT_STRCASESTR + +DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcasestr, uptr called_pc, + const char *s1, const char *s2, char *result); + INTERCEPTOR(char*, strcasestr, const char *s1, const char *s2) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, strcasestr, s1, s2); char *r = REAL(strcasestr)(s1, s2); if (common_flags()->intercept_strstr) StrstrCheck(ctx, r, s1, s2); + CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcasestr, GET_CALLER_PC(), + s1, s2, r); return r; } @@ -406,6 +431,30 @@ INTERCEPTOR(char*, strcasestr, const char *s1, const char *s2) { #define INIT_STRCASESTR #endif +#if SANITIZER_INTERCEPT_MEMMEM +DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memmem, uptr called_pc, + const void *s1, SIZE_T len1, const void *s2, + SIZE_T len2, void *result); + +INTERCEPTOR(void*, memmem, const void *s1, SIZE_T len1, const void *s2, + SIZE_T len2) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, memmem, s1, len1, s2, len2); + void *r = REAL(memmem)(s1, len1, s2, len2); + if (common_flags()->intercept_memmem) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, len1); + COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, len2); + } + CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memmem, GET_CALLER_PC(), + s1, len1, s2, len2, r); + return r; +} + +#define INIT_MEMMEM COMMON_INTERCEPT_FUNCTION(memmem); +#else +#define INIT_MEMMEM +#endif // SANITIZER_INTERCEPT_MEMMEM + #if SANITIZER_INTERCEPT_STRCHR INTERCEPTOR(char*, strchr, const char *s, int c) { void *ctx; @@ -5830,6 +5879,7 @@ static void InitializeCommonInterceptors() { INIT_MEMCHR; INIT_MEMCMP; INIT_MEMRCHR; + INIT_MEMMEM; INIT_READ; INIT_PREAD; INIT_PREAD64; diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index ff03c0625..203f41ca3 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -199,6 +199,8 @@ COMMON_FLAG(bool, intercept_memcmp, true, COMMON_FLAG(bool, strict_memcmp, true, "If true, assume that memcmp(p1, p2, n) always reads n bytes before " "comparing p1 and p2.") +COMMON_FLAG(bool, intercept_memmem, true, + "If set, uses a wrapper for memmem() to find more errors.") COMMON_FLAG(bool, intercept_intrin, true, "If set, uses custom wrappers for memset/memcpy/memmove " "intrinsics to find more errors.") diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index 0e70a1800..1c7e46e1d 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -83,6 +83,7 @@ #define SANITIZER_INTERCEPT_MEMMOVE 1 #define SANITIZER_INTERCEPT_MEMCPY 1 #define SANITIZER_INTERCEPT_MEMCMP 1 +#define SANITIZER_INTERCEPT_MEMMEM 1 // The function memchr() contains a jump in the first 6 bytes // that is problematic to intercept correctly on Win64. // Disable memchr() interception for Win64. diff --git a/test/asan/TestCases/memmem_test.cc b/test/asan/TestCases/memmem_test.cc new file mode 100644 index 000000000..54883004e --- /dev/null +++ b/test/asan/TestCases/memmem_test.cc @@ -0,0 +1,21 @@ +// RUN: %clangxx_asan %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=A1 +// RUN: not %run %t 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=A2 +// RUN: %env_asan_opts=intercept_memmem=0 %run %t + +#include <string.h> +int main(int argc, char **argv) { + char a1[] = {1, 2, 3, 4, 5, 6, 7, 8}; + char a2[] = {3, 4, 5}; + void *res; + if (argc == 1) + res = memmem(a1, sizeof(a1) + 1, a2, sizeof(a2)); // BOOM + else + res = memmem(a1, sizeof(a1), a2, sizeof(a2) + 1); // BOOM + // CHECK: AddressSanitizer: stack-buffer-overflow + // CHECK: {{#0.*memmem}} + // CHECK: {{#1.*main}} + // A1: 'a1' <== Memory access at offset + // A2: 'a2' <== Memory access at offset + return res == NULL; +} diff --git a/test/sanitizer_common/TestCases/Linux/weak_hook_test.cc b/test/sanitizer_common/TestCases/Linux/weak_hook_test.cc new file mode 100644 index 000000000..d5667649b --- /dev/null +++ b/test/sanitizer_common/TestCases/Linux/weak_hook_test.cc @@ -0,0 +1,82 @@ +// Test the weak hooks. +// RUN: %clangxx %s -o %t +// RUN: %run %t + +// Hooks are not implemented for lsan. +// XFAIL: lsan + +#include <string.h> +#include <assert.h> + +bool seen_memcmp, seen_strncmp, seen_strncasecmp, seen_strcmp, seen_strcasecmp, + seen_strstr, seen_strcasestr, seen_memmem; + +extern "C" { +void __sanitizer_weak_hook_memcmp(void *called_pc, const void *s1, + const void *s2, size_t n, int result) { + seen_memcmp = true; +} +void __sanitizer_weak_hook_strncmp(void *called_pc, const char *s1, + const char *s2, size_t n, int result) { + seen_strncmp = true; +} +void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1, + const char *s2, size_t n, int result){ + seen_strncasecmp = true; +} +void __sanitizer_weak_hook_strcmp(void *called_pc, const char *s1, + const char *s2, int result){ + seen_strcmp = true; +} +void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1, + const char *s2, int result){ + seen_strcasecmp = true; +} +void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1, + const char *s2, char *result){ + seen_strstr = true; +} +void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1, + const char *s2, char *result){ + seen_strcasestr = true; +} +void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1, + const void *s2, size_t len2, void *result){ + seen_memmem = true; +} +} // extern "C" + +char s1[] = "ABCDEF"; +char s2[] = "CDE"; + +static volatile int int_sink; +static volatile void *ptr_sink; + +int main() { + assert(sizeof(s2) < sizeof(s1)); + + int_sink = memcmp(s1, s2, sizeof(s2)); + assert(seen_memcmp); + + int_sink = strncmp(s1, s2, sizeof(s2)); + assert(seen_strncmp); + + int_sink = strncasecmp(s1, s2, sizeof(s2)); + assert(seen_strncasecmp); + + int_sink = strcmp(s1, s2); + assert(seen_strcmp); + + int_sink = strcasecmp(s1, s2); + assert(seen_strcasecmp); + + ptr_sink = strstr(s1, s2); + assert(seen_strstr); + + ptr_sink = strcasestr(s1, s2); + assert(seen_strcasestr); + + ptr_sink = memmem(s1, sizeof(s1), s2, sizeof(s2)); + assert(seen_memmem); + return 0; +} |