1//===-- asan_linux.cc -----------------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of AddressSanitizer, an address sanity checker.
11//
12// Linux-specific details.
13//===----------------------------------------------------------------------===//
14
15#include "sanitizer_common/sanitizer_platform.h"
16#if SANITIZER_FREEBSD || SANITIZER_LINUX
17
18#include "asan_interceptors.h"
19#include "asan_internal.h"
20#include "asan_thread.h"
21#include "sanitizer_common/sanitizer_flags.h"
22#include "sanitizer_common/sanitizer_freebsd.h"
23#include "sanitizer_common/sanitizer_libc.h"
24#include "sanitizer_common/sanitizer_procmaps.h"
25
26#include <sys/time.h>
27#include <sys/resource.h>
28#include <sys/mman.h>
29#include <sys/syscall.h>
30#include <sys/types.h>
31#include <dlfcn.h>
32#include <fcntl.h>
33#include <pthread.h>
34#include <stdio.h>
35#include <unistd.h>
36#include <unwind.h>
37
38#if SANITIZER_FREEBSD
39#include <sys/link_elf.h>
40#endif
41
42#if SANITIZER_ANDROID || SANITIZER_FREEBSD
43#include <ucontext.h>
44extern "C" void* _DYNAMIC;
45#else
46#include <sys/ucontext.h>
47#include <link.h>
48#endif
49
50// x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
51// 32-bit mode.
52#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \
53  __FreeBSD_version <= 902001  // v9.2
54#define ucontext_t xucontext_t
55#endif
56
57typedef enum {
58  ASAN_RT_VERSION_UNDEFINED = 0,
59  ASAN_RT_VERSION_DYNAMIC,
60  ASAN_RT_VERSION_STATIC,
61} asan_rt_version_t;
62
63// FIXME: perhaps also store abi version here?
64extern "C" {
65SANITIZER_INTERFACE_ATTRIBUTE
66asan_rt_version_t  __asan_rt_version;
67}
68
69namespace __asan {
70
71void MaybeReexec() {
72  // No need to re-exec on Linux.
73}
74
75void *AsanDoesNotSupportStaticLinkage() {
76  // This will fail to link with -static.
77  return &_DYNAMIC;  // defined in link.h
78}
79
80#if SANITIZER_ANDROID
81// FIXME: should we do anything for Android?
82void AsanCheckDynamicRTPrereqs() {}
83void AsanCheckIncompatibleRT() {}
84#else
85static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
86                                void *data) {
87  // Continue until the first dynamic library is found
88  if (!info->dlpi_name || info->dlpi_name[0] == 0)
89    return 0;
90
91  // Ignore vDSO
92  if (internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0)
93    return 0;
94
95  *(const char **)data = info->dlpi_name;
96  return 1;
97}
98
99static bool IsDynamicRTName(const char *libname) {
100  return internal_strstr(libname, "libclang_rt.asan") ||
101    internal_strstr(libname, "libasan.so");
102}
103
104static void ReportIncompatibleRT() {
105  Report("Your application is linked against incompatible ASan runtimes.\n");
106  Die();
107}
108
109void AsanCheckDynamicRTPrereqs() {
110  // Ensure that dynamic RT is the first DSO in the list
111  const char *first_dso_name = 0;
112  dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name);
113  if (first_dso_name && !IsDynamicRTName(first_dso_name)) {
114    Report("ASan runtime does not come first in initial library list; "
115           "you should either link runtime to your application or "
116           "manually preload it with LD_PRELOAD.\n");
117    Die();
118  }
119}
120
121void AsanCheckIncompatibleRT() {
122  if (ASAN_DYNAMIC) {
123    if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
124      __asan_rt_version = ASAN_RT_VERSION_DYNAMIC;
125    } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) {
126      ReportIncompatibleRT();
127    }
128  } else {
129    if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
130      // Ensure that dynamic runtime is not present. We should detect it
131      // as early as possible, otherwise ASan interceptors could bind to
132      // the functions in dynamic ASan runtime instead of the functions in
133      // system libraries, causing crashes later in ASan initialization.
134      MemoryMappingLayout proc_maps(/*cache_enabled*/true);
135      char filename[128];
136      while (proc_maps.Next(0, 0, 0, filename, sizeof(filename), 0)) {
137        if (IsDynamicRTName(filename)) {
138          Report("Your application is linked against "
139                 "incompatible ASan runtimes.\n");
140          Die();
141        }
142      }
143      __asan_rt_version = ASAN_RT_VERSION_STATIC;
144    } else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) {
145      ReportIncompatibleRT();
146    }
147  }
148}
149#endif  // SANITIZER_ANDROID
150
151void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
152#if defined(__arm__)
153  ucontext_t *ucontext = (ucontext_t*)context;
154  *pc = ucontext->uc_mcontext.arm_pc;
155  *bp = ucontext->uc_mcontext.arm_fp;
156  *sp = ucontext->uc_mcontext.arm_sp;
157#elif defined(__aarch64__)
158  ucontext_t *ucontext = (ucontext_t*)context;
159  *pc = ucontext->uc_mcontext.pc;
160  *bp = ucontext->uc_mcontext.regs[29];
161  *sp = ucontext->uc_mcontext.sp;
162#elif defined(__hppa__)
163  ucontext_t *ucontext = (ucontext_t*)context;
164  *pc = ucontext->uc_mcontext.sc_iaoq[0];
165  /* GCC uses %r3 whenever a frame pointer is needed.  */
166  *bp = ucontext->uc_mcontext.sc_gr[3];
167  *sp = ucontext->uc_mcontext.sc_gr[30];
168#elif defined(__x86_64__)
169# if SANITIZER_FREEBSD
170  ucontext_t *ucontext = (ucontext_t*)context;
171  *pc = ucontext->uc_mcontext.mc_rip;
172  *bp = ucontext->uc_mcontext.mc_rbp;
173  *sp = ucontext->uc_mcontext.mc_rsp;
174# else
175  ucontext_t *ucontext = (ucontext_t*)context;
176  *pc = ucontext->uc_mcontext.gregs[REG_RIP];
177  *bp = ucontext->uc_mcontext.gregs[REG_RBP];
178  *sp = ucontext->uc_mcontext.gregs[REG_RSP];
179# endif
180#elif defined(__i386__)
181# if SANITIZER_FREEBSD
182  ucontext_t *ucontext = (ucontext_t*)context;
183  *pc = ucontext->uc_mcontext.mc_eip;
184  *bp = ucontext->uc_mcontext.mc_ebp;
185  *sp = ucontext->uc_mcontext.mc_esp;
186# else
187  ucontext_t *ucontext = (ucontext_t*)context;
188  *pc = ucontext->uc_mcontext.gregs[REG_EIP];
189  *bp = ucontext->uc_mcontext.gregs[REG_EBP];
190  *sp = ucontext->uc_mcontext.gregs[REG_ESP];
191# endif
192#elif defined(__powerpc__) || defined(__powerpc64__)
193  ucontext_t *ucontext = (ucontext_t*)context;
194  *pc = ucontext->uc_mcontext.regs->nip;
195  *sp = ucontext->uc_mcontext.regs->gpr[PT_R1];
196  // The powerpc{,64}-linux ABIs do not specify r31 as the frame
197  // pointer, but GCC always uses r31 when we need a frame pointer.
198  *bp = ucontext->uc_mcontext.regs->gpr[PT_R31];
199#elif defined(__sparc__)
200  ucontext_t *ucontext = (ucontext_t*)context;
201  uptr *stk_ptr;
202# if defined (__arch64__)
203  *pc = ucontext->uc_mcontext.mc_gregs[MC_PC];
204  *sp = ucontext->uc_mcontext.mc_gregs[MC_O6];
205  stk_ptr = (uptr *) (*sp + 2047);
206  *bp = stk_ptr[15];
207# else
208  *pc = ucontext->uc_mcontext.gregs[REG_PC];
209  *sp = ucontext->uc_mcontext.gregs[REG_O6];
210  stk_ptr = (uptr *) *sp;
211  *bp = stk_ptr[15];
212# endif
213#elif defined(__mips__)
214  ucontext_t *ucontext = (ucontext_t*)context;
215  *pc = ucontext->uc_mcontext.gregs[31];
216  *bp = ucontext->uc_mcontext.gregs[30];
217  *sp = ucontext->uc_mcontext.gregs[29];
218#else
219# error "Unsupported arch"
220#endif
221}
222
223bool AsanInterceptsSignal(int signum) {
224  return signum == SIGSEGV && common_flags()->handle_segv;
225}
226
227void AsanPlatformThreadInit() {
228  // Nothing here for now.
229}
230
231#if !SANITIZER_ANDROID
232void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
233  ucontext_t *ucp = (ucontext_t*)context;
234  *stack = (uptr)ucp->uc_stack.ss_sp;
235  *ssize = ucp->uc_stack.ss_size;
236}
237#else
238void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
239  UNIMPLEMENTED();
240}
241#endif
242
243void *AsanDlSymNext(const char *sym) {
244  return dlsym(RTLD_NEXT, sym);
245}
246
247}  // namespace __asan
248
249#endif  // SANITIZER_FREEBSD || SANITIZER_LINUX
250