1353944Sdim//===-- asan_linux.cpp ----------------------------------------------------===//
2353944Sdim//
3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353944Sdim// See https://llvm.org/LICENSE.txt for license information.
5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6353944Sdim//
7353944Sdim//===----------------------------------------------------------------------===//
8353944Sdim//
9353944Sdim// This file is a part of AddressSanitizer, an address sanity checker.
10353944Sdim//
11353944Sdim// Linux-specific details.
12353944Sdim//===----------------------------------------------------------------------===//
13353944Sdim
14353944Sdim#include "sanitizer_common/sanitizer_platform.h"
15353944Sdim#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
16353944Sdim    SANITIZER_SOLARIS
17353944Sdim
18353944Sdim#include "asan_interceptors.h"
19353944Sdim#include "asan_internal.h"
20353944Sdim#include "asan_premap_shadow.h"
21353944Sdim#include "asan_thread.h"
22353944Sdim#include "sanitizer_common/sanitizer_flags.h"
23353944Sdim#include "sanitizer_common/sanitizer_freebsd.h"
24353944Sdim#include "sanitizer_common/sanitizer_libc.h"
25353944Sdim#include "sanitizer_common/sanitizer_procmaps.h"
26353944Sdim
27353944Sdim#include <sys/time.h>
28353944Sdim#include <sys/resource.h>
29353944Sdim#include <sys/mman.h>
30353944Sdim#include <sys/syscall.h>
31353944Sdim#include <sys/types.h>
32353944Sdim#include <dlfcn.h>
33353944Sdim#include <fcntl.h>
34353944Sdim#include <limits.h>
35353944Sdim#include <pthread.h>
36353944Sdim#include <stdio.h>
37353944Sdim#include <unistd.h>
38353944Sdim#include <unwind.h>
39353944Sdim
40353944Sdim#if SANITIZER_FREEBSD
41353944Sdim#include <sys/link_elf.h>
42353944Sdim#endif
43353944Sdim
44353944Sdim#if SANITIZER_SOLARIS
45353944Sdim#include <link.h>
46353944Sdim#endif
47353944Sdim
48353944Sdim#if SANITIZER_ANDROID || SANITIZER_FREEBSD || SANITIZER_SOLARIS
49353944Sdim#include <ucontext.h>
50353944Sdimextern "C" void* _DYNAMIC;
51353944Sdim#elif SANITIZER_NETBSD
52353944Sdim#include <link_elf.h>
53353944Sdim#include <ucontext.h>
54353944Sdimextern Elf_Dyn _DYNAMIC;
55353944Sdim#else
56353944Sdim#include <sys/ucontext.h>
57353944Sdim#include <link.h>
58353944Sdim#endif
59353944Sdim
60353944Sdim// x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
61353944Sdim// 32-bit mode.
62353944Sdim#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \
63353944Sdim  __FreeBSD_version <= 902001  // v9.2
64353944Sdim#define ucontext_t xucontext_t
65353944Sdim#endif
66353944Sdim
67353944Sdimtypedef enum {
68353944Sdim  ASAN_RT_VERSION_UNDEFINED = 0,
69353944Sdim  ASAN_RT_VERSION_DYNAMIC,
70353944Sdim  ASAN_RT_VERSION_STATIC,
71353944Sdim} asan_rt_version_t;
72353944Sdim
73353944Sdim// FIXME: perhaps also store abi version here?
74353944Sdimextern "C" {
75353944SdimSANITIZER_INTERFACE_ATTRIBUTE
76353944Sdimasan_rt_version_t  __asan_rt_version;
77353944Sdim}
78353944Sdim
79353944Sdimnamespace __asan {
80353944Sdim
81353944Sdimvoid InitializePlatformInterceptors() {}
82353944Sdimvoid InitializePlatformExceptionHandlers() {}
83353944Sdimbool IsSystemHeapAddress (uptr addr) { return false; }
84353944Sdim
85353944Sdimvoid *AsanDoesNotSupportStaticLinkage() {
86353944Sdim  // This will fail to link with -static.
87353944Sdim  return &_DYNAMIC;  // defined in link.h
88353944Sdim}
89353944Sdim
90353944Sdimstatic void UnmapFromTo(uptr from, uptr to) {
91353944Sdim  CHECK(to >= from);
92353944Sdim  if (to == from) return;
93353944Sdim  uptr res = internal_munmap(reinterpret_cast<void *>(from), to - from);
94353944Sdim  if (UNLIKELY(internal_iserror(res))) {
95353944Sdim    Report(
96353944Sdim        "ERROR: AddresSanitizer failed to unmap 0x%zx (%zd) bytes at address "
97353944Sdim        "%p\n",
98353944Sdim        to - from, to - from, from);
99353944Sdim    CHECK("unable to unmap" && 0);
100353944Sdim  }
101353944Sdim}
102353944Sdim
103353944Sdim#if ASAN_PREMAP_SHADOW
104353944Sdimuptr FindPremappedShadowStart() {
105353944Sdim  uptr granularity = GetMmapGranularity();
106353944Sdim  uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow);
107353944Sdim  uptr premap_shadow_size = PremapShadowSize();
108353944Sdim  uptr shadow_size = RoundUpTo(kHighShadowEnd, granularity);
109353944Sdim  // We may have mapped too much. Release extra memory.
110353944Sdim  UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size);
111353944Sdim  return shadow_start;
112353944Sdim}
113353944Sdim#endif
114353944Sdim
115353944Sdimuptr FindDynamicShadowStart() {
116353944Sdim#if ASAN_PREMAP_SHADOW
117353944Sdim  if (!PremapShadowFailed())
118353944Sdim    return FindPremappedShadowStart();
119353944Sdim#endif
120353944Sdim
121353944Sdim  uptr granularity = GetMmapGranularity();
122353944Sdim  uptr alignment = granularity * 8;
123353944Sdim  uptr left_padding = granularity;
124353944Sdim  uptr shadow_size = RoundUpTo(kHighShadowEnd, granularity);
125353944Sdim  uptr map_size = shadow_size + left_padding + alignment;
126353944Sdim
127353944Sdim  uptr map_start = (uptr)MmapNoAccess(map_size);
128353944Sdim  CHECK_NE(map_start, ~(uptr)0);
129353944Sdim
130353944Sdim  uptr shadow_start = RoundUpTo(map_start + left_padding, alignment);
131353944Sdim  UnmapFromTo(map_start, shadow_start - left_padding);
132353944Sdim  UnmapFromTo(shadow_start + shadow_size, map_start + map_size);
133353944Sdim
134353944Sdim  return shadow_start;
135353944Sdim}
136353944Sdim
137353944Sdimvoid AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
138353944Sdim  UNIMPLEMENTED();
139353944Sdim}
140353944Sdim
141353944Sdim#if SANITIZER_ANDROID
142353944Sdim// FIXME: should we do anything for Android?
143353944Sdimvoid AsanCheckDynamicRTPrereqs() {}
144353944Sdimvoid AsanCheckIncompatibleRT() {}
145353944Sdim#else
146353944Sdimstatic int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
147353944Sdim                                void *data) {
148353944Sdim  VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n",
149353944Sdim          info->dlpi_name, info->dlpi_addr);
150353944Sdim
151353944Sdim  // Continue until the first dynamic library is found
152353944Sdim  if (!info->dlpi_name || info->dlpi_name[0] == 0)
153353944Sdim    return 0;
154353944Sdim
155353944Sdim  // Ignore vDSO
156353944Sdim  if (internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0)
157353944Sdim    return 0;
158353944Sdim
159353944Sdim#if SANITIZER_FREEBSD || SANITIZER_NETBSD
160353944Sdim  // Ignore first entry (the main program)
161353944Sdim  char **p = (char **)data;
162353944Sdim  if (!(*p)) {
163353944Sdim    *p = (char *)-1;
164353944Sdim    return 0;
165353944Sdim  }
166353944Sdim#endif
167353944Sdim
168353944Sdim#if SANITIZER_SOLARIS
169353944Sdim  // Ignore executable on Solaris
170353944Sdim  if (info->dlpi_addr == 0)
171353944Sdim    return 0;
172353944Sdim#endif
173353944Sdim
174353944Sdim  *(const char **)data = info->dlpi_name;
175353944Sdim  return 1;
176353944Sdim}
177353944Sdim
178353944Sdimstatic bool IsDynamicRTName(const char *libname) {
179353944Sdim  return internal_strstr(libname, "libclang_rt.asan") ||
180353944Sdim    internal_strstr(libname, "libasan.so");
181353944Sdim}
182353944Sdim
183353944Sdimstatic void ReportIncompatibleRT() {
184353944Sdim  Report("Your application is linked against incompatible ASan runtimes.\n");
185353944Sdim  Die();
186353944Sdim}
187353944Sdim
188353944Sdimvoid AsanCheckDynamicRTPrereqs() {
189353944Sdim  if (!ASAN_DYNAMIC || !flags()->verify_asan_link_order)
190353944Sdim    return;
191353944Sdim
192353944Sdim  // Ensure that dynamic RT is the first DSO in the list
193353944Sdim  const char *first_dso_name = nullptr;
194353944Sdim  dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name);
195353944Sdim  if (first_dso_name && !IsDynamicRTName(first_dso_name)) {
196353944Sdim    Report("ASan runtime does not come first in initial library list; "
197353944Sdim           "you should either link runtime to your application or "
198353944Sdim           "manually preload it with LD_PRELOAD.\n");
199353944Sdim    Die();
200353944Sdim  }
201353944Sdim}
202353944Sdim
203353944Sdimvoid AsanCheckIncompatibleRT() {
204353944Sdim  if (ASAN_DYNAMIC) {
205353944Sdim    if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
206353944Sdim      __asan_rt_version = ASAN_RT_VERSION_DYNAMIC;
207353944Sdim    } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) {
208353944Sdim      ReportIncompatibleRT();
209353944Sdim    }
210353944Sdim  } else {
211353944Sdim    if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) {
212353944Sdim      // Ensure that dynamic runtime is not present. We should detect it
213353944Sdim      // as early as possible, otherwise ASan interceptors could bind to
214353944Sdim      // the functions in dynamic ASan runtime instead of the functions in
215353944Sdim      // system libraries, causing crashes later in ASan initialization.
216353944Sdim      MemoryMappingLayout proc_maps(/*cache_enabled*/true);
217353944Sdim      char filename[PATH_MAX];
218353944Sdim      MemoryMappedSegment segment(filename, sizeof(filename));
219353944Sdim      while (proc_maps.Next(&segment)) {
220353944Sdim        if (IsDynamicRTName(segment.filename)) {
221353944Sdim          Report("Your application is linked against "
222353944Sdim                 "incompatible ASan runtimes.\n");
223353944Sdim          Die();
224353944Sdim        }
225353944Sdim      }
226353944Sdim      __asan_rt_version = ASAN_RT_VERSION_STATIC;
227353944Sdim    } else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) {
228353944Sdim      ReportIncompatibleRT();
229353944Sdim    }
230353944Sdim  }
231353944Sdim}
232353944Sdim#endif // SANITIZER_ANDROID
233353944Sdim
234353944Sdim#if !SANITIZER_ANDROID
235353944Sdimvoid ReadContextStack(void *context, uptr *stack, uptr *ssize) {
236353944Sdim  ucontext_t *ucp = (ucontext_t*)context;
237353944Sdim  *stack = (uptr)ucp->uc_stack.ss_sp;
238353944Sdim  *ssize = ucp->uc_stack.ss_size;
239353944Sdim}
240353944Sdim#else
241353944Sdimvoid ReadContextStack(void *context, uptr *stack, uptr *ssize) {
242353944Sdim  UNIMPLEMENTED();
243353944Sdim}
244353944Sdim#endif
245353944Sdim
246353944Sdimvoid *AsanDlSymNext(const char *sym) {
247353944Sdim  return dlsym(RTLD_NEXT, sym);
248353944Sdim}
249353944Sdim
250353944Sdimbool HandleDlopenInit() {
251353944Sdim  // Not supported on this platform.
252353944Sdim  static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
253353944Sdim                "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
254353944Sdim  return false;
255353944Sdim}
256353944Sdim
257353944Sdim} // namespace __asan
258353944Sdim
259353944Sdim#endif  // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||
260353944Sdim        // SANITIZER_SOLARIS
261