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
16namespace __hwasan {
17
18enum { NT_LLVM_HWASAN_GLOBALS = 3 };
19struct 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.
27static 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
50ArrayRef<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