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_interface.h" 21 #include "sanitizer_common/sanitizer_common.h" 22 #include "sanitizer_common/sanitizer_errno.h" 23 #include "sanitizer_common/sanitizer_platform_limits_posix.h" 24 #include "sanitizer_common/sanitizer_posix.h" 25 #include "sanitizer_common/sanitizer_tls_get_addr.h" 26 27 using namespace __sanitizer; 28 29 namespace { 30 31 bool interceptors_initialized; 32 33 } // namespace 34 35 INTERCEPTOR(void *, reallocarray, void *ptr, SIZE_T nmemb, SIZE_T size) { 36 return __dfsan::dfsan_reallocarray(ptr, nmemb, size); 37 } 38 39 INTERCEPTOR(void *, __libc_memalign, SIZE_T alignment, SIZE_T size) { 40 void *ptr = __dfsan::dfsan_memalign(alignment, size); 41 if (ptr) 42 DTLS_on_libc_memalign(ptr, size); 43 return ptr; 44 } 45 46 INTERCEPTOR(void *, aligned_alloc, SIZE_T alignment, SIZE_T size) { 47 return __dfsan::dfsan_aligned_alloc(alignment, size); 48 } 49 50 static uptr allocated_for_dlsym; 51 static const uptr kDlsymAllocPoolSize = 1024; 52 static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize]; 53 54 static bool IsInDlsymAllocPool(const void *ptr) { 55 uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym; 56 return off < sizeof(alloc_memory_for_dlsym); 57 } 58 59 static void *AllocateFromLocalPool(uptr size_in_bytes) { 60 uptr size_in_words = RoundUpTo(size_in_bytes, kWordSize) / kWordSize; 61 void *mem = (void *)&alloc_memory_for_dlsym[allocated_for_dlsym]; 62 allocated_for_dlsym += size_in_words; 63 CHECK_LT(allocated_for_dlsym, kDlsymAllocPoolSize); 64 return mem; 65 } 66 67 INTERCEPTOR(void *, calloc, SIZE_T nmemb, SIZE_T size) { 68 if (UNLIKELY(!__dfsan::dfsan_inited)) 69 // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym. 70 return AllocateFromLocalPool(nmemb * size); 71 return __dfsan::dfsan_calloc(nmemb, size); 72 } 73 74 INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) { 75 if (UNLIKELY(IsInDlsymAllocPool(ptr))) { 76 uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym; 77 uptr copy_size = Min(size, kDlsymAllocPoolSize - offset); 78 void *new_ptr; 79 if (UNLIKELY(!__dfsan::dfsan_inited)) { 80 new_ptr = AllocateFromLocalPool(copy_size); 81 } else { 82 copy_size = size; 83 new_ptr = __dfsan::dfsan_malloc(copy_size); 84 } 85 internal_memcpy(new_ptr, ptr, copy_size); 86 return new_ptr; 87 } 88 return __dfsan::dfsan_realloc(ptr, size); 89 } 90 91 INTERCEPTOR(void *, malloc, SIZE_T size) { 92 if (UNLIKELY(!__dfsan::dfsan_inited)) 93 // Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym. 94 return AllocateFromLocalPool(size); 95 return __dfsan::dfsan_malloc(size); 96 } 97 98 INTERCEPTOR(void, free, void *ptr) { 99 if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) 100 return; 101 return __dfsan::dfsan_deallocate(ptr); 102 } 103 104 INTERCEPTOR(void, cfree, void *ptr) { 105 if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) 106 return; 107 return __dfsan::dfsan_deallocate(ptr); 108 } 109 110 INTERCEPTOR(int, posix_memalign, void **memptr, SIZE_T alignment, SIZE_T size) { 111 CHECK_NE(memptr, 0); 112 int res = __dfsan::dfsan_posix_memalign(memptr, alignment, size); 113 if (!res) 114 dfsan_set_label(0, memptr, sizeof(*memptr)); 115 return res; 116 } 117 118 INTERCEPTOR(void *, memalign, SIZE_T alignment, SIZE_T size) { 119 return __dfsan::dfsan_memalign(alignment, size); 120 } 121 122 INTERCEPTOR(void *, valloc, SIZE_T size) { return __dfsan::dfsan_valloc(size); } 123 124 INTERCEPTOR(void *, pvalloc, SIZE_T size) { 125 return __dfsan::dfsan_pvalloc(size); 126 } 127 128 INTERCEPTOR(void, mallinfo, __sanitizer_struct_mallinfo *sret) { 129 internal_memset(sret, 0, sizeof(*sret)); 130 dfsan_set_label(0, sret, sizeof(*sret)); 131 } 132 133 INTERCEPTOR(int, mallopt, int cmd, int value) { return 0; } 134 135 INTERCEPTOR(void, malloc_stats, void) { 136 // FIXME: implement, but don't call REAL(malloc_stats)! 137 } 138 139 INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { 140 return __sanitizer_get_allocated_size(ptr); 141 } 142 143 #define ENSURE_DFSAN_INITED() \ 144 do { \ 145 CHECK(!__dfsan::dfsan_init_is_running); \ 146 if (!__dfsan::dfsan_inited) { \ 147 __dfsan::dfsan_init(); \ 148 } \ 149 } while (0) 150 151 #define COMMON_INTERCEPTOR_ENTER(func, ...) \ 152 if (__dfsan::dfsan_init_is_running) \ 153 return REAL(func)(__VA_ARGS__); \ 154 ENSURE_DFSAN_INITED(); \ 155 dfsan_set_label(0, __errno_location(), sizeof(int)); /* NOLINT */ 156 157 INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, 158 int fd, OFF_T offset) { 159 if (common_flags()->detect_write_exec) 160 ReportMmapWriteExec(prot); 161 if (!__dfsan::dfsan_inited) 162 return (void *)internal_mmap(addr, length, prot, flags, fd, offset); 163 COMMON_INTERCEPTOR_ENTER(mmap, addr, length, prot, flags, fd, offset); 164 void *res = REAL(mmap)(addr, length, prot, flags, fd, offset); 165 if (res != (void *)-1) { 166 dfsan_set_label(0, res, RoundUpTo(length, GetPageSizeCached())); 167 } 168 return res; 169 } 170 171 INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags, 172 int fd, OFF64_T offset) { 173 if (common_flags()->detect_write_exec) 174 ReportMmapWriteExec(prot); 175 if (!__dfsan::dfsan_inited) 176 return (void *)internal_mmap(addr, length, prot, flags, fd, offset); 177 COMMON_INTERCEPTOR_ENTER(mmap64, addr, length, prot, flags, fd, offset); 178 void *res = REAL(mmap64)(addr, length, prot, flags, fd, offset); 179 if (res != (void *)-1) { 180 dfsan_set_label(0, res, RoundUpTo(length, GetPageSizeCached())); 181 } 182 return res; 183 } 184 185 INTERCEPTOR(int, munmap, void *addr, SIZE_T length) { 186 if (!__dfsan::dfsan_inited) 187 return internal_munmap(addr, length); 188 COMMON_INTERCEPTOR_ENTER(munmap, addr, length); 189 int res = REAL(munmap)(addr, length); 190 if (res != -1) 191 dfsan_set_label(0, addr, RoundUpTo(length, GetPageSizeCached())); 192 return res; 193 } 194 195 #define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \ 196 if (__dfsan::DFsanThread *t = __dfsan::GetCurrentThread()) { \ 197 *begin = t->tls_begin(); \ 198 *end = t->tls_end(); \ 199 } else { \ 200 *begin = *end = 0; \ 201 } 202 #define COMMON_INTERCEPTOR_INITIALIZE_RANGE(ptr, size) \ 203 dfsan_set_label(0, ptr, size) 204 205 INTERCEPTOR(void *, __tls_get_addr, void *arg) { 206 COMMON_INTERCEPTOR_ENTER(__tls_get_addr, arg); 207 void *res = REAL(__tls_get_addr)(arg); 208 uptr tls_begin, tls_end; 209 COMMON_INTERCEPTOR_GET_TLS_RANGE(&tls_begin, &tls_end); 210 DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res, tls_begin, tls_end); 211 if (dtv) { 212 // New DTLS block has been allocated. 213 COMMON_INTERCEPTOR_INITIALIZE_RANGE((void *)dtv->beg, dtv->size); 214 } 215 return res; 216 } 217 218 namespace __dfsan { 219 void initialize_interceptors() { 220 CHECK(!interceptors_initialized); 221 222 INTERCEPT_FUNCTION(aligned_alloc); 223 INTERCEPT_FUNCTION(calloc); 224 INTERCEPT_FUNCTION(cfree); 225 INTERCEPT_FUNCTION(free); 226 INTERCEPT_FUNCTION(mallinfo); 227 INTERCEPT_FUNCTION(malloc); 228 INTERCEPT_FUNCTION(malloc_stats); 229 INTERCEPT_FUNCTION(malloc_usable_size); 230 INTERCEPT_FUNCTION(mallopt); 231 INTERCEPT_FUNCTION(memalign); 232 INTERCEPT_FUNCTION(mmap); 233 INTERCEPT_FUNCTION(mmap64); 234 INTERCEPT_FUNCTION(munmap); 235 INTERCEPT_FUNCTION(posix_memalign); 236 INTERCEPT_FUNCTION(pvalloc); 237 INTERCEPT_FUNCTION(realloc); 238 INTERCEPT_FUNCTION(reallocarray); 239 INTERCEPT_FUNCTION(valloc); 240 INTERCEPT_FUNCTION(__tls_get_addr); 241 INTERCEPT_FUNCTION(__libc_memalign); 242 243 interceptors_initialized = true; 244 } 245 } // namespace __dfsan 246