diff options
-rw-r--r-- | lib/sanitizer_common/sanitizer_common_interceptors.inc | 138 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_platform_interceptors.h | 1 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_platform_limits_posix.cc | 15 | ||||
-rw-r--r-- | lib/sanitizer_common/sanitizer_platform_limits_posix.h | 17 | ||||
-rw-r--r-- | test/msan/Linux/sunrpc.cc | 40 | ||||
-rw-r--r-- | test/msan/Linux/sunrpc_bytes.cc | 38 | ||||
-rw-r--r-- | test/msan/Linux/sunrpc_string.cc | 35 |
7 files changed, 283 insertions, 1 deletions
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index 84c75abaa..0d076a021 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -3707,6 +3707,141 @@ INTERCEPTOR(int, ftime, __sanitizer_timeb *tp) { #define INIT_FTIME #endif // SANITIZER_INTERCEPT_FTIME +#if SANITIZER_INTERCEPT_XDR +INTERCEPTOR(void, xdrmem_create, __sanitizer_XDR *xdrs, uptr addr, + unsigned size, int op) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, xdrmem_create, xdrs, addr, size, op); + REAL(xdrmem_create)(xdrs, addr, size, op); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdrs, sizeof(*xdrs)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdrs->x_ops, sizeof(*xdrs->x_ops)); + if (op == __sanitizer_XDR_ENCODE) { + // It's not obvious how much data individual xdr_ routines write. + // Simply unpoison the entire target buffer in advance. + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (void *)addr, size); + } +} + +INTERCEPTOR(void, xdrstdio_create, __sanitizer_XDR *xdrs, void *file, int op) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, xdrstdio_create, xdrs, file, op); + REAL(xdrstdio_create)(xdrs, file, op); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdrs, sizeof(*xdrs)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdrs->x_ops, sizeof(*xdrs->x_ops)); +} + +#define XDR_INTERCEPTOR(F, T) \ + INTERCEPTOR(int, F, __sanitizer_XDR *xdrs, T *p) { \ + void *ctx; \ + COMMON_INTERCEPTOR_ENTER(ctx, F, xdrs, p); \ + if (p && xdrs->x_op == __sanitizer_XDR_ENCODE) \ + COMMON_INTERCEPTOR_READ_RANGE(ctx, p, sizeof(*p)); \ + int res = REAL(F)(xdrs, p); \ + if (res && p && xdrs->x_op == __sanitizer_XDR_DECODE) \ + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); \ + return res; \ + } + +XDR_INTERCEPTOR(xdr_short, short) +XDR_INTERCEPTOR(xdr_u_short, unsigned short) +XDR_INTERCEPTOR(xdr_int, int) +XDR_INTERCEPTOR(xdr_u_int, unsigned) +XDR_INTERCEPTOR(xdr_long, long) +XDR_INTERCEPTOR(xdr_u_long, unsigned long) +XDR_INTERCEPTOR(xdr_hyper, long long) +XDR_INTERCEPTOR(xdr_u_hyper, unsigned long long) +XDR_INTERCEPTOR(xdr_longlong_t, long long) +XDR_INTERCEPTOR(xdr_u_longlong_t, unsigned long long) +XDR_INTERCEPTOR(xdr_int8_t, u8) +XDR_INTERCEPTOR(xdr_uint8_t, u8) +XDR_INTERCEPTOR(xdr_int16_t, u16) +XDR_INTERCEPTOR(xdr_uint16_t, u16) +XDR_INTERCEPTOR(xdr_int32_t, u32) +XDR_INTERCEPTOR(xdr_uint32_t, u32) +XDR_INTERCEPTOR(xdr_int64_t, u64) +XDR_INTERCEPTOR(xdr_uint64_t, u64) +XDR_INTERCEPTOR(xdr_quad_t, long long) +XDR_INTERCEPTOR(xdr_u_quad_t, unsigned long long) +XDR_INTERCEPTOR(xdr_bool, bool) +XDR_INTERCEPTOR(xdr_enum, int) +XDR_INTERCEPTOR(xdr_char, char) +XDR_INTERCEPTOR(xdr_u_char, unsigned char) +XDR_INTERCEPTOR(xdr_float, float) +XDR_INTERCEPTOR(xdr_double, double) + +// FIXME: intercept xdr_array, opaque, union, vector, reference, pointer, +// wrapstring, sizeof + +INTERCEPTOR(int, xdr_bytes, __sanitizer_XDR *xdrs, char **p, unsigned *sizep, + unsigned maxsize) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, xdr_bytes, xdrs, p, sizep, maxsize); + if (p && sizep && xdrs->x_op == __sanitizer_XDR_ENCODE) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, p, sizeof(*p)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, sizep, sizeof(*sizep)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, *p, *sizep); + } + int res = REAL(xdr_bytes)(xdrs, p, sizep, maxsize); + if (p && sizep && xdrs->x_op == __sanitizer_XDR_DECODE) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sizep, sizeof(*sizep)); + if (res && *p && *sizep) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, *sizep); + } + return res; +} + +INTERCEPTOR(int, xdr_string, __sanitizer_XDR *xdrs, char **p, + unsigned maxsize) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, xdr_string, xdrs, p, maxsize); + if (p && xdrs->x_op == __sanitizer_XDR_ENCODE) { + COMMON_INTERCEPTOR_READ_RANGE(ctx, p, sizeof(*p)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, *p, REAL(strlen)(*p) + 1); + } + int res = REAL(xdr_string)(xdrs, p, maxsize); + if (p && xdrs->x_op == __sanitizer_XDR_DECODE) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); + if (res && *p) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *p, REAL(strlen)(*p) + 1); + } + return res; +} + +#define INIT_XDR \ + COMMON_INTERCEPT_FUNCTION(xdrmem_create); \ + COMMON_INTERCEPT_FUNCTION(xdrstdio_create); \ + COMMON_INTERCEPT_FUNCTION(xdr_short); \ + COMMON_INTERCEPT_FUNCTION(xdr_u_short); \ + COMMON_INTERCEPT_FUNCTION(xdr_int); \ + COMMON_INTERCEPT_FUNCTION(xdr_u_int); \ + COMMON_INTERCEPT_FUNCTION(xdr_long); \ + COMMON_INTERCEPT_FUNCTION(xdr_u_long); \ + COMMON_INTERCEPT_FUNCTION(xdr_hyper); \ + COMMON_INTERCEPT_FUNCTION(xdr_u_hyper); \ + COMMON_INTERCEPT_FUNCTION(xdr_longlong_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_u_longlong_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_int8_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_uint8_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_int16_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_uint16_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_int32_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_uint32_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_int64_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_uint64_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_quad_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_u_quad_t); \ + COMMON_INTERCEPT_FUNCTION(xdr_bool); \ + COMMON_INTERCEPT_FUNCTION(xdr_enum); \ + COMMON_INTERCEPT_FUNCTION(xdr_char); \ + COMMON_INTERCEPT_FUNCTION(xdr_u_char); \ + COMMON_INTERCEPT_FUNCTION(xdr_float); \ + COMMON_INTERCEPT_FUNCTION(xdr_double); \ + COMMON_INTERCEPT_FUNCTION(xdr_bytes); \ + COMMON_INTERCEPT_FUNCTION(xdr_string); +#else +#define INIT_XDR +#endif // SANITIZER_INTERCEPT_XDR + #define SANITIZER_COMMON_INTERCEPTORS_INIT \ INIT_TEXTDOMAIN; \ INIT_STRCMP; \ @@ -3836,5 +3971,6 @@ INTERCEPTOR(int, ftime, __sanitizer_timeb *tp) { INIT_CAPGET; \ INIT_AEABI_MEM; \ INIT___BZERO; \ - INIT_FTIME; + INIT_FTIME; \ + INIT_XDR; /**/ diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index 39ae2e6f5..2ea6ddd98 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -195,5 +195,6 @@ #define SANITIZER_INTERCEPT_AEABI_MEM SI_LINUX && defined(__arm__) #define SANITIZER_INTERCEPT___BZERO SI_MAC #define SANITIZER_INTERCEPT_FTIME SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc index 961aeb8ab..9ae4870c1 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc +++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc @@ -120,6 +120,7 @@ #include <netax25/ax25.h> #include <netipx/ipx.h> #include <netrom/netrom.h> +#include <rpc/xdr.h> #include <scsi/scsi.h> #include <sys/mtio.h> #include <sys/kd.h> @@ -1111,4 +1112,18 @@ CHECK_SIZE_AND_OFFSET(group, gr_passwd); CHECK_SIZE_AND_OFFSET(group, gr_gid); CHECK_SIZE_AND_OFFSET(group, gr_mem); +#if SANITIZER_LINUX && !SANITIZER_ANDROID +CHECK_TYPE_SIZE(XDR); +CHECK_SIZE_AND_OFFSET(XDR, x_op); +CHECK_SIZE_AND_OFFSET(XDR, x_ops); +CHECK_SIZE_AND_OFFSET(XDR, x_public); +CHECK_SIZE_AND_OFFSET(XDR, x_private); +CHECK_SIZE_AND_OFFSET(XDR, x_base); +CHECK_SIZE_AND_OFFSET(XDR, x_handy); +CHECK_TYPE_SIZE(XDR::xdr_ops); +COMPILER_CHECK(__sanitizer_XDR_ENCODE == XDR_ENCODE); +COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE); +COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE); +#endif + #endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h index b1fb0ae12..a780ee282 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -274,6 +274,23 @@ namespace __sanitizer { typedef unsigned __sanitizer_pthread_key_t; #endif +#if SANITIZER_LINUX && !SANITIZER_ANDROID + struct __sanitizer_XDR { + int x_op; + struct xdr_ops { + uptr fns[10]; + } *x_ops; + uptr x_public; + uptr x_private; + uptr x_base; + unsigned x_handy; + }; + + const int __sanitizer_XDR_ENCODE = 0; + const int __sanitizer_XDR_DECODE = 1; + const int __sanitizer_XDR_FREE = 2; +#endif + struct __sanitizer_passwd { char *pw_name; char *pw_passwd; diff --git a/test/msan/Linux/sunrpc.cc b/test/msan/Linux/sunrpc.cc new file mode 100644 index 000000000..3d2bb3994 --- /dev/null +++ b/test/msan/Linux/sunrpc.cc @@ -0,0 +1,40 @@ +// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=int -DFN=xdr_int %s -o %t && \ +// RUN: %t 2>&1 +// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=int -DFN=xdr_int -DUNINIT=1 %s -o %t && \ +// RUN: not %t 2>&1 | FileCheck %s +// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=double -DFN=xdr_double %s -o %t && \ +// RUN: %t 2>&1 +// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=double -DFN=xdr_double -DUNINIT=1 %s -o %t && \ +// RUN: not %t 2>&1 | FileCheck %s +// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=u_quad_t -DFN=xdr_u_longlong_t %s -o %t && \ +// RUN: %t 2>&1 +// RUN: %clangxx_msan -m64 -g -O0 -DTYPE=u_quad_t -DFN=xdr_u_longlong_t -DUNINIT=1 %s -o %t && \ +// RUN: not %t 2>&1 | FileCheck %s + +#include <assert.h> +#include <rpc/xdr.h> + +#include <sanitizer/msan_interface.h> + +int main(int argc, char *argv[]) { + XDR xdrs; + char buf[100]; + xdrmem_create(&xdrs, buf, sizeof(buf), XDR_ENCODE); + TYPE x; +#ifndef UNINIT + x = 42; +#endif + bool_t res = FN(&xdrs, &x); + // CHECK: MemorySanitizer: use-of-uninitialized-value + // CHECK: {{in main.*sunrpc.cc:}}[[@LINE-2]] + assert(res == TRUE); + xdr_destroy(&xdrs); + + xdrmem_create(&xdrs, buf, sizeof(buf), XDR_DECODE); + TYPE y; + res = FN(&xdrs, &y); + assert(res == TRUE); + assert(__msan_test_shadow(&y, sizeof(y)) == -1); + xdr_destroy(&xdrs); + return 0; +} diff --git a/test/msan/Linux/sunrpc_bytes.cc b/test/msan/Linux/sunrpc_bytes.cc new file mode 100644 index 000000000..be8f6be8f --- /dev/null +++ b/test/msan/Linux/sunrpc_bytes.cc @@ -0,0 +1,38 @@ +// RUN: %clangxx_msan -m64 -g -O0 %s -o %t && \ +// RUN: %t 2>&1 +// RUN: %clangxx_msan -m64 -g -O0 -DUNINIT=1 %s -o %t && \ +// RUN: not %t 2>&1 | FileCheck %s + +#include <assert.h> +#include <string.h> +#include <rpc/xdr.h> + +#include <sanitizer/msan_interface.h> + +int main(int argc, char *argv[]) { + XDR xdrs; + char buf[100]; + xdrmem_create(&xdrs, buf, sizeof(buf), XDR_ENCODE); + char s[20]; +#ifndef UNINIT + strcpy(s, "hello"); +#endif + char *sp = s; + unsigned sz = 6; + bool_t res = xdr_bytes(&xdrs, &sp, &sz, sizeof(s)); + // CHECK: MemorySanitizer: use-of-uninitialized-value + // CHECK: {{in main.*sunrpc_bytes.cc:}}[[@LINE-2]] + assert(res == TRUE); + xdr_destroy(&xdrs); + + xdrmem_create(&xdrs, buf, sizeof(buf), XDR_DECODE); + char s2[20]; + char *sp2 = s2; + unsigned sz2; + res = xdr_bytes(&xdrs, &sp2, &sz2, sizeof(s2)); + assert(res == TRUE); + assert(sz == sz2); + assert(strcmp(s, s2) == 0); + xdr_destroy(&xdrs); + return 0; +} diff --git a/test/msan/Linux/sunrpc_string.cc b/test/msan/Linux/sunrpc_string.cc new file mode 100644 index 000000000..e800dea19 --- /dev/null +++ b/test/msan/Linux/sunrpc_string.cc @@ -0,0 +1,35 @@ +// RUN: %clangxx_msan -m64 -g -O0 %s -o %t && \ +// RUN: %t 2>&1 +// RUN: %clangxx_msan -m64 -g -O0 -DUNINIT=1 %s -o %t && \ +// RUN: not %t 2>&1 | FileCheck %s + +#include <assert.h> +#include <string.h> +#include <rpc/xdr.h> + +#include <sanitizer/msan_interface.h> + +int main(int argc, char *argv[]) { + XDR xdrs; + char buf[100]; + xdrmem_create(&xdrs, buf, sizeof(buf), XDR_ENCODE); + char s[20]; +#ifndef UNINIT + strcpy(s, "hello"); +#endif + char *sp = s; + bool_t res = xdr_string(&xdrs, &sp, sizeof(s)); + // CHECK: MemorySanitizer: use-of-uninitialized-value + // CHECK: {{in main.*sunrpc_string.cc:}}[[@LINE-2]] + assert(res == TRUE); + xdr_destroy(&xdrs); + + xdrmem_create(&xdrs, buf, sizeof(buf), XDR_DECODE); + char s2[20]; + char *sp2 = s2; + res = xdr_string(&xdrs, &sp2, sizeof(s2)); + assert(res == TRUE); + assert(strcmp(s, s2) == 0); + xdr_destroy(&xdrs); + return 0; +} |