summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/sanitizer_common/sanitizer_common_interceptors.inc138
-rw-r--r--lib/sanitizer_common/sanitizer_platform_interceptors.h1
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_posix.cc15
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_posix.h17
-rw-r--r--test/msan/Linux/sunrpc.cc40
-rw-r--r--test/msan/Linux/sunrpc_bytes.cc38
-rw-r--r--test/msan/Linux/sunrpc_string.cc35
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;
+}