[msan] getaddrinfo & nested interceptor support.

Multiple connected changes:
- Ignore reads from nested interceptors.
- Check shadow on reads from common interceptors.
- getaddrinfo interceptor.

llvm-svn: 182466
This commit is contained in:
Evgeniy Stepanov 2013-05-22 12:50:26 +00:00
parent 155dd46e04
commit bfd2122b20
9 changed files with 157 additions and 27 deletions

View File

@ -0,0 +1,19 @@
// RUN: %clangxx_msan -m64 -O0 %s -o %t && not %t >%t.out 2>&1
// RUN: FileCheck %s < %t.out
// RUN: %clangxx_msan -m64 -O3 %s -o %t && not %t >%t.out 2>&1
// RUN: FileCheck %s < %t.out
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
int main(void) {
struct addrinfo *ai;
struct addrinfo hint;
int res = getaddrinfo("localhost", NULL, &hint, &ai);
// CHECK: UMR in __interceptor_getaddrinfo at offset 0 inside
// CHECK: WARNING: Use of uninitialized value
// CHECK: #0 {{.*}} in main {{.*}}getaddrinfo-positive.cc:[[@LINE-3]]
return 0;
}

View File

@ -0,0 +1,24 @@
// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
void poison_stack_ahead() {
char buf[100000];
// With -O0 this poisons a large chunk of stack.
}
int main(void) {
poison_stack_ahead();
struct addrinfo *ai;
// This should trigger loading of libnss_dns and friends.
// Those libraries are typically uninstrumented.They will call strlen() on a
// stack-allocated buffer, which is very likely to be poisoned. Test that we
// don't report this as an UMR.
int res = getaddrinfo("not-in-etc-hosts", NULL, NULL, &ai);
return 0;
}

View File

