[compiler-rt] r368102 - hwasan: Instrument globals.

Peter Collingbourne via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 6 15:07:30 PDT 2019


Author: pcc
Date: Tue Aug  6 15:07:29 2019
New Revision: 368102

URL: http://llvm.org/viewvc/llvm-project?rev=368102&view=rev
Log:
hwasan: Instrument globals.

Globals are instrumented by adding a pointer tag to their symbol values
and emitting metadata into a special section that allows the runtime to tag
their memory when the library is loaded.

Due to order of initialization issues explained in more detail in the comments,
shadow initialization cannot happen during regular global initialization.
Instead, the location of the global section is marked using an ELF note,
and we require libc support for calling a function provided by the HWASAN
runtime when libraries are loaded and unloaded.

Based on ideas discussed with @evgeny777 in D56672.

Differential Revision: https://reviews.llvm.org/D65770

Added:
    compiler-rt/trunk/test/hwasan/TestCases/global.c
Modified:
    compiler-rt/trunk/lib/hwasan/hwasan.cpp
    compiler-rt/trunk/lib/hwasan/hwasan.h
    compiler-rt/trunk/lib/hwasan/hwasan_interface_internal.h
    compiler-rt/trunk/lib/hwasan/hwasan_report.cpp
    compiler-rt/trunk/test/hwasan/lit.cfg.py

Modified: compiler-rt/trunk/lib/hwasan/hwasan.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/hwasan/hwasan.cpp?rev=368102&r1=368101&r2=368102&view=diff
==============================================================================
--- compiler-rt/trunk/lib/hwasan/hwasan.cpp (original)
+++ compiler-rt/trunk/lib/hwasan/hwasan.cpp Tue Aug  6 15:07:29 2019
@@ -193,27 +193,12 @@ void UpdateMemoryUsage() {
 void UpdateMemoryUsage() {}
 #endif
 
-// Prepare to run instrumented code on the main thread.
-void InitInstrumentation() {
-  if (hwasan_instrumentation_inited) return;
-
-  if (!InitShadow()) {
-    Printf("FATAL: HWAddressSanitizer cannot mmap the shadow memory.\n");
-    DumpProcessMap();
-    Die();
-  }
-
-  InitThreads();
-  hwasanThreadList().CreateCurrentThread();
-
-  hwasan_instrumentation_inited = 1;
-}
-
 } // namespace __hwasan
 
