[sanitizers] add interceptor for memmem; add weak hooks for strncasecmp, strcasecmp, strstr, strcasestr, memmem

llvm-svn: 275621
This commit is contained in:
Kostya Serebryany 2016-07-15 21:28:58 +00:00
parent a65e6b8335
commit ad0724692e
6 changed files with 169 additions and 2 deletions

View File

@ -131,8 +131,19 @@ extern "C" {
const void *s2, size_t n, int result); const void *s2, size_t n, int result);
void __sanitizer_weak_hook_strncmp(void *called_pc, const char *s1, void __sanitizer_weak_hook_strncmp(void *called_pc, const char *s1,
const char *s2, size_t n, int result); 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, void __sanitizer_weak_hook_strcmp(void *called_pc, const char *s1,
const char *s2, int result); 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 // Prints stack traces for all live heap allocations ordered by total
// allocation size until `top_percent` of total live heap is shown. // allocation size until `top_percent` of total live heap is shown.

View File

@ -326,6 +326,9 @@ static inline int CharCaseCmp(unsigned char c1, unsigned char c2) {
return c1_low - c2_low; 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) { INTERCEPTOR(int, strcasecmp, const char *s1, const char *s2) {
void *ctx; void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, strcasecmp, s1, s2); 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, s1, i + 1);
COMMON_INTERCEPTOR_READ_STRING(ctx, s2, 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) { INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, SIZE_T n) {
void *ctx; void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, strncasecmp, s1, s2, n); 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, s1, Min(i + 1, n));
COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, 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) #define INIT_STRCASECMP COMMON_INTERCEPT_FUNCTION(strcasecmp)
@ -375,6 +388,10 @@ static inline void StrstrCheck(void *ctx, char *r, const char *s1,
#endif #endif
#if SANITIZER_INTERCEPT_STRSTR #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) { INTERCEPTOR(char*, strstr, const char *s1, const char *s2) {
if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
return internal_strstr(s1, s2); return internal_strstr(s1, s2);
@ -383,6 +400,8 @@ INTERCEPTOR(char*, strstr, const char *s1, const char *s2) {
char *r = REAL(strstr)(s1, s2); char *r = REAL(strstr)(s1, s2);
if (common_flags()->intercept_strstr) if (common_flags()->intercept_strstr)
StrstrCheck(ctx, r, s1, s2); StrstrCheck(ctx, r, s1, s2);
CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strstr, GET_CALLER_PC(), s1,
s2, r);
return r; return r;
} }
@ -392,12 +411,18 @@ INTERCEPTOR(char*, strstr, const char *s1, const char *s2) {
#endif #endif
#if SANITIZER_INTERCEPT_STRCASESTR #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) { INTERCEPTOR(char*, strcasestr, const char *s1, const char *s2) {
void *ctx; void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, strcasestr, s1, s2); COMMON_INTERCEPTOR_ENTER(ctx, strcasestr, s1, s2);
char *r = REAL(strcasestr)(s1, s2); char *r = REAL(strcasestr)(s1, s2);
if (common_flags()->intercept_strstr) if (common_flags()->intercept_strstr)
StrstrCheck(ctx, r, s1, s2); StrstrCheck(ctx, r, s1, s2);
CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcasestr, GET_CALLER_PC(),
s1, s2, r);
return r; return r;
} }
@ -406,6 +431,30 @@ INTERCEPTOR(char*, strcasestr, const char *s1, const char *s2) {
#define INIT_STRCASESTR #define INIT_STRCASESTR
#endif #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 #if SANITIZER_INTERCEPT_STRCHR
INTERCEPTOR(char*, strchr, const char *s, int c) { INTERCEPTOR(char*, strchr, const char *s, int c) {
void *ctx; void *ctx;
@ -5830,6 +5879,7 @@ static void InitializeCommonInterceptors() {
INIT_MEMCHR; INIT_MEMCHR;
INIT_MEMCMP; INIT_MEMCMP;
INIT_MEMRCHR; INIT_MEMRCHR;
INIT_MEMMEM;
INIT_READ; INIT_READ;
INIT_PREAD; INIT_PREAD;
INIT_PREAD64; INIT_PREAD64;

View File

@ -199,6 +199,8 @@ COMMON_FLAG(bool, intercept_memcmp, true,
COMMON_FLAG(bool, strict_memcmp, true, COMMON_FLAG(bool, strict_memcmp, true,
"If true, assume that memcmp(p1, p2, n) always reads n bytes before " "If true, assume that memcmp(p1, p2, n) always reads n bytes before "
"comparing p1 and p2.") "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, COMMON_FLAG(bool, intercept_intrin, true,
"If set, uses custom wrappers for memset/memcpy/memmove " "If set, uses custom wrappers for memset/memcpy/memmove "
"intrinsics to find more errors.") "intrinsics to find more errors.")

View File

@ -83,6 +83,7 @@
#define SANITIZER_INTERCEPT_MEMMOVE 1 #define SANITIZER_INTERCEPT_MEMMOVE 1
#define SANITIZER_INTERCEPT_MEMCPY 1 #define SANITIZER_INTERCEPT_MEMCPY 1
#define SANITIZER_INTERCEPT_MEMCMP 1 #define SANITIZER_INTERCEPT_MEMCMP 1
#define SANITIZER_INTERCEPT_MEMMEM 1
// The function memchr() contains a jump in the first 6 bytes // The function memchr() contains a jump in the first 6 bytes
// that is problematic to intercept correctly on Win64. // that is problematic to intercept correctly on Win64.
// Disable memchr() interception for Win64. // Disable memchr() interception for Win64.

View File

@ -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;
}

View File

@ -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;
}