]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/cfi/cfi.cc
Vendor import of compiler-rt trunk r351319 (just before the release_80
[FreeBSD/FreeBSD.git] / lib / cfi / cfi.cc
1 //===-------- cfi.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 implements the runtime support for the cross-DSO CFI.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include <assert.h>
15 #include <elf.h>
16
17 #include "sanitizer_common/sanitizer_common.h"
18 #if SANITIZER_FREEBSD
19 #include <sys/link_elf.h>
20 #endif
21 #include <link.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <sys/mman.h>
25
26 #if SANITIZER_LINUX
27 typedef ElfW(Phdr) Elf_Phdr;
28 typedef ElfW(Ehdr) Elf_Ehdr;
29 typedef ElfW(Addr) Elf_Addr;
30 typedef ElfW(Sym) Elf_Sym;
31 typedef ElfW(Dyn) Elf_Dyn;
32 #elif SANITIZER_FREEBSD
33 #if SANITIZER_WORDSIZE == 64
34 #define ElfW64_Dyn Elf_Dyn
35 #define ElfW64_Sym Elf_Sym
36 #else
37 #define ElfW32_Dyn Elf_Dyn
38 #define ElfW32_Sym Elf_Sym
39 #endif
40 #endif
41
42 #include "interception/interception.h"
43 #include "sanitizer_common/sanitizer_flag_parser.h"
44 #include "ubsan/ubsan_init.h"
45 #include "ubsan/ubsan_flags.h"
46
47 #ifdef CFI_ENABLE_DIAG
48 #include "ubsan/ubsan_handlers.h"
49 #endif
50
51 using namespace __sanitizer;
52
53 namespace __cfi {
54
55 #define kCfiShadowLimitsStorageSize 4096 // 1 page
56 // Lets hope that the data segment is mapped with 4K pages.
57 // The pointer to the cfi shadow region is stored at the start of this page.
58 // The rest of the page is unused and re-mapped read-only.
59 static union {
60   char space[kCfiShadowLimitsStorageSize];
61   struct {
62     uptr start;
63     uptr size;
64   } limits;
65 } cfi_shadow_limits_storage
66     __attribute__((aligned(kCfiShadowLimitsStorageSize)));
67 static constexpr uptr kShadowGranularity = 12;
68 static constexpr uptr kShadowAlign = 1UL << kShadowGranularity; // 4096
69
70 static constexpr uint16_t kInvalidShadow = 0;
71 static constexpr uint16_t kUncheckedShadow = 0xFFFFU;
72
73 // Get the start address of the CFI shadow region.
74 uptr GetShadow() {
75   return cfi_shadow_limits_storage.limits.start;
76 }
77
78 uptr GetShadowSize() {
79   return cfi_shadow_limits_storage.limits.size;
80 }
81
82 // This will only work while the shadow is not allocated.
83 void SetShadowSize(uptr size) {
84   cfi_shadow_limits_storage.limits.size = size;
85 }
86
87 uptr MemToShadowOffset(uptr x) {
88   return (x >> kShadowGranularity) << 1;
89 }
90
91 uint16_t *MemToShadow(uptr x, uptr shadow_base) {
92   return (uint16_t *)(shadow_base + MemToShadowOffset(x));
93 }
94
95 typedef int (*CFICheckFn)(u64, void *, void *);
96
97 // This class reads and decodes the shadow contents.
98 class ShadowValue {
99   uptr addr;
100   uint16_t v;
101   explicit ShadowValue(uptr addr, uint16_t v) : addr(addr), v(v) {}
102
103 public:
104   bool is_invalid() const { return v == kInvalidShadow; }
105
106   bool is_unchecked() const { return v == kUncheckedShadow; }
107
108   CFICheckFn get_cfi_check() const {
109     assert(!is_invalid() && !is_unchecked());
110     uptr aligned_addr = addr & ~(kShadowAlign - 1);
111     uptr p = aligned_addr - (((uptr)v - 1) << kShadowGranularity);
112     return reinterpret_cast<CFICheckFn>(p);
113   }
114
115   // Load a shadow value for the given application memory address.
116   static const ShadowValue load(uptr addr) {
117     uptr shadow_base = GetShadow();
118     uptr shadow_offset = MemToShadowOffset(addr);
119     if (shadow_offset > GetShadowSize())
120       return ShadowValue(addr, kInvalidShadow);
121     else
122       return ShadowValue(
123           addr, *reinterpret_cast<uint16_t *>(shadow_base + shadow_offset));
124   }
125 };
126
127 class ShadowBuilder {
128   uptr shadow_;
129
130 public:
131   // Allocate a new empty shadow (for the entire address space) on the side.
132   void Start();
133   // Mark the given address range as unchecked.
134   // This is used for uninstrumented libraries like libc.
135   // Any CFI check with a target in that range will pass.
136   void AddUnchecked(uptr begin, uptr end);
137   // Mark the given address range as belonging to a library with the given
138   // cfi_check function.
139   void Add(uptr begin, uptr end, uptr cfi_check);
140   // Finish shadow construction. Atomically switch the current active shadow
141   // region with the newly constructed one and deallocate the former.
142   void Install();
143 };
144
145 void ShadowBuilder::Start() {
146   shadow_ = (uptr)MmapNoReserveOrDie(GetShadowSize(), "CFI shadow");
147   VReport(1, "CFI: shadow at %zx .. %zx\n", shadow_, shadow_ + GetShadowSize());
148 }
149
150 void ShadowBuilder::AddUnchecked(uptr begin, uptr end) {
151   uint16_t *shadow_begin = MemToShadow(begin, shadow_);
152   uint16_t *shadow_end = MemToShadow(end - 1, shadow_) + 1;
153   // memset takes a byte, so our unchecked shadow value requires both bytes to
154   // be the same. Make sure we're ok during compilation.
155   static_assert((kUncheckedShadow & 0xff) == ((kUncheckedShadow >> 8) & 0xff),
156                 "Both bytes of the 16-bit value must be the same!");
157   memset(shadow_begin, kUncheckedShadow & 0xff,
158          (shadow_end - shadow_begin) * sizeof(*shadow_begin));
159 }
160
161 void ShadowBuilder::Add(uptr begin, uptr end, uptr cfi_check) {
162   assert((cfi_check & (kShadowAlign - 1)) == 0);
163
164   // Don't fill anything below cfi_check. We can not represent those addresses
165   // in the shadow, and must make sure at codegen to place all valid call
166   // targets above cfi_check.
167   begin = Max(begin, cfi_check);
168   uint16_t *s = MemToShadow(begin, shadow_);
169   uint16_t *s_end = MemToShadow(end - 1, shadow_) + 1;
170   uint16_t sv = ((begin - cfi_check) >> kShadowGranularity) + 1;
171   for (; s < s_end; s++, sv++)
172     *s = sv;
173 }
174
175 #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD
176 void ShadowBuilder::Install() {
177   MprotectReadOnly(shadow_, GetShadowSize());
178   uptr main_shadow = GetShadow();
179   if (main_shadow) {
180     // Update.
181 #if SANITIZER_LINUX
182     void *res = mremap((void *)shadow_, GetShadowSize(), GetShadowSize(),
183                        MREMAP_MAYMOVE | MREMAP_FIXED, (void *)main_shadow);
184     CHECK(res != MAP_FAILED);
185 #elif SANITIZER_NETBSD
186     void *res = mremap((void *)shadow_, GetShadowSize(), (void *)main_shadow,
187                        GetShadowSize(), MAP_FIXED);
188     CHECK(res != MAP_FAILED);
189 #else
190     void *res = MmapFixedOrDie(shadow_, GetShadowSize());
191     CHECK(res != MAP_FAILED);
192     ::memcpy(&shadow_, &main_shadow, GetShadowSize());
193 #endif
194   } else {
195     // Initial setup.
196     CHECK_EQ(kCfiShadowLimitsStorageSize, GetPageSizeCached());
197     CHECK_EQ(0, GetShadow());
198     cfi_shadow_limits_storage.limits.start = shadow_;
199     MprotectReadOnly((uptr)&cfi_shadow_limits_storage,
200                      sizeof(cfi_shadow_limits_storage));
201     CHECK_EQ(shadow_, GetShadow());
202   }
203 }
204 #else
205 #error not implemented
206 #endif
207
208 // This is a workaround for a glibc bug:
209 // https://sourceware.org/bugzilla/show_bug.cgi?id=15199
210 // Other platforms can, hopefully, just do
211 //    dlopen(RTLD_NOLOAD | RTLD_LAZY)
212 //    dlsym("__cfi_check").
213 uptr find_cfi_check_in_dso(dl_phdr_info *info) {
214   const Elf_Dyn *dynamic = nullptr;
215   for (int i = 0; i < info->dlpi_phnum; ++i) {
216     if (info->dlpi_phdr[i].p_type == PT_DYNAMIC) {
217       dynamic =
218           (const Elf_Dyn *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
219       break;
220     }
221   }
222   if (!dynamic) return 0;
223   uptr strtab = 0, symtab = 0, strsz = 0;
224   for (const Elf_Dyn *p = dynamic; p->d_tag != PT_NULL; ++p) {
225     if (p->d_tag == DT_SYMTAB)
226       symtab = p->d_un.d_ptr;
227     else if (p->d_tag == DT_STRTAB)
228       strtab = p->d_un.d_ptr;
229     else if (p->d_tag == DT_STRSZ)
230       strsz = p->d_un.d_ptr;
231   }
232
233   if (symtab > strtab) {
234     VReport(1, "Can not handle: symtab > strtab (%p > %zx)\n", symtab, strtab);
235     return 0;
236   }
237
238   // Verify that strtab and symtab are inside of the same LOAD segment.
239   // This excludes VDSO, which has (very high) bogus strtab and symtab pointers.
240   int phdr_idx;
241   for (phdr_idx = 0; phdr_idx < info->dlpi_phnum; phdr_idx++) {
242     const Elf_Phdr *phdr = &info->dlpi_phdr[phdr_idx];
243     if (phdr->p_type == PT_LOAD) {
244       uptr beg = info->dlpi_addr + phdr->p_vaddr;
245       uptr end = beg + phdr->p_memsz;
246       if (strtab >= beg && strtab + strsz < end && symtab >= beg &&
247           symtab < end)
248         break;
249     }
250   }
251   if (phdr_idx == info->dlpi_phnum) {
252     // Nope, either different segments or just bogus pointers.
253     // Can not handle this.
254     VReport(1, "Can not handle: symtab %p, strtab %zx\n", symtab, strtab);
255     return 0;
256   }
257
258   for (const Elf_Sym *p = (const Elf_Sym *)symtab; (Elf_Addr)p < strtab;
259        ++p) {
260     // There is no reliable way to find the end of the symbol table. In
261     // lld-produces files, there are other sections between symtab and strtab.
262     // Stop looking when the symbol name is not inside strtab.
263     if (p->st_name >= strsz) break;
264     char *name = (char*)(strtab + p->st_name);
265     if (strcmp(name, "__cfi_check") == 0) {
266       assert(p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC) ||
267              p->st_info == ELF32_ST_INFO(STB_WEAK, STT_FUNC));
268       uptr addr = info->dlpi_addr + p->st_value;
269       return addr;
270     }
271   }
272   return 0;
273 }
274
275 int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *data) {
276   uptr cfi_check = find_cfi_check_in_dso(info);
277   if (cfi_check)
278     VReport(1, "Module '%s' __cfi_check %zx\n", info->dlpi_name, cfi_check);
279
280   ShadowBuilder *b = reinterpret_cast<ShadowBuilder *>(data);
281
282   for (int i = 0; i < info->dlpi_phnum; i++) {
283     const Elf_Phdr *phdr = &info->dlpi_phdr[i];
284     if (phdr->p_type == PT_LOAD) {
285       // Jump tables are in the executable segment.
286       // VTables are in the non-executable one.
287       // Need to fill shadow for both.
288       // FIXME: reject writable if vtables are in the r/o segment. Depend on
289       // PT_RELRO?
290       uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
291       uptr cur_end = cur_beg + phdr->p_memsz;
292       if (cfi_check) {
293         VReport(1, "   %zx .. %zx\n", cur_beg, cur_end);
294         b->Add(cur_beg, cur_end, cfi_check);
295       } else {
296         b->AddUnchecked(cur_beg, cur_end);
297       }
298     }
299   }
300   return 0;
301 }
302
303 // Init or update shadow for the current set of loaded libraries.
304 void UpdateShadow() {
305   ShadowBuilder b;
306   b.Start();
307   dl_iterate_phdr(dl_iterate_phdr_cb, &b);
308   b.Install();
309 }
310
311 void InitShadow() {
312   CHECK_EQ(0, GetShadow());
313   CHECK_EQ(0, GetShadowSize());
314
315   uptr vma = GetMaxUserVirtualAddress();
316   // Shadow is 2 -> 2**kShadowGranularity.
317   SetShadowSize((vma >> (kShadowGranularity - 1)) + 1);
318   VReport(1, "CFI: VMA size %zx, shadow size %zx\n", vma, GetShadowSize());
319
320   UpdateShadow();
321 }
322
323 THREADLOCAL int in_loader;
324 BlockingMutex shadow_update_lock(LINKER_INITIALIZED);
325
326 void EnterLoader() {
327   if (in_loader == 0) {
328     shadow_update_lock.Lock();
329   }
330   ++in_loader;
331 }
332
333 void ExitLoader() {
334   CHECK(in_loader > 0);
335   --in_loader;
336   UpdateShadow();
337   if (in_loader == 0) {
338     shadow_update_lock.Unlock();
339   }
340 }
341
342 ALWAYS_INLINE void CfiSlowPathCommon(u64 CallSiteTypeId, void *Ptr,
343                                      void *DiagData) {
344   uptr Addr = (uptr)Ptr;
345   VReport(3, "__cfi_slowpath: %llx, %p\n", CallSiteTypeId, Ptr);
346   ShadowValue sv = ShadowValue::load(Addr);
347   if (sv.is_invalid()) {
348     VReport(1, "CFI: invalid memory region for a check target: %p\n", Ptr);
349 #ifdef CFI_ENABLE_DIAG
350     if (DiagData) {
351       __ubsan_handle_cfi_check_fail(
352           reinterpret_cast<__ubsan::CFICheckFailData *>(DiagData), Addr, false);
353       return;
354     }
355 #endif
356     Trap();
357   }
358   if (sv.is_unchecked()) {
359     VReport(2, "CFI: unchecked call (shadow=FFFF): %p\n", Ptr);
360     return;
361   }
362   CFICheckFn cfi_check = sv.get_cfi_check();
363   VReport(2, "__cfi_check at %p\n", cfi_check);
364   cfi_check(CallSiteTypeId, Ptr, DiagData);
365 }
366
367 void InitializeFlags() {
368   SetCommonFlagsDefaults();
369 #ifdef CFI_ENABLE_DIAG
370   __ubsan::Flags *uf = __ubsan::flags();
371   uf->SetDefaults();
372 #endif
373
374   FlagParser cfi_parser;
375   RegisterCommonFlags(&cfi_parser);
376   cfi_parser.ParseString(GetEnv("CFI_OPTIONS"));
377
378 #ifdef CFI_ENABLE_DIAG
379   FlagParser ubsan_parser;
380   __ubsan::RegisterUbsanFlags(&ubsan_parser, uf);
381   RegisterCommonFlags(&ubsan_parser);
382
383   const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions();
384   ubsan_parser.ParseString(ubsan_default_options);
385   ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS"));
386 #endif
387
388   InitializeCommonFlags();
389
390   if (Verbosity())
391     ReportUnrecognizedFlags();
392
393   if (common_flags()->help) {
394     cfi_parser.PrintFlagDescriptions();
395   }
396 }
397
398 } // namespace __cfi
399
400 using namespace __cfi;
401
402 extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
403 __cfi_slowpath(u64 CallSiteTypeId, void *Ptr) {
404   CfiSlowPathCommon(CallSiteTypeId, Ptr, nullptr);
405 }
406
407 #ifdef CFI_ENABLE_DIAG
408 extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
409 __cfi_slowpath_diag(u64 CallSiteTypeId, void *Ptr, void *DiagData) {
410   CfiSlowPathCommon(CallSiteTypeId, Ptr, DiagData);
411 }
412 #endif
413
414 static void EnsureInterceptorsInitialized();
415
416 // Setup shadow for dlopen()ed libraries.
417 // The actual shadow setup happens after dlopen() returns, which means that
418 // a library can not be a target of any CFI checks while its constructors are
419 // running. It's unclear how to fix this without some extra help from libc.
420 // In glibc, mmap inside dlopen is not interceptable.
421 // Maybe a seccomp-bpf filter?
422 // We could insert a high-priority constructor into the library, but that would
423 // not help with the uninstrumented libraries.
424 INTERCEPTOR(void*, dlopen, const char *filename, int flag) {
425   EnsureInterceptorsInitialized();
426   EnterLoader();
427   void *handle = REAL(dlopen)(filename, flag);
428   ExitLoader();
429   return handle;
430 }
431
432 INTERCEPTOR(int, dlclose, void *handle) {
433   EnsureInterceptorsInitialized();
434   EnterLoader();
435   int res = REAL(dlclose)(handle);
436   ExitLoader();
437   return res;
438 }
439
440 static BlockingMutex interceptor_init_lock(LINKER_INITIALIZED);
441 static bool interceptors_inited = false;
442
443 static void EnsureInterceptorsInitialized() {
444   BlockingMutexLock lock(&interceptor_init_lock);
445   if (interceptors_inited)
446     return;
447
448   INTERCEPT_FUNCTION(dlopen);
449   INTERCEPT_FUNCTION(dlclose);
450
451   interceptors_inited = true;
452 }
453
454 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
455 #if !SANITIZER_CAN_USE_PREINIT_ARRAY
456 // On ELF platforms, the constructor is invoked using .preinit_array (see below)
457 __attribute__((constructor(0)))
458 #endif
459 void __cfi_init() {
460   SanitizerToolName = "CFI";
461   InitializeFlags();
462   InitShadow();
463
464 #ifdef CFI_ENABLE_DIAG
465   __ubsan::InitAsPlugin();
466 #endif
467 }
468
469 #if SANITIZER_CAN_USE_PREINIT_ARRAY
470 // On ELF platforms, run cfi initialization before any other constructors.
471 // On other platforms we use the constructor attribute to arrange to run our
472 // initialization early.
473 extern "C" {
474 __attribute__((section(".preinit_array"),
475                used)) void (*__cfi_preinit)(void) = __cfi_init;
476 }
477 #endif