xref: /freebsd/contrib/llvm-project/compiler-rt/lib/asan/asan_linux.cpp (revision e64bea71c21eb42e97aa615188ba91f6cce0d36d)
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 
84 void InitializePlatformInterceptors() {}
85 void InitializePlatformExceptionHandlers() {}
86 bool IsSystemHeapAddress(uptr addr) { return false; }
87 
88 #  if ASAN_PREMAP_SHADOW
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 
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 
112 void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
113   UNIMPLEMENTED();
114 }
115 
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 
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?
157 void AsanCheckDynamicRTPrereqs() {}
158 void AsanCheckIncompatibleRT() {}
159 #  else
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 
197 static bool IsDynamicRTName(const char *libname) {
198   return internal_strstr(libname, "libclang_rt.asan") ||
199          internal_strstr(libname, "libasan.so");
200 }
201 
202 static void ReportIncompatibleRT() {
203   Report("Your application is linked against incompatible ASan runtimes.\n");
204   Die();
205 }
206 
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 
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 
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 
262 void SignContextStack(void *context) {
263   ucontext_t *ucp = reinterpret_cast<ucontext_t *>(context);
264   ucp->uc_stack.ss_flags = HashContextStack(*ucp);
265 }
266 
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 
279 void *AsanDlSymNext(const char *sym) { return dlsym(RTLD_NEXT, sym); }
280 
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