xref: /freebsd/contrib/llvm-project/compiler-rt/lib/asan/asan_linux.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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
17 
18 #  include <dlfcn.h>
19 #  include <fcntl.h>
20 #  include <limits.h>
21 #  include <pthread.h>
22 #  include <stdio.h>
23 #  include <sys/mman.h>
24 #  include <sys/resource.h>
25 #  include <sys/syscall.h>
26 #  include <sys/time.h>
27 #  include <sys/types.h>
28 #  include <unistd.h>
29 #  include <unwind.h>
30 
31 #  include "asan_interceptors.h"
32 #  include "asan_internal.h"
33 #  include "asan_premap_shadow.h"
34 #  include "asan_thread.h"
35 #  include "sanitizer_common/sanitizer_flags.h"
36 #  include "sanitizer_common/sanitizer_hash.h"
37 #  include "sanitizer_common/sanitizer_libc.h"
38 #  include "sanitizer_common/sanitizer_procmaps.h"
39 
40 #  if SANITIZER_FREEBSD
41 #    include <sys/link_elf.h>
42 #  endif
43 
44 #  if SANITIZER_SOLARIS
45 #    include <link.h>
46 #  endif
47 
48 #  if SANITIZER_ANDROID || SANITIZER_FREEBSD || SANITIZER_SOLARIS
49 #    include <ucontext.h>
50 #  elif SANITIZER_NETBSD
51 #    include <link_elf.h>
52 #    include <ucontext.h>
53 #  else
54 #    include <link.h>
55 #    include <sys/ucontext.h>
56 #  endif
57 
58 typedef enum {
59   ASAN_RT_VERSION_UNDEFINED = 0,
60   ASAN_RT_VERSION_DYNAMIC,
61   ASAN_RT_VERSION_STATIC,
62 } asan_rt_version_t;
63 
64 // FIXME: perhaps also store abi version here?
65 extern "C" {
66 SANITIZER_INTERFACE_ATTRIBUTE
67 asan_rt_version_t __asan_rt_version;
68 }
69 
70 namespace __asan {
71 
InitializePlatformInterceptors()72 void InitializePlatformInterceptors() {}
InitializePlatformExceptionHandlers()73 void InitializePlatformExceptionHandlers() {}
IsSystemHeapAddress(uptr addr)74 bool IsSystemHeapAddress(uptr addr) { return false; }
75 
76 #  if ASAN_PREMAP_SHADOW
FindPremappedShadowStart(uptr shadow_size_bytes)77 uptr FindPremappedShadowStart(uptr shadow_size_bytes) {
78   uptr granularity = GetMmapGranularity();
79   uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow);
80   uptr premap_shadow_size = PremapShadowSize();
81   uptr shadow_size = RoundUpTo(shadow_size_bytes, granularity);
82   // We may have mapped too much. Release extra memory.
83   UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size);
84   return shadow_start;
85 }
86 #  endif
87 
FindDynamicShadowStart()88 uptr FindDynamicShadowStart() {
89   uptr shadow_size_bytes = MemToShadowSize(kHighMemEnd);
90 #  if ASAN_PREMAP_SHADOW
91   if (!PremapShadowFailed())
92     return FindPremappedShadowStart(shadow_size_bytes);
93 #  endif
94 
95   return MapDynamicShadow(shadow_size_bytes, ASAN_SHADOW_SCALE,
96                           /*min_shadow_base_alignment*/ 0, kHighMemEnd,
97                           GetMmapGranularity());
98 }
99 
AsanApplyToGlobals(globals_op_fptr op,const void * needle)100 void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
101   UNIMPLEMENTED();
102 }
103 
FlushUnneededASanShadowMemory(uptr p,uptr size)104 void FlushUnneededASanShadowMemory(uptr p, uptr size) {
105   // Since asan's mapping is compacting, the shadow chunk may be
106   // not page-aligned, so we only flush the page-aligned portion.
107   ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size));
108 }
109 
110 #  if SANITIZER_ANDROID
111 // FIXME: should we do anything for Android?
AsanCheckDynamicRTPrereqs()112 void AsanCheckDynamicRTPrereqs() {}
AsanCheckIncompatibleRT()113 void AsanCheckIncompatibleRT() {}
114 #  else
FindFirstDSOCallback(struct dl_phdr_info * info,size_t size,void * data)115 static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
116                                 void *data) {
117   VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n", info->dlpi_name,
118           (void *)info->dlpi_addr);
119 
120   const char **name = (const char **)data;
121 
122   // Ignore first entry (the main program)
123   if (!*name) {
124     *name = "";
125     return 0;
126   }
127 
128 #    if SANITIZER_LINUX
129   // Ignore vDSO. glibc versions earlier than 2.15 (and some patched
130   // by distributors) return an empty name for the vDSO entry, so
131   // detect this as well.
132   if (!info->dlpi_name[0] ||
133       internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0)
134     return 0;
135 #    endif
136 #    if SANITIZER_FREEBSD
137   // Ignore vDSO.
138   if (internal_strcmp(info->dlpi_name, "[vdso]") == 0)
139     return 0;
140 #    endif
141 
142   *name = info->dlpi_name;
143   return 1;
144 }
145 
IsDynamicRTName(const char * libname)146 static bool IsDynamicRTName(const char *libname) {
147   return internal_strstr(libname, "libclang_rt.asan") ||
148          internal_strstr(libname, "libasan.so");
149 }
150 
ReportIncompatibleRT()151 static void ReportIncompatibleRT() {
152   Report("Your application is linked against incompatible ASan runtimes.\n");
153   Die();
154 }
155 
AsanCheckDynamicRTPrereqs()156 void AsanCheckDynamicRTPrereqs() {
157   if (!ASAN_DYNAMIC || !flags()->verify_asan_link_order)
158     return;
159 
160   // Ensure that dynamic RT is the first DSO in the list
161   const char *first_dso_name = nullptr;
162   dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name);
163   if (first_dso_name && first_dso_name[0] && !IsDynamicRTName(first_dso_name)) {
164     Report(
165         "ASan runtime does not come first in initial library list; "
166         "you should either link runtime to your application or "
167         "manually preload it with LD_PRELOAD.\n");
168     Die();
169   }
170 }
171 
AsanCheckIncompatibleRT()172 void AsanCheckIncompatibleRT() {
173   if (ASAN_DYNAMIC) {
174     if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
175       __asan_rt_version = ASAN_RT_VERSION_DYNAMIC;
176     } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) {
177       ReportIncompatibleRT();
178     }
179   } else {
180     if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
181       // Ensure that dynamic runtime is not present. We should detect it
182       // as early as possible, otherwise ASan interceptors could bind to
183       // the functions in dynamic ASan runtime instead of the functions in
184       // system libraries, causing crashes later in ASan initialization.
185       MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
186       char filename[PATH_MAX];
187       MemoryMappedSegment segment(filename, sizeof(filename));
188       while (proc_maps.Next(&segment)) {
189         if (IsDynamicRTName(segment.filename)) {
190           Report(
191               "Your application is linked against "
192               "incompatible ASan runtimes.\n");
193           Die();
194         }
195       }
196       __asan_rt_version = ASAN_RT_VERSION_STATIC;
197     } else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) {
198       ReportIncompatibleRT();
199     }
200   }
201 }
202 #  endif  // SANITIZER_ANDROID
203 
204 #  if ASAN_INTERCEPT_SWAPCONTEXT
205 constexpr u32 kAsanContextStackFlagsMagic = 0x51260eea;
206 
HashContextStack(const ucontext_t & ucp)207 static int HashContextStack(const ucontext_t &ucp) {
208   MurMur2Hash64Builder hash(kAsanContextStackFlagsMagic);
209   hash.add(reinterpret_cast<uptr>(ucp.uc_stack.ss_sp));
210   hash.add(ucp.uc_stack.ss_size);
211   return static_cast<int>(hash.get());
212 }
213 
SignContextStack(void * context)214 void SignContextStack(void *context) {
215   ucontext_t *ucp = reinterpret_cast<ucontext_t *>(context);
216   ucp->uc_stack.ss_flags = HashContextStack(*ucp);
217 }
218 
ReadContextStack(void * context,uptr * stack,uptr * ssize)219 void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
220   const ucontext_t *ucp = reinterpret_cast<const ucontext_t *>(context);
221   if (HashContextStack(*ucp) == ucp->uc_stack.ss_flags) {
222     *stack = reinterpret_cast<uptr>(ucp->uc_stack.ss_sp);
223     *ssize = ucp->uc_stack.ss_size;
224     return;
225   }
226   *stack = 0;
227   *ssize = 0;
228 }
229 #  endif  // ASAN_INTERCEPT_SWAPCONTEXT
230 
AsanDlSymNext(const char * sym)231 void *AsanDlSymNext(const char *sym) { return dlsym(RTLD_NEXT, sym); }
232 
HandleDlopenInit()233 bool HandleDlopenInit() {
234   // Not supported on this platform.
235   static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
236                 "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
237   return false;
238 }
239 
240 }  // namespace __asan
241 
242 #endif  // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||
243         // SANITIZER_SOLARIS
244