xref: /freebsd/contrib/llvm-project/compiler-rt/lib/asan/asan_linux.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
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 "asan_interceptors.h"
19 #include "asan_internal.h"
20 #include "asan_premap_shadow.h"
21 #include "asan_thread.h"
22 #include "sanitizer_common/sanitizer_flags.h"
23 #include "sanitizer_common/sanitizer_freebsd.h"
24 #include "sanitizer_common/sanitizer_libc.h"
25 #include "sanitizer_common/sanitizer_procmaps.h"
26 
27 #include <sys/time.h>
28 #include <sys/resource.h>
29 #include <sys/mman.h>
30 #include <sys/syscall.h>
31 #include <sys/types.h>
32 #include <dlfcn.h>
33 #include <fcntl.h>
34 #include <limits.h>
35 #include <pthread.h>
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <unwind.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 extern "C" void* _DYNAMIC;
51 #elif SANITIZER_NETBSD
52 #include <link_elf.h>
53 #include <ucontext.h>
54 extern Elf_Dyn _DYNAMIC;
55 #else
56 #include <sys/ucontext.h>
57 #include <link.h>
58 #endif
59 
60 // x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
61 // 32-bit mode.
62 #if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \
63   __FreeBSD_version <= 902001  // v9.2
64 #define ucontext_t xucontext_t
65 #endif
66 
67 typedef enum {
68   ASAN_RT_VERSION_UNDEFINED = 0,
69   ASAN_RT_VERSION_DYNAMIC,
70   ASAN_RT_VERSION_STATIC,
71 } asan_rt_version_t;
72 
73 // FIXME: perhaps also store abi version here?
74 extern "C" {
75 SANITIZER_INTERFACE_ATTRIBUTE
76 asan_rt_version_t  __asan_rt_version;
77 }
78 
79 namespace __asan {
80 
81 void InitializePlatformInterceptors() {}
82 void InitializePlatformExceptionHandlers() {}
83 bool IsSystemHeapAddress (uptr addr) { return false; }
84 
85 void *AsanDoesNotSupportStaticLinkage() {
86   // This will fail to link with -static.
87   return &_DYNAMIC;  // defined in link.h
88 }
89 
90 static void UnmapFromTo(uptr from, uptr to) {
91   CHECK(to >= from);
92   if (to == from) return;
93   uptr res = internal_munmap(reinterpret_cast<void *>(from), to - from);
94   if (UNLIKELY(internal_iserror(res))) {
95     Report(
96         "ERROR: AddresSanitizer failed to unmap 0x%zx (%zd) bytes at address "
97         "%p\n",
98         to - from, to - from, from);
99     CHECK("unable to unmap" && 0);
100   }
101 }
102 
103 #if ASAN_PREMAP_SHADOW
104 uptr FindPremappedShadowStart() {
105   uptr granularity = GetMmapGranularity();
106   uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow);
107   uptr premap_shadow_size = PremapShadowSize();
108   uptr shadow_size = RoundUpTo(kHighShadowEnd, granularity);
109   // We may have mapped too much. Release extra memory.
110   UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size);
111   return shadow_start;
112 }
113 #endif
114 
115 uptr FindDynamicShadowStart() {
116 #if ASAN_PREMAP_SHADOW
117   if (!PremapShadowFailed())
118     return FindPremappedShadowStart();
119 #endif
120 
121   uptr granularity = GetMmapGranularity();
122   uptr alignment = granularity * 8;
123   uptr left_padding = granularity;
124   uptr shadow_size = RoundUpTo(kHighShadowEnd, granularity);
125   uptr map_size = shadow_size + left_padding + alignment;
126 
127   uptr map_start = (uptr)MmapNoAccess(map_size);
128   CHECK_NE(map_start, ~(uptr)0);
129 
130   uptr shadow_start = RoundUpTo(map_start + left_padding, alignment);
131   UnmapFromTo(map_start, shadow_start - left_padding);
132   UnmapFromTo(shadow_start + shadow_size, map_start + map_size);
133 
134   return shadow_start;
135 }
136 
137 void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
138   UNIMPLEMENTED();
139 }
140 
141 #if SANITIZER_ANDROID
142 // FIXME: should we do anything for Android?
143 void AsanCheckDynamicRTPrereqs() {}
144 void AsanCheckIncompatibleRT() {}
145 #else
146 static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
147                                 void *data) {
148   VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n",
149           info->dlpi_name, info->dlpi_addr);
150 
151   // Continue until the first dynamic library is found
152   if (!info->dlpi_name || info->dlpi_name[0] == 0)
153     return 0;
154 
155   // Ignore vDSO
156   if (internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0)
157     return 0;
158 
159 #if SANITIZER_FREEBSD || SANITIZER_NETBSD
160   // Ignore first entry (the main program)
161   char **p = (char **)data;
162   if (!(*p)) {
163     *p = (char *)-1;
164     return 0;
165   }
166 #endif
167 
168 #if SANITIZER_SOLARIS
169   // Ignore executable on Solaris
170   if (info->dlpi_addr == 0)
171     return 0;
172 #endif
173 
174   *(const char **)data = info->dlpi_name;
175   return 1;
176 }
177 
178 static bool IsDynamicRTName(const char *libname) {
179   return internal_strstr(libname, "libclang_rt.asan") ||
180     internal_strstr(libname, "libasan.so");
181 }
182 
183 static void ReportIncompatibleRT() {
184   Report("Your application is linked against incompatible ASan runtimes.\n");
185   Die();
186 }
187 
188 void AsanCheckDynamicRTPrereqs() {
189   if (!ASAN_DYNAMIC || !flags()->verify_asan_link_order)
190     return;
191 
192   // Ensure that dynamic RT is the first DSO in the list
193   const char *first_dso_name = nullptr;
194   dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name);
195   if (first_dso_name && !IsDynamicRTName(first_dso_name)) {
196     Report("ASan runtime does not come first in initial library list; "
197            "you should either link runtime to your application or "
198            "manually preload it with LD_PRELOAD.\n");
199     Die();
200   }
201 }
202 
203 void AsanCheckIncompatibleRT() {
204   if (ASAN_DYNAMIC) {
205     if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
206       __asan_rt_version = ASAN_RT_VERSION_DYNAMIC;
207     } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) {
208       ReportIncompatibleRT();
209     }
210   } else {
211     if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
212       // Ensure that dynamic runtime is not present. We should detect it
213       // as early as possible, otherwise ASan interceptors could bind to
214       // the functions in dynamic ASan runtime instead of the functions in
215       // system libraries, causing crashes later in ASan initialization.
216       MemoryMappingLayout proc_maps(/*cache_enabled*/true);
217       char filename[PATH_MAX];
218       MemoryMappedSegment segment(filename, sizeof(filename));
219       while (proc_maps.Next(&segment)) {
220         if (IsDynamicRTName(segment.filename)) {
221           Report("Your application is linked against "
222                  "incompatible ASan runtimes.\n");
223           Die();
224         }
225       }
226       __asan_rt_version = ASAN_RT_VERSION_STATIC;
227     } else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) {
228       ReportIncompatibleRT();
229     }
230   }
231 }
232 #endif // SANITIZER_ANDROID
233 
234 #if !SANITIZER_ANDROID
235 void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
236   ucontext_t *ucp = (ucontext_t*)context;
237   *stack = (uptr)ucp->uc_stack.ss_sp;
238   *ssize = ucp->uc_stack.ss_size;
239 }
240 #else
241 void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
242   UNIMPLEMENTED();
243 }
244 #endif
245 
246 void *AsanDlSymNext(const char *sym) {
247   return dlsym(RTLD_NEXT, sym);
248 }
249 
250 bool HandleDlopenInit() {
251   // Not supported on this platform.
252   static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
253                 "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
254   return false;
255 }
256 
257 } // namespace __asan
258 
259 #endif  // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||
260         // SANITIZER_SOLARIS
261