xref: /freebsd/contrib/llvm-project/compiler-rt/lib/hwasan/hwasan_globals.cpp (revision 7ef62cebc2f965b0f640263e179276928885e33d)
1 //===-- hwasan_globals.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 is a part of HWAddressSanitizer.
10 //
11 // HWAddressSanitizer globals-specific runtime.
12 //===----------------------------------------------------------------------===//
13 
14 #include "hwasan_globals.h"
15 
16 namespace __hwasan {
17 
18 enum { NT_LLVM_HWASAN_GLOBALS = 3 };
19 struct hwasan_global_note {
20   s32 begin_relptr;
21   s32 end_relptr;
22 };
23 
24 // Check that the given library meets the code model requirements for tagged
25 // globals. These properties are not checked at link time so they need to be
26 // checked at runtime.
27 static void CheckCodeModel(ElfW(Addr) base, const ElfW(Phdr) * phdr,
28                            ElfW(Half) phnum) {
29   ElfW(Addr) min_addr = -1ull, max_addr = 0;
30   for (unsigned i = 0; i != phnum; ++i) {
31     if (phdr[i].p_type != PT_LOAD)
32       continue;
33     ElfW(Addr) lo = base + phdr[i].p_vaddr, hi = lo + phdr[i].p_memsz;
34     if (min_addr > lo)
35       min_addr = lo;
36     if (max_addr < hi)
37       max_addr = hi;
38   }
39 
40   if (max_addr - min_addr > 1ull << 32) {
41     Report("FATAL: HWAddressSanitizer: library size exceeds 2^32\n");
42     Die();
43   }
44   if (max_addr > 1ull << 48) {
45     Report("FATAL: HWAddressSanitizer: library loaded above address 2^48\n");
46     Die();
47   }
48 }
49 
50 ArrayRef<const hwasan_global> HwasanGlobalsFor(ElfW(Addr) base,
51                                                const ElfW(Phdr) * phdr,
52                                                ElfW(Half) phnum) {
53   // Read the phdrs from this DSO.
54   for (unsigned i = 0; i != phnum; ++i) {
55     if (phdr[i].p_type != PT_NOTE)
56       continue;
57 
58     const char *note = reinterpret_cast<const char *>(base + phdr[i].p_vaddr);
59     const char *nend = note + phdr[i].p_memsz;
60 
61     // Traverse all the notes until we find a HWASan note.
62     while (note < nend) {
63       auto *nhdr = reinterpret_cast<const ElfW(Nhdr) *>(note);
64       const char *name = note + sizeof(ElfW(Nhdr));
65       const char *desc = name + RoundUpTo(nhdr->n_namesz, 4);
66 
67       // Discard non-HWASan-Globals notes.
68       if (nhdr->n_type != NT_LLVM_HWASAN_GLOBALS ||
69           internal_strcmp(name, "LLVM") != 0) {
70         note = desc + RoundUpTo(nhdr->n_descsz, 4);
71         continue;
72       }
73 
74       // Only libraries with instrumented globals need to be checked against the
75       // code model since they use relocations that aren't checked at link time.
76       CheckCodeModel(base, phdr, phnum);
77 
78       auto *global_note = reinterpret_cast<const hwasan_global_note *>(desc);
79       auto *globals_begin = reinterpret_cast<const hwasan_global *>(
80           note + global_note->begin_relptr);
81       auto *globals_end = reinterpret_cast<const hwasan_global *>(
82           note + global_note->end_relptr);
83 
84       return {globals_begin, globals_end};
85     }
86   }
87 
88   return {};
89 }
90 
91 }  // namespace __hwasan
92