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