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 // FIXME: Intercept dlopen/dlclose. 15 // FIXME: Support diagnostic mode. 16 // FIXME: Harden: 17 // * mprotect shadow, use mremap for updates 18 // * something else equally important 19 20 #include <assert.h> 21 #include <elf.h> 22 #include <link.h> 23 #include <string.h> 24 25 typedef ElfW(Phdr) Elf_Phdr; 26 typedef ElfW(Ehdr) Elf_Ehdr; 27 28 #include "interception/interception.h" 29 #include "sanitizer_common/sanitizer_common.h" 30 #include "sanitizer_common/sanitizer_flag_parser.h" 31 #include "ubsan/ubsan_init.h" 32 #include "ubsan/ubsan_flags.h" 33 34 static uptr __cfi_shadow; 35 static constexpr uptr kShadowGranularity = 12; 36 static constexpr uptr kShadowAlign = 1UL << kShadowGranularity; // 4096 37 38 static constexpr uint16_t kInvalidShadow = 0; 39 static constexpr uint16_t kUncheckedShadow = 0xFFFFU; 40 41 static uint16_t *mem_to_shadow(uptr x) { 42 return (uint16_t *)(__cfi_shadow + ((x >> kShadowGranularity) << 1)); 43 } 44 45 typedef int (*CFICheckFn)(uptr, void *); 46 47 class ShadowValue { 48 uptr addr; 49 uint16_t v; 50 explicit ShadowValue(uptr addr, uint16_t v) : addr(addr), v(v) {} 51 52 public: 53 bool is_invalid() const { return v == kInvalidShadow; } 54 55 bool is_unchecked() const { return v == kUncheckedShadow; } 56 57 CFICheckFn get_cfi_check() const { 58 assert(!is_invalid() && !is_unchecked()); 59 uptr aligned_addr = addr & ~(kShadowAlign - 1); 60 uptr p = aligned_addr - (((uptr)v - 1) << kShadowGranularity); 61 return reinterpret_cast<CFICheckFn>(p); 62 } 63 64 // Load a shadow valud for the given application memory address. 65 static const ShadowValue load(uptr addr) { 66 return ShadowValue(addr, *mem_to_shadow(addr)); 67 } 68 }; 69 70 static void fill_shadow_constant(uptr begin, uptr end, uint16_t v) { 71 assert(v == kInvalidShadow || v == kUncheckedShadow); 72 uint16_t *shadow_begin = mem_to_shadow(begin); 73 uint16_t *shadow_end = mem_to_shadow(end - 1) + 1; 74 memset(shadow_begin, v, (shadow_end - shadow_begin) * sizeof(*shadow_begin)); 75 } 76 77 static void fill_shadow(uptr begin, uptr end, uptr cfi_check) { 78 assert((cfi_check & (kShadowAlign - 1)) == 0); 79 80 // Don't fill anything below cfi_check. We can not represent those addresses 81 // in the shadow, and must make sure at codegen to place all valid call 82 // targets above cfi_check. 83 uptr p = Max(begin, cfi_check); 84 uint16_t *s = mem_to_shadow(p); 85 uint16_t *s_end = mem_to_shadow(end - 1) + 1; 86 uint16_t sv = ((p - cfi_check) >> kShadowGranularity) + 1; 87 for (; s < s_end; s++, sv++) 88 *s = sv; 89 90 // Sanity checks. 91 uptr q = p & ~(kShadowAlign - 1); 92 for (; q < end; q += kShadowAlign) { 93 assert((uptr)ShadowValue::load(q).get_cfi_check() == cfi_check); 94 assert((uptr)ShadowValue::load(q + kShadowAlign / 2).get_cfi_check() == 95 cfi_check); 96 assert((uptr)ShadowValue::load(q + kShadowAlign - 1).get_cfi_check() == 97 cfi_check); 98 } 99 } 100 101 // This is a workaround for a glibc bug: 102 // https://sourceware.org/bugzilla/show_bug.cgi?id=15199 103 // Other platforms can, hopefully, just do 104 // dlopen(RTLD_NOLOAD | RTLD_LAZY) 105 // dlsym("__cfi_check"). 106 static uptr find_cfi_check_in_dso(dl_phdr_info *info) { 107 const ElfW(Dyn) *dynamic = nullptr; 108 for (int i = 0; i < info->dlpi_phnum; ++i) { 109 if (info->dlpi_phdr[i].p_type == PT_DYNAMIC) { 110 dynamic = 111 (const ElfW(Dyn) *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr); 112 break; 113 } 114 } 115 if (!dynamic) return 0; 116 uptr strtab = 0, symtab = 0; 117 for (const ElfW(Dyn) *p = dynamic; p->d_tag != PT_NULL; ++p) { 118 if (p->d_tag == DT_SYMTAB) 119 symtab = p->d_un.d_ptr; 120 else if (p->d_tag == DT_STRTAB) 121 strtab = p->d_un.d_ptr; 122 } 123 124 if (symtab > strtab) { 125 VReport(1, "Can not handle: symtab > strtab (%p > %zx)\n", symtab, strtab); 126 return 0; 127 } 128 129 // Verify that strtab and symtab are inside of the same LOAD segment. 130 // This excludes VDSO, which has (very high) bogus strtab and symtab pointers. 131 int phdr_idx; 132 for (phdr_idx = 0; phdr_idx < info->dlpi_phnum; phdr_idx++) { 133 const Elf_Phdr *phdr = &info->dlpi_phdr[phdr_idx]; 134 if (phdr->p_type == PT_LOAD) { 135 uptr beg = info->dlpi_addr + phdr->p_vaddr; 136 uptr end = beg + phdr->p_memsz; 137 if (strtab >= beg && strtab < end && symtab >= beg && symtab < end) 138 break; 139 } 140 } 141 if (phdr_idx == info->dlpi_phnum) { 142 // Nope, either different segments or just bogus pointers. 143 // Can not handle this. 144 VReport(1, "Can not handle: symtab %p, strtab %zx\n", symtab, strtab); 145 return 0; 146 } 147 148 for (const ElfW(Sym) *p = (const ElfW(Sym) *)symtab; (ElfW(Addr))p < strtab; 149 ++p) { 150 char *name = (char*)(strtab + p->st_name); 151 if (strcmp(name, "__cfi_check") == 0) { 152 assert(p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC)); 153 uptr addr = info->dlpi_addr + p->st_value; 154 return addr; 155 } 156 } 157 return 0; 158 } 159 160 static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *data) { 161 uptr cfi_check = find_cfi_check_in_dso(info); 162 if (cfi_check) 163 VReport(1, "Module '%s' __cfi_check %zx\n", info->dlpi_name, cfi_check); 164 165 for (int i = 0; i < info->dlpi_phnum; i++) { 166 const Elf_Phdr *phdr = &info->dlpi_phdr[i]; 167 if (phdr->p_type == PT_LOAD) { 168 // Jump tables are in the executable segment. 169 // VTables are in the non-executable one. 170 // Need to fill shadow for both. 171 // FIXME: reject writable if vtables are in the r/o segment. Depend on 172 // PT_RELRO? 173 uptr cur_beg = info->dlpi_addr + phdr->p_vaddr; 174 uptr cur_end = cur_beg + phdr->p_memsz; 175 if (cfi_check) { 176 VReport(1, " %zx .. %zx\n", cur_beg, cur_end); 177 fill_shadow(cur_beg, cur_end, cfi_check ? cfi_check : (uptr)(-1)); 178 } else { 179 fill_shadow_constant(cur_beg, cur_end, kInvalidShadow); 180 } 181 } 182 } 183 return 0; 184 } 185 186 // Fill shadow for the initial libraries. 187 static void init_shadow() { 188 dl_iterate_phdr(dl_iterate_phdr_cb, nullptr); 189 } 190 191 extern "C" SANITIZER_INTERFACE_ATTRIBUTE 192 void __cfi_slowpath(uptr CallSiteTypeId, void *Ptr) { 193 uptr Addr = (uptr)Ptr; 194 VReport(3, "__cfi_slowpath: %zx, %p\n", CallSiteTypeId, Ptr); 195 ShadowValue sv = ShadowValue::load(Addr); 196 if (sv.is_invalid()) { 197 VReport(2, "CFI: invalid memory region for a function pointer (shadow==0): %p\n", Ptr); 198 Die(); 199 } 200 if (sv.is_unchecked()) { 201 VReport(2, "CFI: unchecked call (shadow=FFFF): %p\n", Ptr); 202 return; 203 } 204 CFICheckFn cfi_check = sv.get_cfi_check(); 205 VReport(2, "__cfi_check at %p\n", cfi_check); 206 cfi_check(CallSiteTypeId, Ptr); 207 } 208 209 static void InitializeFlags() { 210 SetCommonFlagsDefaults(); 211 #ifdef CFI_ENABLE_DIAG 212 __ubsan::Flags *uf = __ubsan::flags(); 213 uf->SetDefaults(); 214 #endif 215 216 FlagParser cfi_parser; 217 RegisterCommonFlags(&cfi_parser); 218 cfi_parser.ParseString(GetEnv("CFI_OPTIONS")); 219 220 #ifdef CFI_ENABLE_DIAG 221 FlagParser ubsan_parser; 222 __ubsan::RegisterUbsanFlags(&ubsan_parser, uf); 223 RegisterCommonFlags(&ubsan_parser); 224 225 const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions(); 226 ubsan_parser.ParseString(ubsan_default_options); 227 ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS")); 228 #endif 229 230 SetVerbosity(common_flags()->verbosity); 231 232 if (Verbosity()) ReportUnrecognizedFlags(); 233 234 if (common_flags()->help) { 235 cfi_parser.PrintFlagDescriptions(); 236 } 237 } 238 239 extern "C" SANITIZER_INTERFACE_ATTRIBUTE 240 #if !SANITIZER_CAN_USE_PREINIT_ARRAY 241 // On ELF platforms, the constructor is invoked using .preinit_array (see below) 242 __attribute__((constructor(0))) 243 #endif 244 void __cfi_init() { 245 SanitizerToolName = "CFI"; 246 InitializeFlags(); 247 248 uptr vma = GetMaxVirtualAddress(); 249 // Shadow is 2 -> 2**kShadowGranularity. 250 uptr shadow_size = (vma >> (kShadowGranularity - 1)) + 1; 251 VReport(1, "CFI: VMA size %zx, shadow size %zx\n", vma, shadow_size); 252 void *shadow = MmapNoReserveOrDie(shadow_size, "CFI shadow"); 253 VReport(1, "CFI: shadow at %zx .. %zx\n", shadow, 254 reinterpret_cast<uptr>(shadow) + shadow_size); 255 __cfi_shadow = (uptr)shadow; 256 init_shadow(); 257 258 #ifdef CFI_ENABLE_DIAG 259 __ubsan::InitAsPlugin(); 260 #endif 261 } 262 263 #if SANITIZER_CAN_USE_PREINIT_ARRAY 264 // On ELF platforms, run cfi initialization before any other constructors. 265 // On other platforms we use the constructor attribute to arrange to run our 266 // initialization early. 267 extern "C" { 268 __attribute__((section(".preinit_array"), 269 used)) void (*__cfi_preinit)(void) = __cfi_init; 270 } 271 #endif 272