1 //===-- dfsan_interceptors.cpp --------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file is a part of DataFlowSanitizer. 10 // 11 // Interceptors for standard library functions. 12 //===----------------------------------------------------------------------===// 13 14 #include <sys/syscall.h> 15 #include <unistd.h> 16 17 #include "dfsan/dfsan.h" 18 #include "dfsan/dfsan_thread.h" 19 #include "interception/interception.h" 20 #include "sanitizer_common/sanitizer_allocator_dlsym.h" 21 #include "sanitizer_common/sanitizer_allocator_interface.h" 22 #include "sanitizer_common/sanitizer_common.h" 23 #include "sanitizer_common/sanitizer_errno.h" 24 #include "sanitizer_common/sanitizer_platform_limits_posix.h" 25 #include "sanitizer_common/sanitizer_posix.h" 26 #include "sanitizer_common/sanitizer_tls_get_addr.h" 27 28 using namespace __dfsan; 29 using namespace __sanitizer; 30 31 static bool interceptors_initialized; 32 33 struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> { 34 static bool UseImpl() { return !dfsan_inited; } 35 }; 36 37 INTERCEPTOR(void *, reallocarray, void *ptr, SIZE_T nmemb, SIZE_T size) { 38 return dfsan_reallocarray(ptr, nmemb, size); 39 } 40 41 INTERCEPTOR(void *, __libc_memalign, SIZE_T alignment, SIZE_T size) { 42 return dfsan_memalign(alignment, size); 43 } 44 45 INTERCEPTOR(void *, aligned_alloc, SIZE_T alignment, SIZE_T size) { 46 return dfsan_aligned_alloc(alignment, size); 47 } 48 49 INTERCEPTOR(void *, calloc, SIZE_T nmemb, SIZE_T size) { 50 if (DlsymAlloc::Use()) 51 return DlsymAlloc::Callocate(nmemb, size); 52 return dfsan_calloc(nmemb, size); 53 } 54 55 INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) { 56 if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr)) 57 return DlsymAlloc::Realloc(ptr, size); 58 return dfsan_realloc(ptr, size); 59 } 60 61 INTERCEPTOR(void *, malloc, SIZE_T size) { 62 if (DlsymAlloc::Use()) 63 return DlsymAlloc::Allocate(size); 64 return dfsan_malloc(size); 65 } 66 67 INTERCEPTOR(void, free, void *ptr) { 68 if (!ptr) 69 return; 70 if (DlsymAlloc::PointerIsMine(ptr)) 71 return DlsymAlloc::Free(ptr); 72 return dfsan_deallocate(ptr); 73 } 74 75 INTERCEPTOR(void, cfree, void *ptr) { 76 if (!ptr) 77 return; 78 if (DlsymAlloc::PointerIsMine(ptr)) 79 return DlsymAlloc::Free(ptr); 80 return dfsan_deallocate(ptr); 81 } 82 83 INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) { 84 CHECK_NE(memptr, 0); 85 int res = dfsan_posix_memalign(memptr, alignment, size); 86 if (!res) 87 dfsan_set_label(0, memptr, sizeof(*memptr)); 88 return res; 89 } 90 91 INTERCEPTOR(void *, memalign, SIZE_T alignment, SIZE_T size) { 92 return dfsan_memalign(alignment, size); 93 } 94 95 INTERCEPTOR(void *, valloc, SIZE_T size) { return dfsan_valloc(size); } 96 97 INTERCEPTOR(void *, pvalloc, SIZE_T size) { return dfsan_pvalloc(size); } 98 99 INTERCEPTOR(void, mallinfo, __sanitizer_struct_mallinfo *sret) { 100 internal_memset(sret, 0, sizeof(*sret)); 101 dfsan_set_label(0, sret, sizeof(*sret)); 102 } 103 104 INTERCEPTOR(int, mallopt, int cmd, int value) { return 0; } 105 106 INTERCEPTOR(void, malloc_stats, void) { 107 // FIXME: implement, but don't call REAL(malloc_stats)! 108 } 109 110 INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { 111 return __sanitizer_get_allocated_size(ptr); 112 } 113 114 #define ENSURE_DFSAN_INITED() \ 115 do { \ 116 CHECK(!dfsan_init_is_running); \ 117 if (!dfsan_inited) { \ 118 dfsan_init(); \ 119 } \ 120 } while (0) 121 122 #define COMMON_INTERCEPTOR_ENTER(func, ...) \ 123 if (dfsan_init_is_running) \ 124 return REAL(func)(__VA_ARGS__); \ 125 ENSURE_DFSAN_INITED(); \ 126 dfsan_set_label(0, __errno_location(), sizeof(int)); 127 128 INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, 129 int fd, OFF_T offset) { 130 if (common_flags()->detect_write_exec) 131 ReportMmapWriteExec(prot, flags); 132 if (!dfsan_inited) 133 return (void *)internal_mmap(addr, length, prot, flags, fd, offset); 134 COMMON_INTERCEPTOR_ENTER(mmap, addr, length, prot, flags, fd, offset); 135 void *res = REAL(mmap)(addr, length, prot, flags, fd, offset); 136 if (res != (void *)-1) { 137 dfsan_set_label(0, res, RoundUpTo(length, GetPageSizeCached())); 138 } 139 return res; 140 } 141 142 INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags, 143 int fd, OFF64_T offset) { 144 if (common_flags()->detect_write_exec) 145 ReportMmapWriteExec(prot, flags); 146 if (!dfsan_inited) 147 return (void *)internal_mmap(addr, length, prot, flags, fd, offset); 148 COMMON_INTERCEPTOR_ENTER(mmap64, addr, length, prot, flags, fd, offset); 149 void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset); 150 if (res != (void *)-1) { 151 dfsan_set_label(0, res, RoundUpTo(length, GetPageSizeCached())); 152 } 153 return res; 154 } 155 156 INTERCEPTOR(int, munmap, void *addr, SIZE_T length) { 157 if (!dfsan_inited) 158 return internal_munmap(addr, length); 159 COMMON_INTERCEPTOR_ENTER(munmap, addr, length); 160 int res = REAL(munmap)(addr, length); 161 if (res != -1) 162 dfsan_set_label(0, addr, RoundUpTo(length, GetPageSizeCached())); 163 return res; 164 } 165 166 #define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \ 167 if (DFsanThread *t = GetCurrentThread()) { \ 168 *begin = t->tls_begin(); \ 169 *end = t->tls_end(); \ 170 } else { \ 171 *begin = *end = 0; \ 172 } 173 #define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ptr, size) \ 174 dfsan_set_label(0, ptr, size) 175 176 INTERCEPTOR(void *, __tls_get_addr, void *arg) { 177 COMMON_INTERCEPTOR_ENTER(__tls_get_addr, arg); 178 void *res = REAL(__tls_get_addr)(arg); 179 uptr tls_begin, tls_end; 180 COMMON_INTERCEPTOR_GET_TLS_RANGE(&tls_begin, &tls_end); 181 DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res, tls_begin, tls_end); 182 if (dtv) { 183 // New DTLS block has been allocated. 184 COMMON_INTERCEPTOR_INITIALIZE_RANGE((void *)dtv->beg, dtv->size); 185 } 186 return res; 187 } 188 189 void __dfsan::initialize_interceptors() { 190 CHECK(!interceptors_initialized); 191 192 INTERCEPT_FUNCTION(aligned_alloc); 193 INTERCEPT_FUNCTION(calloc); 194 INTERCEPT_FUNCTION(cfree); 195 INTERCEPT_FUNCTION(free); 196 INTERCEPT_FUNCTION(mallinfo); 197 INTERCEPT_FUNCTION(malloc); 198 INTERCEPT_FUNCTION(malloc_stats); 199 INTERCEPT_FUNCTION(malloc_usable_size); 200 INTERCEPT_FUNCTION(mallopt); 201 INTERCEPT_FUNCTION(memalign); 202 INTERCEPT_FUNCTION(mmap); 203 INTERCEPT_FUNCTION(mmap64); 204 INTERCEPT_FUNCTION(munmap); 205 INTERCEPT_FUNCTION(posix_memalign); 206 INTERCEPT_FUNCTION(pvalloc); 207 INTERCEPT_FUNCTION(realloc); 208 INTERCEPT_FUNCTION(reallocarray); 209 INTERCEPT_FUNCTION(valloc); 210 INTERCEPT_FUNCTION(__tls_get_addr); 211 INTERCEPT_FUNCTION(__libc_memalign); 212 213 interceptors_initialized = true; 214 } 215