xref: /openbsd-src/gnu/llvm/compiler-rt/lib/cfi/cfi.cpp (revision 810390e339a5425391477d5d41c78d7cab2424ac)
13cab2bb3Spatrick //===-------- cfi.cpp -----------------------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file implements the runtime support for the cross-DSO CFI.
103cab2bb3Spatrick //
113cab2bb3Spatrick //===----------------------------------------------------------------------===//
123cab2bb3Spatrick 
133cab2bb3Spatrick #include <assert.h>
143cab2bb3Spatrick #include <elf.h>
153cab2bb3Spatrick 
163cab2bb3Spatrick #include "sanitizer_common/sanitizer_common.h"
173cab2bb3Spatrick #if SANITIZER_FREEBSD
183cab2bb3Spatrick #include <sys/link_elf.h>
193cab2bb3Spatrick #endif
203cab2bb3Spatrick #include <link.h>
213cab2bb3Spatrick #include <string.h>
223cab2bb3Spatrick #include <stdlib.h>
233cab2bb3Spatrick #include <sys/mman.h>
243cab2bb3Spatrick 
253cab2bb3Spatrick #if SANITIZER_LINUX
263cab2bb3Spatrick typedef ElfW(Phdr) Elf_Phdr;
273cab2bb3Spatrick typedef ElfW(Ehdr) Elf_Ehdr;
283cab2bb3Spatrick typedef ElfW(Addr) Elf_Addr;
293cab2bb3Spatrick typedef ElfW(Sym) Elf_Sym;
303cab2bb3Spatrick typedef ElfW(Dyn) Elf_Dyn;
313cab2bb3Spatrick #elif SANITIZER_FREEBSD
323cab2bb3Spatrick #if SANITIZER_WORDSIZE == 64
333cab2bb3Spatrick #define ElfW64_Dyn Elf_Dyn
343cab2bb3Spatrick #define ElfW64_Sym Elf_Sym
353cab2bb3Spatrick #else
363cab2bb3Spatrick #define ElfW32_Dyn Elf_Dyn
373cab2bb3Spatrick #define ElfW32_Sym Elf_Sym
383cab2bb3Spatrick #endif
393cab2bb3Spatrick #endif
403cab2bb3Spatrick 
413cab2bb3Spatrick #include "interception/interception.h"
423cab2bb3Spatrick #include "sanitizer_common/sanitizer_flag_parser.h"
433cab2bb3Spatrick #include "ubsan/ubsan_init.h"
443cab2bb3Spatrick #include "ubsan/ubsan_flags.h"
453cab2bb3Spatrick 
463cab2bb3Spatrick #ifdef CFI_ENABLE_DIAG
473cab2bb3Spatrick #include "ubsan/ubsan_handlers.h"
483cab2bb3Spatrick #endif
493cab2bb3Spatrick 
503cab2bb3Spatrick using namespace __sanitizer;
513cab2bb3Spatrick 
523cab2bb3Spatrick namespace __cfi {
533cab2bb3Spatrick 
543cab2bb3Spatrick #define kCfiShadowLimitsStorageSize 4096 // 1 page
553cab2bb3Spatrick // Lets hope that the data segment is mapped with 4K pages.
563cab2bb3Spatrick // The pointer to the cfi shadow region is stored at the start of this page.
573cab2bb3Spatrick // The rest of the page is unused and re-mapped read-only.
583cab2bb3Spatrick static union {
593cab2bb3Spatrick   char space[kCfiShadowLimitsStorageSize];
603cab2bb3Spatrick   struct {
613cab2bb3Spatrick     uptr start;
623cab2bb3Spatrick     uptr size;
633cab2bb3Spatrick   } limits;
643cab2bb3Spatrick } cfi_shadow_limits_storage
653cab2bb3Spatrick     __attribute__((aligned(kCfiShadowLimitsStorageSize)));
663cab2bb3Spatrick static constexpr uptr kShadowGranularity = 12;
673cab2bb3Spatrick static constexpr uptr kShadowAlign = 1UL << kShadowGranularity; // 4096
683cab2bb3Spatrick 
693cab2bb3Spatrick static constexpr uint16_t kInvalidShadow = 0;
703cab2bb3Spatrick static constexpr uint16_t kUncheckedShadow = 0xFFFFU;
713cab2bb3Spatrick 
723cab2bb3Spatrick // Get the start address of the CFI shadow region.
GetShadow()733cab2bb3Spatrick uptr GetShadow() {
743cab2bb3Spatrick   return cfi_shadow_limits_storage.limits.start;
753cab2bb3Spatrick }
763cab2bb3Spatrick 
GetShadowSize()773cab2bb3Spatrick uptr GetShadowSize() {
783cab2bb3Spatrick   return cfi_shadow_limits_storage.limits.size;
793cab2bb3Spatrick }
803cab2bb3Spatrick 
813cab2bb3Spatrick // This will only work while the shadow is not allocated.
SetShadowSize(uptr size)823cab2bb3Spatrick void SetShadowSize(uptr size) {
833cab2bb3Spatrick   cfi_shadow_limits_storage.limits.size = size;
843cab2bb3Spatrick }
853cab2bb3Spatrick 
MemToShadowOffset(uptr x)863cab2bb3Spatrick uptr MemToShadowOffset(uptr x) {
873cab2bb3Spatrick   return (x >> kShadowGranularity) << 1;
883cab2bb3Spatrick }
893cab2bb3Spatrick 
MemToShadow(uptr x,uptr shadow_base)903cab2bb3Spatrick uint16_t *MemToShadow(uptr x, uptr shadow_base) {
913cab2bb3Spatrick   return (uint16_t *)(shadow_base + MemToShadowOffset(x));
923cab2bb3Spatrick }
933cab2bb3Spatrick 
943cab2bb3Spatrick typedef int (*CFICheckFn)(u64, void *, void *);
953cab2bb3Spatrick 
963cab2bb3Spatrick // This class reads and decodes the shadow contents.
973cab2bb3Spatrick class ShadowValue {
983cab2bb3Spatrick   uptr addr;
993cab2bb3Spatrick   uint16_t v;
ShadowValue(uptr addr,uint16_t v)1003cab2bb3Spatrick   explicit ShadowValue(uptr addr, uint16_t v) : addr(addr), v(v) {}
1013cab2bb3Spatrick 
1023cab2bb3Spatrick public:
is_invalid() const1033cab2bb3Spatrick   bool is_invalid() const { return v == kInvalidShadow; }
1043cab2bb3Spatrick 
is_unchecked() const1053cab2bb3Spatrick   bool is_unchecked() const { return v == kUncheckedShadow; }
1063cab2bb3Spatrick 
get_cfi_check() const1073cab2bb3Spatrick   CFICheckFn get_cfi_check() const {
1083cab2bb3Spatrick     assert(!is_invalid() && !is_unchecked());
1093cab2bb3Spatrick     uptr aligned_addr = addr & ~(kShadowAlign - 1);
1103cab2bb3Spatrick     uptr p = aligned_addr - (((uptr)v - 1) << kShadowGranularity);
1113cab2bb3Spatrick     return reinterpret_cast<CFICheckFn>(p);
1123cab2bb3Spatrick   }
1133cab2bb3Spatrick 
1143cab2bb3Spatrick   // Load a shadow value for the given application memory address.
load(uptr addr)1153cab2bb3Spatrick   static const ShadowValue load(uptr addr) {
1163cab2bb3Spatrick     uptr shadow_base = GetShadow();
1173cab2bb3Spatrick     uptr shadow_offset = MemToShadowOffset(addr);
1183cab2bb3Spatrick     if (shadow_offset > GetShadowSize())
1193cab2bb3Spatrick       return ShadowValue(addr, kInvalidShadow);
1203cab2bb3Spatrick     else
1213cab2bb3Spatrick       return ShadowValue(
1223cab2bb3Spatrick           addr, *reinterpret_cast<uint16_t *>(shadow_base + shadow_offset));
1233cab2bb3Spatrick   }
1243cab2bb3Spatrick };
1253cab2bb3Spatrick 
1263cab2bb3Spatrick class ShadowBuilder {
1273cab2bb3Spatrick   uptr shadow_;
1283cab2bb3Spatrick 
1293cab2bb3Spatrick public:
1303cab2bb3Spatrick   // Allocate a new empty shadow (for the entire address space) on the side.
1313cab2bb3Spatrick   void Start();
1323cab2bb3Spatrick   // Mark the given address range as unchecked.
1333cab2bb3Spatrick   // This is used for uninstrumented libraries like libc.
1343cab2bb3Spatrick   // Any CFI check with a target in that range will pass.
1353cab2bb3Spatrick   void AddUnchecked(uptr begin, uptr end);
1363cab2bb3Spatrick   // Mark the given address range as belonging to a library with the given
1373cab2bb3Spatrick   // cfi_check function.
1383cab2bb3Spatrick   void Add(uptr begin, uptr end, uptr cfi_check);
1393cab2bb3Spatrick   // Finish shadow construction. Atomically switch the current active shadow
1403cab2bb3Spatrick   // region with the newly constructed one and deallocate the former.
1413cab2bb3Spatrick   void Install();
1423cab2bb3Spatrick };
1433cab2bb3Spatrick 
Start()1443cab2bb3Spatrick void ShadowBuilder::Start() {
1453cab2bb3Spatrick   shadow_ = (uptr)MmapNoReserveOrDie(GetShadowSize(), "CFI shadow");
1463cab2bb3Spatrick   VReport(1, "CFI: shadow at %zx .. %zx\n", shadow_, shadow_ + GetShadowSize());
1473cab2bb3Spatrick }
1483cab2bb3Spatrick 
AddUnchecked(uptr begin,uptr end)1493cab2bb3Spatrick void ShadowBuilder::AddUnchecked(uptr begin, uptr end) {
1503cab2bb3Spatrick   uint16_t *shadow_begin = MemToShadow(begin, shadow_);
1513cab2bb3Spatrick   uint16_t *shadow_end = MemToShadow(end - 1, shadow_) + 1;
1523cab2bb3Spatrick   // memset takes a byte, so our unchecked shadow value requires both bytes to
1533cab2bb3Spatrick   // be the same. Make sure we're ok during compilation.
1543cab2bb3Spatrick   static_assert((kUncheckedShadow & 0xff) == ((kUncheckedShadow >> 8) & 0xff),
1553cab2bb3Spatrick                 "Both bytes of the 16-bit value must be the same!");
1563cab2bb3Spatrick   memset(shadow_begin, kUncheckedShadow & 0xff,
1573cab2bb3Spatrick          (shadow_end - shadow_begin) * sizeof(*shadow_begin));
1583cab2bb3Spatrick }
1593cab2bb3Spatrick 
Add(uptr begin,uptr end,uptr cfi_check)1603cab2bb3Spatrick void ShadowBuilder::Add(uptr begin, uptr end, uptr cfi_check) {
1613cab2bb3Spatrick   assert((cfi_check & (kShadowAlign - 1)) == 0);
1623cab2bb3Spatrick 
1633cab2bb3Spatrick   // Don't fill anything below cfi_check. We can not represent those addresses
1643cab2bb3Spatrick   // in the shadow, and must make sure at codegen to place all valid call
1653cab2bb3Spatrick   // targets above cfi_check.
1663cab2bb3Spatrick   begin = Max(begin, cfi_check);
1673cab2bb3Spatrick   uint16_t *s = MemToShadow(begin, shadow_);
1683cab2bb3Spatrick   uint16_t *s_end = MemToShadow(end - 1, shadow_) + 1;
1693cab2bb3Spatrick   uint16_t sv = ((begin - cfi_check) >> kShadowGranularity) + 1;
1703cab2bb3Spatrick   for (; s < s_end; s++, sv++)
1713cab2bb3Spatrick     *s = sv;
1723cab2bb3Spatrick }
1733cab2bb3Spatrick 
1743cab2bb3Spatrick #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD
Install()1753cab2bb3Spatrick void ShadowBuilder::Install() {
1763cab2bb3Spatrick   MprotectReadOnly(shadow_, GetShadowSize());
1773cab2bb3Spatrick   uptr main_shadow = GetShadow();
1783cab2bb3Spatrick   if (main_shadow) {
1793cab2bb3Spatrick     // Update.
1803cab2bb3Spatrick #if SANITIZER_LINUX
1813cab2bb3Spatrick     void *res = mremap((void *)shadow_, GetShadowSize(), GetShadowSize(),
1823cab2bb3Spatrick                        MREMAP_MAYMOVE | MREMAP_FIXED, (void *)main_shadow);
1833cab2bb3Spatrick     CHECK(res != MAP_FAILED);
1843cab2bb3Spatrick #elif SANITIZER_NETBSD
1853cab2bb3Spatrick     void *res = mremap((void *)shadow_, GetShadowSize(), (void *)main_shadow,
1863cab2bb3Spatrick                        GetShadowSize(), MAP_FIXED);
1873cab2bb3Spatrick     CHECK(res != MAP_FAILED);
1883cab2bb3Spatrick #else
1893cab2bb3Spatrick     void *res = MmapFixedOrDie(shadow_, GetShadowSize(), "cfi shadow");
1903cab2bb3Spatrick     CHECK(res != MAP_FAILED);
1913cab2bb3Spatrick     ::memcpy(&shadow_, &main_shadow, GetShadowSize());
1923cab2bb3Spatrick #endif
1933cab2bb3Spatrick   } else {
1943cab2bb3Spatrick     // Initial setup.
1953cab2bb3Spatrick     CHECK_EQ(kCfiShadowLimitsStorageSize, GetPageSizeCached());
1963cab2bb3Spatrick     CHECK_EQ(0, GetShadow());
1973cab2bb3Spatrick     cfi_shadow_limits_storage.limits.start = shadow_;
1983cab2bb3Spatrick     MprotectReadOnly((uptr)&cfi_shadow_limits_storage,
1993cab2bb3Spatrick                      sizeof(cfi_shadow_limits_storage));
2003cab2bb3Spatrick     CHECK_EQ(shadow_, GetShadow());
2013cab2bb3Spatrick   }
2023cab2bb3Spatrick }
2033cab2bb3Spatrick #else
2043cab2bb3Spatrick #error not implemented
2053cab2bb3Spatrick #endif
2063cab2bb3Spatrick 
2073cab2bb3Spatrick // This is a workaround for a glibc bug:
2083cab2bb3Spatrick // https://sourceware.org/bugzilla/show_bug.cgi?id=15199
2093cab2bb3Spatrick // Other platforms can, hopefully, just do
2103cab2bb3Spatrick //    dlopen(RTLD_NOLOAD | RTLD_LAZY)
2113cab2bb3Spatrick //    dlsym("__cfi_check").
find_cfi_check_in_dso(dl_phdr_info * info)2123cab2bb3Spatrick uptr find_cfi_check_in_dso(dl_phdr_info *info) {
2133cab2bb3Spatrick   const Elf_Dyn *dynamic = nullptr;
2143cab2bb3Spatrick   for (int i = 0; i < info->dlpi_phnum; ++i) {
2153cab2bb3Spatrick     if (info->dlpi_phdr[i].p_type == PT_DYNAMIC) {
2163cab2bb3Spatrick       dynamic =
2173cab2bb3Spatrick           (const Elf_Dyn *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
2183cab2bb3Spatrick       break;
2193cab2bb3Spatrick     }
2203cab2bb3Spatrick   }
2213cab2bb3Spatrick   if (!dynamic) return 0;
2223cab2bb3Spatrick   uptr strtab = 0, symtab = 0, strsz = 0;
2233cab2bb3Spatrick   for (const Elf_Dyn *p = dynamic; p->d_tag != PT_NULL; ++p) {
2243cab2bb3Spatrick     if (p->d_tag == DT_SYMTAB)
2253cab2bb3Spatrick       symtab = p->d_un.d_ptr;
2263cab2bb3Spatrick     else if (p->d_tag == DT_STRTAB)
2273cab2bb3Spatrick       strtab = p->d_un.d_ptr;
2283cab2bb3Spatrick     else if (p->d_tag == DT_STRSZ)
2293cab2bb3Spatrick       strsz = p->d_un.d_ptr;
2303cab2bb3Spatrick   }
2313cab2bb3Spatrick 
2323cab2bb3Spatrick   if (symtab > strtab) {
233*810390e3Srobert     VReport(1, "Can not handle: symtab > strtab (%zx > %zx)\n", symtab, strtab);
2343cab2bb3Spatrick     return 0;
2353cab2bb3Spatrick   }
2363cab2bb3Spatrick 
2373cab2bb3Spatrick   // Verify that strtab and symtab are inside of the same LOAD segment.
2383cab2bb3Spatrick   // This excludes VDSO, which has (very high) bogus strtab and symtab pointers.
2393cab2bb3Spatrick   int phdr_idx;
2403cab2bb3Spatrick   for (phdr_idx = 0; phdr_idx < info->dlpi_phnum; phdr_idx++) {
2413cab2bb3Spatrick     const Elf_Phdr *phdr = &info->dlpi_phdr[phdr_idx];
2423cab2bb3Spatrick     if (phdr->p_type == PT_LOAD) {
2433cab2bb3Spatrick       uptr beg = info->dlpi_addr + phdr->p_vaddr;
2443cab2bb3Spatrick       uptr end = beg + phdr->p_memsz;
2453cab2bb3Spatrick       if (strtab >= beg && strtab + strsz < end && symtab >= beg &&
2463cab2bb3Spatrick           symtab < end)
2473cab2bb3Spatrick         break;
2483cab2bb3Spatrick     }
2493cab2bb3Spatrick   }
2503cab2bb3Spatrick   if (phdr_idx == info->dlpi_phnum) {
2513cab2bb3Spatrick     // Nope, either different segments or just bogus pointers.
2523cab2bb3Spatrick     // Can not handle this.
253*810390e3Srobert     VReport(1, "Can not handle: symtab %zx, strtab %zx\n", symtab, strtab);
2543cab2bb3Spatrick     return 0;
2553cab2bb3Spatrick   }
2563cab2bb3Spatrick 
2573cab2bb3Spatrick   for (const Elf_Sym *p = (const Elf_Sym *)symtab; (Elf_Addr)p < strtab;
2583cab2bb3Spatrick        ++p) {
2593cab2bb3Spatrick     // There is no reliable way to find the end of the symbol table. In
2603cab2bb3Spatrick     // lld-produces files, there are other sections between symtab and strtab.
2613cab2bb3Spatrick     // Stop looking when the symbol name is not inside strtab.
2623cab2bb3Spatrick     if (p->st_name >= strsz) break;
2633cab2bb3Spatrick     char *name = (char*)(strtab + p->st_name);
2643cab2bb3Spatrick     if (strcmp(name, "__cfi_check") == 0) {
2653cab2bb3Spatrick       assert(p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC) ||
2663cab2bb3Spatrick              p->st_info == ELF32_ST_INFO(STB_WEAK, STT_FUNC));
2673cab2bb3Spatrick       uptr addr = info->dlpi_addr + p->st_value;
2683cab2bb3Spatrick       return addr;
2693cab2bb3Spatrick     }
2703cab2bb3Spatrick   }
2713cab2bb3Spatrick   return 0;
2723cab2bb3Spatrick }
2733cab2bb3Spatrick 
dl_iterate_phdr_cb(dl_phdr_info * info,size_t size,void * data)2743cab2bb3Spatrick int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *data) {
2753cab2bb3Spatrick   uptr cfi_check = find_cfi_check_in_dso(info);
2763cab2bb3Spatrick   if (cfi_check)
2773cab2bb3Spatrick     VReport(1, "Module '%s' __cfi_check %zx\n", info->dlpi_name, cfi_check);
2783cab2bb3Spatrick 
2793cab2bb3Spatrick   ShadowBuilder *b = reinterpret_cast<ShadowBuilder *>(data);
2803cab2bb3Spatrick 
2813cab2bb3Spatrick   for (int i = 0; i < info->dlpi_phnum; i++) {
2823cab2bb3Spatrick     const Elf_Phdr *phdr = &info->dlpi_phdr[i];
2833cab2bb3Spatrick     if (phdr->p_type == PT_LOAD) {
2843cab2bb3Spatrick       // Jump tables are in the executable segment.
2853cab2bb3Spatrick       // VTables are in the non-executable one.
2863cab2bb3Spatrick       // Need to fill shadow for both.
2873cab2bb3Spatrick       // FIXME: reject writable if vtables are in the r/o segment. Depend on
2883cab2bb3Spatrick       // PT_RELRO?
2893cab2bb3Spatrick       uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
2903cab2bb3Spatrick       uptr cur_end = cur_beg + phdr->p_memsz;
2913cab2bb3Spatrick       if (cfi_check) {
2923cab2bb3Spatrick         VReport(1, "   %zx .. %zx\n", cur_beg, cur_end);
2933cab2bb3Spatrick         b->Add(cur_beg, cur_end, cfi_check);
2943cab2bb3Spatrick       } else {
2953cab2bb3Spatrick         b->AddUnchecked(cur_beg, cur_end);
2963cab2bb3Spatrick       }
2973cab2bb3Spatrick     }
2983cab2bb3Spatrick   }
2993cab2bb3Spatrick   return 0;
3003cab2bb3Spatrick }
3013cab2bb3Spatrick 
3023cab2bb3Spatrick // Init or update shadow for the current set of loaded libraries.
UpdateShadow()3033cab2bb3Spatrick void UpdateShadow() {
3043cab2bb3Spatrick   ShadowBuilder b;
3053cab2bb3Spatrick   b.Start();
3063cab2bb3Spatrick   dl_iterate_phdr(dl_iterate_phdr_cb, &b);
3073cab2bb3Spatrick   b.Install();
3083cab2bb3Spatrick }
3093cab2bb3Spatrick 
InitShadow()3103cab2bb3Spatrick void InitShadow() {
3113cab2bb3Spatrick   CHECK_EQ(0, GetShadow());
3123cab2bb3Spatrick   CHECK_EQ(0, GetShadowSize());
3133cab2bb3Spatrick 
3143cab2bb3Spatrick   uptr vma = GetMaxUserVirtualAddress();
3153cab2bb3Spatrick   // Shadow is 2 -> 2**kShadowGranularity.
3163cab2bb3Spatrick   SetShadowSize((vma >> (kShadowGranularity - 1)) + 1);
3173cab2bb3Spatrick   VReport(1, "CFI: VMA size %zx, shadow size %zx\n", vma, GetShadowSize());
3183cab2bb3Spatrick 
3193cab2bb3Spatrick   UpdateShadow();
3203cab2bb3Spatrick }
3213cab2bb3Spatrick 
3223cab2bb3Spatrick THREADLOCAL int in_loader;
323*810390e3Srobert Mutex shadow_update_lock;
3243cab2bb3Spatrick 
EnterLoader()325*810390e3Srobert void EnterLoader() SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
3263cab2bb3Spatrick   if (in_loader == 0) {
3273cab2bb3Spatrick     shadow_update_lock.Lock();
3283cab2bb3Spatrick   }
3293cab2bb3Spatrick   ++in_loader;
3303cab2bb3Spatrick }
3313cab2bb3Spatrick 
ExitLoader()332*810390e3Srobert void ExitLoader() SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
3333cab2bb3Spatrick   CHECK(in_loader > 0);
3343cab2bb3Spatrick   --in_loader;
3353cab2bb3Spatrick   UpdateShadow();
3363cab2bb3Spatrick   if (in_loader == 0) {
3373cab2bb3Spatrick     shadow_update_lock.Unlock();
3383cab2bb3Spatrick   }
3393cab2bb3Spatrick }
3403cab2bb3Spatrick 
CfiSlowPathCommon(u64 CallSiteTypeId,void * Ptr,void * DiagData)3413cab2bb3Spatrick ALWAYS_INLINE void CfiSlowPathCommon(u64 CallSiteTypeId, void *Ptr,
3423cab2bb3Spatrick                                      void *DiagData) {
3433cab2bb3Spatrick   uptr Addr = (uptr)Ptr;
3443cab2bb3Spatrick   VReport(3, "__cfi_slowpath: %llx, %p\n", CallSiteTypeId, Ptr);
3453cab2bb3Spatrick   ShadowValue sv = ShadowValue::load(Addr);
3463cab2bb3Spatrick   if (sv.is_invalid()) {
3473cab2bb3Spatrick     VReport(1, "CFI: invalid memory region for a check target: %p\n", Ptr);
3483cab2bb3Spatrick #ifdef CFI_ENABLE_DIAG
3493cab2bb3Spatrick     if (DiagData) {
3503cab2bb3Spatrick       __ubsan_handle_cfi_check_fail(
3513cab2bb3Spatrick           reinterpret_cast<__ubsan::CFICheckFailData *>(DiagData), Addr, false);
3523cab2bb3Spatrick       return;
3533cab2bb3Spatrick     }
3543cab2bb3Spatrick #endif
3553cab2bb3Spatrick     Trap();
3563cab2bb3Spatrick   }
3573cab2bb3Spatrick   if (sv.is_unchecked()) {
3583cab2bb3Spatrick     VReport(2, "CFI: unchecked call (shadow=FFFF): %p\n", Ptr);
3593cab2bb3Spatrick     return;
3603cab2bb3Spatrick   }
3613cab2bb3Spatrick   CFICheckFn cfi_check = sv.get_cfi_check();
362*810390e3Srobert   VReport(2, "__cfi_check at %p\n", (void *)cfi_check);
3633cab2bb3Spatrick   cfi_check(CallSiteTypeId, Ptr, DiagData);
3643cab2bb3Spatrick }
3653cab2bb3Spatrick 
InitializeFlags()3663cab2bb3Spatrick void InitializeFlags() {
3673cab2bb3Spatrick   SetCommonFlagsDefaults();
3683cab2bb3Spatrick #ifdef CFI_ENABLE_DIAG
3693cab2bb3Spatrick   __ubsan::Flags *uf = __ubsan::flags();
3703cab2bb3Spatrick   uf->SetDefaults();
3713cab2bb3Spatrick #endif
3723cab2bb3Spatrick 
3733cab2bb3Spatrick   FlagParser cfi_parser;
3743cab2bb3Spatrick   RegisterCommonFlags(&cfi_parser);
3753cab2bb3Spatrick   cfi_parser.ParseStringFromEnv("CFI_OPTIONS");
3763cab2bb3Spatrick 
3773cab2bb3Spatrick #ifdef CFI_ENABLE_DIAG
3783cab2bb3Spatrick   FlagParser ubsan_parser;
3793cab2bb3Spatrick   __ubsan::RegisterUbsanFlags(&ubsan_parser, uf);
3803cab2bb3Spatrick   RegisterCommonFlags(&ubsan_parser);
3813cab2bb3Spatrick 
382d89ec533Spatrick   const char *ubsan_default_options = __ubsan_default_options();
3833cab2bb3Spatrick   ubsan_parser.ParseString(ubsan_default_options);
3843cab2bb3Spatrick   ubsan_parser.ParseStringFromEnv("UBSAN_OPTIONS");
3853cab2bb3Spatrick #endif
3863cab2bb3Spatrick 
3873cab2bb3Spatrick   InitializeCommonFlags();
3883cab2bb3Spatrick 
3893cab2bb3Spatrick   if (Verbosity())
3903cab2bb3Spatrick     ReportUnrecognizedFlags();
3913cab2bb3Spatrick 
3923cab2bb3Spatrick   if (common_flags()->help) {
3933cab2bb3Spatrick     cfi_parser.PrintFlagDescriptions();
3943cab2bb3Spatrick   }
3953cab2bb3Spatrick }
3963cab2bb3Spatrick 
3973cab2bb3Spatrick } // namespace __cfi
3983cab2bb3Spatrick 
3993cab2bb3Spatrick using namespace __cfi;
4003cab2bb3Spatrick 
4013cab2bb3Spatrick extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__cfi_slowpath(u64 CallSiteTypeId,void * Ptr)4023cab2bb3Spatrick __cfi_slowpath(u64 CallSiteTypeId, void *Ptr) {
4033cab2bb3Spatrick   CfiSlowPathCommon(CallSiteTypeId, Ptr, nullptr);
4043cab2bb3Spatrick }
4053cab2bb3Spatrick 
4063cab2bb3Spatrick #ifdef CFI_ENABLE_DIAG
4073cab2bb3Spatrick extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
__cfi_slowpath_diag(u64 CallSiteTypeId,void * Ptr,void * DiagData)4083cab2bb3Spatrick __cfi_slowpath_diag(u64 CallSiteTypeId, void *Ptr, void *DiagData) {
4093cab2bb3Spatrick   CfiSlowPathCommon(CallSiteTypeId, Ptr, DiagData);
4103cab2bb3Spatrick }
4113cab2bb3Spatrick #endif
4123cab2bb3Spatrick 
4133cab2bb3Spatrick static void EnsureInterceptorsInitialized();
4143cab2bb3Spatrick 
4153cab2bb3Spatrick // Setup shadow for dlopen()ed libraries.
4163cab2bb3Spatrick // The actual shadow setup happens after dlopen() returns, which means that
4173cab2bb3Spatrick // a library can not be a target of any CFI checks while its constructors are
4183cab2bb3Spatrick // running. It's unclear how to fix this without some extra help from libc.
4193cab2bb3Spatrick // In glibc, mmap inside dlopen is not interceptable.
4203cab2bb3Spatrick // Maybe a seccomp-bpf filter?
4213cab2bb3Spatrick // We could insert a high-priority constructor into the library, but that would
4223cab2bb3Spatrick // not help with the uninstrumented libraries.
INTERCEPTOR(void *,dlopen,const char * filename,int flag)4233cab2bb3Spatrick INTERCEPTOR(void*, dlopen, const char *filename, int flag) {
4243cab2bb3Spatrick   EnsureInterceptorsInitialized();
4253cab2bb3Spatrick   EnterLoader();
4263cab2bb3Spatrick   void *handle = REAL(dlopen)(filename, flag);
4273cab2bb3Spatrick   ExitLoader();
4283cab2bb3Spatrick   return handle;
4293cab2bb3Spatrick }
4303cab2bb3Spatrick 
INTERCEPTOR(int,dlclose,void * handle)4313cab2bb3Spatrick INTERCEPTOR(int, dlclose, void *handle) {
4323cab2bb3Spatrick   EnsureInterceptorsInitialized();
4333cab2bb3Spatrick   EnterLoader();
4343cab2bb3Spatrick   int res = REAL(dlclose)(handle);
4353cab2bb3Spatrick   ExitLoader();
4363cab2bb3Spatrick   return res;
4373cab2bb3Spatrick }
4383cab2bb3Spatrick 
439*810390e3Srobert static Mutex interceptor_init_lock;
4403cab2bb3Spatrick static bool interceptors_inited = false;
4413cab2bb3Spatrick 
EnsureInterceptorsInitialized()4423cab2bb3Spatrick static void EnsureInterceptorsInitialized() {
443*810390e3Srobert   Lock lock(&interceptor_init_lock);
4443cab2bb3Spatrick   if (interceptors_inited)
4453cab2bb3Spatrick     return;
4463cab2bb3Spatrick 
4473cab2bb3Spatrick   INTERCEPT_FUNCTION(dlopen);
4483cab2bb3Spatrick   INTERCEPT_FUNCTION(dlclose);
4493cab2bb3Spatrick 
4503cab2bb3Spatrick   interceptors_inited = true;
4513cab2bb3Spatrick }
4523cab2bb3Spatrick 
4533cab2bb3Spatrick extern "C" SANITIZER_INTERFACE_ATTRIBUTE
4543cab2bb3Spatrick #if !SANITIZER_CAN_USE_PREINIT_ARRAY
4553cab2bb3Spatrick // On ELF platforms, the constructor is invoked using .preinit_array (see below)
4563cab2bb3Spatrick __attribute__((constructor(0)))
4573cab2bb3Spatrick #endif
__cfi_init()4583cab2bb3Spatrick void __cfi_init() {
4593cab2bb3Spatrick   SanitizerToolName = "CFI";
4603cab2bb3Spatrick   InitializeFlags();
4613cab2bb3Spatrick   InitShadow();
4623cab2bb3Spatrick 
4633cab2bb3Spatrick #ifdef CFI_ENABLE_DIAG
4643cab2bb3Spatrick   __ubsan::InitAsPlugin();
4653cab2bb3Spatrick #endif
4663cab2bb3Spatrick }
4673cab2bb3Spatrick 
4683cab2bb3Spatrick #if SANITIZER_CAN_USE_PREINIT_ARRAY
4693cab2bb3Spatrick // On ELF platforms, run cfi initialization before any other constructors.
4703cab2bb3Spatrick // On other platforms we use the constructor attribute to arrange to run our
4713cab2bb3Spatrick // initialization early.
4723cab2bb3Spatrick extern "C" {
4733cab2bb3Spatrick __attribute__((section(".preinit_array"),
4743cab2bb3Spatrick                used)) void (*__cfi_preinit)(void) = __cfi_init;
4753cab2bb3Spatrick }
4763cab2bb3Spatrick #endif
477