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