13cab2bb3Spatrick //===-- sanitizer_common_libcdep.cpp --------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is shared between AddressSanitizer and ThreadSanitizer
103cab2bb3Spatrick // run-time libraries.
113cab2bb3Spatrick //===----------------------------------------------------------------------===//
123cab2bb3Spatrick
13*810390e3Srobert #include "sanitizer_allocator.h"
143cab2bb3Spatrick #include "sanitizer_allocator_interface.h"
153cab2bb3Spatrick #include "sanitizer_common.h"
163cab2bb3Spatrick #include "sanitizer_flags.h"
17*810390e3Srobert #include "sanitizer_interface_internal.h"
183cab2bb3Spatrick #include "sanitizer_procmaps.h"
19*810390e3Srobert #include "sanitizer_stackdepot.h"
203cab2bb3Spatrick
213cab2bb3Spatrick namespace __sanitizer {
223cab2bb3Spatrick
233cab2bb3Spatrick #if (SANITIZER_LINUX || SANITIZER_NETBSD) && !SANITIZER_GO
243cab2bb3Spatrick // Weak default implementation for when sanitizer_stackdepot is not linked in.
StackDepotGetStats()25*810390e3Srobert SANITIZER_WEAK_ATTRIBUTE StackDepotStats StackDepotGetStats() { return {}; }
263cab2bb3Spatrick
BackgroundThread(void * arg)271f9cb04fSpatrick void *BackgroundThread(void *arg) {
28*810390e3Srobert VPrintf(1, "%s: Started BackgroundThread\n", SanitizerToolName);
293cab2bb3Spatrick const uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb;
303cab2bb3Spatrick const uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb;
313cab2bb3Spatrick const bool heap_profile = common_flags()->heap_profile;
323cab2bb3Spatrick uptr prev_reported_rss = 0;
333cab2bb3Spatrick uptr prev_reported_stack_depot_size = 0;
343cab2bb3Spatrick bool reached_soft_rss_limit = false;
353cab2bb3Spatrick uptr rss_during_last_reported_profile = 0;
363cab2bb3Spatrick while (true) {
373cab2bb3Spatrick SleepForMillis(100);
383cab2bb3Spatrick const uptr current_rss_mb = GetRSS() >> 20;
393cab2bb3Spatrick if (Verbosity()) {
403cab2bb3Spatrick // If RSS has grown 10% since last time, print some information.
413cab2bb3Spatrick if (prev_reported_rss * 11 / 10 < current_rss_mb) {
423cab2bb3Spatrick Printf("%s: RSS: %zdMb\n", SanitizerToolName, current_rss_mb);
433cab2bb3Spatrick prev_reported_rss = current_rss_mb;
443cab2bb3Spatrick }
453cab2bb3Spatrick // If stack depot has grown 10% since last time, print it too.
46*810390e3Srobert StackDepotStats stack_depot_stats = StackDepotGetStats();
473cab2bb3Spatrick if (prev_reported_stack_depot_size * 11 / 10 <
48*810390e3Srobert stack_depot_stats.allocated) {
49*810390e3Srobert Printf("%s: StackDepot: %zd ids; %zdM allocated\n", SanitizerToolName,
50*810390e3Srobert stack_depot_stats.n_uniq_ids, stack_depot_stats.allocated >> 20);
51*810390e3Srobert prev_reported_stack_depot_size = stack_depot_stats.allocated;
523cab2bb3Spatrick }
533cab2bb3Spatrick }
543cab2bb3Spatrick // Check RSS against the limit.
553cab2bb3Spatrick if (hard_rss_limit_mb && hard_rss_limit_mb < current_rss_mb) {
563cab2bb3Spatrick Report("%s: hard rss limit exhausted (%zdMb vs %zdMb)\n",
573cab2bb3Spatrick SanitizerToolName, hard_rss_limit_mb, current_rss_mb);
583cab2bb3Spatrick DumpProcessMap();
593cab2bb3Spatrick Die();
603cab2bb3Spatrick }
613cab2bb3Spatrick if (soft_rss_limit_mb) {
623cab2bb3Spatrick if (soft_rss_limit_mb < current_rss_mb && !reached_soft_rss_limit) {
633cab2bb3Spatrick reached_soft_rss_limit = true;
643cab2bb3Spatrick Report("%s: soft rss limit exhausted (%zdMb vs %zdMb)\n",
653cab2bb3Spatrick SanitizerToolName, soft_rss_limit_mb, current_rss_mb);
66*810390e3Srobert SetRssLimitExceeded(true);
673cab2bb3Spatrick } else if (soft_rss_limit_mb >= current_rss_mb &&
683cab2bb3Spatrick reached_soft_rss_limit) {
693cab2bb3Spatrick reached_soft_rss_limit = false;
70*810390e3Srobert SetRssLimitExceeded(false);
713cab2bb3Spatrick }
723cab2bb3Spatrick }
733cab2bb3Spatrick if (heap_profile &&
743cab2bb3Spatrick current_rss_mb > rss_during_last_reported_profile * 1.1) {
753cab2bb3Spatrick Printf("\n\nHEAP PROFILE at RSS %zdMb\n", current_rss_mb);
763cab2bb3Spatrick __sanitizer_print_memory_profile(90, 20);
773cab2bb3Spatrick rss_during_last_reported_profile = current_rss_mb;
783cab2bb3Spatrick }
793cab2bb3Spatrick }
803cab2bb3Spatrick }
81*810390e3Srobert
MaybeStartBackgroudThread()82*810390e3Srobert void MaybeStartBackgroudThread() {
83*810390e3Srobert // Need to implement/test on other platforms.
84*810390e3Srobert // Start the background thread if one of the rss limits is given.
85*810390e3Srobert if (!common_flags()->hard_rss_limit_mb &&
86*810390e3Srobert !common_flags()->soft_rss_limit_mb &&
87*810390e3Srobert !common_flags()->heap_profile) return;
88*810390e3Srobert if (!&real_pthread_create) {
89*810390e3Srobert VPrintf(1, "%s: real_pthread_create undefined\n", SanitizerToolName);
90*810390e3Srobert return; // Can't spawn the thread anyway.
91*810390e3Srobert }
92*810390e3Srobert
93*810390e3Srobert static bool started = false;
94*810390e3Srobert if (!started) {
95*810390e3Srobert started = true;
96*810390e3Srobert internal_start_thread(BackgroundThread, nullptr);
97*810390e3Srobert }
98*810390e3Srobert }
99*810390e3Srobert
100*810390e3Srobert # if !SANITIZER_START_BACKGROUND_THREAD_IN_ASAN_INTERNAL
101*810390e3Srobert # ifdef __clang__
102*810390e3Srobert # pragma clang diagnostic push
103*810390e3Srobert // We avoid global-constructors to be sure that globals are ready when
104*810390e3Srobert // sanitizers need them. This can happend before global constructors executed.
105*810390e3Srobert // Here we don't mind if thread is started on later stages.
106*810390e3Srobert # pragma clang diagnostic ignored "-Wglobal-constructors"
107*810390e3Srobert # endif
108*810390e3Srobert static struct BackgroudThreadStarted {
BackgroudThreadStarted__sanitizer::BackgroudThreadStarted109*810390e3Srobert BackgroudThreadStarted() { MaybeStartBackgroudThread(); }
110*810390e3Srobert } background_thread_strarter UNUSED;
111*810390e3Srobert # ifdef __clang__
112*810390e3Srobert # pragma clang diagnostic pop
113*810390e3Srobert # endif
114*810390e3Srobert # endif
115*810390e3Srobert #else
116*810390e3Srobert void MaybeStartBackgroudThread() {}
1173cab2bb3Spatrick #endif
1183cab2bb3Spatrick
WriteToSyslog(const char * msg)1193cab2bb3Spatrick void WriteToSyslog(const char *msg) {
120d89ec533Spatrick InternalScopedString msg_copy;
1213cab2bb3Spatrick msg_copy.append("%s", msg);
122d89ec533Spatrick const char *p = msg_copy.data();
1233cab2bb3Spatrick
1243cab2bb3Spatrick // Print one line at a time.
1253cab2bb3Spatrick // syslog, at least on Android, has an implicit message length limit.
126d89ec533Spatrick while (char* q = internal_strchr(p, '\n')) {
1273cab2bb3Spatrick *q = '\0';
1283cab2bb3Spatrick WriteOneLineToSyslog(p);
1293cab2bb3Spatrick p = q + 1;
1303cab2bb3Spatrick }
1313cab2bb3Spatrick // Print remaining characters, if there are any.
1323cab2bb3Spatrick // Note that this will add an extra newline at the end.
1333cab2bb3Spatrick // FIXME: buffer extra output. This would need a thread-local buffer, which
1343cab2bb3Spatrick // on Android requires plugging into the tools (ex. ASan's) Thread class.
1353cab2bb3Spatrick if (*p)
1363cab2bb3Spatrick WriteOneLineToSyslog(p);
1373cab2bb3Spatrick }
1383cab2bb3Spatrick
1393cab2bb3Spatrick static void (*sandboxing_callback)();
SetSandboxingCallback(void (* f)())1403cab2bb3Spatrick void SetSandboxingCallback(void (*f)()) {
1413cab2bb3Spatrick sandboxing_callback = f;
1423cab2bb3Spatrick }
1433cab2bb3Spatrick
InitAligned(uptr size,uptr align,const char * name)1441f9cb04fSpatrick uptr ReservedAddressRange::InitAligned(uptr size, uptr align,
1451f9cb04fSpatrick const char *name) {
1461f9cb04fSpatrick CHECK(IsPowerOfTwo(align));
1471f9cb04fSpatrick if (align <= GetPageSizeCached())
1481f9cb04fSpatrick return Init(size, name);
1491f9cb04fSpatrick uptr start = Init(size + align, name);
1501f9cb04fSpatrick start += align - (start & (align - 1));
1511f9cb04fSpatrick return start;
1521f9cb04fSpatrick }
1531f9cb04fSpatrick
154d89ec533Spatrick #if !SANITIZER_FUCHSIA
155d89ec533Spatrick
156d89ec533Spatrick // Reserve memory range [beg, end].
157d89ec533Spatrick // We need to use inclusive range because end+1 may not be representable.
ReserveShadowMemoryRange(uptr beg,uptr end,const char * name,bool madvise_shadow)158d89ec533Spatrick void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name,
159d89ec533Spatrick bool madvise_shadow) {
160d89ec533Spatrick CHECK_EQ((beg % GetMmapGranularity()), 0);
161d89ec533Spatrick CHECK_EQ(((end + 1) % GetMmapGranularity()), 0);
162d89ec533Spatrick uptr size = end - beg + 1;
163d89ec533Spatrick DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb.
164d89ec533Spatrick if (madvise_shadow ? !MmapFixedSuperNoReserve(beg, size, name)
165d89ec533Spatrick : !MmapFixedNoReserve(beg, size, name)) {
166d89ec533Spatrick Report(
167d89ec533Spatrick "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "
168d89ec533Spatrick "Perhaps you're using ulimit -v\n",
169d89ec533Spatrick size);
170d89ec533Spatrick Abort();
171d89ec533Spatrick }
172d89ec533Spatrick if (madvise_shadow && common_flags()->use_madv_dontdump)
173d89ec533Spatrick DontDumpShadowMemory(beg, size);
174d89ec533Spatrick }
175d89ec533Spatrick
ProtectGap(uptr addr,uptr size,uptr zero_base_shadow_start,uptr zero_base_max_shadow_start)176d89ec533Spatrick void ProtectGap(uptr addr, uptr size, uptr zero_base_shadow_start,
177d89ec533Spatrick uptr zero_base_max_shadow_start) {
178d89ec533Spatrick if (!size)
179d89ec533Spatrick return;
180d89ec533Spatrick void *res = MmapFixedNoAccess(addr, size, "shadow gap");
181d89ec533Spatrick if (addr == (uptr)res)
182d89ec533Spatrick return;
183d89ec533Spatrick // A few pages at the start of the address space can not be protected.
184d89ec533Spatrick // But we really want to protect as much as possible, to prevent this memory
185d89ec533Spatrick // being returned as a result of a non-FIXED mmap().
186d89ec533Spatrick if (addr == zero_base_shadow_start) {
187d89ec533Spatrick uptr step = GetMmapGranularity();
188d89ec533Spatrick while (size > step && addr < zero_base_max_shadow_start) {
189d89ec533Spatrick addr += step;
190d89ec533Spatrick size -= step;
191d89ec533Spatrick void *res = MmapFixedNoAccess(addr, size, "shadow gap");
192d89ec533Spatrick if (addr == (uptr)res)
193d89ec533Spatrick return;
194d89ec533Spatrick }
195d89ec533Spatrick }
196d89ec533Spatrick
197d89ec533Spatrick Report(
198d89ec533Spatrick "ERROR: Failed to protect the shadow gap. "
199d89ec533Spatrick "%s cannot proceed correctly. ABORTING.\n",
200d89ec533Spatrick SanitizerToolName);
201d89ec533Spatrick DumpProcessMap();
202d89ec533Spatrick Die();
203d89ec533Spatrick }
204d89ec533Spatrick
205d89ec533Spatrick #endif // !SANITIZER_FUCHSIA
206d89ec533Spatrick
207*810390e3Srobert #if !SANITIZER_WINDOWS && !SANITIZER_GO
208*810390e3Srobert // Weak default implementation for when sanitizer_stackdepot is not linked in.
StackDepotStopBackgroundThread()209*810390e3Srobert SANITIZER_WEAK_ATTRIBUTE void StackDepotStopBackgroundThread() {}
StopStackDepotBackgroundThread()210*810390e3Srobert static void StopStackDepotBackgroundThread() {
211*810390e3Srobert StackDepotStopBackgroundThread();
212*810390e3Srobert }
213*810390e3Srobert #else
214*810390e3Srobert // SANITIZER_WEAK_ATTRIBUTE is unsupported.
StopStackDepotBackgroundThread()215*810390e3Srobert static void StopStackDepotBackgroundThread() {}
216*810390e3Srobert #endif
217*810390e3Srobert
2183cab2bb3Spatrick } // namespace __sanitizer
2193cab2bb3Spatrick
SANITIZER_INTERFACE_WEAK_DEF(void,__sanitizer_sandbox_on_notify,__sanitizer_sandbox_arguments * args)2203cab2bb3Spatrick SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_sandbox_on_notify,
2213cab2bb3Spatrick __sanitizer_sandbox_arguments *args) {
222*810390e3Srobert __sanitizer::StopStackDepotBackgroundThread();
2233cab2bb3Spatrick __sanitizer::PlatformPrepareForSandboxing(args);
2243cab2bb3Spatrick if (__sanitizer::sandboxing_callback)
2253cab2bb3Spatrick __sanitizer::sandboxing_callback();
2263cab2bb3Spatrick }
227