@ -32,6 +32,18 @@ extern "C" const int __msan_keep_going;
using namespace __msan;
// True if this is a nested interceptor.
static THREADLOCAL int in_interceptor_scope;
struct InterceptorScope {
InterceptorScope() { ++in_interceptor_scope; }
~InterceptorScope() { --in_interceptor_scope; }
};
bool IsInInterceptorScope() {
return in_interceptor_scope;
}
#define ENSURE_MSAN_INITED() do { \
CHECK(!msan_init_is_running); \
if (!msan_inited) { \
@ -39,24 +51,30 @@ using namespace __msan;
} \
} while (0)
#define CHECK_UNPOISONED(x, n) \
do { \
sptr offset = __msan_test_shadow(x, n); \
if (__msan::IsInSymbolizer()) break; \
if (offset >= 0 && __msan::flags()->report_umrs) { \
GET_CALLER_PC_BP_SP; \
(void)sp; \
Printf("UMR in %s at offset %d inside [%p, +%d) \n", \
__FUNCTION__, offset, x, n); \
__msan::PrintWarningWithOrigin( \
pc, bp, __msan_get_origin((char*)x + offset)); \
if (!__msan_keep_going) { \
Printf("Exiting\n"); \
Die(); \
} \
} \
// Check that [x, x+n) range is unpoisoned.
#define CHECK_UNPOISONED_0(x, n) \
do { \
sptr offset = __msan_test_shadow(x, n); \
if (__msan::IsInSymbolizer()) break; \
if (offset >= 0 && __msan::flags()->report_umrs) { \
GET_CALLER_PC_BP_SP; \
(void) sp; \
Printf("UMR in %s at offset %d inside [%p, +%d) \n", __FUNCTION__, \
offset, x, n); \
__msan::PrintWarningWithOrigin(pc, bp, \
__msan_get_origin((char *) x + offset)); \
if (!__msan_keep_going) { \
Printf("Exiting\n"); \
Die(); \
} \
} \
} while (0)
// Check that [x, x+n) range is unpoisoned unless we are in a nested
// interceptor.
#define CHECK_UNPOISONED(x, n) \
if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n);
static void *fast_memset(void *ptr, int c, SIZE_T n);
static void *fast_memcpy(void *dst, const void *src, SIZE_T n);
@ -953,18 +971,28 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
return res;
}
struct MSanInterceptorContext {
bool in_interceptor_scope;
};
// A version of CHECK_UNPOISED using a saved scope value. Used in common interceptors.
#define CHECK_UNPOISONED_CTX(ctx, x, n) \
if (!((MSanInterceptorContext *) ctx)->in_interceptor_scope) \
CHECK_UNPOISONED_0(x, n);
#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
__msan_unpoison(ptr, size)
#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) do { } while (false)
#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
do { \
if (msan_init_is_running) \
return REAL(func)(__VA_ARGS__); \
ctx = 0; \
(void)ctx; \
ENSURE_MSAN_INITED(); \
__msan_unpoison(ptr, size)
#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
CHECK_UNPOISONED_CTX(ctx, ptr, size);
#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
if (msan_init_is_running) return REAL(func)(__VA_ARGS__); \
MSanInterceptorContext msan_ctx = { IsInInterceptorScope() }; \
ctx = (void *)&msan_ctx; \
InterceptorScope interceptor_scope; \
ENSURE_MSAN_INITED();
#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
do { \
} while (false)
#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) do { } while (false)
#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) do { } while (false)
#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \
do { } while (false) // FIXME

View File

@ -748,6 +748,38 @@ INTERCEPTOR(int, pthread_getschedparam, uptr thread, int *policy, int *param) {
#define INIT_PTHREAD_GETSCHEDPARAM
#endif
#if SANITIZER_INTERCEPT_GETADDRINFO
INTERCEPTOR(int, getaddrinfo, char *node, char *service,
struct __sanitizer_addrinfo *hints,
struct __sanitizer_addrinfo **out) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getaddrinfo, node, service, hints, out);
if (node) COMMON_INTERCEPTOR_READ_RANGE(ctx, node, REAL(strlen)(node) + 1);
if (service)
COMMON_INTERCEPTOR_READ_RANGE(ctx, service, REAL(strlen)(service) + 1);
if (hints)
COMMON_INTERCEPTOR_READ_RANGE(ctx, hints, sizeof(__sanitizer_addrinfo));
int res = REAL(getaddrinfo)(node, service, hints, out);
if (res == 0) {
struct __sanitizer_addrinfo *p = *out;
while (p) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(__sanitizer_addrinfo));
if (p->ai_addr)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ai_addr, struct_sockaddr_sz);
if (p->ai_canonname)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->ai_canonname,
REAL(strlen)(p->ai_canonname) + 1);
p = p->ai_next;
}
}
return res;
}
#define INIT_GETADDRINFO INTERCEPT_FUNCTION(getaddrinfo);
#else
#define INIT_GETADDRINFO
#endif
#define SANITIZER_COMMON_INTERCEPTORS_INIT \
INIT_STRCASECMP; \
INIT_STRNCASECMP; \
@ -770,4 +802,5 @@ INTERCEPTOR(int, pthread_getschedparam, uptr thread, int *policy, int *param) {
INIT_GLOB; \
INIT_WAIT; \
INIT_INET; \
INIT_PTHREAD_GETSCHEDPARAM;
INIT_PTHREAD_GETSCHEDPARAM; \
INIT_GETADDRINFO;

View File

@ -70,5 +70,6 @@
# define SANITIZER_INTERCEPT_WAIT SI_NOT_WINDOWS
# define SANITIZER_INTERCEPT_INET SI_NOT_WINDOWS
# define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM SI_NOT_WINDOWS
# define SANITIZER_INTERCEPT_GETADDRINFO SI_NOT_WINDOWS
#endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H

View File

@ -29,9 +29,11 @@
#include <sys/utsname.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <netdb.h>
#include <time.h>
#if !SANITIZER_ANDROID
@ -56,6 +58,7 @@ namespace __sanitizer {
unsigned struct_sigaction_sz = sizeof(struct sigaction);
unsigned struct_itimerval_sz = sizeof(struct itimerval);
unsigned pthread_t_sz = sizeof(pthread_t);
unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
#if !SANITIZER_ANDROID
unsigned ucontext_t_sz = sizeof(ucontext_t);
@ -133,4 +136,12 @@ COMPILER_CHECK(offsetof(struct __sanitizer_dl_phdr_info, dlpi_phnum) ==
offsetof(struct dl_phdr_info, dlpi_phnum));
#endif
COMPILER_CHECK(sizeof(struct __sanitizer_addrinfo) == sizeof(struct addrinfo));
COMPILER_CHECK(offsetof(struct __sanitizer_addrinfo, ai_addr) ==
offsetof(struct addrinfo, ai_addr));
COMPILER_CHECK(offsetof(struct __sanitizer_addrinfo, ai_canonname) ==
offsetof(struct addrinfo, ai_canonname));
COMPILER_CHECK(offsetof(struct __sanitizer_addrinfo, ai_next) ==
offsetof(struct addrinfo, ai_next));
#endif // SANITIZER_LINUX || SANITIZER_MAC

View File

@ -29,6 +29,7 @@ namespace __sanitizer {
extern unsigned siginfo_t_sz;
extern unsigned struct_itimerval_sz;
extern unsigned pthread_t_sz;
extern unsigned struct_sockaddr_sz;
#if !SANITIZER_ANDROID
extern unsigned ucontext_t_sz;
@ -83,6 +84,17 @@ namespace __sanitizer {
short dlpi_phnum;
};
#endif
struct __sanitizer_addrinfo {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
uptr ai_addrlen;
void *ai_addr;
char *ai_canonname;
struct __sanitizer_addrinfo *ai_next;
};
} // namespace __sanitizer
#endif

View File

@ -311,6 +311,7 @@ void StatOutput(u64 *stat) {
name[StatInt_wait4] = " wait4 ";
name[StatInt_inet_ntop] = " inet_ntop ";
name[StatInt_inet_pton] = " inet_pton ";
name[StatInt_getaddrinfo] = " getaddrinfo ";
name[StatAnnotation] = "Dynamic annotations ";
name[StatAnnotateHappensBefore] = " HappensBefore ";

View File

@ -306,6 +306,7 @@ enum StatType {
StatInt_wait4,
StatInt_inet_ntop,
StatInt_inet_pton,
StatInt_getaddrinfo,
// Dynamic annotations.
StatAnnotation,