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
58typedef 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?
65extern "C" {
66SANITIZER_INTERFACE_ATTRIBUTE
67asan_rt_version_t __asan_rt_version;
68}
69
70namespace __asan {
71
72void InitializePlatformInterceptors() {}
73void InitializePlatformExceptionHandlers() {}
74bool IsSystemHeapAddress(uptr addr) { return false; }
75
76# if ASAN_PREMAP_SHADOW
77uptr 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
88uptr FindDynamicShadowStart() {
89 uptr shadow_size_bytes = MemToShadowSize(size: 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, high_mem_end&: kHighMemEnd);
97}
98
99void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
100 UNIMPLEMENTED();
101}
102
103void FlushUnneededASanShadowMemory(uptr p, uptr size) {
104 // Since asan's mapping is compacting, the shadow chunk may be
105 // not page-aligned, so we only flush the page-aligned portion.
106 ReleaseMemoryPagesToOS(beg: MemToShadow(p), end: MemToShadow(p: p + size));
107}
108
109# if SANITIZER_ANDROID
110// FIXME: should we do anything for Android?
111void AsanCheckDynamicRTPrereqs() {}
112void AsanCheckIncompatibleRT() {}
113# else
114static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
115 void *data) {
116 VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n", info->dlpi_name,
117 (void *)info->dlpi_addr);
118
119 const char **name = (const char **)data;
120
121 // Ignore first entry (the main program)
122 if (!*name) {
123 *name = "";
124 return 0;
125 }
126
127# if SANITIZER_LINUX
128 // Ignore vDSO. glibc versions earlier than 2.15 (and some patched
129 // by distributors) return an empty name for the vDSO entry, so
130 // detect this as well.
131 if (!info->dlpi_name[0] ||
132 internal_strncmp(s1: info->dlpi_name, s2: "linux-", n: sizeof("linux-") - 1) == 0)
133 return 0;
134# endif
135# if SANITIZER_FREEBSD
136 // Ignore vDSO.
137 if (internal_strcmp(info->dlpi_name, "[vdso]") == 0)
138 return 0;
139# endif
140
141 *name = info->dlpi_name;
142 return 1;
143}
144
145static bool IsDynamicRTName(const char *libname) {
146 return internal_strstr(haystack: libname, needle: "libclang_rt.asan") ||
147 internal_strstr(haystack: libname, needle: "libasan.so");
148}
149
150static void ReportIncompatibleRT() {
151 Report(format: "Your application is linked against incompatible ASan runtimes.\n");
152 Die();
153}
154
155void AsanCheckDynamicRTPrereqs() {
156 if (!ASAN_DYNAMIC || !flags()->verify_asan_link_order)
157 return;
158
159 // Ensure that dynamic RT is the first DSO in the list
160 const char *first_dso_name = nullptr;
161 dl_iterate_phdr(callback: FindFirstDSOCallback, data: &first_dso_name);
162 if (first_dso_name && first_dso_name[0] && !IsDynamicRTName(libname: first_dso_name)) {
163 Report(
164 format: "ASan runtime does not come first in initial library list; "
165 "you should either link runtime to your application or "
166 "manually preload it with LD_PRELOAD.\n");
167 Die();
168 }
169}
170
171void AsanCheckIncompatibleRT() {
172 if (ASAN_DYNAMIC) {
173 if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
174 __asan_rt_version = ASAN_RT_VERSION_DYNAMIC;
175 } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) {
176 ReportIncompatibleRT();
177 }
178 } else {
179 if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
180 // Ensure that dynamic runtime is not present. We should detect it
181 // as early as possible, otherwise ASan interceptors could bind to
182 // the functions in dynamic ASan runtime instead of the functions in
183 // system libraries, causing crashes later in ASan initialization.
184 MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
185 char filename[PATH_MAX];
186 MemoryMappedSegment segment(filename, sizeof(filename));
187 while (proc_maps.Next(segment: &segment)) {
188 if (IsDynamicRTName(libname: segment.filename)) {
189 Report(
190 format: "Your application is linked against "
191 "incompatible ASan runtimes.\n");
192 Die();
193 }
194 }
195 __asan_rt_version = ASAN_RT_VERSION_STATIC;
196 } else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) {
197 ReportIncompatibleRT();
198 }
199 }
200}
201# endif // SANITIZER_ANDROID
202
203# if ASAN_INTERCEPT_SWAPCONTEXT
204constexpr u32 kAsanContextStackFlagsMagic = 0x51260eea;
205
206static int HashContextStack(const ucontext_t &ucp) {
207 MurMur2Hash64Builder hash(kAsanContextStackFlagsMagic);
208 hash.add(k: reinterpret_cast<uptr>(ucp.uc_stack.ss_sp));
209 hash.add(k: ucp.uc_stack.ss_size);
210 return static_cast<int>(hash.get());
211}
212
213void SignContextStack(void *context) {
214 ucontext_t *ucp = reinterpret_cast<ucontext_t *>(context);
215 ucp->uc_stack.ss_flags = HashContextStack(ucp: *ucp);
216}
217
218void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
219 const ucontext_t *ucp = reinterpret_cast<const ucontext_t *>(context);
220 if (HashContextStack(ucp: *ucp) == ucp->uc_stack.ss_flags) {
221 *stack = reinterpret_cast<uptr>(ucp->uc_stack.ss_sp);
222 *ssize = ucp->uc_stack.ss_size;
223 return;
224 }
225 *stack = 0;
226 *ssize = 0;
227}
228# endif // ASAN_INTERCEPT_SWAPCONTEXT
229
230void *AsanDlSymNext(const char *sym) { return dlsym(RTLD_NEXT, name: sym); }
231
232bool HandleDlopenInit() {
233 // Not supported on this platform.
234 static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
235 "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
236 return false;
237}
238
239} // namespace __asan
240
241#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||
242 // SANITIZER_SOLARIS
243

source code of compiler-rt/lib/asan/asan_linux.cpp