1 //===-- asan_linux.cc -----------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file is a part of AddressSanitizer, an address sanity checker.
11 // Linux-specific details.
12 //===----------------------------------------------------------------------===//
14 #include "sanitizer_common/sanitizer_platform.h"
15 #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
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"
28 #include <sys/resource.h>
30 #include <sys/syscall.h>
31 #include <sys/types.h>
41 #include <sys/link_elf.h>
48 #if SANITIZER_ANDROID || SANITIZER_FREEBSD || SANITIZER_SOLARIS
50 extern "C" void* _DYNAMIC;
51 #elif SANITIZER_NETBSD
54 extern Elf_Dyn _DYNAMIC;
56 #include <sys/ucontext.h>
60 // x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
62 #if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \
63 __FreeBSD_version <= 902001 // v9.2
64 #define ucontext_t xucontext_t
68 ASAN_RT_VERSION_UNDEFINED = 0,
69 ASAN_RT_VERSION_DYNAMIC,
70 ASAN_RT_VERSION_STATIC,
73 // FIXME: perhaps also store abi version here?
75 SANITIZER_INTERFACE_ATTRIBUTE
76 asan_rt_version_t __asan_rt_version;
81 void InitializePlatformInterceptors() {}
82 void InitializePlatformExceptionHandlers() {}
83 bool IsSystemHeapAddress (uptr addr) { return false; }
85 void *AsanDoesNotSupportStaticLinkage() {
86 // This will fail to link with -static.
87 return &_DYNAMIC; // defined in link.h
90 static void UnmapFromTo(uptr from, uptr to) {
92 if (to == from) return;
93 uptr res = internal_munmap(reinterpret_cast<void *>(from), to - from);
94 if (UNLIKELY(internal_iserror(res))) {
96 "ERROR: AddresSanitizer failed to unmap 0x%zx (%zd) bytes at address "
98 to - from, to - from, from);
99 CHECK("unable to unmap" && 0);
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);
115 uptr FindDynamicShadowStart() {
116 #if ASAN_PREMAP_SHADOW
117 if (!PremapShadowFailed())
118 return FindPremappedShadowStart();
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;
127 uptr map_start = (uptr)MmapNoAccess(map_size);
128 CHECK_NE(map_start, ~(uptr)0);
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);
137 void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
141 #if SANITIZER_ANDROID
142 // FIXME: should we do anything for Android?
143 void AsanCheckDynamicRTPrereqs() {}
144 void AsanCheckIncompatibleRT() {}
146 static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
148 VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n",
149 info->dlpi_name, info->dlpi_addr);
151 // Continue until the first dynamic library is found
152 if (!info->dlpi_name || info->dlpi_name[0] == 0)
156 if (internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0)
159 #if SANITIZER_FREEBSD || SANITIZER_NETBSD
160 // Ignore first entry (the main program)
161 char **p = (char **)data;
168 #if SANITIZER_SOLARIS
169 // Ignore executable on Solaris
170 if (info->dlpi_addr == 0)
174 *(const char **)data = info->dlpi_name;
178 static bool IsDynamicRTName(const char *libname) {
179 return internal_strstr(libname, "libclang_rt.asan") ||
180 internal_strstr(libname, "libasan.so");
183 static void ReportIncompatibleRT() {
184 Report("Your application is linked against incompatible ASan runtimes.\n");
188 void AsanCheckDynamicRTPrereqs() {
189 if (!ASAN_DYNAMIC || !flags()->verify_asan_link_order)
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");
203 void AsanCheckIncompatibleRT() {
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();
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");
226 __asan_rt_version = ASAN_RT_VERSION_STATIC;
227 } else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) {
228 ReportIncompatibleRT();
232 #endif // SANITIZER_ANDROID
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;
241 void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
246 void *AsanDlSymNext(const char *sym) {
247 return dlsym(RTLD_NEXT, sym);
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");
257 } // namespace __asan
259 #endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||