1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *  * Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 *  * Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in
12 *    the documentation and/or other materials provided with the
13 *    distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include "linker_cfi.h"
30
31#include "linker_debug.h"
32#include "linker_globals.h"
33#include "private/bionic_page.h"
34#include "private/bionic_prctl.h"
35
36#include <sys/mman.h>
37#include <sys/types.h>
38#include <cstdint>
39
40// Update shadow without making it writable by preparing the data on the side and mremap-ing it in
41// place.
42class ShadowWrite {
43  char* shadow_start;
44  char* shadow_end;
45  char* aligned_start;
46  char* aligned_end;
47  char* tmp_start;
48
49 public:
50  ShadowWrite(uint16_t* s, uint16_t* e) {
51    shadow_start = reinterpret_cast<char*>(s);
52    shadow_end = reinterpret_cast<char*>(e);
53    aligned_start = reinterpret_cast<char*>(PAGE_START(reinterpret_cast<uintptr_t>(shadow_start)));
54    aligned_end = reinterpret_cast<char*>(PAGE_END(reinterpret_cast<uintptr_t>(shadow_end)));
55    tmp_start =
56        reinterpret_cast<char*>(mmap(nullptr, aligned_end - aligned_start, PROT_READ | PROT_WRITE,
57                                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
58    CHECK(tmp_start != MAP_FAILED);
59    memcpy(tmp_start, aligned_start, shadow_start - aligned_start);
60    memcpy(tmp_start + (shadow_end - aligned_start), shadow_end, aligned_end - shadow_end);
61  }
62
63  uint16_t* begin() {
64    return reinterpret_cast<uint16_t*>(tmp_start + (shadow_start - aligned_start));
65  }
66
67  uint16_t* end() {
68    return reinterpret_cast<uint16_t*>(tmp_start + (shadow_end - aligned_start));
69  }
70
71  ~ShadowWrite() {
72    size_t size = aligned_end - aligned_start;
73    mprotect(tmp_start, size, PROT_READ);
74    void* res = mremap(tmp_start, size, size, MREMAP_MAYMOVE | MREMAP_FIXED,
75                       reinterpret_cast<void*>(aligned_start));
76    CHECK(res != MAP_FAILED);
77  }
78};
79
80void CFIShadowWriter::FixupVmaName() {
81  prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, *shadow_start, kShadowSize, "cfi shadow");
82}
83
84void CFIShadowWriter::AddConstant(uintptr_t begin, uintptr_t end, uint16_t v) {
85  uint16_t* shadow_begin = MemToShadow(begin);
86  uint16_t* shadow_end = MemToShadow(end - 1) + 1;
87
88  ShadowWrite sw(shadow_begin, shadow_end);
89  std::fill(sw.begin(), sw.end(), v);
90}
91
92void CFIShadowWriter::AddUnchecked(uintptr_t begin, uintptr_t end) {
93  AddConstant(begin, end, kUncheckedShadow);
94}
95
96void CFIShadowWriter::AddInvalid(uintptr_t begin, uintptr_t end) {
97  AddConstant(begin, end, kInvalidShadow);
98}
99
100void CFIShadowWriter::Add(uintptr_t begin, uintptr_t end, uintptr_t cfi_check) {
101  CHECK((cfi_check & (kCfiCheckAlign - 1)) == 0);
102
103  // Don't fill anything below cfi_check. We can not represent those addresses
104  // in the shadow, and must make sure at codegen to place all valid call
105  // targets above cfi_check.
106  begin = std::max(begin, cfi_check) & ~(kShadowAlign - 1);
107  uint16_t* shadow_begin = MemToShadow(begin);
108  uint16_t* shadow_end = MemToShadow(end - 1) + 1;
109
110  ShadowWrite sw(shadow_begin, shadow_end);
111  uint16_t sv_begin = ((begin + kShadowAlign - cfi_check) >> kCfiCheckGranularity) + kRegularShadowMin;
112
113  // With each step of the loop below, __cfi_check address computation base is increased by
114  // 2**ShadowGranularity.
115  // To compensate for that, each next shadow value must be increased by 2**ShadowGranularity /
116  // 2**CfiCheckGranularity.
117  uint16_t sv_step = 1 << (kShadowGranularity - kCfiCheckGranularity);
118  uint16_t sv = sv_begin;
119  for (uint16_t& s : sw) {
120    if (sv < sv_begin) {
121      // If shadow value wraps around, also fall back to unchecked. This means the binary is too
122      // large. FIXME: consider using a (slow) resolution function instead.
123      s = kUncheckedShadow;
124      continue;
125    }
126    // If there is something there already, fall back to unchecked. This may happen in rare cases
127    // with MAP_FIXED libraries. FIXME: consider using a (slow) resolution function instead.
128    s = (s == kInvalidShadow) ? sv : kUncheckedShadow;
129    sv += sv_step;
130  }
131}
132
133static soinfo* find_libdl(soinfo* solist) {
134  for (soinfo* si = solist; si != nullptr; si = si->next) {
135    const char* soname = si->get_soname();
136    if (soname && strcmp(soname, "libdl.so") == 0) {
137      return si;
138    }
139  }
140  return nullptr;
141}
142
143static uintptr_t soinfo_find_symbol(soinfo* si, const char* s) {
144  SymbolName name(s);
145  const ElfW(Sym) * sym;
146  if (si->find_symbol_by_name(name, nullptr, &sym) && sym) {
147    return si->resolve_symbol_address(sym);
148  }
149  return 0;
150}
151
152uintptr_t soinfo_find_cfi_check(soinfo* si) {
153  return soinfo_find_symbol(si, "__cfi_check");
154}
155
156uintptr_t CFIShadowWriter::MapShadow() {
157  void* p =
158      mmap(nullptr, kShadowSize, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
159  CHECK(p != MAP_FAILED);
160  return reinterpret_cast<uintptr_t>(p);
161}
162
163bool CFIShadowWriter::AddLibrary(soinfo* si) {
164  CHECK(shadow_start != nullptr);
165  if (si->base == 0 || si->size == 0) {
166    return true;
167  }
168  uintptr_t cfi_check = soinfo_find_cfi_check(si);
169  if (cfi_check == 0) {
170    INFO("[ CFI add 0x%zx + 0x%zx %s ]", static_cast<uintptr_t>(si->base),
171         static_cast<uintptr_t>(si->size), si->get_soname());
172    AddUnchecked(si->base, si->base + si->size);
173    return true;
174  }
175
176  INFO("[ CFI add 0x%zx + 0x%zx %s: 0x%zx ]", static_cast<uintptr_t>(si->base),
177       static_cast<uintptr_t>(si->size), si->get_soname(), cfi_check);
178#ifdef __arm__
179  // Require Thumb encoding.
180  if ((cfi_check & 1UL) != 1UL) {
181    DL_ERR("__cfi_check in not a Thumb function in the library \"%s\"", si->get_soname());
182    return false;
183  }
184  cfi_check &= ~1UL;
185#endif
186  if ((cfi_check & (kCfiCheckAlign - 1)) != 0) {
187    DL_ERR("unaligned __cfi_check in the library \"%s\"", si->get_soname());
188    return false;
189  }
190  Add(si->base, si->base + si->size, cfi_check);
191  return true;
192}
193
194// Pass the shadow mapping address to libdl.so. In return, we get an pointer to the location
195// libdl.so uses to store the address.
196bool CFIShadowWriter::NotifyLibDl(soinfo* solist, uintptr_t p) {
197  soinfo* libdl = find_libdl(solist);
198  if (libdl == nullptr) {
199    DL_ERR("CFI could not find libdl");
200    return false;
201  }
202
203  uintptr_t cfi_init = soinfo_find_symbol(libdl, "__cfi_init");
204  CHECK(cfi_init != 0);
205  shadow_start = reinterpret_cast<uintptr_t* (*)(uintptr_t)>(cfi_init)(p);
206  CHECK(shadow_start != nullptr);
207  CHECK(*shadow_start == p);
208  mprotect(shadow_start, PAGE_SIZE, PROT_READ);
209  return true;
210}
211
212bool CFIShadowWriter::MaybeInit(soinfo* new_si, soinfo* solist) {
213  CHECK(initial_link_done);
214  CHECK(shadow_start == nullptr);
215  // Check if CFI shadow must be initialized at this time.
216  bool found = false;
217  if (new_si == nullptr) {
218    // This is the case when we've just completed the initial link. There may have been earlier
219    // calls to MaybeInit that were skipped. Look though the entire solist.
220    for (soinfo* si = solist; si != nullptr; si = si->next) {
221      if (soinfo_find_cfi_check(si)) {
222        found = true;
223        break;
224      }
225    }
226  } else {
227    // See if the new library uses CFI.
228    found = soinfo_find_cfi_check(new_si);
229  }
230
231  // Nothing found.
232  if (!found) {
233    return true;
234  }
235
236  // Init shadow and add all currently loaded libraries (not just the new ones).
237  if (!NotifyLibDl(solist, MapShadow()))
238    return false;
239  for (soinfo* si = solist; si != nullptr; si = si->next) {
240    if (!AddLibrary(si))
241      return false;
242  }
243  FixupVmaName();
244  return true;
245}
246
247bool CFIShadowWriter::AfterLoad(soinfo* si, soinfo* solist) {
248  if (!initial_link_done) {
249    // Too early.
250    return true;
251  }
252
253  if (shadow_start == nullptr) {
254    return MaybeInit(si, solist);
255  }
256
257  // Add the new library to the CFI shadow.
258  if (!AddLibrary(si))
259    return false;
260  FixupVmaName();
261  return true;
262}
263
264void CFIShadowWriter::BeforeUnload(soinfo* si) {
265  if (shadow_start == nullptr) return;
266  if (si->base == 0 || si->size == 0) return;
267  INFO("[ CFI remove 0x%zx + 0x%zx: %s ]", static_cast<uintptr_t>(si->base),
268       static_cast<uintptr_t>(si->size), si->get_soname());
269  AddInvalid(si->base, si->base + si->size);
270  FixupVmaName();
271}
272
273bool CFIShadowWriter::InitialLinkDone(soinfo* solist) {
274  CHECK(!initial_link_done);
275  initial_link_done = true;
276  return MaybeInit(nullptr, solist);
277}
278
279// Find __cfi_check in the caller and let it handle the problem. Since caller_pc is likely not a
280// valid CFI target, we can not use CFI shadow for lookup. This does not need to be fast, do the
281// regular symbol lookup.
282void CFIShadowWriter::CfiFail(uint64_t CallSiteTypeId, void* Ptr, void* DiagData, void* CallerPc) {
283  soinfo* si = find_containing_library(CallerPc);
284  if (!si) {
285    __builtin_trap();
286  }
287
288  uintptr_t cfi_check = soinfo_find_cfi_check(si);
289  if (!cfi_check) {
290    __builtin_trap();
291  }
292
293  reinterpret_cast<CFICheckFn>(cfi_check)(CallSiteTypeId, Ptr, DiagData);
294}
295