91 lines
3 KiB
C++
91 lines
3 KiB
C++
//===-- hwasan_globals.cpp ------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file is a part of HWAddressSanitizer.
|
|
//
|
|
// HWAddressSanitizer globals-specific runtime.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "hwasan_globals.h"
|
|
|
|
namespace __hwasan {
|
|
|
|
enum { NT_LLVM_HWASAN_GLOBALS = 3 };
|
|
struct hwasan_global_note {
|
|
s32 begin_relptr;
|
|
s32 end_relptr;
|
|
};
|
|
|
|
// Check that the given library meets the code model requirements for tagged
|
|
// globals. These properties are not checked at link time so they need to be
|
|
// checked at runtime.
|
|
static void CheckCodeModel(ElfW(Addr) base, const ElfW(Phdr) * phdr,
|
|
ElfW(Half) phnum) {
|
|
ElfW(Addr) min_addr = -1ull, max_addr = 0;
|
|
for (unsigned i = 0; i != phnum; ++i) {
|
|
if (phdr[i].p_type != PT_LOAD)
|
|
continue;
|
|
ElfW(Addr) lo = base + phdr[i].p_vaddr, hi = lo + phdr[i].p_memsz;
|
|
if (min_addr > lo)
|
|
min_addr = lo;
|
|
if (max_addr < hi)
|
|
max_addr = hi;
|
|
}
|
|
|
|
if (max_addr - min_addr > 1ull << 32) {
|
|
Report("FATAL: HWAddressSanitizer: library size exceeds 2^32\n");
|
|
Die();
|
|
}
|
|
if (max_addr > 1ull << 48) {
|
|
Report("FATAL: HWAddressSanitizer: library loaded above address 2^48\n");
|
|
Die();
|
|
}
|
|
}
|
|
|
|
ArrayRef<const hwasan_global> HwasanGlobalsFor(ElfW(Addr) base,
|
|
const ElfW(Phdr) * phdr,
|
|
ElfW(Half) phnum) {
|
|
// Read the phdrs from this DSO.
|
|
for (unsigned i = 0; i != phnum; ++i) {
|
|
if (phdr[i].p_type != PT_NOTE)
|
|
continue;
|
|
|
|
const char *note = reinterpret_cast<const char *>(base + phdr[i].p_vaddr);
|
|
const char *nend = note + phdr[i].p_memsz;
|
|
|
|
// Traverse all the notes until we find a HWASan note.
|
|
while (note < nend) {
|
|
auto *nhdr = reinterpret_cast<const ElfW(Nhdr) *>(note);
|
|
const char *name = note + sizeof(ElfW(Nhdr));
|
|
const char *desc = name + RoundUpTo(nhdr->n_namesz, 4);
|
|
|
|
// Discard non-HWASan-Globals notes.
|
|
if (nhdr->n_type != NT_LLVM_HWASAN_GLOBALS ||
|
|
internal_strcmp(name, "LLVM") != 0) {
|
|
note = desc + RoundUpTo(nhdr->n_descsz, 4);
|
|
continue;
|
|
}
|
|
|
|
// Only libraries with instrumented globals need to be checked against the
|
|
// code model since they use relocations that aren't checked at link time.
|
|
CheckCodeModel(base, phdr, phnum);
|
|
|
|
auto *global_note = reinterpret_cast<const hwasan_global_note *>(desc);
|
|
auto *globals_begin = reinterpret_cast<const hwasan_global *>(
|
|
note + global_note->begin_relptr);
|
|
auto *globals_end = reinterpret_cast<const hwasan_global *>(
|
|
note + global_note->end_relptr);
|
|
|
|
return {globals_begin, globals_end};
|
|
}
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
} // namespace __hwasan
|