From 25469d9bd4174709ad3c4b85dadfa7892ebf3171 Mon Sep 17 00:00:00 2001 From: Pierre Gousseau Date: Tue, 2 May 2017 09:01:02 +0000 Subject: [asan] Add strndup/__strndup interceptors if targeting linux. Differential Revision: https://reviews.llvm.org/D31457 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@301904 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_flags.cc | 4 ++ lib/asan/tests/asan_str_test.cc | 21 +++++++++++ lib/msan/msan_interceptors.cc | 36 ++++-------------- lib/msan/tests/msan_test.cc | 6 ++- .../sanitizer_common_interceptors.inc | 43 ++++++++++++++++++++++ lib/sanitizer_common/sanitizer_flags.inc | 3 ++ .../sanitizer_platform_interceptors.h | 14 +++++++ lib/sanitizer_common/tests/sanitizer_test_utils.h | 6 +++ 8 files changed, 102 insertions(+), 31 deletions(-) (limited to 'lib') diff --git a/lib/asan/asan_flags.cc b/lib/asan/asan_flags.cc index c8ae3faed..6be0d6e94 100644 --- a/lib/asan/asan_flags.cc +++ b/lib/asan/asan_flags.cc @@ -194,6 +194,10 @@ void InitializeFlags() { Report("WARNING: strchr* interceptors are enabled even though " "replace_str=0. Use intercept_strchr=0 to disable them."); } + if (!f->replace_str && common_flags()->intercept_strndup) { + Report("WARNING: strndup* interceptors are enabled even though " + "replace_str=0. Use intercept_strndup=0 to disable them."); + } } } // namespace __asan diff --git a/lib/asan/tests/asan_str_test.cc b/lib/asan/tests/asan_str_test.cc index c790088f8..8f4911fd9 100644 --- a/lib/asan/tests/asan_str_test.cc +++ b/lib/asan/tests/asan_str_test.cc @@ -154,6 +154,27 @@ TEST(AddressSanitizer, MAYBE_StrDupOOBTest) { free(str); } +#if SANITIZER_TEST_HAS_STRNDUP +TEST(AddressSanitizer, MAYBE_StrNDupOOBTest) { + size_t size = Ident(42); + char *str = MallocAndMemsetString(size); + char *new_str; + // Normal strndup calls. + str[size - 1] = '\0'; + new_str = strndup(str, size - 13); + free(new_str); + new_str = strndup(str + size - 1, 13); + free(new_str); + // Argument points to not allocated memory. + EXPECT_DEATH(Ident(strndup(str - 1, 13)), LeftOOBReadMessage(1)); + EXPECT_DEATH(Ident(strndup(str + size, 13)), RightOOBReadMessage(0)); + // Overwrite the terminating '\0' and hit unallocated memory. + str[size - 1] = 'z'; + EXPECT_DEATH(Ident(strndup(str, size + 13)), RightOOBReadMessage(0)); + free(str); +} +#endif // SANITIZER_TEST_HAS_STRNDUP + TEST(AddressSanitizer, StrCpyOOBTest) { size_t to_size = Ident(30); size_t from_size = Ident(6); // less than to_size diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc index 15543bd91..0f5069344 100644 --- a/lib/msan/msan_interceptors.cc +++ b/lib/msan/msan_interceptors.cc @@ -341,33 +341,6 @@ INTERCEPTOR(char *, __strdup, char *src) { #define MSAN_MAYBE_INTERCEPT___STRDUP #endif -INTERCEPTOR(char *, strndup, char *src, SIZE_T n) { - ENSURE_MSAN_INITED(); - GET_STORE_STACK_TRACE; - // On FreeBSD strndup() leverages strnlen(). - InterceptorScope interceptor_scope; - SIZE_T copy_size = REAL(strnlen)(src, n); - char *res = REAL(strndup)(src, n); - CopyShadowAndOrigin(res, src, copy_size, &stack); - __msan_unpoison(res + copy_size, 1); // \0 - return res; -} - -#if !SANITIZER_FREEBSD -INTERCEPTOR(char *, __strndup, char *src, SIZE_T n) { - ENSURE_MSAN_INITED(); - GET_STORE_STACK_TRACE; - SIZE_T copy_size = REAL(strnlen)(src, n); - char *res = REAL(__strndup)(src, n); - CopyShadowAndOrigin(res, src, copy_size, &stack); - __msan_unpoison(res + copy_size, 1); // \0 - return res; -} -#define MSAN_MAYBE_INTERCEPT___STRNDUP INTERCEPT_FUNCTION(__strndup) -#else -#define MSAN_MAYBE_INTERCEPT___STRNDUP -#endif - INTERCEPTOR(char *, gcvt, double number, SIZE_T ndigit, char *buf) { ENSURE_MSAN_INITED(); char *res = REAL(gcvt)(number, ndigit, buf); @@ -1371,6 +1344,13 @@ int OnExit() { return __msan_memcpy(to, from, size); \ } +#define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) \ + do { \ + GET_STORE_STACK_TRACE; \ + CopyShadowAndOrigin(to, from, size, &stack); \ + __msan_unpoison(to + size, 1); \ + } while (false) + #include "sanitizer_common/sanitizer_platform_interceptors.h" #include "sanitizer_common/sanitizer_common_interceptors.inc" @@ -1538,8 +1518,6 @@ void InitializeInterceptors() { INTERCEPT_FUNCTION(stpcpy); // NOLINT INTERCEPT_FUNCTION(strdup); MSAN_MAYBE_INTERCEPT___STRDUP; - INTERCEPT_FUNCTION(strndup); - MSAN_MAYBE_INTERCEPT___STRNDUP; INTERCEPT_FUNCTION(strncpy); // NOLINT INTERCEPT_FUNCTION(gcvt); INTERCEPT_FUNCTION(strcat); // NOLINT diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc index dd81c4d79..432d92c2e 100644 --- a/lib/msan/tests/msan_test.cc +++ b/lib/msan/tests/msan_test.cc @@ -1581,7 +1581,8 @@ TEST(MemorySanitizer, strdup) { TEST(MemorySanitizer, strndup) { char buf[4] = "abc"; __msan_poison(buf + 2, sizeof(*buf)); - char *x = strndup(buf, 3); + char *x; + EXPECT_UMR(x = strndup(buf, 3)); EXPECT_NOT_POISONED(x[0]); EXPECT_NOT_POISONED(x[1]); EXPECT_POISONED(x[2]); @@ -1593,7 +1594,8 @@ TEST(MemorySanitizer, strndup_short) { char buf[4] = "abc"; __msan_poison(buf + 1, sizeof(*buf)); __msan_poison(buf + 2, sizeof(*buf)); - char *x = strndup(buf, 2); + char *x; + EXPECT_UMR(x = strndup(buf, 2)); EXPECT_NOT_POISONED(x[0]); EXPECT_POISONED(x[1]); EXPECT_NOT_POISONED(x[2]); diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 4fe1ac8f9..04a38b9b2 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -34,6 +34,8 @@ // COMMON_INTERCEPTOR_MEMSET_IMPL // COMMON_INTERCEPTOR_MEMMOVE_IMPL // COMMON_INTERCEPTOR_MEMCPY_IMPL +// COMMON_INTERCEPTOR_COPY_STRING +// COMMON_INTERCEPTOR_STRNDUP_IMPL //===----------------------------------------------------------------------===// #include "interception/interception.h" @@ -217,6 +219,25 @@ bool PlatformHasDifferentMemcpyAndMemmove(); } #endif +#ifndef COMMON_INTERCEPTOR_COPY_STRING +#define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) {} +#endif + +#ifndef COMMON_INTERCEPTOR_STRNDUP_IMPL +#define COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size) \ + COMMON_INTERCEPTOR_ENTER(ctx, strndup, s, size); \ + uptr from_length = REAL(strnlen)(s, size); \ + uptr copy_length = Min(size, from_length); \ + char *new_mem = (char *)WRAP(malloc)(copy_length + 1); \ + if (common_flags()->intercept_strndup) { \ + COMMON_INTERCEPTOR_READ_RANGE(ctx, s, copy_length + 1); \ + } \ + COMMON_INTERCEPTOR_COPY_STRING(ctx, new_mem, s, copy_length); \ + internal_memcpy(new_mem, s, copy_length); \ + new_mem[copy_length] = '\0'; \ + return new_mem; +#endif + struct FileMetadata { // For open_memstream(). char **addr; @@ -300,6 +321,26 @@ INTERCEPTOR(SIZE_T, strnlen, const char *s, SIZE_T maxlen) { #define INIT_STRNLEN #endif +#if SANITIZER_INTERCEPT_STRNDUP +INTERCEPTOR(char*, strndup, const char *s, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size); +} +#define INIT_STRNDUP COMMON_INTERCEPT_FUNCTION(strndup) +#else +#define INIT_STRNDUP +#endif // SANITIZER_INTERCEPT_STRNDUP + +#if SANITIZER_INTERCEPT___STRNDUP +INTERCEPTOR(char*, __strndup, const char *s, uptr size) { + void *ctx; + COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size); +} +#define INIT___STRNDUP COMMON_INTERCEPT_FUNCTION(__strndup) +#else +#define INIT___STRNDUP +#endif // SANITIZER_INTERCEPT___STRNDUP + #if SANITIZER_INTERCEPT_TEXTDOMAIN INTERCEPTOR(char*, textdomain, const char *domainname) { void *ctx; @@ -6149,6 +6190,8 @@ static void InitializeCommonInterceptors() { INIT_TEXTDOMAIN; INIT_STRLEN; INIT_STRNLEN; + INIT_STRNDUP; + INIT___STRNDUP; INIT_STRCMP; INIT_STRNCMP; INIT_STRCASECMP; diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index 7a5fffcf6..67a0a5810 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -195,6 +195,9 @@ COMMON_FLAG(bool, intercept_strpbrk, true, COMMON_FLAG(bool, intercept_strlen, true, "If set, uses custom wrappers for strlen and strnlen functions " "to find more errors.") +COMMON_FLAG(bool, intercept_strndup, true, + "If set, uses custom wrappers for strndup functions " + "to find more errors.") COMMON_FLAG(bool, intercept_strchr, true, "If set, uses custom wrappers for strchr, strchrnul, and strrchr " "functions to find more errors.") diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index a583e989c..5083ffc1e 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -25,6 +25,12 @@ # define SI_NOT_WINDOWS 0 #endif +#if SANITIZER_POSIX +# define SI_POSIX 1 +#else +# define SI_POSIX 0 +#endif + #if SANITIZER_LINUX && !SANITIZER_ANDROID # define SI_LINUX_NOT_ANDROID 1 #else @@ -69,6 +75,12 @@ # define SI_UNIX_NOT_MAC 0 #endif +#if SANITIZER_LINUX && !SANITIZER_FREEBSD +# define SI_LINUX_NOT_FREEBSD 1 +# else +# define SI_LINUX_NOT_FREEBSD 0 +#endif + #define SANITIZER_INTERCEPT_STRLEN 1 #define SANITIZER_INTERCEPT_STRNLEN SI_NOT_MAC #define SANITIZER_INTERCEPT_STRCMP 1 @@ -86,6 +98,8 @@ #define SANITIZER_INTERCEPT_MEMMOVE 1 #define SANITIZER_INTERCEPT_MEMCPY 1 #define SANITIZER_INTERCEPT_MEMCMP 1 +#define SANITIZER_INTERCEPT_STRNDUP SI_POSIX +#define SANITIZER_INTERCEPT___STRNDUP SI_LINUX_NOT_FREEBSD #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 # define SI_MAC_DEPLOYMENT_BELOW_10_7 1 diff --git a/lib/sanitizer_common/tests/sanitizer_test_utils.h b/lib/sanitizer_common/tests/sanitizer_test_utils.h index 9c162a66f..b7728d9ea 100644 --- a/lib/sanitizer_common/tests/sanitizer_test_utils.h +++ b/lib/sanitizer_common/tests/sanitizer_test_utils.h @@ -124,4 +124,10 @@ static inline uint32_t my_rand() { # define SANITIZER_TEST_HAS_PRINTF_L 0 #endif +#if !defined(_MSC_VER) +# define SANITIZER_TEST_HAS_STRNDUP 1 +#else +# define SANITIZER_TEST_HAS_STRNDUP 0 +#endif + #endif // SANITIZER_TEST_UTILS_H -- cgit v1.2.3