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