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