+using namespace __hwasan;
+
 void __sanitizer::BufferedStackTrace::UnwindImpl(
     uptr pc, uptr bp, void *context, bool request_fast, u32 max_depth) {
-  using namespace __hwasan;
   Thread *t = GetCurrentThread();
   if (!t) {
     // the thread is still being created.
@@ -231,9 +216,85 @@ void __sanitizer::BufferedStackTrace::Un
     Unwind(max_depth, pc, 0, context, 0, 0, false);
 }
 
-// Interface.
+struct hwasan_global {
+  s32 gv_relptr;
+  u32 info;
+};
+
+static void InitGlobals(const hwasan_global *begin, const hwasan_global *end) {
+  for (auto *desc = begin; desc != end; ++desc) {
+    uptr gv = reinterpret_cast<uptr>(desc) + desc->gv_relptr;
+    uptr size = desc->info & 0xffffff;
+    uptr full_granule_size = RoundDownTo(size, 16);
+    u8 tag = desc->info >> 24;
+    TagMemoryAligned(gv, full_granule_size, tag);
+    if (size % 16)
+      TagMemoryAligned(gv + full_granule_size, 16, size % 16);
+  }
+}
 
-using namespace __hwasan;
+enum { NT_LLVM_HWASAN_GLOBALS = 3 };
+
+struct hwasan_global_note {
+  s32 begin_relptr;
+  s32 end_relptr;
+};
+
+static void InitGlobalsFromPhdrs(ElfW(Addr) base, const ElfW(Phdr) * phdr,
+                                 ElfW(Half) phnum) {
+  for (; phnum != 0; ++phdr, --phnum) {
+    if (phdr->p_type != PT_NOTE)
+      continue;
+    const char *note = reinterpret_cast<const char *>(base + phdr->p_vaddr);
+    const char *nend = note + phdr->p_memsz;
+    while (note < nend) {
+      auto *nhdr = reinterpret_cast<const ElfW(Nhdr) *>(note);
+      const char *name = note + sizeof(ElfW(Nhdr));
+      const char *desc = name + nhdr->n_namesz;
+      if (nhdr->n_type != NT_LLVM_HWASAN_GLOBALS ||
+          internal_strcmp(name, "LLVM") != 0) {
+        note = desc + nhdr->n_descsz;
+        continue;
+      }
+
+      auto *global_note = reinterpret_cast<const hwasan_global_note *>(desc);
+      auto *global_begin = reinterpret_cast<const hwasan_global *>(
+          note + global_note->begin_relptr);
+      auto *global_end = reinterpret_cast<const hwasan_global *>(
+          note + global_note->end_relptr);
+      InitGlobals(global_begin, global_end);
+      return;
+    }
+  }
+}
+
+static void InitLoadedGlobals() {
+  dl_iterate_phdr(
+      [](dl_phdr_info *info, size_t size, void *data) {
+        InitGlobalsFromPhdrs(info->dlpi_addr, info->dlpi_phdr,
+                             info->dlpi_phnum);
+        return 0;
+      },
+      nullptr);
+}
+
+// Prepare to run instrumented code on the main thread.
+static void InitInstrumentation() {
+  if (hwasan_instrumentation_inited) return;
+
+  if (!InitShadow()) {
+    Printf("FATAL: HWAddressSanitizer cannot mmap the shadow memory.\n");
+    DumpProcessMap();
+    Die();
+  }
+
+  InitThreads();
+  hwasanThreadList().CreateCurrentThread();
+
+  hwasan_instrumentation_inited = 1;
+}
+
+// Interface.
 
 uptr __hwasan_shadow_memory_dynamic_address;  // Global interface symbol.
 
@@ -244,6 +305,17 @@ void __hwasan_init_frames(uptr beg, uptr
 void __hwasan_init_static() {
   InitShadowGOT();
   InitInstrumentation();
+
+  // In the non-static code path we call dl_iterate_phdr here. But at this point
+  // libc might not have been initialized enough for dl_iterate_phdr to work.
+  // Fortunately, since this is a statically linked executable we can use the
+  // linker-defined symbol __ehdr_start to find the only relevant set of phdrs.
+  extern ElfW(Ehdr) __ehdr_start;
+  InitGlobalsFromPhdrs(
+      0,
+      reinterpret_cast<const ElfW(Phdr) *>(
+          reinterpret_cast<const char *>(&__ehdr_start) + __ehdr_start.e_phoff),
+      __ehdr_start.e_phnum);
 }
 
 void __hwasan_init() {
@@ -267,6 +339,7 @@ void __hwasan_init() {
   DisableCoreDumperIfNecessary();
 
   InitInstrumentation();
+  InitLoadedGlobals();
 
   // Needs to be called here because flags()->random_tags might not have been
   // initialized when InitInstrumentation() was called.
@@ -301,6 +374,18 @@ void __hwasan_init() {
   hwasan_inited = 1;
 }
 
+void __hwasan_library_loaded(ElfW(Addr) base, const ElfW(Phdr) * phdr,
+                             ElfW(Half) phnum) {
+  InitGlobalsFromPhdrs(base, phdr, phnum);
+}
+
+void __hwasan_library_unloaded(ElfW(Addr) base, const ElfW(Phdr) * phdr,
+                               ElfW(Half) phnum) {
+  for (; phnum != 0; ++phdr, --phnum)
+    if (phdr->p_type == PT_LOAD)
+      TagMemory(base + phdr->p_vaddr, phdr->p_memsz, 0);
+}
+
 void __hwasan_print_shadow(const void *p, uptr sz) {
   uptr ptr_raw = UntagAddr(reinterpret_cast<uptr>(p));
   uptr shadow_first = MemToShadow(ptr_raw);

Modified: compiler-rt/trunk/lib/hwasan/hwasan.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/hwasan/hwasan.h?rev=368102&r1=368101&r2=368102&view=diff
==============================================================================
--- compiler-rt/trunk/lib/hwasan/hwasan.h (original)
+++ compiler-rt/trunk/lib/hwasan/hwasan.h Tue Aug  6 15:07:29 2019
@@ -75,7 +75,6 @@ extern int hwasan_report_count;
 bool ProtectRange(uptr beg, uptr end);
 bool InitShadow();
 void InitThreads();
-void InitInstrumentation();
 void MadviseShadow();
 char *GetProcSelfMaps();
 void InitializeInterceptors();

Modified: compiler-rt/trunk/lib/hwasan/hwasan_interface_internal.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/hwasan/hwasan_interface_internal.h?rev=368102&r1=368101&r2=368102&view=diff
==============================================================================
--- compiler-rt/trunk/lib/hwasan/hwasan_interface_internal.h (original)
+++ compiler-rt/trunk/lib/hwasan/hwasan_interface_internal.h Tue Aug  6 15:07:29 2019
@@ -16,6 +16,7 @@
 
 #include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_common/sanitizer_platform_limits_posix.h"
+#include <link.h>
 
 extern "C" {
 
@@ -25,6 +26,14 @@ void __hwasan_init_static();
 SANITIZER_INTERFACE_ATTRIBUTE
 void __hwasan_init();
 
+SANITIZER_INTERFACE_ATTRIBUTE
+void __hwasan_library_loaded(ElfW(Addr) base, const ElfW(Phdr) * phdr,
+                             ElfW(Half) phnum);
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __hwasan_library_unloaded(ElfW(Addr) base, const ElfW(Phdr) * phdr,
+                               ElfW(Half) phnum);
+
 using __sanitizer::uptr;
 using __sanitizer::sptr;
 using __sanitizer::uu64;

Modified: compiler-rt/trunk/lib/hwasan/hwasan_report.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/hwasan/hwasan_report.cpp?rev=368102&r1=368101&r2=368102&view=diff
==============================================================================
--- compiler-rt/trunk/lib/hwasan/hwasan_report.cpp (original)
+++ compiler-rt/trunk/lib/hwasan/hwasan_report.cpp Tue Aug  6 15:07:29 2019
@@ -278,6 +278,31 @@ void PrintAddressDescription(
       Printf("%s", d.Default());
       GetStackTraceFromId(chunk.GetAllocStackId()).Print();
       num_descriptions_printed++;
+    } else {
+      // Check whether the address points into a loaded library. If so, this is
+      // most likely a global variable.
+      const char *module_name;
+      uptr module_address;
+      Symbolizer *sym = Symbolizer::GetOrInit();
+      if (sym->GetModuleNameAndOffsetForPC(mem, &module_name,
+                                           &module_address)) {
+        DataInfo info;
+        if (sym->SymbolizeData(mem, &info) && info.start) {
+          Printf(
+              "%p is located %zd bytes to the %s of %zd-byte global variable "
+              "%s [%p,%p) in %s\n",
+              untagged_addr,
+              candidate == left ? untagged_addr - (info.start + info.size)
+                                : info.start - untagged_addr,
+              candidate == left ? "right" : "left", info.size, info.name,
+              info.start, info.start + info.size, module_name);
+        } else {
+          Printf("%p is located to the %s of a global variable in (%s+0x%x)\n",
+                 untagged_addr, candidate == left ? "right" : "left",
+                 module_name, module_address);
+        }
+        num_descriptions_printed++;
+      }
     }
   }
 

Added: compiler-rt/trunk/test/hwasan/TestCases/global.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/hwasan/TestCases/global.c?rev=368102&view=auto
==============================================================================
--- compiler-rt/trunk/test/hwasan/TestCases/global.c (added)
+++ compiler-rt/trunk/test/hwasan/TestCases/global.c Tue Aug  6 15:07:29 2019
@@ -0,0 +1,17 @@
+// RUN: %clang_hwasan %s -o %t
+// RUN: %run %t 0
+// RUN: not %run %t 1 2>&1 | FileCheck --check-prefixes=CHECK,RSYM %s
+// RUN: not %env_hwasan_opts=symbolize=0 %run %t 1 2>&1 | FileCheck --check-prefixes=CHECK,RNOSYM %s
+// RUN: not %run %t -1 2>&1 | FileCheck --check-prefixes=CHECK,LSYM %s
+// RUN: not %env_hwasan_opts=symbolize=0 %run %t -1 2>&1 | FileCheck --check-prefixes=CHECK,LNOSYM %s
+
+int x = 1;
+
+int main(int argc, char **argv) {
+  // RSYM: is located 0 bytes to the right of 4-byte global variable x {{.*}} in {{.*}}global.c.tmp
+  // RNOSYM: is located to the right of a global variable in ({{.*}}global.c.tmp+{{.*}})
+  // LSYM: is located 4 bytes to the left of 4-byte global variable x {{.*}} in {{.*}}global.c.tmp
+  // LNOSYM: is located to the left of a global variable in ({{.*}}global.c.tmp+{{.*}})
+  // CHECK-NOT: can not describe
+  (&x)[atoi(argv[1])] = 1;
+}

Modified: compiler-rt/trunk/test/hwasan/lit.cfg.py
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/hwasan/lit.cfg.py?rev=368102&r1=368101&r2=368102&view=diff
==============================================================================
--- compiler-rt/trunk/test/hwasan/lit.cfg.py (original)
+++ compiler-rt/trunk/test/hwasan/lit.cfg.py Tue Aug  6 15:07:29 2019
@@ -11,7 +11,12 @@ config.test_source_root = os.path.dirnam
 # Setup default compiler flags used with -fsanitize=memory option.
 clang_cflags = [config.target_cflags] + config.debug_info_flags
 clang_cxxflags = config.cxx_mode_flags + clang_cflags
-clang_hwasan_cflags = ["-fsanitize=hwaddress"] + clang_cflags
+clang_hwasan_cflags = ["-fsanitize=hwaddress", "-mllvm", "-hwasan-globals"] + clang_cflags
+if config.target_arch == 'x86_64':
+  # This does basically the same thing as tagged-globals on aarch64. Because
+  # the x86_64 implementation is for testing purposes only there is no
+  # equivalent target feature implemented on x86_64.
+  clang_hwasan_cflags += ["-mcmodel=large"]
 clang_hwasan_cxxflags = config.cxx_mode_flags + clang_hwasan_cflags
 
 def build_invocation(compile_flags):




More information about the llvm-commits mailing list