1 //===-- esan_interceptors.cpp ---------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file is a part of EfficiencySanitizer, a family of performance tuners. 11 // 12 // Interception routines for the esan run-time. 13 //===----------------------------------------------------------------------===// 14 15 #include "esan.h" 16 #include "esan_shadow.h" 17 #include "interception/interception.h" 18 #include "sanitizer_common/sanitizer_common.h" 19 #include "sanitizer_common/sanitizer_libc.h" 20 #include "sanitizer_common/sanitizer_linux.h" 21 #include "sanitizer_common/sanitizer_stacktrace.h" 22 23 using namespace __esan; // NOLINT 24 25 #define CUR_PC() (StackTrace::GetCurrentPc()) 26 27 //===----------------------------------------------------------------------===// 28 // Interception via sanitizer common interceptors 29 //===----------------------------------------------------------------------===// 30 31 // Get the per-platform defines for what is possible to intercept 32 #include "sanitizer_common/sanitizer_platform_interceptors.h" 33 34 DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr) 35 36 // TODO(bruening): tsan disables several interceptors (getpwent, etc.) claiming 37 // that interception is a perf hit: should we do the same? 38 39 // We have no need to intercept: 40 #undef SANITIZER_INTERCEPT_TLS_GET_ADDR 41 42 // TODO(bruening): the common realpath interceptor assumes malloc is 43 // intercepted! We should try to parametrize that, though we'll 44 // intercept malloc soon ourselves and can then remove this undef. 45 #undef SANITIZER_INTERCEPT_REALPATH 46 47 // We provide our own version: 48 #undef SANITIZER_INTERCEPT_SIGPROCMASK 49 50 #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!EsanIsInitialized) 51 52 #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) 53 #define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \ 54 INTERCEPT_FUNCTION_VER(name, ver) 55 56 // We must initialize during early interceptors, to support tcmalloc. 57 // This means that for some apps we fully initialize prior to 58 // __esan_init() being called. 59 // We currently do not use ctx. 60 #define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ 61 do { \ 62 if (UNLIKELY(COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)) { \ 63 if (!UNLIKELY(EsanDuringInit)) \ 64 initializeLibrary(__esan_which_tool); \ 65 return REAL(func)(__VA_ARGS__); \ 66 } \ 67 ctx = nullptr; \ 68 (void)ctx; \ 69 } while (false) 70 71 #define COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, func, ...) \ 72 COMMON_INTERCEPTOR_ENTER(ctx, func, __VA_ARGS__) 73 74 #define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \ 75 processRangeAccess(CUR_PC(), (uptr)ptr, size, true) 76 77 #define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \ 78 processRangeAccess(CUR_PC(), (uptr)ptr, size, false) 79 80 // This is only called if the app explicitly calls exit(), not on 81 // a normal exit. 82 #define COMMON_INTERCEPTOR_ON_EXIT(ctx) finalizeLibrary() 83 84 #define COMMON_INTERCEPTOR_FILE_OPEN(ctx, file, path) \ 85 do { \ 86 (void)(ctx); \ 87 (void)(file); \ 88 (void)(path); \ 89 } while (false) 90 #define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) \ 91 do { \ 92 (void)(ctx); \ 93 (void)(file); \ 94 } while (false) 95 #define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \ 96 do { \ 97 (void)(filename); \ 98 (void)(handle); \ 99 } while (false) 100 #define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() \ 101 do { \ 102 } while (false) 103 #define COMMON_INTERCEPTOR_ACQUIRE(ctx, u) \ 104 do { \ 105 (void)(ctx); \ 106 (void)(u); \ 107 } while (false) 108 #define COMMON_INTERCEPTOR_RELEASE(ctx, u) \ 109 do { \ 110 (void)(ctx); \ 111 (void)(u); \ 112 } while (false) 113 #define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \ 114 do { \ 115 (void)(ctx); \ 116 (void)(path); \ 117 } while (false) 118 #define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \ 119 do { \ 120 (void)(ctx); \ 121 (void)(fd); \ 122 } while (false) 123 #define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \ 124 do { \ 125 (void)(ctx); \ 126 (void)(fd); \ 127 } while (false) 128 #define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) \ 129 do { \ 130 (void)(ctx); \ 131 (void)(fd); \ 132 } while (false) 133 #define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \ 134 do { \ 135 (void)(ctx); \ 136 (void)(fd); \ 137 (void)(newfd); \ 138 } while (false) 139 #define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \ 140 do { \ 141 (void)(ctx); \ 142 (void)(name); \ 143 } while (false) 144 #define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \ 145 do { \ 146 (void)(ctx); \ 147 (void)(thread); \ 148 (void)(name); \ 149 } while (false) 150 #define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name) 151 #define COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m) \ 152 do { \ 153 (void)(ctx); \ 154 (void)(m); \ 155 } while (false) 156 #define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) \ 157 do { \ 158 (void)(ctx); \ 159 (void)(m); \ 160 } while (false) 161 #define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) \ 162 do { \ 163 (void)(ctx); \ 164 (void)(m); \ 165 } while (false) 166 #define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) \ 167 do { \ 168 (void)(ctx); \ 169 (void)(msg); \ 170 } while (false) 171 #define COMMON_INTERCEPTOR_USER_CALLBACK_START() \ 172 do { \ 173 } while (false) 174 #define COMMON_INTERCEPTOR_USER_CALLBACK_END() \ 175 do { \ 176 } while (false) 177 178 #include "sanitizer_common/sanitizer_common_interceptors.inc" 179 180 //===----------------------------------------------------------------------===// 181 // Syscall interception 182 //===----------------------------------------------------------------------===// 183 184 // We want the caller's PC b/c unlike the other function interceptors these 185 // are separate pre and post functions called around the app's syscall(). 186 187 #define COMMON_SYSCALL_PRE_READ_RANGE(ptr, size) \ 188 processRangeAccess(GET_CALLER_PC(), (uptr)ptr, size, false) 189 190 #define COMMON_SYSCALL_PRE_WRITE_RANGE(ptr, size) \ 191 do { \ 192 (void)(ptr); \ 193 (void)(size); \ 194 } while (false) 195 196 #define COMMON_SYSCALL_POST_READ_RANGE(ptr, size) \ 197 do { \ 198 (void)(ptr); \ 199 (void)(size); \ 200 } while (false) 201 202 // The actual amount written is in post, not pre. 203 #define COMMON_SYSCALL_POST_WRITE_RANGE(ptr, size) \ 204 processRangeAccess(GET_CALLER_PC(), (uptr)ptr, size, true) 205 206 #define COMMON_SYSCALL_ACQUIRE(addr) \ 207 do { \ 208 (void)(addr); \ 209 } while (false) 210 #define COMMON_SYSCALL_RELEASE(addr) \ 211 do { \ 212 (void)(addr); \ 213 } while (false) 214 #define COMMON_SYSCALL_FD_CLOSE(fd) \ 215 do { \ 216 (void)(fd); \ 217 } while (false) 218 #define COMMON_SYSCALL_FD_ACQUIRE(fd) \ 219 do { \ 220 (void)(fd); \ 221 } while (false) 222 #define COMMON_SYSCALL_FD_RELEASE(fd) \ 223 do { \ 224 (void)(fd); \ 225 } while (false) 226 #define COMMON_SYSCALL_PRE_FORK() \ 227 do { \ 228 } while (false) 229 #define COMMON_SYSCALL_POST_FORK(res) \ 230 do { \ 231 (void)(res); \ 232 } while (false) 233 234 #include "sanitizer_common/sanitizer_common_syscalls.inc" 235 236 //===----------------------------------------------------------------------===// 237 // Custom interceptors 238 //===----------------------------------------------------------------------===// 239 240 // TODO(bruening): move more of these to the common interception pool as they 241 // are shared with tsan and asan. 242 // While our other files match LLVM style, here we match sanitizer style as we 243 // expect to move these to the common pool. 244 245 INTERCEPTOR(char *, strcpy, char *dst, const char *src) { // NOLINT 246 void *ctx; 247 COMMON_INTERCEPTOR_ENTER(ctx, strcpy, dst, src); 248 uptr srclen = internal_strlen(src); 249 COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, srclen + 1); 250 COMMON_INTERCEPTOR_READ_RANGE(ctx, src, srclen + 1); 251 return REAL(strcpy)(dst, src); // NOLINT 252 } 253 254 INTERCEPTOR(char *, strncpy, char *dst, char *src, uptr n) { 255 void *ctx; 256 COMMON_INTERCEPTOR_ENTER(ctx, strncpy, dst, src, n); 257 uptr srclen = internal_strnlen(src, n); 258 uptr copied_size = srclen + 1 > n ? n : srclen + 1; 259 COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, copied_size); 260 COMMON_INTERCEPTOR_READ_RANGE(ctx, src, copied_size); 261 return REAL(strncpy)(dst, src, n); 262 } 263 264 INTERCEPTOR(int, open, const char *name, int flags, int mode) { 265 void *ctx; 266 COMMON_INTERCEPTOR_ENTER(ctx, open, name, flags, mode); 267 COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); 268 return REAL(open)(name, flags, mode); 269 } 270 271 #if SANITIZER_LINUX 272 INTERCEPTOR(int, open64, const char *name, int flags, int mode) { 273 void *ctx; 274 COMMON_INTERCEPTOR_ENTER(ctx, open64, name, flags, mode); 275 COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); 276 return REAL(open64)(name, flags, mode); 277 } 278 #define ESAN_MAYBE_INTERCEPT_OPEN64 INTERCEPT_FUNCTION(open64) 279 #else 280 #define ESAN_MAYBE_INTERCEPT_OPEN64 281 #endif 282 283 INTERCEPTOR(int, creat, const char *name, int mode) { 284 void *ctx; 285 COMMON_INTERCEPTOR_ENTER(ctx, creat, name, mode); 286 COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); 287 return REAL(creat)(name, mode); 288 } 289 290 #if SANITIZER_LINUX 291 INTERCEPTOR(int, creat64, const char *name, int mode) { 292 void *ctx; 293 COMMON_INTERCEPTOR_ENTER(ctx, creat64, name, mode); 294 COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); 295 return REAL(creat64)(name, mode); 296 } 297 #define ESAN_MAYBE_INTERCEPT_CREAT64 INTERCEPT_FUNCTION(creat64) 298 #else 299 #define ESAN_MAYBE_INTERCEPT_CREAT64 300 #endif 301 302 INTERCEPTOR(int, unlink, char *path) { 303 void *ctx; 304 COMMON_INTERCEPTOR_ENTER(ctx, unlink, path); 305 COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); 306 return REAL(unlink)(path); 307 } 308 309 INTERCEPTOR(int, puts, const char *s) { 310 void *ctx; 311 COMMON_INTERCEPTOR_ENTER(ctx, puts, s); 312 COMMON_INTERCEPTOR_READ_RANGE(ctx, s, internal_strlen(s)); 313 return REAL(puts)(s); 314 } 315 316 INTERCEPTOR(int, rmdir, char *path) { 317 void *ctx; 318 COMMON_INTERCEPTOR_ENTER(ctx, rmdir, path); 319 COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); 320 return REAL(rmdir)(path); 321 } 322 323 //===----------------------------------------------------------------------===// 324 // Shadow-related interceptors 325 //===----------------------------------------------------------------------===// 326 327 // These are candidates for sharing with all sanitizers if shadow memory 328 // support is also standardized. 329 330 INTERCEPTOR(void *, mmap, void *addr, SIZE_T sz, int prot, int flags, 331 int fd, OFF_T off) { 332 if (UNLIKELY(REAL(mmap) == nullptr)) { 333 // With esan init during interceptor init and a static libc preventing 334 // our early-calloc from triggering, we can end up here before our 335 // REAL pointer is set up. 336 return (void *)internal_mmap(addr, sz, prot, flags, fd, off); 337 } 338 void *ctx; 339 COMMON_INTERCEPTOR_ENTER(ctx, mmap, addr, sz, prot, flags, fd, off); 340 if (!fixMmapAddr(&addr, sz, flags)) 341 return (void *)-1; 342 void *result = REAL(mmap)(addr, sz, prot, flags, fd, off); 343 return (void *)checkMmapResult((uptr)result, sz); 344 } 345 346 #if SANITIZER_LINUX 347 INTERCEPTOR(void *, mmap64, void *addr, SIZE_T sz, int prot, int flags, 348 int fd, OFF64_T off) { 349 void *ctx; 350 COMMON_INTERCEPTOR_ENTER(ctx, mmap64, addr, sz, prot, flags, fd, off); 351 if (!fixMmapAddr(&addr, sz, flags)) 352 return (void *)-1; 353 void *result = REAL(mmap64)(addr, sz, prot, flags, fd, off); 354 return (void *)checkMmapResult((uptr)result, sz); 355 } 356 #define ESAN_MAYBE_INTERCEPT_MMAP64 INTERCEPT_FUNCTION(mmap64) 357 #else 358 #define ESAN_MAYBE_INTERCEPT_MMAP64 359 #endif 360 361 //===----------------------------------------------------------------------===// 362 // Signal-related interceptors 363 //===----------------------------------------------------------------------===// 364 365 #if SANITIZER_LINUX 366 typedef void (*signal_handler_t)(int); 367 INTERCEPTOR(signal_handler_t, signal, int signum, signal_handler_t handler) { 368 void *ctx; 369 COMMON_INTERCEPTOR_ENTER(ctx, signal, signum, handler); 370 signal_handler_t result; 371 if (!processSignal(signum, handler, &result)) 372 return result; 373 else 374 return REAL(signal)(signum, handler); 375 } 376 #define ESAN_MAYBE_INTERCEPT_SIGNAL INTERCEPT_FUNCTION(signal) 377 #else 378 #error Platform not supported 379 #define ESAN_MAYBE_INTERCEPT_SIGNAL 380 #endif 381 382 #if SANITIZER_LINUX 383 DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act, 384 struct sigaction *oldact) 385 INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act, 386 struct sigaction *oldact) { 387 void *ctx; 388 COMMON_INTERCEPTOR_ENTER(ctx, sigaction, signum, act, oldact); 389 if (!processSigaction(signum, act, oldact)) 390 return 0; 391 else 392 return REAL(sigaction)(signum, act, oldact); 393 } 394 395 // This is required to properly use internal_sigaction. 396 namespace __sanitizer { 397 int real_sigaction(int signum, const void *act, void *oldact) { 398 if (REAL(sigaction) == nullptr) { 399 // With an instrumented allocator, this is called during interceptor init 400 // and we need a raw syscall solution. 401 return internal_sigaction_syscall(signum, act, oldact); 402 } 403 return REAL(sigaction)(signum, (const struct sigaction *)act, 404 (struct sigaction *)oldact); 405 } 406 } // namespace __sanitizer 407 408 #define ESAN_MAYBE_INTERCEPT_SIGACTION INTERCEPT_FUNCTION(sigaction) 409 #else 410 #error Platform not supported 411 #define ESAN_MAYBE_INTERCEPT_SIGACTION 412 #endif 413 414 #if SANITIZER_LINUX 415 INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set, 416 __sanitizer_sigset_t *oldset) { 417 void *ctx; 418 COMMON_INTERCEPTOR_ENTER(ctx, sigprocmask, how, set, oldset); 419 int res = 0; 420 if (processSigprocmask(how, set, oldset)) 421 res = REAL(sigprocmask)(how, set, oldset); 422 if (!res && oldset) 423 COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset)); 424 return res; 425 } 426 #define ESAN_MAYBE_INTERCEPT_SIGPROCMASK INTERCEPT_FUNCTION(sigprocmask) 427 #else 428 #define ESAN_MAYBE_INTERCEPT_SIGPROCMASK 429 #endif 430 431 #if !SANITIZER_WINDOWS 432 INTERCEPTOR(int, pthread_sigmask, int how, __sanitizer_sigset_t *set, 433 __sanitizer_sigset_t *oldset) { 434 void *ctx; 435 COMMON_INTERCEPTOR_ENTER(ctx, pthread_sigmask, how, set, oldset); 436 int res = 0; 437 if (processSigprocmask(how, set, oldset)) 438 res = REAL(sigprocmask)(how, set, oldset); 439 if (!res && oldset) 440 COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset)); 441 return res; 442 } 443 #define ESAN_MAYBE_INTERCEPT_PTHREAD_SIGMASK INTERCEPT_FUNCTION(pthread_sigmask) 444 #else 445 #define ESAN_MAYBE_INTERCEPT_PTHREAD_SIGMASK 446 #endif 447 448 //===----------------------------------------------------------------------===// 449 // Malloc interceptors 450 //===----------------------------------------------------------------------===// 451 452 static const uptr early_alloc_buf_size = 4096; 453 static uptr allocated_bytes; 454 static char early_alloc_buf[early_alloc_buf_size]; 455 456 static bool isInEarlyAllocBuf(const void *ptr) { 457 return ((uptr)ptr >= (uptr)early_alloc_buf && 458 ((uptr)ptr - (uptr)early_alloc_buf) < sizeof(early_alloc_buf)); 459 } 460 461 static void *handleEarlyAlloc(uptr size) { 462 // If esan is initialized during an interceptor (which happens with some 463 // tcmalloc implementations that call pthread_mutex_lock), the call from 464 // dlsym to calloc will deadlock. 465 // dlsym may also call malloc before REAL(malloc) is retrieved from dlsym. 466 // We work around it by using a static buffer for the early malloc/calloc 467 // requests. 468 // This solution will also allow us to deliberately intercept malloc & family 469 // in the future (to perform tool actions on each allocation, without 470 // replacing the allocator), as it also solves the problem of intercepting 471 // calloc when it will itself be called before its REAL pointer is 472 // initialized. 473 // We do not handle multiple threads here. This only happens at process init 474 // time, and while it's possible for a shared library to create early threads 475 // that race here, we consider that to be a corner case extreme enough that 476 // it's not worth the effort to handle. 477 void *mem = (void *)&early_alloc_buf[allocated_bytes]; 478 allocated_bytes += size; 479 CHECK_LT(allocated_bytes, early_alloc_buf_size); 480 return mem; 481 } 482 483 INTERCEPTOR(void*, calloc, uptr size, uptr n) { 484 if (EsanDuringInit && REAL(calloc) == nullptr) 485 return handleEarlyAlloc(size * n); 486 void *ctx; 487 COMMON_INTERCEPTOR_ENTER(ctx, calloc, size, n); 488 void *res = REAL(calloc)(size, n); 489 // The memory is zeroed and thus is all written. 490 COMMON_INTERCEPTOR_WRITE_RANGE(nullptr, (uptr)res, size * n); 491 return res; 492 } 493 494 INTERCEPTOR(void*, malloc, uptr size) { 495 if (EsanDuringInit && REAL(malloc) == nullptr) 496 return handleEarlyAlloc(size); 497 void *ctx; 498 COMMON_INTERCEPTOR_ENTER(ctx, malloc, size); 499 return REAL(malloc)(size); 500 } 501 502 INTERCEPTOR(void, free, void *p) { 503 void *ctx; 504 // There are only a few early allocation requests, so we simply skip the free. 505 if (isInEarlyAllocBuf(p)) 506 return; 507 COMMON_INTERCEPTOR_ENTER(ctx, free, p); 508 REAL(free)(p); 509 } 510 511 namespace __esan { 512 513 void initializeInterceptors() { 514 InitializeCommonInterceptors(); 515 516 INTERCEPT_FUNCTION(strcpy); // NOLINT 517 INTERCEPT_FUNCTION(strncpy); 518 519 INTERCEPT_FUNCTION(open); 520 ESAN_MAYBE_INTERCEPT_OPEN64; 521 INTERCEPT_FUNCTION(creat); 522 ESAN_MAYBE_INTERCEPT_CREAT64; 523 INTERCEPT_FUNCTION(unlink); 524 INTERCEPT_FUNCTION(fread); 525 INTERCEPT_FUNCTION(fwrite); 526 INTERCEPT_FUNCTION(puts); 527 INTERCEPT_FUNCTION(rmdir); 528 529 INTERCEPT_FUNCTION(mmap); 530 ESAN_MAYBE_INTERCEPT_MMAP64; 531 532 ESAN_MAYBE_INTERCEPT_SIGNAL; 533 ESAN_MAYBE_INTERCEPT_SIGACTION; 534 ESAN_MAYBE_INTERCEPT_SIGPROCMASK; 535 ESAN_MAYBE_INTERCEPT_PTHREAD_SIGMASK; 536 537 INTERCEPT_FUNCTION(calloc); 538 INTERCEPT_FUNCTION(malloc); 539 INTERCEPT_FUNCTION(free); 540 541 // TODO(bruening): intercept routines that other sanitizers intercept that 542 // are not in the common pool or here yet, ideally by adding to the common 543 // pool. Examples include wcslen and bcopy. 544 545 // TODO(bruening): there are many more libc routines that read or write data 546 // structures that no sanitizer is intercepting: sigaction, strtol, etc. 547 } 548 549 } // namespace __esan 550