Bug Summary

File:projects/compiler-rt/lib/cfi/cfi.cpp
Warning:line 262, column 9
Access to field 'st_name' results in a dereference of a null pointer (loaded from variable 'p')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name cfi.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mthread-model posix -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -momit-leaf-frame-pointer -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-9/lib/clang/9.0.0 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-9~svn362543/build-llvm/projects/compiler-rt/lib/cfi -I /build/llvm-toolchain-snapshot-9~svn362543/projects/compiler-rt/lib/cfi -I /build/llvm-toolchain-snapshot-9~svn362543/build-llvm/include -I /build/llvm-toolchain-snapshot-9~svn362543/include -I /build/llvm-toolchain-snapshot-9~svn362543/projects/compiler-rt/lib/cfi/.. -U NDEBUG -D CFI_ENABLE_DIAG=1 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/backward -internal-isystem /usr/include/clang/9.0.0/include/ -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-9/lib/clang/9.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-comment -Wno-unused-parameter -Wno-variadic-macros -Wno-non-virtual-dtor -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /build/llvm-toolchain-snapshot-9~svn362543/build-llvm/projects/compiler-rt/lib/cfi -fdebug-prefix-map=/build/llvm-toolchain-snapshot-9~svn362543=. -ferror-limit 19 -fmessage-length 0 -fvisibility hidden -fvisibility-inlines-hidden -fno-builtin -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -o /tmp/scan-build-2019-06-05-060531-1271-1 -x c++ /build/llvm-toolchain-snapshot-9~svn362543/projects/compiler-rt/lib/cfi/cfi.cpp -faddrsig
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
13#include <assert.h>
14#include <elf.h>
15
16#include "sanitizer_common/sanitizer_common.h"
17#if SANITIZER_FREEBSD0
18#include <sys/link_elf.h>
19#endif
20#include <link.h>
21#include <string.h>
22#include <stdlib.h>
23#include <sys/mman.h>
24
25#if SANITIZER_LINUX1
26typedef ElfW(Phdr)Elf64_Phdr Elf_Phdr;
27typedef ElfW(Ehdr)Elf64_Ehdr Elf_Ehdr;
28typedef ElfW(Addr)Elf64_Addr Elf_Addr;
29typedef ElfW(Sym)Elf64_Sym Elf_Sym;
30typedef ElfW(Dyn)Elf64_Dyn Elf_Dyn;
31#elif SANITIZER_FREEBSD0
32#if SANITIZER_WORDSIZE64 == 64
33#define ElfW64_Dyn Elf_Dyn
34#define ElfW64_Sym Elf_Sym
35#else
36#define ElfW32_Dyn Elf_Dyn
37#define ElfW32_Sym Elf_Sym
38#endif
39#endif
40
41#include "interception/interception.h"
42#include "sanitizer_common/sanitizer_flag_parser.h"
43#include "ubsan/ubsan_init.h"
44#include "ubsan/ubsan_flags.h"
45
46#ifdef CFI_ENABLE_DIAG1
47#include "ubsan/ubsan_handlers.h"
48#endif
49
50using namespace __sanitizer;
51
52namespace __cfi {
53
54#define kCfiShadowLimitsStorageSize4096 4096 // 1 page
55// Lets hope that the data segment is mapped with 4K pages.
56// The pointer to the cfi shadow region is stored at the start of this page.
57// The rest of the page is unused and re-mapped read-only.
58static union {
59 char space[kCfiShadowLimitsStorageSize4096];
60 struct {
61 uptr start;
62 uptr size;
63 } limits;
64} cfi_shadow_limits_storage
65 __attribute__((aligned(kCfiShadowLimitsStorageSize4096)));
66static constexpr uptr kShadowGranularity = 12;
67static constexpr uptr kShadowAlign = 1UL << kShadowGranularity; // 4096
68
69static constexpr uint16_t kInvalidShadow = 0;
70static constexpr uint16_t kUncheckedShadow = 0xFFFFU;
71
72// Get the start address of the CFI shadow region.
73uptr GetShadow() {
74 return cfi_shadow_limits_storage.limits.start;
75}
76
77uptr GetShadowSize() {
78 return cfi_shadow_limits_storage.limits.size;
79}
80
81// This will only work while the shadow is not allocated.
82void SetShadowSize(uptr size) {
83 cfi_shadow_limits_storage.limits.size = size;
84}
85
86uptr MemToShadowOffset(uptr x) {
87 return (x >> kShadowGranularity) << 1;
88}
89
90uint16_t *MemToShadow(uptr x, uptr shadow_base) {
91 return (uint16_t *)(shadow_base + MemToShadowOffset(x));
92}
93
94typedef int (*CFICheckFn)(u64, void *, void *);
95
96// This class reads and decodes the shadow contents.
97class ShadowValue {
98 uptr addr;
99 uint16_t v;
100 explicit ShadowValue(uptr addr, uint16_t v) : addr(addr), v(v) {}
101
102public:
103 bool is_invalid() const { return v == kInvalidShadow; }
104
105 bool is_unchecked() const { return v == kUncheckedShadow; }
106
107 CFICheckFn get_cfi_check() const {
108 assert(!is_invalid() && !is_unchecked())((!is_invalid() && !is_unchecked()) ? static_cast<
void> (0) : __assert_fail ("!is_invalid() && !is_unchecked()"
, "/build/llvm-toolchain-snapshot-9~svn362543/projects/compiler-rt/lib/cfi/cfi.cpp"
, 108, __PRETTY_FUNCTION__))
;
109 uptr aligned_addr = addr & ~(kShadowAlign - 1);
110 uptr p = aligned_addr - (((uptr)v - 1) << kShadowGranularity);
111 return reinterpret_cast<CFICheckFn>(p);
112 }
113
114 // Load a shadow value for the given application memory address.
115 static const ShadowValue load(uptr addr) {
116 uptr shadow_base = GetShadow();
117 uptr shadow_offset = MemToShadowOffset(addr);
118 if (shadow_offset > GetShadowSize())
119 return ShadowValue(addr, kInvalidShadow);
120 else
121 return ShadowValue(
122 addr, *reinterpret_cast<uint16_t *>(shadow_base + shadow_offset));
123 }
124};
125
126class ShadowBuilder {
127 uptr shadow_;
128
129public:
130 // Allocate a new empty shadow (for the entire address space) on the side.
131 void Start();
132 // Mark the given address range as unchecked.
133 // This is used for uninstrumented libraries like libc.
134 // Any CFI check with a target in that range will pass.
135 void AddUnchecked(uptr begin, uptr end);
136 // Mark the given address range as belonging to a library with the given
137 // cfi_check function.
138 void Add(uptr begin, uptr end, uptr cfi_check);
139 // Finish shadow construction. Atomically switch the current active shadow
140 // region with the newly constructed one and deallocate the former.
141 void Install();
142};
143
144void ShadowBuilder::Start() {
145 shadow_ = (uptr)MmapNoReserveOrDie(GetShadowSize(), "CFI shadow");
146 VReport(1, "CFI: shadow at %zx .. %zx\n", shadow_, shadow_ + GetShadowSize())do { if ((uptr)Verbosity() >= (1)) Report("CFI: shadow at %zx .. %zx\n"
, shadow_, shadow_ + GetShadowSize()); } while (0)
;
147}
148
149void ShadowBuilder::AddUnchecked(uptr begin, uptr end) {
150 uint16_t *shadow_begin = MemToShadow(begin, shadow_);
151 uint16_t *shadow_end = MemToShadow(end - 1, shadow_) + 1;
152 // memset takes a byte, so our unchecked shadow value requires both bytes to
153 // be the same. Make sure we're ok during compilation.
154 static_assert((kUncheckedShadow & 0xff) == ((kUncheckedShadow >> 8) & 0xff),
155 "Both bytes of the 16-bit value must be the same!");
156 memset(shadow_begin, kUncheckedShadow & 0xff,
157 (shadow_end - shadow_begin) * sizeof(*shadow_begin));
158}
159
160void ShadowBuilder::Add(uptr begin, uptr end, uptr cfi_check) {
161 assert((cfi_check & (kShadowAlign - 1)) == 0)(((cfi_check & (kShadowAlign - 1)) == 0) ? static_cast<
void> (0) : __assert_fail ("(cfi_check & (kShadowAlign - 1)) == 0"
, "/build/llvm-toolchain-snapshot-9~svn362543/projects/compiler-rt/lib/cfi/cfi.cpp"
, 161, __PRETTY_FUNCTION__))
;
162
163 // Don't fill anything below cfi_check. We can not represent those addresses
164 // in the shadow, and must make sure at codegen to place all valid call
165 // targets above cfi_check.
166 begin = Max(begin, cfi_check);
167 uint16_t *s = MemToShadow(begin, shadow_);
168 uint16_t *s_end = MemToShadow(end - 1, shadow_) + 1;
169 uint16_t sv = ((begin - cfi_check) >> kShadowGranularity) + 1;
170 for (; s < s_end; s++, sv++)
171 *s = sv;
172}
173
174#if SANITIZER_LINUX1 || SANITIZER_FREEBSD0 || SANITIZER_NETBSD0
175void ShadowBuilder::Install() {
176 MprotectReadOnly(shadow_, GetShadowSize());
177 uptr main_shadow = GetShadow();
178 if (main_shadow) {
179 // Update.
180#if SANITIZER_LINUX1
181 void *res = mremap((void *)shadow_, GetShadowSize(), GetShadowSize(),
182 MREMAP_MAYMOVE1 | MREMAP_FIXED2, (void *)main_shadow);
183 CHECK(res != MAP_FAILED)do { __sanitizer::u64 v1 = (__sanitizer::u64)((res != ((void *
) -1))); __sanitizer::u64 v2 = (__sanitizer::u64)(0); if (__builtin_expect
(!!(!(v1 != v2)), 0)) __sanitizer::CheckFailed("/build/llvm-toolchain-snapshot-9~svn362543/projects/compiler-rt/lib/cfi/cfi.cpp"
, 183, "(" "(res != ((void *) -1))" ") " "!=" " (" "0" ")", v1
, v2); } while (false)
;
184#elif SANITIZER_NETBSD0
185 void *res = mremap((void *)shadow_, GetShadowSize(), (void *)main_shadow,
186 GetShadowSize(), MAP_FIXED0x10);
187 CHECK(res != MAP_FAILED)do { __sanitizer::u64 v1 = (__sanitizer::u64)((res != ((void *
) -1))); __sanitizer::u64 v2 = (__sanitizer::u64)(0); if (__builtin_expect
(!!(!(v1 != v2)), 0)) __sanitizer::CheckFailed("/build/llvm-toolchain-snapshot-9~svn362543/projects/compiler-rt/lib/cfi/cfi.cpp"
, 187, "(" "(res != ((void *) -1))" ") " "!=" " (" "0" ")", v1
, v2); } while (false)
;
188#else
189 void *res = MmapFixedOrDie(shadow_, GetShadowSize(), "cfi shadow");
190 CHECK(res != MAP_FAILED)do { __sanitizer::u64 v1 = (__sanitizer::u64)((res != ((void *
) -1))); __sanitizer::u64 v2 = (__sanitizer::u64)(0); if (__builtin_expect
(!!(!(v1 != v2)), 0)) __sanitizer::CheckFailed("/build/llvm-toolchain-snapshot-9~svn362543/projects/compiler-rt/lib/cfi/cfi.cpp"
, 190, "(" "(res != ((void *) -1))" ") " "!=" " (" "0" ")", v1
, v2); } while (false)
;
191 ::memcpy(&shadow_, &main_shadow, GetShadowSize());
192#endif
193 } else {
194 // Initial setup.
195 CHECK_EQ(kCfiShadowLimitsStorageSize, GetPageSizeCached())do { __sanitizer::u64 v1 = (__sanitizer::u64)((4096)); __sanitizer
::u64 v2 = (__sanitizer::u64)((GetPageSizeCached())); if (__builtin_expect
(!!(!(v1 == v2)), 0)) __sanitizer::CheckFailed("/build/llvm-toolchain-snapshot-9~svn362543/projects/compiler-rt/lib/cfi/cfi.cpp"
, 195, "(" "(4096)" ") " "==" " (" "(GetPageSizeCached())" ")"
, v1, v2); } while (false)
;
196 CHECK_EQ(0, GetShadow())do { __sanitizer::u64 v1 = (__sanitizer::u64)((0)); __sanitizer
::u64 v2 = (__sanitizer::u64)((GetShadow())); if (__builtin_expect
(!!(!(v1 == v2)), 0)) __sanitizer::CheckFailed("/build/llvm-toolchain-snapshot-9~svn362543/projects/compiler-rt/lib/cfi/cfi.cpp"
, 196, "(" "(0)" ") " "==" " (" "(GetShadow())" ")", v1, v2);
} while (false)
;
197 cfi_shadow_limits_storage.limits.start = shadow_;
198 MprotectReadOnly((uptr)&cfi_shadow_limits_storage,
199 sizeof(cfi_shadow_limits_storage));
200 CHECK_EQ(shadow_, GetShadow())do { __sanitizer::u64 v1 = (__sanitizer::u64)((shadow_)); __sanitizer
::u64 v2 = (__sanitizer::u64)((GetShadow())); if (__builtin_expect
(!!(!(v1 == v2)), 0)) __sanitizer::CheckFailed("/build/llvm-toolchain-snapshot-9~svn362543/projects/compiler-rt/lib/cfi/cfi.cpp"
, 200, "(" "(shadow_)" ") " "==" " (" "(GetShadow())" ")", v1
, v2); } while (false)
;
201 }
202}
203#else
204#error not implemented
205#endif
206
207// This is a workaround for a glibc bug:
208// https://sourceware.org/bugzilla/show_bug.cgi?id=15199
209// Other platforms can, hopefully, just do
210// dlopen(RTLD_NOLOAD | RTLD_LAZY)
211// dlsym("__cfi_check").
212uptr find_cfi_check_in_dso(dl_phdr_info *info) {
213 const Elf_Dyn *dynamic = nullptr;
214 for (int i = 0; i < info->dlpi_phnum; ++i) {
2
Assuming the condition is true
3
Loop condition is true. Entering loop body
6
Assuming the condition is true
7
Loop condition is true. Entering loop body
215 if (info->dlpi_phdr[i].p_type == PT_DYNAMIC2) {
4
Assuming the condition is false
5
Taking false branch
8
Assuming the condition is true
9
Taking true branch
216 dynamic =
217 (const Elf_Dyn *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
218 break;
10
Execution continues on line 221
219 }
220 }
221 if (!dynamic) return 0;
11
Assuming 'dynamic' is non-null
12
Taking false branch
222 uptr strtab = 0, symtab = 0, strsz = 0;
13
'symtab' initialized to 0
223 for (const Elf_Dyn *p = dynamic; p->d_tag != PT_NULL0; ++p) {
14
Assuming the condition is true
15
Loop condition is true. Entering loop body
20
Assuming the condition is false
21
Loop condition is false. Execution continues on line 232
224 if (p->d_tag == DT_SYMTAB6)
16
Assuming the condition is false
17
Taking false branch
225 symtab = p->d_un.d_ptr;
226 else if (p->d_tag == DT_STRTAB5)
18
Assuming the condition is true
19
Taking true branch
227 strtab = p->d_un.d_ptr;
228 else if (p->d_tag == DT_STRSZ10)
229 strsz = p->d_un.d_ptr;
230 }
231
232 if (symtab > strtab) {
22
Taking false branch
233 VReport(1, "Can not handle: symtab > strtab (%p > %zx)\n", symtab, strtab)do { if ((uptr)Verbosity() >= (1)) Report("Can not handle: symtab > strtab (%p > %zx)\n"
, symtab, strtab); } while (0)
;
234 return 0;
235 }
236
237 // Verify that strtab and symtab are inside of the same LOAD segment.
238 // This excludes VDSO, which has (very high) bogus strtab and symtab pointers.
239 int phdr_idx;
240 for (phdr_idx = 0; phdr_idx < info->dlpi_phnum; phdr_idx++) {
23
Loop condition is true. Entering loop body
241 const Elf_Phdr *phdr = &info->dlpi_phdr[phdr_idx];
242 if (phdr->p_type == PT_LOAD1) {
24
Assuming the condition is true
25
Taking true branch
243 uptr beg = info->dlpi_addr + phdr->p_vaddr;
244 uptr end = beg + phdr->p_memsz;
245 if (strtab >= beg && strtab + strsz < end && symtab >= beg &&
26
Assuming 'strtab' is >= 'beg'
27
Assuming the condition is true
28
Assuming 'symtab' is >= 'beg'
30
Taking true branch
246 symtab < end)
29
Assuming 'symtab' is < 'end'
247 break;
31
Execution continues on line 250
248 }
249 }
250 if (phdr_idx == info->dlpi_phnum) {
32
Taking false branch
251 // Nope, either different segments or just bogus pointers.
252 // Can not handle this.
253 VReport(1, "Can not handle: symtab %p, strtab %zx\n", symtab, strtab)do { if ((uptr)Verbosity() >= (1)) Report("Can not handle: symtab %p, strtab %zx\n"
, symtab, strtab); } while (0)
;
254 return 0;
255 }
256
257 for (const Elf_Sym *p = (const Elf_Sym *)symtab; (Elf_Addr)p < strtab;
33
'p' initialized to a null pointer value
34
Assuming 'p' is < 'strtab'
35
Loop condition is true. Entering loop body
258 ++p) {
259 // There is no reliable way to find the end of the symbol table. In
260 // lld-produces files, there are other sections between symtab and strtab.
261 // Stop looking when the symbol name is not inside strtab.
262 if (p->st_name >= strsz) break;
36
Access to field 'st_name' results in a dereference of a null pointer (loaded from variable 'p')
263 char *name = (char*)(strtab + p->st_name);
264 if (strcmp(name, "__cfi_check") == 0) {
265 assert(p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC) ||((p->st_info == (((1) << 4) + ((2) & 0xf)) || p->
st_info == (((2) << 4) + ((2) & 0xf))) ? static_cast
<void> (0) : __assert_fail ("p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC) || p->st_info == ELF32_ST_INFO(STB_WEAK, STT_FUNC)"
, "/build/llvm-toolchain-snapshot-9~svn362543/projects/compiler-rt/lib/cfi/cfi.cpp"
, 266, __PRETTY_FUNCTION__))
266 p->st_info == ELF32_ST_INFO(STB_WEAK, STT_FUNC))((p->st_info == (((1) << 4) + ((2) & 0xf)) || p->
st_info == (((2) << 4) + ((2) & 0xf))) ? static_cast
<void> (0) : __assert_fail ("p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC) || p->st_info == ELF32_ST_INFO(STB_WEAK, STT_FUNC)"
, "/build/llvm-toolchain-snapshot-9~svn362543/projects/compiler-rt/lib/cfi/cfi.cpp"
, 266, __PRETTY_FUNCTION__))
;
267 uptr addr = info->dlpi_addr + p->st_value;
268 return addr;
269 }
270 }
271 return 0;
272}
273
274int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *data) {
275 uptr cfi_check = find_cfi_check_in_dso(info);
1
Calling 'find_cfi_check_in_dso'
276 if (cfi_check)
277 VReport(1, "Module '%s' __cfi_check %zx\n", info->dlpi_name, cfi_check)do { if ((uptr)Verbosity() >= (1)) Report("Module '%s' __cfi_check %zx\n"
, info->dlpi_name, cfi_check); } while (0)
;
278
279 ShadowBuilder *b = reinterpret_cast<ShadowBuilder *>(data);
280
281 for (int i = 0; i < info->dlpi_phnum; i++) {
282 const Elf_Phdr *phdr = &info->dlpi_phdr[i];
283 if (phdr->p_type == PT_LOAD1) {
284 // Jump tables are in the executable segment.
285 // VTables are in the non-executable one.
286 // Need to fill shadow for both.
287 // FIXME: reject writable if vtables are in the r/o segment. Depend on
288 // PT_RELRO?
289 uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
290 uptr cur_end = cur_beg + phdr->p_memsz;
291 if (cfi_check) {
292 VReport(1, " %zx .. %zx\n", cur_beg, cur_end)do { if ((uptr)Verbosity() >= (1)) Report(" %zx .. %zx\n"
, cur_beg, cur_end); } while (0)
;
293 b->Add(cur_beg, cur_end, cfi_check);
294 } else {
295 b->AddUnchecked(cur_beg, cur_end);
296 }
297 }
298 }
299 return 0;
300}
301
302// Init or update shadow for the current set of loaded libraries.
303void UpdateShadow() {
304 ShadowBuilder b;
305 b.Start();
306 dl_iterate_phdr(dl_iterate_phdr_cb, &b);
307 b.Install();
308}
309
310void InitShadow() {
311 CHECK_EQ(0, GetShadow())do { __sanitizer::u64 v1 = (__sanitizer::u64)((0)); __sanitizer
::u64 v2 = (__sanitizer::u64)((GetShadow())); if (__builtin_expect
(!!(!(v1 == v2)), 0)) __sanitizer::CheckFailed("/build/llvm-toolchain-snapshot-9~svn362543/projects/compiler-rt/lib/cfi/cfi.cpp"
, 311, "(" "(0)" ") " "==" " (" "(GetShadow())" ")", v1, v2);
} while (false)
;
312 CHECK_EQ(0, GetShadowSize())do { __sanitizer::u64 v1 = (__sanitizer::u64)((0)); __sanitizer
::u64 v2 = (__sanitizer::u64)((GetShadowSize())); if (__builtin_expect
(!!(!(v1 == v2)), 0)) __sanitizer::CheckFailed("/build/llvm-toolchain-snapshot-9~svn362543/projects/compiler-rt/lib/cfi/cfi.cpp"
, 312, "(" "(0)" ") " "==" " (" "(GetShadowSize())" ")", v1, v2
); } while (false)
;
313
314 uptr vma = GetMaxUserVirtualAddress();
315 // Shadow is 2 -> 2**kShadowGranularity.
316 SetShadowSize((vma >> (kShadowGranularity - 1)) + 1);
317 VReport(1, "CFI: VMA size %zx, shadow size %zx\n", vma, GetShadowSize())do { if ((uptr)Verbosity() >= (1)) Report("CFI: VMA size %zx, shadow size %zx\n"
, vma, GetShadowSize()); } while (0)
;
318
319 UpdateShadow();
320}
321
322THREADLOCAL__thread int in_loader;
323BlockingMutex shadow_update_lock(LINKER_INITIALIZED);
324
325void EnterLoader() {
326 if (in_loader == 0) {
327 shadow_update_lock.Lock();
328 }
329 ++in_loader;
330}
331
332void ExitLoader() {
333 CHECK(in_loader > 0)do { __sanitizer::u64 v1 = (__sanitizer::u64)((in_loader >
0)); __sanitizer::u64 v2 = (__sanitizer::u64)(0); if (__builtin_expect
(!!(!(v1 != v2)), 0)) __sanitizer::CheckFailed("/build/llvm-toolchain-snapshot-9~svn362543/projects/compiler-rt/lib/cfi/cfi.cpp"
, 333, "(" "(in_loader > 0)" ") " "!=" " (" "0" ")", v1, v2
); } while (false)
;
334 --in_loader;
335 UpdateShadow();
336 if (in_loader == 0) {
337 shadow_update_lock.Unlock();
338 }
339}
340
341ALWAYS_INLINEinline __attribute__((always_inline)) void CfiSlowPathCommon(u64 CallSiteTypeId, void *Ptr,
342 void *DiagData) {
343 uptr Addr = (uptr)Ptr;
344 VReport(3, "__cfi_slowpath: %llx, %p\n", CallSiteTypeId, Ptr)do { if ((uptr)Verbosity() >= (3)) Report("__cfi_slowpath: %llx, %p\n"
, CallSiteTypeId, Ptr); } while (0)
;
345 ShadowValue sv = ShadowValue::load(Addr);
346 if (sv.is_invalid()) {
347 VReport(1, "CFI: invalid memory region for a check target: %p\n", Ptr)do { if ((uptr)Verbosity() >= (1)) Report("CFI: invalid memory region for a check target: %p\n"
, Ptr); } while (0)
;
348#ifdef CFI_ENABLE_DIAG1
349 if (DiagData) {
350 __ubsan_handle_cfi_check_fail(
351 reinterpret_cast<__ubsan::CFICheckFailData *>(DiagData), Addr, false);
352 return;
353 }
354#endif
355 Trap();
356 }
357 if (sv.is_unchecked()) {
358 VReport(2, "CFI: unchecked call (shadow=FFFF): %p\n", Ptr)do { if ((uptr)Verbosity() >= (2)) Report("CFI: unchecked call (shadow=FFFF): %p\n"
, Ptr); } while (0)
;
359 return;
360 }
361 CFICheckFn cfi_check = sv.get_cfi_check();
362 VReport(2, "__cfi_check at %p\n", cfi_check)do { if ((uptr)Verbosity() >= (2)) Report("__cfi_check at %p\n"
, cfi_check); } while (0)
;
363 cfi_check(CallSiteTypeId, Ptr, DiagData);
364}
365
366void InitializeFlags() {
367 SetCommonFlagsDefaults();
368#ifdef CFI_ENABLE_DIAG1
369 __ubsan::Flags *uf = __ubsan::flags();
370 uf->SetDefaults();
371#endif
372
373 FlagParser cfi_parser;
374 RegisterCommonFlags(&cfi_parser);
375 cfi_parser.ParseString(GetEnv("CFI_OPTIONS"));
376
377#ifdef CFI_ENABLE_DIAG1
378 FlagParser ubsan_parser;
379 __ubsan::RegisterUbsanFlags(&ubsan_parser, uf);
380 RegisterCommonFlags(&ubsan_parser);
381
382 const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions();
383 ubsan_parser.ParseString(ubsan_default_options);
384 ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS"));
385#endif
386
387 InitializeCommonFlags();
388
389 if (Verbosity())
390 ReportUnrecognizedFlags();
391
392 if (common_flags()->help) {
393 cfi_parser.PrintFlagDescriptions();
394 }
395}
396
397} // namespace __cfi
398
399using namespace __cfi;
400
401extern "C" SANITIZER_INTERFACE_ATTRIBUTE__attribute__((visibility("default"))) void
402__cfi_slowpath(u64 CallSiteTypeId, void *Ptr) {
403 CfiSlowPathCommon(CallSiteTypeId, Ptr, nullptr);
404}
405
406#ifdef CFI_ENABLE_DIAG1
407extern "C" SANITIZER_INTERFACE_ATTRIBUTE__attribute__((visibility("default"))) void
408__cfi_slowpath_diag(u64 CallSiteTypeId, void *Ptr, void *DiagData) {
409 CfiSlowPathCommon(CallSiteTypeId, Ptr, DiagData);
410}
411#endif
412
413static void EnsureInterceptorsInitialized();
414
415// Setup shadow for dlopen()ed libraries.
416// The actual shadow setup happens after dlopen() returns, which means that
417// a library can not be a target of any CFI checks while its constructors are
418// running. It's unclear how to fix this without some extra help from libc.
419// In glibc, mmap inside dlopen is not interceptable.
420// Maybe a seccomp-bpf filter?
421// We could insert a high-priority constructor into the library, but that would
422// not help with the uninstrumented libraries.
423INTERCEPTOR(void*, dlopen, const char *filename, int flag)typedef void* (*dlopen_type)(const char *filename, int flag);
namespace __interception { dlopen_type real_dlopen; } extern
"C" void* dlopen(const char *filename, int flag) __attribute__
((weak, alias("__interceptor_" "dlopen"), visibility("default"
))); extern "C" __attribute__((visibility("default"))) void* __interceptor_dlopen
(const char *filename, int flag)
{
424 EnsureInterceptorsInitialized();
425 EnterLoader();
426 void *handle = REAL(dlopen)__interception::real_dlopen(filename, flag);
427 ExitLoader();
428 return handle;
429}
430
431INTERCEPTOR(int, dlclose, void *handle)typedef int (*dlclose_type)(void *handle); namespace __interception
{ dlclose_type real_dlclose; } extern "C" int dlclose(void *
handle) __attribute__((weak, alias("__interceptor_" "dlclose"
), visibility("default"))); extern "C" __attribute__((visibility
("default"))) int __interceptor_dlclose(void *handle)
{
432 EnsureInterceptorsInitialized();
433 EnterLoader();
434 int res = REAL(dlclose)__interception::real_dlclose(handle);
435 ExitLoader();
436 return res;
437}
438
439static BlockingMutex interceptor_init_lock(LINKER_INITIALIZED);
440static bool interceptors_inited = false;
441
442static void EnsureInterceptorsInitialized() {
443 BlockingMutexLock lock(&interceptor_init_lock);
444 if (interceptors_inited)
445 return;
446
447 INTERCEPT_FUNCTION(dlopen)::__interception::InterceptFunction( "dlopen", (::__interception
::uptr *) & __interception::real_dlopen, (::__interception
::uptr) & (dlopen), (::__interception::uptr) & __interceptor_dlopen
)
;
448 INTERCEPT_FUNCTION(dlclose)::__interception::InterceptFunction( "dlclose", (::__interception
::uptr *) & __interception::real_dlclose, (::__interception
::uptr) & (dlclose), (::__interception::uptr) & __interceptor_dlclose
)
;
449
450 interceptors_inited = true;
451}
452
453extern "C" SANITIZER_INTERFACE_ATTRIBUTE__attribute__((visibility("default")))
454#if !SANITIZER_CAN_USE_PREINIT_ARRAY1
455// On ELF platforms, the constructor is invoked using .preinit_array (see below)
456__attribute__((constructor(0)))
457#endif
458void __cfi_init() {
459 SanitizerToolName = "CFI";
460 InitializeFlags();
461 InitShadow();
462
463#ifdef CFI_ENABLE_DIAG1
464 __ubsan::InitAsPlugin();
465#endif
466}
467
468#if SANITIZER_CAN_USE_PREINIT_ARRAY1
469// On ELF platforms, run cfi initialization before any other constructors.
470// On other platforms we use the constructor attribute to arrange to run our
471// initialization early.
472extern "C" {
473__attribute__((section(".preinit_array"),
474 used)) void (*__cfi_preinit)(void) = __cfi_init;
475}
476#endif