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