Currently, the code model check is always performed even if there are no globals, because: 1) the HWASan compiler pass always leaves a note 2) the HWASan runtime always performs the check if there is a HWASan globals note. This unnecessarily adds a 2**32 byte size limit. This patch elides the check if the globals note doesn't actually contain globals, thus allowing larger libraries to be successfully instrumented without globals. Sent from my iPhone
99 lines
3.3 KiB
C++
99 lines
3.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"
|
|
|
|
#include "sanitizer_common/sanitizer_array_ref.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;
|
|
}
|
|
|
|
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);
|
|
|
|
// Only libraries with instrumented globals need to be checked against the
|
|
// code model since they use relocations that aren't checked at link time.
|
|
//
|
|
// There is always a HWASan globals note ("Create the note even if we
|
|
// aren't instrumenting globals." - HWAddressSanitizer.cpp), but we can
|
|
// elide the code model check if there are no globals.
|
|
if (globals_begin != globals_end)
|
|
CheckCodeModel(base, phdr, phnum);
|
|
|
|
return {globals_begin, globals_end};
|
|
}
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
} // namespace __hwasan
|