cfi.cpp 14 KB

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