Skip to content

Commit f93b55a

Browse files
committed
[Sanitizers] Add interceptor for xdrrec_create
For now, xdrrec_create is only intercepted Linux as its signature is different on Solaris. The method of intercepting xdrrec_create isn't super ideal but I couldn't think of a way around it: Using an AddrHashMap combined with wrapping the userdata field. We can't just allocate a handle on the heap in xdrrec_create and leave it at that, since there'd be no way to free it later. This is because it doesn't seem to be possible to access handle from the XDR struct, which is the only argument to xdr_destroy. On the other hand, the callbacks don't have a way to get at the x_private field of XDR, which is what I chose for the HashMap key. So we need to wrap the handle parameter of the callbacks. But we can't just pass x_private as handle (as it hasn't been set yet). We can't put the wrapper struct into the HashMap and pass its pointer as handle, as the key we need (x_private again) hasn't been set yet. So I allocate the wrapper struct on the heap, pass its pointer as handle, and put it into the HashMap so xdr_destroy can find it later and destroy it. Differential Revision: https://reviews.llvm.org/D83358
1 parent 746b5fa commit f93b55a

File tree

3 files changed

+102
-0
lines changed

3 files changed

+102
-0
lines changed

compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5836,6 +5836,79 @@ INTERCEPTOR(int, xdr_string, __sanitizer_XDR *xdrs, char **p,
58365836
#define INIT_XDR
58375837
#endif // SANITIZER_INTERCEPT_XDR
58385838

5839+
#if SANITIZER_INTERCEPT_XDRREC
5840+
typedef int (*xdrrec_cb)(char*, char*, int);
5841+
struct XdrRecWrapper {
5842+
char *handle;
5843+
xdrrec_cb rd, wr;
5844+
};
5845+
typedef AddrHashMap<XdrRecWrapper *, 11> XdrRecWrapMap;
5846+
static XdrRecWrapMap *xdrrec_wrap_map;
5847+
5848+
static int xdrrec_wr_wrap(char *handle, char *buf, int count) {
5849+
COMMON_INTERCEPTOR_UNPOISON_PARAM(3);
5850+
COMMON_INTERCEPTOR_INITIALIZE_RANGE(buf, count);
5851+
XdrRecWrapper *wrap = (XdrRecWrapper *)handle;
5852+
return wrap->wr(wrap->handle, buf, count);
5853+
}
5854+
5855+
static int xdrrec_rd_wrap(char *handle, char *buf, int count) {
5856+
COMMON_INTERCEPTOR_UNPOISON_PARAM(3);
5857+
XdrRecWrapper *wrap = (XdrRecWrapper *)handle;
5858+
return wrap->rd(wrap->handle, buf, count);
5859+
}
5860+
5861+
// This doesn't apply to the solaris version as it has a different function
5862+
// signature.
5863+
INTERCEPTOR(void, xdrrec_create, __sanitizer_XDR *xdr, unsigned sndsize,
5864+
unsigned rcvsize, char *handle, int (*rd)(char*, char*, int),
5865+
int (*wr)(char*, char*, int)) {
5866+
void *ctx;
5867+
COMMON_INTERCEPTOR_ENTER(ctx, xdrrec_create, xdr, sndsize, rcvsize,
5868+
handle, rd, wr);
5869+
COMMON_INTERCEPTOR_READ_RANGE(ctx, &xdr->x_op, sizeof xdr->x_op);
5870+
5871+
// We can't allocate a wrapper on the stack, as the handle is used outside
5872+
// this stack frame. So we put it on the heap, and keep track of it with
5873+
// the HashMap (keyed by x_private). When we later need to xdr_destroy,
5874+
// we can index the map, free the wrapper, and then clean the map entry.
5875+
XdrRecWrapper *wrap_data =
5876+
(XdrRecWrapper *)InternalAlloc(sizeof(XdrRecWrapper));
5877+
wrap_data->handle = handle;
5878+
wrap_data->rd = rd;
5879+
wrap_data->wr = wr;
5880+
if (wr)
5881+
wr = xdrrec_wr_wrap;
5882+
if (rd)
5883+
rd = xdrrec_rd_wrap;
5884+
handle = (char *)wrap_data;
5885+
5886+
REAL(xdrrec_create)(xdr, sndsize, rcvsize, handle, rd, wr);
5887+
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdr, sizeof *xdr);
5888+
5889+
XdrRecWrapMap::Handle wrap(xdrrec_wrap_map, xdr->x_private, false, true);
5890+
*wrap = wrap_data;
5891+
}
5892+
5893+
// We have to intercept this to be able to free wrapper memory;
5894+
// otherwise it's not necessary.
5895+
INTERCEPTOR(void, xdr_destroy, __sanitizer_XDR *xdr) {
5896+
void *ctx;
5897+
COMMON_INTERCEPTOR_ENTER(ctx, xdr_destroy, xdr);
5898+
5899+
XdrRecWrapMap::Handle wrap(xdrrec_wrap_map, xdr->x_private, true);
5900+
InternalFree(*wrap);
5901+
REAL(xdr_destroy)(xdr);
5902+
}
5903+
#define INIT_XDRREC_LINUX \
5904+
static u64 xdrrec_wrap_mem[sizeof(XdrRecWrapMap) / sizeof(u64) + 1]; \
5905+
xdrrec_wrap_map = new ((void *)&xdrrec_wrap_mem) XdrRecWrapMap(); \
5906+
COMMON_INTERCEPT_FUNCTION(xdrrec_create); \
5907+
COMMON_INTERCEPT_FUNCTION(xdr_destroy);
5908+
#else
5909+
#define INIT_XDRREC_LINUX
5910+
#endif
5911+
58395912
#if SANITIZER_INTERCEPT_TSEARCH
58405913
INTERCEPTOR(void *, tsearch, void *key, void **rootp,
58415914
int (*compar)(const void *, const void *)) {
@@ -10094,6 +10167,7 @@ static void InitializeCommonInterceptors() {
1009410167
INIT_BZERO;
1009510168
INIT_FTIME;
1009610169
INIT_XDR;
10170+
INIT_XDRREC_LINUX;
1009710171
INIT_TSEARCH;
1009810172
INIT_LIBIO_INTERNALS;
1009910173
INIT_FOPEN;

compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,7 @@
440440
#define SANITIZER_INTERCEPT_FTIME \
441441
(!SI_FREEBSD && !SI_NETBSD && !SI_OPENBSD && SI_POSIX)
442442
#define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID || SI_SOLARIS
443+
#define SANITIZER_INTERCEPT_XDRREC SI_LINUX_NOT_ANDROID
443444
#define SANITIZER_INTERCEPT_TSEARCH \
444445
(SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD || SI_OPENBSD || SI_SOLARIS)
445446
#define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_LINUX_NOT_ANDROID
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %clangxx -O0 %s -o %t && %run %t | FileCheck %s
2+
// REQUIRES: !android
3+
#include <cassert>
4+
#include <rpc/xdr.h>
5+
6+
int print_msg(char *handle, char *buf, int len) {
7+
if (len > 0) {
8+
for (size_t i = 0; i < len; i++) {
9+
printf("%02x ", (uint8_t)buf[i]);
10+
}
11+
printf("\n");
12+
}
13+
return len;
14+
}
15+
16+
int main() {
17+
XDR xdrs;
18+
xdrs.x_op = XDR_ENCODE;
19+
20+
xdrrec_create(&xdrs, 0, 0, nullptr, nullptr, print_msg);
21+
unsigned foo = 42;
22+
assert(xdr_u_int(&xdrs, &foo));
23+
assert(xdrrec_endofrecord(&xdrs, /*sendnow*/ true));
24+
xdr_destroy(&xdrs);
25+
}
26+
27+
// CHECK: 00 00 00 2a

0 commit comments

Comments
 (0)