168d75effSDimitry Andric //===-- sanitizer_common_libcdep.cpp --------------------------------------===// 268d75effSDimitry Andric // 368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 668d75effSDimitry Andric // 768d75effSDimitry Andric //===----------------------------------------------------------------------===// 868d75effSDimitry Andric // 968d75effSDimitry Andric // This file is shared between AddressSanitizer and ThreadSanitizer 1068d75effSDimitry Andric // run-time libraries. 1168d75effSDimitry Andric //===----------------------------------------------------------------------===// 1268d75effSDimitry Andric 130eae32dcSDimitry Andric #include "sanitizer_allocator.h" 1468d75effSDimitry Andric #include "sanitizer_allocator_interface.h" 1568d75effSDimitry Andric #include "sanitizer_common.h" 1668d75effSDimitry Andric #include "sanitizer_flags.h" 1781ad6265SDimitry Andric #include "sanitizer_interface_internal.h" 1868d75effSDimitry Andric #include "sanitizer_procmaps.h" 190eae32dcSDimitry Andric #include "sanitizer_stackdepot.h" 2068d75effSDimitry Andric 2168d75effSDimitry Andric namespace __sanitizer { 2268d75effSDimitry Andric 2368d75effSDimitry Andric #if (SANITIZER_LINUX || SANITIZER_NETBSD) && !SANITIZER_GO 2468d75effSDimitry Andric // Weak default implementation for when sanitizer_stackdepot is not linked in. 25349cc55cSDimitry Andric SANITIZER_WEAK_ATTRIBUTE StackDepotStats StackDepotGetStats() { return {}; } 2668d75effSDimitry Andric 275ffd83dbSDimitry Andric void *BackgroundThread(void *arg) { 280eae32dcSDimitry Andric VPrintf(1, "%s: Started BackgroundThread\n", SanitizerToolName); 2968d75effSDimitry Andric const uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb; 3068d75effSDimitry Andric const uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb; 3168d75effSDimitry Andric const bool heap_profile = common_flags()->heap_profile; 3268d75effSDimitry Andric uptr prev_reported_rss = 0; 3368d75effSDimitry Andric uptr prev_reported_stack_depot_size = 0; 3468d75effSDimitry Andric bool reached_soft_rss_limit = false; 3568d75effSDimitry Andric uptr rss_during_last_reported_profile = 0; 3668d75effSDimitry Andric while (true) { 3768d75effSDimitry Andric SleepForMillis(100); 3868d75effSDimitry Andric const uptr current_rss_mb = GetRSS() >> 20; 3968d75effSDimitry Andric if (Verbosity()) { 4068d75effSDimitry Andric // If RSS has grown 10% since last time, print some information. 4168d75effSDimitry Andric if (prev_reported_rss * 11 / 10 < current_rss_mb) { 4268d75effSDimitry Andric Printf("%s: RSS: %zdMb\n", SanitizerToolName, current_rss_mb); 4368d75effSDimitry Andric prev_reported_rss = current_rss_mb; 4468d75effSDimitry Andric } 4568d75effSDimitry Andric // If stack depot has grown 10% since last time, print it too. 46349cc55cSDimitry Andric StackDepotStats stack_depot_stats = StackDepotGetStats(); 4768d75effSDimitry Andric if (prev_reported_stack_depot_size * 11 / 10 < 48349cc55cSDimitry Andric stack_depot_stats.allocated) { 49349cc55cSDimitry Andric Printf("%s: StackDepot: %zd ids; %zdM allocated\n", SanitizerToolName, 50349cc55cSDimitry Andric stack_depot_stats.n_uniq_ids, stack_depot_stats.allocated >> 20); 51349cc55cSDimitry Andric prev_reported_stack_depot_size = stack_depot_stats.allocated; 5268d75effSDimitry Andric } 5368d75effSDimitry Andric } 5468d75effSDimitry Andric // Check RSS against the limit. 5568d75effSDimitry Andric if (hard_rss_limit_mb && hard_rss_limit_mb < current_rss_mb) { 5668d75effSDimitry Andric Report("%s: hard rss limit exhausted (%zdMb vs %zdMb)\n", 5768d75effSDimitry Andric SanitizerToolName, hard_rss_limit_mb, current_rss_mb); 5868d75effSDimitry Andric DumpProcessMap(); 5968d75effSDimitry Andric Die(); 6068d75effSDimitry Andric } 6168d75effSDimitry Andric if (soft_rss_limit_mb) { 6268d75effSDimitry Andric if (soft_rss_limit_mb < current_rss_mb && !reached_soft_rss_limit) { 6368d75effSDimitry Andric reached_soft_rss_limit = true; 6468d75effSDimitry Andric Report("%s: soft rss limit exhausted (%zdMb vs %zdMb)\n", 6568d75effSDimitry Andric SanitizerToolName, soft_rss_limit_mb, current_rss_mb); 660eae32dcSDimitry Andric SetRssLimitExceeded(true); 6768d75effSDimitry Andric } else if (soft_rss_limit_mb >= current_rss_mb && 6868d75effSDimitry Andric reached_soft_rss_limit) { 6968d75effSDimitry Andric reached_soft_rss_limit = false; 7006c3fb27SDimitry Andric Report("%s: soft rss limit unexhausted (%zdMb vs %zdMb)\n", 7106c3fb27SDimitry Andric SanitizerToolName, soft_rss_limit_mb, current_rss_mb); 720eae32dcSDimitry Andric SetRssLimitExceeded(false); 7368d75effSDimitry Andric } 7468d75effSDimitry Andric } 7568d75effSDimitry Andric if (heap_profile && 7668d75effSDimitry Andric current_rss_mb > rss_during_last_reported_profile * 1.1) { 7768d75effSDimitry Andric Printf("\n\nHEAP PROFILE at RSS %zdMb\n", current_rss_mb); 7868d75effSDimitry Andric __sanitizer_print_memory_profile(90, 20); 7968d75effSDimitry Andric rss_during_last_reported_profile = current_rss_mb; 8068d75effSDimitry Andric } 8168d75effSDimitry Andric } 8268d75effSDimitry Andric } 830eae32dcSDimitry Andric 840eae32dcSDimitry Andric void MaybeStartBackgroudThread() { 850eae32dcSDimitry Andric // Need to implement/test on other platforms. 860eae32dcSDimitry Andric // Start the background thread if one of the rss limits is given. 870eae32dcSDimitry Andric if (!common_flags()->hard_rss_limit_mb && 880eae32dcSDimitry Andric !common_flags()->soft_rss_limit_mb && 890eae32dcSDimitry Andric !common_flags()->heap_profile) return; 90*0fca6ea1SDimitry Andric if (!&internal_pthread_create) { 91*0fca6ea1SDimitry Andric VPrintf(1, "%s: internal_pthread_create undefined\n", SanitizerToolName); 920eae32dcSDimitry Andric return; // Can't spawn the thread anyway. 930eae32dcSDimitry Andric } 940eae32dcSDimitry Andric 950eae32dcSDimitry Andric static bool started = false; 960eae32dcSDimitry Andric if (!started) { 970eae32dcSDimitry Andric started = true; 980eae32dcSDimitry Andric internal_start_thread(BackgroundThread, nullptr); 990eae32dcSDimitry Andric } 1000eae32dcSDimitry Andric } 1010eae32dcSDimitry Andric 1020eae32dcSDimitry Andric # if !SANITIZER_START_BACKGROUND_THREAD_IN_ASAN_INTERNAL 10381ad6265SDimitry Andric # ifdef __clang__ 1040eae32dcSDimitry Andric # pragma clang diagnostic push 1050eae32dcSDimitry Andric // We avoid global-constructors to be sure that globals are ready when 1060eae32dcSDimitry Andric // sanitizers need them. This can happend before global constructors executed. 1070eae32dcSDimitry Andric // Here we don't mind if thread is started on later stages. 1080eae32dcSDimitry Andric # pragma clang diagnostic ignored "-Wglobal-constructors" 10981ad6265SDimitry Andric # endif 1100eae32dcSDimitry Andric static struct BackgroudThreadStarted { 1110eae32dcSDimitry Andric BackgroudThreadStarted() { MaybeStartBackgroudThread(); } 1120eae32dcSDimitry Andric } background_thread_strarter UNUSED; 11381ad6265SDimitry Andric # ifdef __clang__ 1140eae32dcSDimitry Andric # pragma clang diagnostic pop 1150eae32dcSDimitry Andric # endif 11681ad6265SDimitry Andric # endif 1170eae32dcSDimitry Andric #else 1180eae32dcSDimitry Andric void MaybeStartBackgroudThread() {} 11968d75effSDimitry Andric #endif 12068d75effSDimitry Andric 12168d75effSDimitry Andric void WriteToSyslog(const char *msg) { 1225f757f3fSDimitry Andric if (!msg) 1235f757f3fSDimitry Andric return; 124fe6060f1SDimitry Andric InternalScopedString msg_copy; 1255f757f3fSDimitry Andric msg_copy.Append(msg); 126fe6060f1SDimitry Andric const char *p = msg_copy.data(); 12768d75effSDimitry Andric 12868d75effSDimitry Andric // Print one line at a time. 12968d75effSDimitry Andric // syslog, at least on Android, has an implicit message length limit. 130fe6060f1SDimitry Andric while (char* q = internal_strchr(p, '\n')) { 13168d75effSDimitry Andric *q = '\0'; 13268d75effSDimitry Andric WriteOneLineToSyslog(p); 13368d75effSDimitry Andric p = q + 1; 13468d75effSDimitry Andric } 13568d75effSDimitry Andric // Print remaining characters, if there are any. 13668d75effSDimitry Andric // Note that this will add an extra newline at the end. 13768d75effSDimitry Andric // FIXME: buffer extra output. This would need a thread-local buffer, which 13868d75effSDimitry Andric // on Android requires plugging into the tools (ex. ASan's) Thread class. 13968d75effSDimitry Andric if (*p) 14068d75effSDimitry Andric WriteOneLineToSyslog(p); 14168d75effSDimitry Andric } 14268d75effSDimitry Andric 14368d75effSDimitry Andric static void (*sandboxing_callback)(); 14468d75effSDimitry Andric void SetSandboxingCallback(void (*f)()) { 14568d75effSDimitry Andric sandboxing_callback = f; 14668d75effSDimitry Andric } 14768d75effSDimitry Andric 1485ffd83dbSDimitry Andric uptr ReservedAddressRange::InitAligned(uptr size, uptr align, 1495ffd83dbSDimitry Andric const char *name) { 1505ffd83dbSDimitry Andric CHECK(IsPowerOfTwo(align)); 1515ffd83dbSDimitry Andric if (align <= GetPageSizeCached()) 1525ffd83dbSDimitry Andric return Init(size, name); 1535ffd83dbSDimitry Andric uptr start = Init(size + align, name); 1545ffd83dbSDimitry Andric start += align - (start & (align - 1)); 1555ffd83dbSDimitry Andric return start; 1565ffd83dbSDimitry Andric } 1575ffd83dbSDimitry Andric 158fe6060f1SDimitry Andric #if !SANITIZER_FUCHSIA 159e8d8bef9SDimitry Andric 160e8d8bef9SDimitry Andric // Reserve memory range [beg, end]. 161e8d8bef9SDimitry Andric // We need to use inclusive range because end+1 may not be representable. 162e8d8bef9SDimitry Andric void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name, 163e8d8bef9SDimitry Andric bool madvise_shadow) { 164e8d8bef9SDimitry Andric CHECK_EQ((beg % GetMmapGranularity()), 0); 165e8d8bef9SDimitry Andric CHECK_EQ(((end + 1) % GetMmapGranularity()), 0); 166e8d8bef9SDimitry Andric uptr size = end - beg + 1; 167e8d8bef9SDimitry Andric DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb. 168e8d8bef9SDimitry Andric if (madvise_shadow ? !MmapFixedSuperNoReserve(beg, size, name) 169e8d8bef9SDimitry Andric : !MmapFixedNoReserve(beg, size, name)) { 170e8d8bef9SDimitry Andric Report( 171e8d8bef9SDimitry Andric "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. " 172*0fca6ea1SDimitry Andric "Perhaps you're using ulimit -v or ulimit -d\n", 173e8d8bef9SDimitry Andric size); 174e8d8bef9SDimitry Andric Abort(); 175e8d8bef9SDimitry Andric } 176e8d8bef9SDimitry Andric if (madvise_shadow && common_flags()->use_madv_dontdump) 177e8d8bef9SDimitry Andric DontDumpShadowMemory(beg, size); 178e8d8bef9SDimitry Andric } 179e8d8bef9SDimitry Andric 180e8d8bef9SDimitry Andric void ProtectGap(uptr addr, uptr size, uptr zero_base_shadow_start, 181e8d8bef9SDimitry Andric uptr zero_base_max_shadow_start) { 182e8d8bef9SDimitry Andric if (!size) 183e8d8bef9SDimitry Andric return; 184e8d8bef9SDimitry Andric void *res = MmapFixedNoAccess(addr, size, "shadow gap"); 185e8d8bef9SDimitry Andric if (addr == (uptr)res) 186e8d8bef9SDimitry Andric return; 187e8d8bef9SDimitry Andric // A few pages at the start of the address space can not be protected. 188e8d8bef9SDimitry Andric // But we really want to protect as much as possible, to prevent this memory 189e8d8bef9SDimitry Andric // being returned as a result of a non-FIXED mmap(). 190e8d8bef9SDimitry Andric if (addr == zero_base_shadow_start) { 191e8d8bef9SDimitry Andric uptr step = GetMmapGranularity(); 192e8d8bef9SDimitry Andric while (size > step && addr < zero_base_max_shadow_start) { 193e8d8bef9SDimitry Andric addr += step; 194e8d8bef9SDimitry Andric size -= step; 195e8d8bef9SDimitry Andric void *res = MmapFixedNoAccess(addr, size, "shadow gap"); 196e8d8bef9SDimitry Andric if (addr == (uptr)res) 197e8d8bef9SDimitry Andric return; 198e8d8bef9SDimitry Andric } 199e8d8bef9SDimitry Andric } 200e8d8bef9SDimitry Andric 201e8d8bef9SDimitry Andric Report( 202e8d8bef9SDimitry Andric "ERROR: Failed to protect the shadow gap. " 203e8d8bef9SDimitry Andric "%s cannot proceed correctly. ABORTING.\n", 204e8d8bef9SDimitry Andric SanitizerToolName); 205e8d8bef9SDimitry Andric DumpProcessMap(); 206e8d8bef9SDimitry Andric Die(); 207e8d8bef9SDimitry Andric } 208e8d8bef9SDimitry Andric 209fe6060f1SDimitry Andric #endif // !SANITIZER_FUCHSIA 210e8d8bef9SDimitry Andric 2110eae32dcSDimitry Andric #if !SANITIZER_WINDOWS && !SANITIZER_GO 2120eae32dcSDimitry Andric // Weak default implementation for when sanitizer_stackdepot is not linked in. 2130eae32dcSDimitry Andric SANITIZER_WEAK_ATTRIBUTE void StackDepotStopBackgroundThread() {} 2140eae32dcSDimitry Andric static void StopStackDepotBackgroundThread() { 2150eae32dcSDimitry Andric StackDepotStopBackgroundThread(); 2160eae32dcSDimitry Andric } 2170eae32dcSDimitry Andric #else 2180eae32dcSDimitry Andric // SANITIZER_WEAK_ATTRIBUTE is unsupported. 2190eae32dcSDimitry Andric static void StopStackDepotBackgroundThread() {} 2200eae32dcSDimitry Andric #endif 2210eae32dcSDimitry Andric 22268d75effSDimitry Andric } // namespace __sanitizer 22368d75effSDimitry Andric 22468d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_sandbox_on_notify, 22568d75effSDimitry Andric __sanitizer_sandbox_arguments *args) { 2260eae32dcSDimitry Andric __sanitizer::StopStackDepotBackgroundThread(); 22768d75effSDimitry Andric __sanitizer::PlatformPrepareForSandboxing(args); 22868d75effSDimitry Andric if (__sanitizer::sandboxing_callback) 22968d75effSDimitry Andric __sanitizer::sandboxing_callback(); 23068d75effSDimitry Andric } 231