forked from OSchip/llvm-project
[sanitizers] add interceptor for memmem; add weak hooks for strncasecmp, strcasecmp, strstr, strcasestr, memmem
llvm-svn: 275621
This commit is contained in:
parent
a65e6b8335
commit
ad0724692e
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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.")
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in New Issue