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