1 //===-- asan_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 AddressSanitizer, an address sanity checker.
10 //
11 // Linux-specific details.
12 //===----------------------------------------------------------------------===//
13
14 #include "sanitizer_common/sanitizer_platform.h"
15 #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
16 SANITIZER_SOLARIS || SANITIZER_HAIKU
17
18 # if SANITIZER_HAIKU
19 # define _DEFAULT_SOURCE
20 # endif
21
22 # include <dlfcn.h>
23 # include <fcntl.h>
24 # include <limits.h>
25 # include <pthread.h>
26 # include <stdio.h>
27 # include <sys/mman.h>
28 # include <sys/resource.h>
29 # if !SANITIZER_HAIKU
30 # include <sys/syscall.h>
31 # endif
32 # include <sys/time.h>
33 # include <sys/types.h>
34 # include <unistd.h>
35 # include <unwind.h>
36
37 # include "asan_interceptors.h"
38 # include "asan_internal.h"
39 # include "asan_premap_shadow.h"
40 # include "asan_thread.h"
41 # include "sanitizer_common/sanitizer_flags.h"
42 # include "sanitizer_common/sanitizer_hash.h"
43 # include "sanitizer_common/sanitizer_libc.h"
44 # include "sanitizer_common/sanitizer_procmaps.h"
45
46 # if SANITIZER_FREEBSD || SANITIZER_HAIKU
47 # include <sys/link_elf.h>
48 # endif
49
50 # if SANITIZER_LINUX
51 # include <sys/personality.h>
52 # endif
53
54 # if SANITIZER_SOLARIS
55 # include <link.h>
56 # endif
57
58 # if SANITIZER_ANDROID || SANITIZER_FREEBSD || SANITIZER_SOLARIS
59 # include <ucontext.h>
60 # elif SANITIZER_NETBSD
61 # include <link_elf.h>
62 # include <ucontext.h>
63 # elif SANITIZER_HAIKU
64 extern "C" void *_DYNAMIC;
65 # else
66 # include <link.h>
67 # include <sys/ucontext.h>
68 # endif
69
70 typedef enum {
71 ASAN_RT_VERSION_UNDEFINED = 0,
72 ASAN_RT_VERSION_DYNAMIC,
73 ASAN_RT_VERSION_STATIC,
74 } asan_rt_version_t;
75
76 // FIXME: perhaps also store abi version here?
77 extern "C" {
78 SANITIZER_INTERFACE_ATTRIBUTE
79 asan_rt_version_t __asan_rt_version;
80 }
81
82 namespace __asan {
83
InitializePlatformInterceptors()84 void InitializePlatformInterceptors() {}
InitializePlatformExceptionHandlers()85 void InitializePlatformExceptionHandlers() {}
IsSystemHeapAddress(uptr addr)86 bool IsSystemHeapAddress(uptr addr) { return false; }
87
88 # if ASAN_PREMAP_SHADOW
FindPremappedShadowStart(uptr shadow_size_bytes)89 uptr FindPremappedShadowStart(uptr shadow_size_bytes) {
90 uptr granularity = GetMmapGranularity();
91 uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow);
92 uptr premap_shadow_size = PremapShadowSize();
93 uptr shadow_size = RoundUpTo(shadow_size_bytes, granularity);
94 // We may have mapped too much. Release extra memory.
95 UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size);
96 return shadow_start;
97 }
98 # endif
99
FindDynamicShadowStart()100 uptr FindDynamicShadowStart() {
101 uptr shadow_size_bytes = MemToShadowSize(kHighMemEnd);
102 # if ASAN_PREMAP_SHADOW
103 if (!PremapShadowFailed())
104 return FindPremappedShadowStart(shadow_size_bytes);
105 # endif
106
107 return MapDynamicShadow(shadow_size_bytes, ASAN_SHADOW_SCALE,
108 /*min_shadow_base_alignment*/ 0, kHighMemEnd,
109 GetMmapGranularity());
110 }
111
AsanApplyToGlobals(globals_op_fptr op,const void * needle)112 void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
113 UNIMPLEMENTED();
114 }
115
FlushUnneededASanShadowMemory(uptr p,uptr size)116 void FlushUnneededASanShadowMemory(uptr p, uptr size) {
117 // Since asan's mapping is compacting, the shadow chunk may be
118 // not page-aligned, so we only flush the page-aligned portion.
119 ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size));
120 }
121
TryReExecWithoutASLR()122 void TryReExecWithoutASLR() {
123 # if SANITIZER_LINUX
124 // ASLR personality check.
125 // Caution: 'personality' is sometimes forbidden by sandboxes, so only call
126 // this function as a last resort (when the memory mapping is incompatible
127 // and ASan would fail anyway).
128 int old_personality = personality(0xffffffff);
129 if (old_personality == -1) {
130 VReport(1, "WARNING: unable to run personality check.\n");
131 return;
132 }
133
134 bool aslr_on = (old_personality & ADDR_NO_RANDOMIZE) == 0;
135
136 if (aslr_on) {
137 // Disable ASLR if the memory layout was incompatible.
138 // Alternatively, we could just keep re-execing until we get lucky
139 // with a compatible randomized layout, but the risk is that if it's
140 // not an ASLR-related issue, we will be stuck in an infinite loop of
141 // re-execing (unless we change ReExec to pass a parameter of the
142 // number of retries allowed.)
143 VReport(1,
144 "WARNING: AddressSanitizer: memory layout is incompatible, "
145 "possibly due to high-entropy ASLR.\n"
146 "Re-execing with fixed virtual address space.\n"
147 "N.B. reducing ASLR entropy is preferable.\n");
148 CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);
149
150 ReExec();
151 }
152 # endif
153 }
154
155 # if SANITIZER_ANDROID
156 // FIXME: should we do anything for Android?
AsanCheckDynamicRTPrereqs()157 void AsanCheckDynamicRTPrereqs() {}
AsanCheckIncompatibleRT()158 void AsanCheckIncompatibleRT() {}
159 # else
FindFirstDSOCallback(struct dl_phdr_info * info,size_t size,void * data)160 static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
161 void *data) {
162 VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n", info->dlpi_name,
163 (void *)info->dlpi_addr);
164
165 const char **name = (const char **)data;
166
167 // Ignore first entry (the main program)
168 if (!*name) {
169 *name = "";
170 return 0;
171 }
172
173 # if SANITIZER_HAIKU
174 if (!info->dlpi_name[0] ||
175 internal_strncmp(info->dlpi_name, "/boot/system/runtime_loader",
176 sizeof("/boot/system/runtime_loader") - 1) == 0)
177 return 0;
178 # endif
179 # if SANITIZER_LINUX
180 // Ignore vDSO. glibc versions earlier than 2.15 (and some patched
181 // by distributors) return an empty name for the vDSO entry, so
182 // detect this as well.
183 if (!info->dlpi_name[0] ||
184 internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0)
185 return 0;
186 # endif
187 # if SANITIZER_FREEBSD
188 // Ignore vDSO.
189 if (internal_strcmp(info->dlpi_name, "[vdso]") == 0)
190 return 0;
191 # endif
192
193 *name = info->dlpi_name;
194 return 1;
195 }
196
IsDynamicRTName(const char * libname)197 static bool IsDynamicRTName(const char *libname) {
198 return internal_strstr(libname, "libclang_rt.asan") ||
199 internal_strstr(libname, "libasan.so");
200 }
201
ReportIncompatibleRT()202 static void ReportIncompatibleRT() {
203 Report("Your application is linked against incompatible ASan runtimes.\n");
204 Die();
205 }
206
AsanCheckDynamicRTPrereqs()207 void AsanCheckDynamicRTPrereqs() {
208 if (!ASAN_DYNAMIC || !flags()->verify_asan_link_order)
209 return;
210
211 // Ensure that dynamic RT is the first DSO in the list
212 const char *first_dso_name = nullptr;
213 dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name);
214 if (first_dso_name && first_dso_name[0] && !IsDynamicRTName(first_dso_name)) {
215 Report(
216 "ASan runtime does not come first in initial library list; "
217 "you should either link runtime to your application or "
218 "manually preload it with LD_PRELOAD.\n");
219 Die();
220 }
221 }
222
AsanCheckIncompatibleRT()223 void AsanCheckIncompatibleRT() {
224 if (ASAN_DYNAMIC) {
225 if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
226 __asan_rt_version = ASAN_RT_VERSION_DYNAMIC;
227 } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) {
228 ReportIncompatibleRT();
229 }
230 } else {
231 if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
232 // Ensure that dynamic runtime is not present. We should detect it
233 // as early as possible, otherwise ASan interceptors could bind to
234 // the functions in dynamic ASan runtime instead of the functions in
235 // system libraries, causing crashes later in ASan initialization.
236 MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
237 char filename[PATH_MAX];
238 MemoryMappedSegment segment(filename, sizeof(filename));
239 while (proc_maps.Next(&segment)) {
240 if (IsDynamicRTName(segment.filename)) {
241 ReportIncompatibleRT();
242 }
243 }
244 __asan_rt_version = ASAN_RT_VERSION_STATIC;
245 } else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) {
246 ReportIncompatibleRT();
247 }
248 }
249 }
250 # endif // SANITIZER_ANDROID
251
252 # if ASAN_INTERCEPT_SWAPCONTEXT
253 constexpr u32 kAsanContextStackFlagsMagic = 0x51260eea;
254
HashContextStack(const ucontext_t & ucp)255 static int HashContextStack(const ucontext_t &ucp) {
256 MurMur2Hash64Builder hash(kAsanContextStackFlagsMagic);
257 hash.add(reinterpret_cast<uptr>(ucp.uc_stack.ss_sp));
258 hash.add(ucp.uc_stack.ss_size);
259 return static_cast<int>(hash.get());
260 }
261
SignContextStack(void * context)262 void SignContextStack(void *context) {
263 ucontext_t *ucp = reinterpret_cast<ucontext_t *>(context);
264 ucp->uc_stack.ss_flags = HashContextStack(*ucp);
265 }
266
ReadContextStack(void * context,uptr * stack,uptr * ssize)267 void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
268 const ucontext_t *ucp = reinterpret_cast<const ucontext_t *>(context);
269 if (HashContextStack(*ucp) == ucp->uc_stack.ss_flags) {
270 *stack = reinterpret_cast<uptr>(ucp->uc_stack.ss_sp);
271 *ssize = ucp->uc_stack.ss_size;
272 return;
273 }
274 *stack = 0;
275 *ssize = 0;
276 }
277 # endif // ASAN_INTERCEPT_SWAPCONTEXT
278
AsanDlSymNext(const char * sym)279 void *AsanDlSymNext(const char *sym) { return dlsym(RTLD_NEXT, sym); }
280
HandleDlopenInit()281 bool HandleDlopenInit() {
282 // Not supported on this platform.
283 static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
284 "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
285 return false;
286 }
287
288 } // namespace __asan
289
290 #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||
291 // SANITIZER_SOLARIS || SANITIZER_HAIKU
292