[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:
parent
155dd46e04
commit
bfd2122b20
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ";
|
||||
|
|
|
@ -306,6 +306,7 @@ enum StatType {
|
|||
StatInt_wait4,
|
||||
StatInt_inet_ntop,
|
||||
StatInt_inet_pton,
|
||||
StatInt_getaddrinfo,
|
||||
|
||||
// Dynamic annotations.
|
||||
StatAnnotation,
|
||||
|
|
Loading…
Reference in New Issue