[HWASan] Add __hwasan_init to .preinit_array.
authorMatt Morehouse <mascasa@google.com>
Thu, 3 Feb 2022 21:07:11 +0000 (13:07 -0800)
committerMatt Morehouse <mascasa@google.com>
Thu, 3 Feb 2022 21:07:58 +0000 (13:07 -0800)
Fixes segfaults on x86_64 caused by instrumented code running before
shadow is set up.

Reviewed By: pcc

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

clang/lib/Driver/ToolChains/CommonArgs.cpp
compiler-rt/lib/hwasan/CMakeLists.txt
compiler-rt/lib/hwasan/hwasan_preinit.cpp [new file with mode: 0644]
compiler-rt/test/hwasan/TestCases/preinit_array.c [new file with mode: 0644]

index 6364cd1..aa6e852 100644 (file)
@@ -838,6 +838,8 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
         SharedRuntimes.push_back("hwasan_aliases");
       else
         SharedRuntimes.push_back("hwasan");
+      if (!Args.hasArg(options::OPT_shared))
+        HelperStaticRuntimes.push_back("hwasan-preinit");
     }
   }
 
index 9e61255..1f0aa0b 100644 (file)
@@ -27,6 +27,10 @@ set(HWASAN_RTL_CXX_SOURCES
   hwasan_new_delete.cpp
   )
 
+set(HWASAN_RTL_PREINIT_SOURCES
+  hwasan_preinit.cpp
+  )
+
 set(HWASAN_RTL_HEADERS
   hwasan.h
   hwasan_allocator.h
@@ -103,6 +107,12 @@ add_compiler_rt_object_libraries(RTHwasan_dynamic
   ADDITIONAL_HEADERS ${HWASAN_RTL_HEADERS}
   CFLAGS ${HWASAN_DYNAMIC_CFLAGS}
   DEFS ${HWASAN_DEFINITIONS})
+add_compiler_rt_object_libraries(RTHwasan_preinit
+  ARCHS ${HWASAN_SUPPORTED_ARCH}
+  SOURCES ${HWASAN_RTL_PREINIT_SOURCES}
+  ADDITIONAL_HEADERS ${HWASAN_RTL_HEADERS}
+  CFLAGS ${HWASAN_RTL_CFLAGS}
+  DEFS ${HWASAN_DEFINITIONS})
 
 file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp "")
 add_compiler_rt_object_libraries(RTHwasan_dynamic_version_script_dummy
@@ -143,6 +153,7 @@ function(add_hwasan_runtimes arch use_aliases)
     STATIC
     ARCHS ${arch}
     OBJECT_LIBS ${hwasan_object_lib}
+                RTHwasan_preinit
                 RTInterception
                 RTSanitizerCommon
                 RTSanitizerCommonLibc
@@ -218,6 +229,13 @@ foreach(arch ${HWASAN_SUPPORTED_ARCH})
   endif()
 endforeach()
 
+add_compiler_rt_runtime(clang_rt.hwasan-preinit
+  STATIC
+  ARCHS ${HWASAN_SUPPORTED_ARCH}
+  OBJECT_LIBS RTHwasan_preinit
+  CFLAGS ${HWASAN_RTL_CFLAGS}
+  PARENT_TARGET hwasan)
+
 add_compiler_rt_resource_file(hwasan_ignorelist hwasan_ignorelist.txt hwasan)
 
 add_subdirectory("scripts")
diff --git a/compiler-rt/lib/hwasan/hwasan_preinit.cpp b/compiler-rt/lib/hwasan/hwasan_preinit.cpp
new file mode 100644 (file)
index 0000000..8c9c95f
--- /dev/null
@@ -0,0 +1,23 @@
+//===-- hwasan_preinit.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, an address sanity checker.
+//
+// Call __hwasan_init at the very early stage of process startup.
+//===----------------------------------------------------------------------===//
+#include "hwasan_interface_internal.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
+// The symbol is called __local_hwasan_preinit, because it's not intended to
+// be exported.
+// This code linked into the main executable when -fsanitize=hwaddress is in
+// the link flags. It can only use exported interface functions.
+__attribute__((section(".preinit_array"), used)) static void (
+    *__local_hwasan_preinit)(void) = __hwasan_init;
+#endif
diff --git a/compiler-rt/test/hwasan/TestCases/preinit_array.c b/compiler-rt/test/hwasan/TestCases/preinit_array.c
new file mode 100644 (file)
index 0000000..54d3ee7
--- /dev/null
@@ -0,0 +1,12 @@
+// Test that HWASan shadow is initialized before .preinit_array functions run.
+
+// RUN: %clang_hwasan %s -o %t
+// RUN: %run %t
+
+volatile int Global;
+void StoreToGlobal() { Global = 42; }
+
+__attribute__((section(".preinit_array"), used))
+void (*__StoreToGlobal_preinit)() = StoreToGlobal;
+
+int main() { return Global != 42; }