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