1 //===-- hwasan_linux.cpp ----------------------------------------*- C++ -*-===// 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 /// \file 10 /// This file is a part of HWAddressSanitizer and contains Linux-, NetBSD- and 11 /// FreeBSD-specific code. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #include "sanitizer_common/sanitizer_platform.h" 16 #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD 17 18 #include "hwasan.h" 19 #include "hwasan_dynamic_shadow.h" 20 #include "hwasan_interface_internal.h" 21 #include "hwasan_mapping.h" 22 #include "hwasan_report.h" 23 #include "hwasan_thread.h" 24 #include "hwasan_thread_list.h" 25 26 #include <dlfcn.h> 27 #include <elf.h> 28 #include <link.h> 29 #include <pthread.h> 30 #include <signal.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <sys/resource.h> 34 #include <sys/time.h> 35 #include <unistd.h> 36 #include <unwind.h> 37 38 #include "sanitizer_common/sanitizer_common.h" 39 #include "sanitizer_common/sanitizer_procmaps.h" 40 41 #if HWASAN_WITH_INTERCEPTORS && !SANITIZER_ANDROID 42 SANITIZER_INTERFACE_ATTRIBUTE 43 THREADLOCAL uptr __hwasan_tls; 44 #endif 45 46 namespace __hwasan { 47 48 static void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) { 49 CHECK_EQ((beg % GetMmapGranularity()), 0); 50 CHECK_EQ(((end + 1) % GetMmapGranularity()), 0); 51 uptr size = end - beg + 1; 52 DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb. 53 if (!MmapFixedNoReserve(beg, size, name)) { 54 Report( 55 "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. " 56 "Perhaps you're using ulimit -v\n", 57 size); 58 Abort(); 59 } 60 } 61 62 static void ProtectGap(uptr addr, uptr size) { 63 if (!size) 64 return; 65 void *res = MmapFixedNoAccess(addr, size, "shadow gap"); 66 if (addr == (uptr)res) 67 return; 68 // A few pages at the start of the address space can not be protected. 69 // But we really want to protect as much as possible, to prevent this memory 70 // being returned as a result of a non-FIXED mmap(). 71 if (addr == 0) { 72 uptr step = GetMmapGranularity(); 73 while (size > step) { 74 addr += step; 75 size -= step; 76 void *res = MmapFixedNoAccess(addr, size, "shadow gap"); 77 if (addr == (uptr)res) 78 return; 79 } 80 } 81 82 Report( 83 "ERROR: Failed to protect shadow gap [%p, %p]. " 84 "HWASan cannot proceed correctly. ABORTING.\n", (void *)addr, 85 (void *)(addr + size)); 86 DumpProcessMap(); 87 Die(); 88 } 89 90 static uptr kLowMemStart; 91 static uptr kLowMemEnd; 92 static uptr kLowShadowEnd; 93 static uptr kLowShadowStart; 94 static uptr kHighShadowStart; 95 static uptr kHighShadowEnd; 96 static uptr kHighMemStart; 97 static uptr kHighMemEnd; 98 99 static void PrintRange(uptr start, uptr end, const char *name) { 100 Printf("|| [%p, %p] || %.*s ||\n", (void *)start, (void *)end, 10, name); 101 } 102 103 static void PrintAddressSpaceLayout() { 104 PrintRange(kHighMemStart, kHighMemEnd, "HighMem"); 105 if (kHighShadowEnd + 1 < kHighMemStart) 106 PrintRange(kHighShadowEnd + 1, kHighMemStart - 1, "ShadowGap"); 107 else 108 CHECK_EQ(kHighShadowEnd + 1, kHighMemStart); 109 PrintRange(kHighShadowStart, kHighShadowEnd, "HighShadow"); 110 if (kLowShadowEnd + 1 < kHighShadowStart) 111 PrintRange(kLowShadowEnd + 1, kHighShadowStart - 1, "ShadowGap"); 112 else 113 CHECK_EQ(kLowMemEnd + 1, kHighShadowStart); 114 PrintRange(kLowShadowStart, kLowShadowEnd, "LowShadow"); 115 if (kLowMemEnd + 1 < kLowShadowStart) 116 PrintRange(kLowMemEnd + 1, kLowShadowStart - 1, "ShadowGap"); 117 else 118 CHECK_EQ(kLowMemEnd + 1, kLowShadowStart); 119 PrintRange(kLowMemStart, kLowMemEnd, "LowMem"); 120 CHECK_EQ(0, kLowMemStart); 121 } 122 123 static uptr GetHighMemEnd() { 124 // HighMem covers the upper part of the address space. 125 uptr max_address = GetMaxUserVirtualAddress(); 126 // Adjust max address to make sure that kHighMemEnd and kHighMemStart are 127 // properly aligned: 128 max_address |= (GetMmapGranularity() << kShadowScale) - 1; 129 return max_address; 130 } 131 132 static void InitializeShadowBaseAddress(uptr shadow_size_bytes) { 133 __hwasan_shadow_memory_dynamic_address = 134 FindDynamicShadowStart(shadow_size_bytes); 135 } 136 137 bool InitShadow() { 138 // Define the entire memory range. 139 kHighMemEnd = GetHighMemEnd(); 140 141 // Determine shadow memory base offset. 142 InitializeShadowBaseAddress(MemToShadowSize(kHighMemEnd)); 143 144 // Place the low memory first. 145 kLowMemEnd = __hwasan_shadow_memory_dynamic_address - 1; 146 kLowMemStart = 0; 147 148 // Define the low shadow based on the already placed low memory. 149 kLowShadowEnd = MemToShadow(kLowMemEnd); 150 kLowShadowStart = __hwasan_shadow_memory_dynamic_address; 151 152 // High shadow takes whatever memory is left up there (making sure it is not 153 // interfering with low memory in the fixed case). 154 kHighShadowEnd = MemToShadow(kHighMemEnd); 155 kHighShadowStart = Max(kLowMemEnd, MemToShadow(kHighShadowEnd)) + 1; 156 157 // High memory starts where allocated shadow allows. 158 kHighMemStart = ShadowToMem(kHighShadowStart); 159 160 // Check the sanity of the defined memory ranges (there might be gaps). 161 CHECK_EQ(kHighMemStart % GetMmapGranularity(), 0); 162 CHECK_GT(kHighMemStart, kHighShadowEnd); 163 CHECK_GT(kHighShadowEnd, kHighShadowStart); 164 CHECK_GT(kHighShadowStart, kLowMemEnd); 165 CHECK_GT(kLowMemEnd, kLowMemStart); 166 CHECK_GT(kLowShadowEnd, kLowShadowStart); 167 CHECK_GT(kLowShadowStart, kLowMemEnd); 168 169 if (Verbosity()) 170 PrintAddressSpaceLayout(); 171 172 // Reserve shadow memory. 173 ReserveShadowMemoryRange(kLowShadowStart, kLowShadowEnd, "low shadow"); 174 ReserveShadowMemoryRange(kHighShadowStart, kHighShadowEnd, "high shadow"); 175 176 // Protect all the gaps. 177 ProtectGap(0, Min(kLowMemStart, kLowShadowStart)); 178 if (kLowMemEnd + 1 < kLowShadowStart) 179 ProtectGap(kLowMemEnd + 1, kLowShadowStart - kLowMemEnd - 1); 180 if (kLowShadowEnd + 1 < kHighShadowStart) 181 ProtectGap(kLowShadowEnd + 1, kHighShadowStart - kLowShadowEnd - 1); 182 if (kHighShadowEnd + 1 < kHighMemStart) 183 ProtectGap(kHighShadowEnd + 1, kHighMemStart - kHighShadowEnd - 1); 184 185 return true; 186 } 187 188 void InitThreads() { 189 CHECK(__hwasan_shadow_memory_dynamic_address); 190 uptr guard_page_size = GetMmapGranularity(); 191 uptr thread_space_start = 192 __hwasan_shadow_memory_dynamic_address - (1ULL << kShadowBaseAlignment); 193 uptr thread_space_end = 194 __hwasan_shadow_memory_dynamic_address - guard_page_size; 195 ReserveShadowMemoryRange(thread_space_start, thread_space_end - 1, 196 "hwasan threads"); 197 ProtectGap(thread_space_end, 198 __hwasan_shadow_memory_dynamic_address - thread_space_end); 199 InitThreadList(thread_space_start, thread_space_end - thread_space_start); 200 } 201 202 static void MadviseShadowRegion(uptr beg, uptr end) { 203 uptr size = end - beg + 1; 204 if (common_flags()->no_huge_pages_for_shadow) 205 NoHugePagesInRegion(beg, size); 206 if (common_flags()->use_madv_dontdump) 207 DontDumpShadowMemory(beg, size); 208 } 209 210 void MadviseShadow() { 211 MadviseShadowRegion(kLowShadowStart, kLowShadowEnd); 212 MadviseShadowRegion(kHighShadowStart, kHighShadowEnd); 213 } 214 215 bool MemIsApp(uptr p) { 216 CHECK(GetTagFromPointer(p) == 0); 217 return p >= kHighMemStart || (p >= kLowMemStart && p <= kLowMemEnd); 218 } 219 220 static void HwasanAtExit(void) { 221 if (common_flags()->print_module_map) 222 DumpProcessMap(); 223 if (flags()->print_stats && (flags()->atexit || hwasan_report_count > 0)) 224 ReportStats(); 225 if (hwasan_report_count > 0) { 226 // ReportAtExitStatistics(); 227 if (common_flags()->exitcode) 228 internal__exit(common_flags()->exitcode); 229 } 230 } 231 232 void InstallAtExitHandler() { 233 atexit(HwasanAtExit); 234 } 235 236 // ---------------------- TSD ---------------- {{{1 237 238 extern "C" void __hwasan_thread_enter() { 239 hwasanThreadList().CreateCurrentThread()->InitRandomState(); 240 } 241 242 extern "C" void __hwasan_thread_exit() { 243 Thread *t = GetCurrentThread(); 244 // Make sure that signal handler can not see a stale current thread pointer. 245 atomic_signal_fence(memory_order_seq_cst); 246 if (t) 247 hwasanThreadList().ReleaseThread(t); 248 } 249 250 #if HWASAN_WITH_INTERCEPTORS 251 static pthread_key_t tsd_key; 252 static bool tsd_key_inited = false; 253 254 void HwasanTSDThreadInit() { 255 if (tsd_key_inited) 256 CHECK_EQ(0, pthread_setspecific(tsd_key, 257 (void *)GetPthreadDestructorIterations())); 258 } 259 260 void HwasanTSDDtor(void *tsd) { 261 uptr iterations = (uptr)tsd; 262 if (iterations > 1) { 263 CHECK_EQ(0, pthread_setspecific(tsd_key, (void *)(iterations - 1))); 264 return; 265 } 266 __hwasan_thread_exit(); 267 } 268 269 void HwasanTSDInit() { 270 CHECK(!tsd_key_inited); 271 tsd_key_inited = true; 272 CHECK_EQ(0, pthread_key_create(&tsd_key, HwasanTSDDtor)); 273 } 274 #else 275 void HwasanTSDInit() {} 276 void HwasanTSDThreadInit() {} 277 #endif 278 279 #if SANITIZER_ANDROID 280 uptr *GetCurrentThreadLongPtr() { 281 return (uptr *)get_android_tls_ptr(); 282 } 283 #else 284 uptr *GetCurrentThreadLongPtr() { 285 return &__hwasan_tls; 286 } 287 #endif 288 289 #if SANITIZER_ANDROID 290 void AndroidTestTlsSlot() { 291 uptr kMagicValue = 0x010203040A0B0C0D; 292 uptr *tls_ptr = GetCurrentThreadLongPtr(); 293 uptr old_value = *tls_ptr; 294 *tls_ptr = kMagicValue; 295 dlerror(); 296 if (*(uptr *)get_android_tls_ptr() != kMagicValue) { 297 Printf( 298 "ERROR: Incompatible version of Android: TLS_SLOT_SANITIZER(6) is used " 299 "for dlerror().\n"); 300 Die(); 301 } 302 *tls_ptr = old_value; 303 } 304 #else 305 void AndroidTestTlsSlot() {} 306 #endif 307 308 Thread *GetCurrentThread() { 309 uptr *ThreadLong = GetCurrentThreadLongPtr(); 310 #if HWASAN_WITH_INTERCEPTORS 311 if (!*ThreadLong) 312 __hwasan_thread_enter(); 313 #endif 314 auto *R = (StackAllocationsRingBuffer *)ThreadLong; 315 return hwasanThreadList().GetThreadByBufferAddress((uptr)(R->Next())); 316 } 317 318 struct AccessInfo { 319 uptr addr; 320 uptr size; 321 bool is_store; 322 bool is_load; 323 bool recover; 324 }; 325 326 static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) { 327 // Access type is passed in a platform dependent way (see below) and encoded 328 // as 0xXY, where X&1 is 1 for store, 0 for load, and X&2 is 1 if the error is 329 // recoverable. Valid values of Y are 0 to 4, which are interpreted as 330 // log2(access_size), and 0xF, which means that access size is passed via 331 // platform dependent register (see below). 332 #if defined(__aarch64__) 333 // Access type is encoded in BRK immediate as 0x900 + 0xXY. For Y == 0xF, 334 // access size is stored in X1 register. Access address is always in X0 335 // register. 336 uptr pc = (uptr)info->si_addr; 337 const unsigned code = ((*(u32 *)pc) >> 5) & 0xffff; 338 if ((code & 0xff00) != 0x900) 339 return AccessInfo{}; // Not ours. 340 341 const bool is_store = code & 0x10; 342 const bool recover = code & 0x20; 343 const uptr addr = uc->uc_mcontext.regs[0]; 344 const unsigned size_log = code & 0xf; 345 if (size_log > 4 && size_log != 0xf) 346 return AccessInfo{}; // Not ours. 347 const uptr size = size_log == 0xf ? uc->uc_mcontext.regs[1] : 1U << size_log; 348 349 #elif defined(__x86_64__) 350 // Access type is encoded in the instruction following INT3 as 351 // NOP DWORD ptr [EAX + 0x40 + 0xXY]. For Y == 0xF, access size is stored in 352 // RSI register. Access address is always in RDI register. 353 uptr pc = (uptr)uc->uc_mcontext.gregs[REG_RIP]; 354 uint8_t *nop = (uint8_t*)pc; 355 if (*nop != 0x0f || *(nop + 1) != 0x1f || *(nop + 2) != 0x40 || 356 *(nop + 3) < 0x40) 357 return AccessInfo{}; // Not ours. 358 const unsigned code = *(nop + 3); 359 360 const bool is_store = code & 0x10; 361 const bool recover = code & 0x20; 362 const uptr addr = uc->uc_mcontext.gregs[REG_RDI]; 363 const unsigned size_log = code & 0xf; 364 if (size_log > 4 && size_log != 0xf) 365 return AccessInfo{}; // Not ours. 366 const uptr size = 367 size_log == 0xf ? uc->uc_mcontext.gregs[REG_RSI] : 1U << size_log; 368 369 #else 370 # error Unsupported architecture 371 #endif 372 373 return AccessInfo{addr, size, is_store, !is_store, recover}; 374 } 375 376 static void HandleTagMismatch(AccessInfo ai, uptr pc, uptr frame, 377 ucontext_t *uc, uptr *registers_frame = nullptr) { 378 InternalMmapVector<BufferedStackTrace> stack_buffer(1); 379 BufferedStackTrace *stack = stack_buffer.data(); 380 stack->Reset(); 381 stack->Unwind(pc, frame, uc, common_flags()->fast_unwind_on_fatal); 382 383 // The second stack frame contains the failure __hwasan_check function, as 384 // we have a stack frame for the registers saved in __hwasan_tag_mismatch that 385 // we wish to ignore. This (currently) only occurs on AArch64, as x64 386 // implementations use SIGTRAP to implement the failure, and thus do not go 387 // through the stack saver. 388 if (registers_frame && stack->trace && stack->size > 0) { 389 stack->trace++; 390 stack->size--; 391 } 392 393 bool fatal = flags()->halt_on_error || !ai.recover; 394 ReportTagMismatch(stack, ai.addr, ai.size, ai.is_store, fatal, 395 registers_frame); 396 } 397 398 static bool HwasanOnSIGTRAP(int signo, siginfo_t *info, ucontext_t *uc) { 399 AccessInfo ai = GetAccessInfo(info, uc); 400 if (!ai.is_store && !ai.is_load) 401 return false; 402 403 SignalContext sig{info, uc}; 404 HandleTagMismatch(ai, StackTrace::GetNextInstructionPc(sig.pc), sig.bp, uc); 405 406 #if defined(__aarch64__) 407 uc->uc_mcontext.pc += 4; 408 #elif defined(__x86_64__) 409 #else 410 # error Unsupported architecture 411 #endif 412 return true; 413 } 414 415 // Entry point stub for interoperability between __hwasan_tag_mismatch (ASM) and 416 // the rest of the mismatch handling code (C++). 417 extern "C" void __hwasan_tag_mismatch_stub(uptr addr, uptr access_info, 418 uptr *registers_frame) { 419 AccessInfo ai; 420 ai.is_store = access_info & 0x10; 421 ai.recover = false; 422 ai.addr = addr; 423 ai.size = 1 << (access_info & 0xf); 424 425 HandleTagMismatch(ai, (uptr)__builtin_return_address(0), 426 (uptr)__builtin_frame_address(0), nullptr, registers_frame); 427 __builtin_unreachable(); 428 } 429 430 static void OnStackUnwind(const SignalContext &sig, const void *, 431 BufferedStackTrace *stack) { 432 stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context, 433 common_flags()->fast_unwind_on_fatal); 434 } 435 436 void HwasanOnDeadlySignal(int signo, void *info, void *context) { 437 // Probably a tag mismatch. 438 if (signo == SIGTRAP) 439 if (HwasanOnSIGTRAP(signo, (siginfo_t *)info, (ucontext_t*)context)) 440 return; 441 442 HandleDeadlySignal(info, context, GetTid(), &OnStackUnwind, nullptr); 443 } 444 445 446 } // namespace __hwasan 447 448 #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD 449