Home | History | Annotate | Line # | Download | only in hwasan
      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 
     18 namespace __hwasan {
     19 
     20 enum { NT_LLVM_HWASAN_GLOBALS = 3 };
     21 struct 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.
     29 static 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("FATAL: HWAddressSanitizer: library size exceeds 2^32\n");
     44     Die();
     45   }
     46   if (max_addr > 1ull << 48) {
     47     Report("FATAL: HWAddressSanitizer: library loaded above address 2^48\n");
     48     Die();
     49   }
     50 }
     51 
     52 ArrayRef<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(nhdr->n_namesz, 4);
     68 
     69       // Discard non-HWASan-Globals notes.
     70       if (nhdr->n_type != NT_LLVM_HWASAN_GLOBALS ||
     71           internal_strcmp(name, "LLVM") != 0) {
     72         note = desc + RoundUpTo(nhdr->n_descsz, 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