1 //=-- lsan_common_linux.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 LeakSanitizer.
10 // Implementation of common leak checking functionality. Linux/NetBSD-specific
11 // code.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "sanitizer_common/sanitizer_platform.h"
16 #include "lsan_common.h"
17 
18 #if CAN_SANITIZE_LEAKS && (SANITIZER_LINUX || SANITIZER_NETBSD)
19 #include <link.h>
20 
21 #include "sanitizer_common/sanitizer_common.h"
22 #include "sanitizer_common/sanitizer_flags.h"
23 #include "sanitizer_common/sanitizer_getauxval.h"
24 #include "sanitizer_common/sanitizer_linux.h"
25 #include "sanitizer_common/sanitizer_stackdepot.h"
26 
27 namespace __lsan {
28 
29 static const char kLinkerName[] = "ld";
30 
31 static char linker_placeholder[sizeof(LoadedModule)] ALIGNED(64);
32 static LoadedModule *linker = nullptr;
33 
34 static bool IsLinker(const LoadedModule& module) {
35 #if SANITIZER_USE_GETAUXVAL
36   return module.base_address() == getauxval(AT_BASE);
37 #else
38   return LibraryNameIs(module.full_name(), kLinkerName);
39 #endif  // SANITIZER_USE_GETAUXVAL
40 }
41 
42 __attribute__((tls_model("initial-exec")))
43 THREADLOCAL int disable_counter;
44 bool DisabledInThisThread() {
45 #if SANITIZER_ANDROID
46   // LSAN is only enabled with Android-S and up.
47   if (!HAS_ANDROID_THREAD_PROPERTIES_API)
48     return true;
49 #endif
50   return disable_counter > 0;
51 }
52 void DisableInThisThread() {
53 #if SANITIZER_ANDROID
54   // LSAN is only enabled with Android-S and up.
55   if (!HAS_ANDROID_THREAD_PROPERTIES_API)
56     return;
57 #endif
58   disable_counter++;
59 }
60 void EnableInThisThread() {
61 #if SANITIZER_ANDROID
62   // LSAN is only enabled with Android-S and up.
63   if (!HAS_ANDROID_THREAD_PROPERTIES_API)
64     return;
65 #endif
66   if (disable_counter == 0) {
67     DisableCounterUnderflow();
68   }
69   disable_counter--;
70 }
71 
72 void InitializePlatformSpecificModules() {
73   ListOfModules modules;
74   modules.init();
75   for (LoadedModule &module : modules) {
76     if (!IsLinker(module))
77       continue;
78     if (linker == nullptr) {
79       linker = reinterpret_cast<LoadedModule *>(linker_placeholder);
80       *linker = module;
81       module = LoadedModule();
82     } else {
83       VReport(1, "LeakSanitizer: Multiple modules match \"%s\". "
84               "TLS and other allocations originating from linker might be "
85               "falsely reported as leaks.\n", kLinkerName);
86       linker->clear();
87       linker = nullptr;
88       return;
89     }
90   }
91   if (linker == nullptr) {
92     VReport(1, "LeakSanitizer: Dynamic linker not found. TLS and other "
93                "allocations originating from linker might be falsely reported "
94                 "as leaks.\n");
95   }
96 }
97 
98 static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size,
99                                         void *data) {
100   Frontier *frontier = reinterpret_cast<Frontier *>(data);
101   for (uptr j = 0; j < info->dlpi_phnum; j++) {
102     const ElfW(Phdr) *phdr = &(info->dlpi_phdr[j]);
103     // We're looking for .data and .bss sections, which reside in writeable,
104     // loadable segments.
105     if (!(phdr->p_flags & PF_W) || (phdr->p_type != PT_LOAD) ||
106         (phdr->p_memsz == 0))
107       continue;
108     uptr begin = info->dlpi_addr + phdr->p_vaddr;
109     uptr end = begin + phdr->p_memsz;
110     ScanGlobalRange(begin, end, frontier);
111   }
112   return 0;
113 }
114 
115 // Scans global variables for heap pointers.
116 void ProcessGlobalRegions(Frontier *frontier) {
117   if (!flags()->use_globals) {
118 #if SANITIZER_ANDROID
119     // There are known malloc'ed global variables from libc[++] on Android.
120     // If use_globals is turnt off, we could see leaks.
121     // Issue a warning in case users turn it off by accident.
122     Report("use_globals=0 on Android could lead to false reports.");
123 #endif
124     return;
125   }
126   dl_iterate_phdr(ProcessGlobalRegionsCallback, frontier);
127 }
128 
129 LoadedModule *GetLinker() { return linker; }
130 
131 void ProcessPlatformSpecificAllocations(Frontier *frontier) {}
132 
133 struct DoStopTheWorldParam {
134   StopTheWorldCallback callback;
135   void *argument;
136 };
137 
138 // While calling Die() here is undefined behavior and can potentially
139 // cause race conditions, it isn't possible to intercept exit on linux,
140 // so we have no choice but to call Die() from the atexit handler.
141 void HandleLeaks() {
142   if (common_flags()->exitcode) Die();
143 }
144 
145 static int LockStuffAndStopTheWorldCallback(struct dl_phdr_info *info,
146                                             size_t size, void *data) {
147   LockThreadRegistry();
148   LockAllocator();
149   DoStopTheWorldParam *param = reinterpret_cast<DoStopTheWorldParam *>(data);
150   StopTheWorld(param->callback, param->argument);
151   UnlockAllocator();
152   UnlockThreadRegistry();
153   return 1;
154 }
155 
156 // LSan calls dl_iterate_phdr() from the tracer task. This may deadlock: if one
157 // of the threads is frozen while holding the libdl lock, the tracer will hang
158 // in dl_iterate_phdr() forever.
159 // Luckily, (a) the lock is reentrant and (b) libc can't distinguish between the
160 // tracer task and the thread that spawned it. Thus, if we run the tracer task
161 // while holding the libdl lock in the parent thread, we can safely reenter it
162 // in the tracer. The solution is to run stoptheworld from a dl_iterate_phdr()
163 // callback in the parent thread.
164 void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
165                               CheckForLeaksParam *argument) {
166   DoStopTheWorldParam param = {callback, argument};
167   dl_iterate_phdr(LockStuffAndStopTheWorldCallback, &param);
168 }
169 
170 } // namespace __lsan
171 
172 #endif
173