From dd885eaf5f36a4d8b34ab50935dbd9c4123b7e13 Mon Sep 17 00:00:00 2001 From: Clement Courbet Date: Fri, 1 Mar 2019 16:42:08 +0000 Subject: [PATCH] Reland "[compiler-rt] Intercept the bcmp() function." Fix test issues on darwin: The REQUIRES for the test should be the same as the guard for whether we intercept bcmp. llvm-svn: 355204 --- compiler-rt/lib/asan/tests/asan_mem_test.cc | 42 ++++++++++++------- .../sanitizer_common_interceptors.inc | 35 ++++++++++++---- .../sanitizer_platform_interceptors.h | 3 ++ .../test/asan/TestCases/Posix/bcmp_test.cc | 18 ++++++++ .../test/asan/TestCases/memcmp_test.cc | 4 +- compiler-rt/test/msan/memcmp_test.cc | 2 +- compiler-rt/test/msan/scoped-interceptors.cc | 2 +- .../TestCases/Posix/weak_hook_test.cc | 11 ++++- 8 files changed, 89 insertions(+), 28 deletions(-) create mode 100644 compiler-rt/test/asan/TestCases/Posix/bcmp_test.cc diff --git a/compiler-rt/lib/asan/tests/asan_mem_test.cc b/compiler-rt/lib/asan/tests/asan_mem_test.cc index b4d3b16ec0ab..1339c1271bdd 100644 --- a/compiler-rt/lib/asan/tests/asan_mem_test.cc +++ b/compiler-rt/lib/asan/tests/asan_mem_test.cc @@ -9,7 +9,11 @@ // This file is a part of AddressSanitizer, an address sanity checker. // //===----------------------------------------------------------------------===// +#include #include "asan_test_utils.h" +#if defined(_GNU_SOURCE) +#include // for bcmp +#endif #include template @@ -205,37 +209,43 @@ TEST(AddressSanitizer, MemMoveOOBTest) { MemTransferOOBTestTemplate(1024); } - -TEST(AddressSanitizer, MemCmpOOBTest) { +template +void CmpOOBTestCommon() { size_t size = Ident(100); char *s1 = MallocAndMemsetString(size); char *s2 = MallocAndMemsetString(size); - // Normal memcmp calls. - Ident(memcmp(s1, s2, size)); - Ident(memcmp(s1 + size - 1, s2 + size - 1, 1)); - Ident(memcmp(s1 - 1, s2 - 1, 0)); + // Normal cmpfn calls. + Ident(cmpfn(s1, s2, size)); + Ident(cmpfn(s1 + size - 1, s2 + size - 1, 1)); + Ident(cmpfn(s1 - 1, s2 - 1, 0)); // One of arguments points to not allocated memory. - EXPECT_DEATH(Ident(memcmp)(s1 - 1, s2, 1), LeftOOBReadMessage(1)); - EXPECT_DEATH(Ident(memcmp)(s1, s2 - 1, 1), LeftOOBReadMessage(1)); - EXPECT_DEATH(Ident(memcmp)(s1 + size, s2, 1), RightOOBReadMessage(0)); - EXPECT_DEATH(Ident(memcmp)(s1, s2 + size, 1), RightOOBReadMessage(0)); + EXPECT_DEATH(Ident(cmpfn)(s1 - 1, s2, 1), LeftOOBReadMessage(1)); + EXPECT_DEATH(Ident(cmpfn)(s1, s2 - 1, 1), LeftOOBReadMessage(1)); + EXPECT_DEATH(Ident(cmpfn)(s1 + size, s2, 1), RightOOBReadMessage(0)); + EXPECT_DEATH(Ident(cmpfn)(s1, s2 + size, 1), RightOOBReadMessage(0)); // Hit unallocated memory and die. - EXPECT_DEATH(Ident(memcmp)(s1 + 1, s2 + 1, size), RightOOBReadMessage(0)); - EXPECT_DEATH(Ident(memcmp)(s1 + size - 1, s2, 2), RightOOBReadMessage(0)); + EXPECT_DEATH(Ident(cmpfn)(s1 + 1, s2 + 1, size), RightOOBReadMessage(0)); + EXPECT_DEATH(Ident(cmpfn)(s1 + size - 1, s2, 2), RightOOBReadMessage(0)); // Zero bytes are not terminators and don't prevent from OOB. s1[size - 1] = '\0'; s2[size - 1] = '\0'; - EXPECT_DEATH(Ident(memcmp)(s1, s2, size + 1), RightOOBReadMessage(0)); + EXPECT_DEATH(Ident(cmpfn)(s1, s2, size + 1), RightOOBReadMessage(0)); // Even if the buffers differ in the first byte, we still assume that - // memcmp may access the whole buffer and thus reporting the overflow here: + // cmpfn may access the whole buffer and thus reporting the overflow here: s1[0] = 1; s2[0] = 123; - EXPECT_DEATH(Ident(memcmp)(s1, s2, size + 1), RightOOBReadMessage(0)); + EXPECT_DEATH(Ident(cmpfn)(s1, s2, size + 1), RightOOBReadMessage(0)); free(s1); free(s2); } +TEST(AddressSanitizer, MemCmpOOBTest) { CmpOOBTestCommon(); } - +TEST(AddressSanitizer, BCmpOOBTest) { +#if (defined(__linux__) && !defined(__ANDROID__) && defined(_GNU_SOURCE)) || \ + defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + CmpOOBTestCommon(); +#endif +} diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index 34544d511e27..5e0be8bb7d0e 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -819,16 +819,14 @@ INTERCEPTOR(void *, memcpy, void *dst, const void *src, uptr size) { #endif #if SANITIZER_INTERCEPT_MEMCMP - DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, uptr called_pc, const void *s1, const void *s2, uptr n, int result) -INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) { - if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) - return internal_memcmp(a1, a2, size); - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, memcmp, a1, a2, size); +// Common code for `memcmp` and `bcmp`. +int MemcmpInterceptorCommon(void *ctx, + int (*real_fn)(const void *, const void *, uptr), + const void *a1, const void *a2, uptr size) { if (common_flags()->intercept_memcmp) { if (common_flags()->strict_memcmp) { // Check the entire regions even if the first bytes of the buffers are @@ -854,17 +852,39 @@ INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) { return r; } } - int result = REAL(memcmp(a1, a2, size)); + int result = real_fn(a1, a2, size); CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, GET_CALLER_PC(), a1, a2, size, result); return result; } +INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) { + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return internal_memcmp(a1, a2, size); + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, memcmp, a1, a2, size); + return MemcmpInterceptorCommon(ctx, REAL(memcmp), a1, a2, size); +} + #define INIT_MEMCMP COMMON_INTERCEPT_FUNCTION(memcmp) #else #define INIT_MEMCMP #endif +#if SANITIZER_INTERCEPT_BCMP +INTERCEPTOR(int, bcmp, const void *a1, const void *a2, uptr size) { + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return internal_memcmp(a1, a2, size); + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, bcmp, a1, a2, size); + return MemcmpInterceptorCommon(ctx, REAL(bcmp), a1, a2, size); +} + +#define INIT_BCMP COMMON_INTERCEPT_FUNCTION(bcmp) +#else +#define INIT_BCMP +#endif + #if SANITIZER_INTERCEPT_MEMCHR INTERCEPTOR(void*, memchr, const void *s, int c, SIZE_T n) { if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) @@ -9492,6 +9512,7 @@ static void InitializeCommonInterceptors() { INIT_MEMCPY; INIT_MEMCHR; INIT_MEMCMP; + INIT_BCMP; INIT_MEMRCHR; INIT_MEMMEM; INIT_READ; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h index 65a78dfb5465..9c71714fa1bf 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -142,6 +142,9 @@ #define SANITIZER_INTERCEPT_MEMMOVE 1 #define SANITIZER_INTERCEPT_MEMCPY 1 #define SANITIZER_INTERCEPT_MEMCMP SI_NOT_FUCHSIA +#define SANITIZER_INTERCEPT_BCMP \ + SANITIZER_INTERCEPT_MEMCMP && \ + ((SI_POSIX && _GNU_SOURCE) || SI_NETBSD || SI_OPENBSD || SI_FREEBSD) #define SANITIZER_INTERCEPT_STRNDUP SI_POSIX #define SANITIZER_INTERCEPT___STRNDUP SI_LINUX_NOT_FREEBSD #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ diff --git a/compiler-rt/test/asan/TestCases/Posix/bcmp_test.cc b/compiler-rt/test/asan/TestCases/Posix/bcmp_test.cc new file mode 100644 index 000000000000..44aa9cd24f6c --- /dev/null +++ b/compiler-rt/test/asan/TestCases/Posix/bcmp_test.cc @@ -0,0 +1,18 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s + +// REQUIRES: compiler-rt-optimized, (linux && !android) || openbsd || freebsd || netbsd +// XFAIL: darwin + +#include +int main(int argc, char **argv) { + char a1[] = {static_cast(argc), 2, 3, 4}; + char a2[] = {1, static_cast(2 * argc), 3, 4}; + int res = bcmp(a1, a2, 4 + argc); // BOOM + // CHECK: AddressSanitizer: stack-buffer-overflow + // CHECK: {{#1.*bcmp}} + // CHECK: {{#2.*main}} + return res; +} diff --git a/compiler-rt/test/asan/TestCases/memcmp_test.cc b/compiler-rt/test/asan/TestCases/memcmp_test.cc index 0dd9820f52ab..e666b6d162b9 100644 --- a/compiler-rt/test/asan/TestCases/memcmp_test.cc +++ b/compiler-rt/test/asan/TestCases/memcmp_test.cc @@ -11,7 +11,7 @@ int main(int argc, char **argv) { char a2[] = {1, static_cast(2*argc), 3, 4}; int res = memcmp(a1, a2, 4 + argc); // BOOM // CHECK: AddressSanitizer: stack-buffer-overflow - // CHECK: {{#0.*memcmp}} - // CHECK: {{#1.*main}} + // CHECK: {{#1.*memcmp}} + // CHECK: {{#2.*main}} return res; } diff --git a/compiler-rt/test/msan/memcmp_test.cc b/compiler-rt/test/msan/memcmp_test.cc index 5ade58a6004a..42230cc4d0c5 100644 --- a/compiler-rt/test/msan/memcmp_test.cc +++ b/compiler-rt/test/msan/memcmp_test.cc @@ -13,6 +13,6 @@ int main(int argc, char **argv) { if (!res) printf("equals"); return 0; - // CHECK: Uninitialized bytes in __interceptor_memcmp at offset 3 + // CHECK: Uninitialized bytes in MemcmpInterceptorCommon at offset 3 // CHECK: MemorySanitizer: use-of-uninitialized-value } diff --git a/compiler-rt/test/msan/scoped-interceptors.cc b/compiler-rt/test/msan/scoped-interceptors.cc index fc7d4578482b..5eff33d6bf69 100644 --- a/compiler-rt/test/msan/scoped-interceptors.cc +++ b/compiler-rt/test/msan/scoped-interceptors.cc @@ -37,7 +37,7 @@ int main(int argc, char *argv[]) { case '2': { int cmp = memcmp(uninit, uninit, sizeof(uninit)); // BOOM break; - // CASE-2: Uninitialized bytes in __interceptor_memcmp + // CASE-2: Uninitialized bytes in MemcmpInterceptorCommon } case '3': { size_t len = strlen(uninit); // BOOM diff --git a/compiler-rt/test/sanitizer_common/TestCases/Posix/weak_hook_test.cc b/compiler-rt/test/sanitizer_common/TestCases/Posix/weak_hook_test.cc index 9176a524dbe8..ba98f47b35e0 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/Posix/weak_hook_test.cc +++ b/compiler-rt/test/sanitizer_common/TestCases/Posix/weak_hook_test.cc @@ -6,8 +6,11 @@ // XFAIL: lsan // XFAIL: ubsan -#include #include +#include +#if defined(_GNU_SOURCE) +#include // for bcmp +#endif bool seen_memcmp, seen_strncmp, seen_strncasecmp, seen_strcmp, seen_strcasecmp, seen_strstr, seen_strcasestr, seen_memmem; @@ -59,6 +62,12 @@ int main() { int_sink = memcmp(s1, s2, sizeof(s2)); assert(seen_memcmp); +#if (defined(__linux__) && !defined(__ANDROID__) && defined(_GNU_SOURCE)) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + seen_memcmp = false; + int_sink = bcmp(s1, s2, sizeof(s2)); + assert(seen_memcmp); +#endif + int_sink = strncmp(s1, s2, sizeof(s2)); assert(seen_strncmp);