forked from OSchip/llvm-project
[asan] Recommit of r301904: Add strndup/__strndup interceptors
Fix undeclared __interceptor_malloc in esan_interceptors.cc Fix undeclared strnlen on OSX Differential Revision: https://reviews.llvm.org/D31457 llvm-svn: 302781
This commit is contained in:
parent
f4dc59ba8e
commit
0550581070
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -31,6 +31,8 @@ using namespace __esan; // NOLINT
|
|||
// Get the per-platform defines for what is possible to intercept
|
||||
#include "sanitizer_common/sanitizer_platform_interceptors.h"
|
||||
|
||||
DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr)
|
||||
|
||||
// TODO(bruening): tsan disables several interceptors (getpwent, etc.) claiming
|
||||
// that interception is a perf hit: should we do the same?
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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 = internal_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;
|
||||
|
@ -6163,6 +6204,8 @@ static void InitializeCommonInterceptors() {
|
|||
INIT_TEXTDOMAIN;
|
||||
INIT_STRLEN;
|
||||
INIT_STRNLEN;
|
||||
INIT_STRNDUP;
|
||||
INIT___STRNDUP;
|
||||
INIT_STRCMP;
|
||||
INIT_STRNCMP;
|
||||
INIT_STRCASECMP;
|
||||
|
|
|
@ -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.")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
// 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
|
||||
|
||||
// When built as C on Linux, strndup is transformed to __strndup.
|
||||
// RUN: %clangxx_asan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck %s
|
||||
|
||||
// UNSUPPORTED: win32
|
||||
|
||||
#include <string.h>
|
||||
|
||||
char kString[] = "foo";
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char *copy = strndup(kString, 2);
|
||||
int x = copy[2 + argc]; // BOOM
|
||||
// CHECK: AddressSanitizer: heap-buffer-overflow
|
||||
// CHECK: #0 {{.*}}main {{.*}}strndup_oob_test.cc:[[@LINE-2]]
|
||||
// CHECK-LABEL: allocated by thread T{{.*}} here:
|
||||
// CHECK: #{{[01]}} {{.*}}strndup
|
||||
// CHECK: #{{.*}}main {{.*}}strndup_oob_test.cc:[[@LINE-6]]
|
||||
// CHECK-LABEL: SUMMARY
|
||||
// CHECK: strndup_oob_test.cc:[[@LINE-7]]
|
||||
return x;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
// RUN: %clangxx_msan %s -o %t && not %run %t 2>&1 | FileCheck --check-prefix=ON %s
|
||||
// RUN: %clangxx_msan %s -o %t && MSAN_OPTIONS=intercept_strndup=0 %run %t 2>&1 | FileCheck --check-prefix=OFF --allow-empty %s
|
||||
|
||||
// When built as C on Linux, strndup is transformed to __strndup.
|
||||
// RUN: %clangxx_msan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck --check-prefix=ON %s
|
||||
|
||||
// UNSUPPORTED: win32
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sanitizer/msan_interface.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char kString[4] = "abc";
|
||||
__msan_poison(kString + 2, 1);
|
||||
char *copy = strndup(kString, 4); // BOOM
|
||||
assert(__msan_test_shadow(copy, 4) == 2); // Poisoning is preserved.
|
||||
free(copy);
|
||||
return 0;
|
||||
// ON: Uninitialized bytes in __interceptor_{{(__)?}}strndup at offset 2 inside [{{.*}}, 4)
|
||||
// ON: MemorySanitizer: use-of-uninitialized-value
|
||||
// ON: #0 {{.*}}main {{.*}}strndup.cc:[[@LINE-6]]
|
||||
// ON-LABEL: SUMMARY
|
||||
// ON: {{.*}}strndup.cc:[[@LINE-8]]
|
||||
// OFF-NOT: MemorySanitizer
|
||||
}
|
||||
|
Loading…
Reference in New Issue