public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [RFC][PATCH 1/X][libsanitizer] Introduce libsanitizer to GCC tree
  2019-09-06 14:46 [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Matthew Malcomson
                   ` (6 preceding siblings ...)
  2019-09-06 14:46 ` [RFC][PATCH 14/X][libsanitizer] Introduce HWASAN block-scope poisoning Matthew Malcomson
@ 2019-09-06 14:46 ` Matthew Malcomson
  2019-09-09  9:26   ` Martin Liška
  2019-09-06 14:47 ` [RFC][PATCH 13/X][libsanitizer] Instrument known builtin function calls Matthew Malcomson
                   ` (9 subsequent siblings)
  17 siblings, 1 reply; 35+ messages in thread
From: Matthew Malcomson @ 2019-09-06 14:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: mliska, dodji, nd, kcc, jakub, dvyukov

[-- Attachment #1: Type: text/plain, Size: 1426 bytes --]

Introduce libsanitizer to GCC tree

Takes the libhwasan library from LLVM and puts it into our source tree
excluding the build system files.

Tieing the source files into our build system is done in a later commit.

We have taken the libsanitizer library from the same SVN revision as
the other sanitizer libraries are taken from (SVN revision 345033 as
mentioned in libsanitizer/MERGE).

libsanitizer/ChangeLog:

2019-09-06  Matthew Malcomson  <matthew.malcomson@arm.com>

	* hwasan/hwasan.cc: New file.
	* hwasan/hwasan.h: New file.
	* hwasan/hwasan.syms.extra: New file.
	* hwasan/hwasan_allocator.cc: New file.
	* hwasan/hwasan_allocator.h: New file.
	* hwasan/hwasan_blacklist.txt: New file.
	* hwasan/hwasan_dynamic_shadow.cc: New file.
	* hwasan/hwasan_dynamic_shadow.h: New file.
	* hwasan/hwasan_flags.h: New file.
	* hwasan/hwasan_flags.inc: New file.
	* hwasan/hwasan_interceptors.cc: New file.
	* hwasan/hwasan_interface_internal.h: New file.
	* hwasan/hwasan_linux.cc: New file.
	* hwasan/hwasan_mapping.h: New file.
	* hwasan/hwasan_new_delete.cc: New file.
	* hwasan/hwasan_poisoning.cc: New file.
	* hwasan/hwasan_poisoning.h: New file.
	* hwasan/hwasan_report.cc: New file.
	* hwasan/hwasan_report.h: New file.
	* hwasan/hwasan_thread.cc: New file.
	* hwasan/hwasan_thread.h: New file.
	* hwasan/hwasan_thread_list.cc: New file.
	* hwasan/hwasan_thread_list.h: New file.

[-- Attachment #2: hwasan-implementation00.patch.gz --]
[-- Type: application/gzip, Size: 26372 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [RFC][PATCH 2/X][libsanitizer] Tie the hwasan library into our build system
  2019-09-06 14:46 [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Matthew Malcomson
  2019-09-06 14:46 ` [RFC][PATCH 3/X][libsanitizer] Allow compilation for HWASAN_WITH_INTERCEPTORS=OFF Matthew Malcomson
@ 2019-09-06 14:46 ` Matthew Malcomson
  2019-09-06 14:46 ` [RFC][PATCH 4/X][libsanitizer] Pass size and pointer info to error reporting functions Matthew Malcomson
                   ` (15 subsequent siblings)
  17 siblings, 0 replies; 35+ messages in thread
From: Matthew Malcomson @ 2019-09-06 14:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: mliska, dodji, nd, kcc, jakub, dvyukov

[-- Attachment #1: Type: text/plain, Size: 45606 bytes --]

This patch does tries to tie libhwasan into the GCC build system in the
same way that the other sanitizer runtime libraries are handled.

libsanitizer/ChangeLog:

2019-09-06  Matthew Malcomson  <matthew.malcomson@arm.com>

	* Makefile.am:  Build libhwasan.
	* Makefile.in:  Build libhwasan.
	* asan/Makefile.in:  Build libhwasan.
	* configure:  Build libhwasan.
	* configure.ac:  Build libhwasan.
	* hwasan/Makefile.am: New file.
	* hwasan/Makefile.in: New file.
	* hwasan/libtool-version: New file.
	* interception/Makefile.in: Build libhwasan.
	* libbacktrace/Makefile.in: Build libhwasan.
	* libsanitizer.spec.in: Build libhwasan.
	* lsan/Makefile.in: Build libhwasan.
	* merge.sh: Build libhwasan.
	* sanitizer_common/Makefile.in: Build libhwasan.
	* tsan/Makefile.in: Build libhwasan.
	* ubsan/Makefile.in: Build libhwasan.



###############     Attachment also inlined for ease of reply    ###############


diff --git a/libsanitizer/Makefile.am b/libsanitizer/Makefile.am
index 65ed1e712378ef453f820f86c4d3221f9dee5f2c..2a7e8e1debe838719db0f0fad218b2543cc3111b 100644
--- a/libsanitizer/Makefile.am
+++ b/libsanitizer/Makefile.am
@@ -14,11 +14,12 @@ endif
 if LIBBACKTRACE_SUPPORTED
 SUBDIRS += libbacktrace
 endif
-SUBDIRS += lsan asan ubsan
+SUBDIRS += lsan asan ubsan hwasan
 nodist_saninclude_HEADERS += \
   include/sanitizer/lsan_interface.h \
   include/sanitizer/asan_interface.h \
-  include/sanitizer/tsan_interface.h
+  include/sanitizer/tsan_interface.h \
+  include/sanitizer/hwasan_interface.h
 if TSAN_SUPPORTED
 SUBDIRS += tsan
 endif
diff --git a/libsanitizer/Makefile.in b/libsanitizer/Makefile.in
index 0d789b3a59d21ea2e5a23057ca3afe15425feec4..404ddcedde5428e0bc6d8ebc5f6568f99741ce2a 100644
--- a/libsanitizer/Makefile.in
+++ b/libsanitizer/Makefile.in
@@ -92,7 +92,8 @@ target_triplet = @target@
 @SANITIZER_SUPPORTED_TRUE@am__append_1 = include/sanitizer/common_interface_defs.h \
 @SANITIZER_SUPPORTED_TRUE@	include/sanitizer/lsan_interface.h \
 @SANITIZER_SUPPORTED_TRUE@	include/sanitizer/asan_interface.h \
-@SANITIZER_SUPPORTED_TRUE@	include/sanitizer/tsan_interface.h
+@SANITIZER_SUPPORTED_TRUE@	include/sanitizer/tsan_interface.h \
+@SANITIZER_SUPPORTED_TRUE@	include/sanitizer/hwasan_interface.h
 @SANITIZER_SUPPORTED_TRUE@@USING_MAC_INTERPOSE_FALSE@am__append_2 = interception
 @LIBBACKTRACE_SUPPORTED_TRUE@@SANITIZER_SUPPORTED_TRUE@am__append_3 = libbacktrace
 @SANITIZER_SUPPORTED_TRUE@@TSAN_SUPPORTED_TRUE@am__append_4 = tsan
@@ -206,7 +207,7 @@ ETAGS = etags
 CTAGS = ctags
 CSCOPE = cscope
 DIST_SUBDIRS = sanitizer_common interception libbacktrace lsan asan \
-	ubsan tsan
+	ubsan hwasan tsan
 ACLOCAL = @ACLOCAL@
 ALLOC_FILE = @ALLOC_FILE@
 AMTAR = @AMTAR@
@@ -328,6 +329,7 @@ install_sh = @install_sh@
 libdir = @libdir@
 libexecdir = @libexecdir@
 link_libasan = @link_libasan@
+link_libhwasan = @link_libhwasan@
 link_liblsan = @link_liblsan@
 link_libtsan = @link_libtsan@
 link_libubsan = @link_libubsan@
@@ -341,6 +343,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
@@ -361,7 +364,7 @@ sanincludedir = $(libdir)/gcc/$(target_alias)/$(gcc_version)/include/sanitizer
 nodist_saninclude_HEADERS = $(am__append_1)
 @SANITIZER_SUPPORTED_TRUE@SUBDIRS = sanitizer_common $(am__append_2) \
 @SANITIZER_SUPPORTED_TRUE@	$(am__append_3) lsan asan ubsan \
-@SANITIZER_SUPPORTED_TRUE@	$(am__append_4)
+@SANITIZER_SUPPORTED_TRUE@	hwasan $(am__append_4)
 gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 
 # Work around what appears to be a GNU make bug handling MAKEFLAGS
diff --git a/libsanitizer/asan/Makefile.in b/libsanitizer/asan/Makefile.in
index 926ff7d7491c9713a43b12bf575e023368526767..d61da1c5567e400a9b9b614f1232f3e9fa10e06a 100644
--- a/libsanitizer/asan/Makefile.in
+++ b/libsanitizer/asan/Makefile.in
@@ -352,6 +352,7 @@ install_sh = @install_sh@
 libdir = @libdir@
 libexecdir = @libexecdir@
 link_libasan = @link_libasan@
+link_libhwasan = @link_libhwasan@
 link_liblsan = @link_liblsan@
 link_libtsan = @link_libtsan@
 link_libubsan = @link_libubsan@
@@ -365,6 +366,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/libsanitizer/configure b/libsanitizer/configure
index 2d25147adbaaa3578388cf75763e6178302aa3dc..7a4779831bc871c8ed552ed9aee1249a6a25f21a 100755
--- a/libsanitizer/configure
+++ b/libsanitizer/configure
@@ -657,6 +657,7 @@ USING_MAC_INTERPOSE_TRUE
 link_liblsan
 link_libubsan
 link_libtsan
+link_libhwasan
 link_libasan
 LSAN_SUPPORTED_FALSE
 LSAN_SUPPORTED_TRUE
@@ -779,6 +780,7 @@ infodir
 docdir
 oldincludedir
 includedir
+runstatedir
 localstatedir
 sharedstatedir
 sysconfdir
@@ -868,6 +870,7 @@ datadir='${datarootdir}'
 sysconfdir='${prefix}/etc'
 sharedstatedir='${prefix}/com'
 localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
 includedir='${prefix}/include'
 oldincludedir='/usr/include'
 docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1120,6 +1123,15 @@ do
   | -silent | --silent | --silen | --sile | --sil)
     silent=yes ;;
 
+  -runstatedir | --runstatedir | --runstatedi | --runstated \
+  | --runstate | --runstat | --runsta | --runst | --runs \
+  | --run | --ru | --r)
+    ac_prev=runstatedir ;;
+  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+  | --run=* | --ru=* | --r=*)
+    runstatedir=$ac_optarg ;;
+
   -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
     ac_prev=sbindir ;;
   -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1257,7 +1269,7 @@ fi
 for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
 		datadir sysconfdir sharedstatedir localstatedir includedir \
 		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
-		libdir localedir mandir
+		libdir localedir mandir runstatedir
 do
   eval ac_val=\$$ac_var
   # Remove trailing slashes.
@@ -1410,6 +1422,7 @@ Fine tuning of the installation directories:
   --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
   --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
   --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
   --libdir=DIR            object code libraries [EPREFIX/lib]
   --includedir=DIR        C header files [PREFIX/include]
   --oldincludedir=DIR     C header files for non-gcc [/usr/include]
@@ -12329,7 +12342,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12332 "configure"
+#line 12345 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12435,7 +12448,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12438 "configure"
+#line 12451 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -15906,6 +15919,10 @@ fi
 link_libasan=$link_sanitizer_common
 
 
+# Set up the set of additional libraries that we need to link against for libhwasan.
+link_libhwasan=$link_sanitizer_common
+
+
 # Set up the set of additional libraries that we need to link against for libtsan.
 link_libtsan=$link_sanitizer_common
 
@@ -16776,7 +16793,7 @@ ac_config_files="$ac_config_files Makefile libsanitizer.spec libbacktrace/backtr
 ac_config_headers="$ac_config_headers config.h"
 
 
-ac_config_files="$ac_config_files interception/Makefile sanitizer_common/Makefile libbacktrace/Makefile lsan/Makefile asan/Makefile ubsan/Makefile"
+ac_config_files="$ac_config_files interception/Makefile sanitizer_common/Makefile libbacktrace/Makefile lsan/Makefile asan/Makefile hwasan/Makefile ubsan/Makefile"
 
 
 if test "x$TSAN_SUPPORTED" = "xyes"; then
@@ -18053,6 +18070,7 @@ do
     "libbacktrace/Makefile") CONFIG_FILES="$CONFIG_FILES libbacktrace/Makefile" ;;
     "lsan/Makefile") CONFIG_FILES="$CONFIG_FILES lsan/Makefile" ;;
     "asan/Makefile") CONFIG_FILES="$CONFIG_FILES asan/Makefile" ;;
+    "hwasan/Makefile") CONFIG_FILES="$CONFIG_FILES hwasan/Makefile" ;;
     "ubsan/Makefile") CONFIG_FILES="$CONFIG_FILES ubsan/Makefile" ;;
     "tsan/Makefile") CONFIG_FILES="$CONFIG_FILES tsan/Makefile" ;;
 
@@ -19988,6 +20006,17 @@ _EOF
    . ${multi_basedir}/config-ml.in
    { ml_norecursion=; unset ml_norecursion;}
  ;;
+    "hwasan/Makefile":F) cat > vpsed$$ << \_EOF
+s!`test -f '$<' || echo '$(srcdir)/'`!!
+_EOF
+   sed -f vpsed$$ $ac_file > tmp$$
+   mv tmp$$ $ac_file
+   rm vpsed$$
+   echo 'MULTISUBDIR =' >> $ac_file
+   ml_norecursion=yes
+   . ${multi_basedir}/config-ml.in
+   { ml_norecursion=; unset ml_norecursion;}
+ ;;
     "ubsan/Makefile":F) cat > vpsed$$ << \_EOF
 s!`test -f '$<' || echo '$(srcdir)/'`!!
 _EOF
diff --git a/libsanitizer/configure.ac b/libsanitizer/configure.ac
index 8aac33cb5c980db77e31e8d799ab5a12f3e3a404..02c0c235171e4c8249821c5db91414f8e4bfb3ee 100644
--- a/libsanitizer/configure.ac
+++ b/libsanitizer/configure.ac
@@ -111,6 +111,10 @@ AC_CHECK_LIB(dl, dlsym,
 link_libasan=$link_sanitizer_common
 AC_SUBST(link_libasan)
 
+# Set up the set of additional libraries that we need to link against for libhwasan.
+link_libhwasan=$link_sanitizer_common
+AC_SUBST(link_libhwasan)
+
 # Set up the set of additional libraries that we need to link against for libtsan.
 link_libtsan=$link_sanitizer_common
 AC_SUBST(link_libtsan)
@@ -339,7 +343,7 @@ AH_BOTTOM([#include "libbacktrace/backtrace-rename.h"])
 AC_CONFIG_FILES([Makefile libsanitizer.spec libbacktrace/backtrace-supported.h])
 AC_CONFIG_HEADER(config.h)
 
-AC_CONFIG_FILES(AC_FOREACH([DIR], [interception sanitizer_common libbacktrace lsan asan ubsan], [DIR/Makefile ]),
+AC_CONFIG_FILES(AC_FOREACH([DIR], [interception sanitizer_common libbacktrace lsan asan hwasan ubsan], [DIR/Makefile ]),
   [cat > vpsed$$ << \_EOF
 s!`test -f '$<' || echo '$(srcdir)/'`!!
 _EOF
diff --git a/libsanitizer/hwasan/Makefile.am b/libsanitizer/hwasan/Makefile.am
new file mode 100644
index 0000000000000000000000000000000000000000..3754f435ce0342f5c8051f6ea44273bb811c9659
--- /dev/null
+++ b/libsanitizer/hwasan/Makefile.am
@@ -0,0 +1,81 @@
+AM_CPPFLAGS = -I $(top_srcdir)/include -I $(top_srcdir)
+ 
+# May be used by toolexeclibdir.
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
+
+DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DCAN_SANITIZE_UB=0
+AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long  -fPIC -fno-builtin -fno-exceptions -fno-rtti -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros -fno-ipa-icf
+AM_CXXFLAGS += $(LIBSTDCXX_RAW_CXX_CXXFLAGS)
+AM_CXXFLAGS += -std=gnu++11
+AM_CXXFLAGS += $(EXTRA_CXXFLAGS)
+ACLOCAL_AMFLAGS = -I $(top_srcdir) -I $(top_srcdir)/config
+
+toolexeclib_LTLIBRARIES = libhwasan.la
+
+hwasan_files = \
+	       hwasan_allocator.cc \
+	       hwasan.cc \
+	       hwasan_dynamic_shadow.cc \
+	       hwasan_interceptors.cc \
+	       hwasan_linux.cc \
+	       hwasan_new_delete.cc \
+	       hwasan_poisoning.cc \
+	       hwasan_report.cc \
+	       hwasan_thread.cc \
+	       hwasan_thread_list.cc
+
+libhwasan_la_SOURCES = $(hwasan_files)
+libhwasan_la_LIBADD = $(top_builddir)/sanitizer_common/libsanitizer_common.la
+if !USING_MAC_INTERPOSE
+libhwasan_la_LIBADD += $(top_builddir)/interception/libinterception.la
+endif
+if LIBBACKTRACE_SUPPORTED
+libhwasan_la_LIBADD += $(top_builddir)/libbacktrace/libsanitizer_libbacktrace.la
+endif
+libhwasan_la_LIBADD += $(LIBSTDCXX_RAW_CXX_LDFLAGS)
+
+libhwasan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(link_libhwasan)
+
+# Work around what appears to be a GNU make bug handling MAKEFLAGS
+# values defined in terms of make variables, as is the case for CC and
+# friends when we are called from the top level Makefile.
+AM_MAKEFLAGS = \
+	"AR_FLAGS=$(AR_FLAGS)" \
+	"CC_FOR_BUILD=$(CC_FOR_BUILD)" \
+	"CFLAGS=$(CFLAGS)" \
+	"CXXFLAGS=$(CXXFLAGS)" \
+	"CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \
+	"CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \
+	"INSTALL=$(INSTALL)" \
+	"INSTALL_DATA=$(INSTALL_DATA)" \
+	"INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
+	"INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \
+	"JC1FLAGS=$(JC1FLAGS)" \
+	"LDFLAGS=$(LDFLAGS)" \
+	"LIBCFLAGS=$(LIBCFLAGS)" \
+	"LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \
+	"MAKE=$(MAKE)" \
+	"MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \
+	"PICFLAG=$(PICFLAG)" \
+	"PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \
+	"SHELL=$(SHELL)" \
+	"RUNTESTFLAGS=$(RUNTESTFLAGS)" \
+	"exec_prefix=$(exec_prefix)" \
+	"infodir=$(infodir)" \
+	"libdir=$(libdir)" \
+	"prefix=$(prefix)" \
+	"includedir=$(includedir)" \
+	"AR=$(AR)" \
+	"AS=$(AS)" \
+	"LD=$(LD)" \
+	"LIBCFLAGS=$(LIBCFLAGS)" \
+	"NM=$(NM)" \
+	"PICFLAG=$(PICFLAG)" \
+	"RANLIB=$(RANLIB)" \
+	"DESTDIR=$(DESTDIR)"
+
+MAKEOVERRIDES=
+
+## ################################################################
+
+
diff --git a/libsanitizer/hwasan/Makefile.in b/libsanitizer/hwasan/Makefile.in
new file mode 100644
index 0000000000000000000000000000000000000000..f89bc9e440502fcf8072d67aa61a4b63cd490b40
--- /dev/null
+++ b/libsanitizer/hwasan/Makefile.in
@@ -0,0 +1,736 @@
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+  if test -z '$(MAKELEVEL)'; then \
+    false; \
+  elif test -n '$(MAKE_HOST)'; then \
+    true; \
+  elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+    true; \
+  else \
+    false; \
+  fi; \
+}
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+@USING_MAC_INTERPOSE_FALSE@am__append_1 = $(top_builddir)/interception/libinterception.la
+@LIBBACKTRACE_SUPPORTED_TRUE@am__append_2 = $(top_builddir)/libbacktrace/libsanitizer_libbacktrace.la
+subdir = hwasan
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \
+	$(top_srcdir)/../config/depstand.m4 \
+	$(top_srcdir)/../config/lead-dot.m4 \
+	$(top_srcdir)/../config/libstdc++-raw-cxx.m4 \
+	$(top_srcdir)/../config/multi.m4 \
+	$(top_srcdir)/../config/override.m4 \
+	$(top_srcdir)/../config/stdint.m4 \
+	$(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
+	$(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
+	$(top_srcdir)/acinclude.m4 $(top_srcdir)/../libtool.m4 \
+	$(top_srcdir)/../config/enable.m4 \
+	$(top_srcdir)/../config/cet.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__installdirs = "$(DESTDIR)$(toolexeclibdir)"
+LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libhwasan_la_DEPENDENCIES =  \
+	$(top_builddir)/sanitizer_common/libsanitizer_common.la \
+	$(am__append_1) $(am__append_2) $(am__DEPENDENCIES_1)
+am__objects_1 = hwasan_allocator.lo hwasan.lo hwasan_dynamic_shadow.lo \
+	hwasan_interceptors.lo hwasan_linux.lo hwasan_new_delete.lo \
+	hwasan_poisoning.lo hwasan_report.lo hwasan_thread.lo \
+	hwasan_thread_list.lo
+am_libhwasan_la_OBJECTS = $(am__objects_1)
+libhwasan_la_OBJECTS = $(am_libhwasan_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+libhwasan_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(libhwasan_la_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/../depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo "  CXX     " $@;
+am__v_CXX_1 = 
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo "  CXXLD   " $@;
+am__v_CXXLD_1 = 
+SOURCES = $(libhwasan_la_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+ACLOCAL = @ACLOCAL@
+ALLOC_FILE = @ALLOC_FILE@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BACKTRACE_SUPPORTED = @BACKTRACE_SUPPORTED@
+BACKTRACE_SUPPORTS_THREADS = @BACKTRACE_SUPPORTS_THREADS@
+BACKTRACE_USES_MALLOC = @BACKTRACE_USES_MALLOC@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DCAN_SANITIZE_UB=0
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXTRA_ASFLAGS = @EXTRA_ASFLAGS@
+EXTRA_CFLAGS = @EXTRA_CFLAGS@
+EXTRA_CXXFLAGS = @EXTRA_CXXFLAGS@
+FGREP = @FGREP@
+FORMAT_FILE = @FORMAT_FILE@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSTDCXX_RAW_CXX_CXXFLAGS = @LIBSTDCXX_RAW_CXX_CXXFLAGS@
+LIBSTDCXX_RAW_CXX_LDFLAGS = @LIBSTDCXX_RAW_CXX_LDFLAGS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+RPC_DEFS = @RPC_DEFS@
+SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS = @SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+TSAN_TARGET_DEPENDENT_OBJECTS = @TSAN_TARGET_DEPENDENT_OBJECTS@
+VERSION = @VERSION@
+VIEW_FILE = @VIEW_FILE@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+enable_shared = @enable_shared@
+enable_static = @enable_static@
+exec_prefix = @exec_prefix@
+get_gcc_base_ver = @get_gcc_base_ver@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+link_libasan = @link_libasan@
+link_libhwasan = @link_libhwasan@
+link_liblsan = @link_liblsan@
+link_libtsan = @link_libtsan@
+link_libubsan = @link_libubsan@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+multi_basedir = @multi_basedir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_noncanonical = @target_noncanonical@
+target_os = @target_os@
+target_vendor = @target_vendor@
+toolexecdir = @toolexecdir@
+toolexeclibdir = @toolexeclibdir@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = -I $(top_srcdir)/include -I $(top_srcdir)
+
+# May be used by toolexeclibdir.
+gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
+AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic \
+	-Wno-long-long -fPIC -fno-builtin -fno-exceptions -fno-rtti \
+	-fomit-frame-pointer -funwind-tables -fvisibility=hidden \
+	-Wno-variadic-macros -fno-ipa-icf \
+	$(LIBSTDCXX_RAW_CXX_CXXFLAGS) -std=gnu++11 $(EXTRA_CXXFLAGS)
+ACLOCAL_AMFLAGS = -I $(top_srcdir) -I $(top_srcdir)/config
+toolexeclib_LTLIBRARIES = libhwasan.la
+hwasan_files = \
+	       hwasan_allocator.cc \
+	       hwasan.cc \
+	       hwasan_dynamic_shadow.cc \
+	       hwasan_interceptors.cc \
+	       hwasan_linux.cc \
+	       hwasan_new_delete.cc \
+	       hwasan_poisoning.cc \
+	       hwasan_report.cc \
+	       hwasan_thread.cc \
+	       hwasan_thread_list.cc
+
+libhwasan_la_SOURCES = $(hwasan_files)
+libhwasan_la_LIBADD =  \
+	$(top_builddir)/sanitizer_common/libsanitizer_common.la \
+	$(am__append_1) $(am__append_2) $(LIBSTDCXX_RAW_CXX_LDFLAGS)
+libhwasan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(link_libhwasan)
+
+# Work around what appears to be a GNU make bug handling MAKEFLAGS
+# values defined in terms of make variables, as is the case for CC and
+# friends when we are called from the top level Makefile.
+AM_MAKEFLAGS = \
+	"AR_FLAGS=$(AR_FLAGS)" \
+	"CC_FOR_BUILD=$(CC_FOR_BUILD)" \
+	"CFLAGS=$(CFLAGS)" \
+	"CXXFLAGS=$(CXXFLAGS)" \
+	"CFLAGS_FOR_BUILD=$(CFLAGS_FOR_BUILD)" \
+	"CFLAGS_FOR_TARGET=$(CFLAGS_FOR_TARGET)" \
+	"INSTALL=$(INSTALL)" \
+	"INSTALL_DATA=$(INSTALL_DATA)" \
+	"INSTALL_PROGRAM=$(INSTALL_PROGRAM)" \
+	"INSTALL_SCRIPT=$(INSTALL_SCRIPT)" \
+	"JC1FLAGS=$(JC1FLAGS)" \
+	"LDFLAGS=$(LDFLAGS)" \
+	"LIBCFLAGS=$(LIBCFLAGS)" \
+	"LIBCFLAGS_FOR_TARGET=$(LIBCFLAGS_FOR_TARGET)" \
+	"MAKE=$(MAKE)" \
+	"MAKEINFO=$(MAKEINFO) $(MAKEINFOFLAGS)" \
+	"PICFLAG=$(PICFLAG)" \
+	"PICFLAG_FOR_TARGET=$(PICFLAG_FOR_TARGET)" \
+	"SHELL=$(SHELL)" \
+	"RUNTESTFLAGS=$(RUNTESTFLAGS)" \
+	"exec_prefix=$(exec_prefix)" \
+	"infodir=$(infodir)" \
+	"libdir=$(libdir)" \
+	"prefix=$(prefix)" \
+	"includedir=$(includedir)" \
+	"AR=$(AR)" \
+	"AS=$(AS)" \
+	"LD=$(LD)" \
+	"LIBCFLAGS=$(LIBCFLAGS)" \
+	"NM=$(NM)" \
+	"PICFLAG=$(PICFLAG)" \
+	"RANLIB=$(RANLIB)" \
+	"DESTDIR=$(DESTDIR)"
+
+MAKEOVERRIDES = 
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+	        && { if test -f $@; then exit 0; else break; fi; }; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign hwasan/Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign hwasan/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-toolexeclibLTLIBRARIES: $(toolexeclib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	@list='$(toolexeclib_LTLIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(toolexeclibdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(toolexeclibdir)" || exit 1; \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(toolexeclibdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(toolexeclibdir)"; \
+	}
+
+uninstall-toolexeclibLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(toolexeclib_LTLIBRARIES)'; test -n "$(toolexeclibdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(toolexeclibdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(toolexeclibdir)/$$f"; \
+	done
+
+clean-toolexeclibLTLIBRARIES:
+	-test -z "$(toolexeclib_LTLIBRARIES)" || rm -f $(toolexeclib_LTLIBRARIES)
+	@list='$(toolexeclib_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+
+libhwasan.la: $(libhwasan_la_OBJECTS) $(libhwasan_la_DEPENDENCIES) $(EXTRA_libhwasan_la_DEPENDENCIES) 
+	$(AM_V_CXXLD)$(libhwasan_la_LINK) -rpath $(toolexeclibdir) $(libhwasan_la_OBJECTS) $(libhwasan_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_allocator.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_dynamic_shadow.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_interceptors.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_linux.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_new_delete.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_poisoning.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_report.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_thread.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_thread_list.Plo@am__quote@
+
+.cc.o:
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+	for dir in "$(DESTDIR)$(toolexeclibdir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-toolexeclibLTLIBRARIES \
+	mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-toolexeclibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-toolexeclibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+	clean-libtool clean-toolexeclibLTLIBRARIES cscopelist-am ctags \
+	ctags-am distclean distclean-compile distclean-generic \
+	distclean-libtool distclean-tags dvi dvi-am html html-am info \
+	info-am install install-am install-data install-data-am \
+	install-dvi install-dvi-am install-exec install-exec-am \
+	install-html install-html-am install-info install-info-am \
+	install-man install-pdf install-pdf-am install-ps \
+	install-ps-am install-strip install-toolexeclibLTLIBRARIES \
+	installcheck installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags tags-am uninstall uninstall-am \
+	uninstall-toolexeclibLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libsanitizer/hwasan/libtool-version b/libsanitizer/hwasan/libtool-version
new file mode 100644
index 0000000000000000000000000000000000000000..204fdd2d8e5fe21a5a9f9e23d6a6cf17d353362a
--- /dev/null
+++ b/libsanitizer/hwasan/libtool-version
@@ -0,0 +1,6 @@
+# This file is used to maintain libtool version info for libmudflap.  See
+# the libtool manual to understand the meaning of the fields.  This is
+# a separate file so that version updates don't involve re-running
+# automake.
+# CURRENT:REVISION:AGE
+0:0:0
diff --git a/libsanitizer/interception/Makefile.in b/libsanitizer/interception/Makefile.in
index 08a33e0e567b808a9390589b27469f13ab645878..f1fe41710a22763416452384f4bcbb3b14c4916e 100644
--- a/libsanitizer/interception/Makefile.in
+++ b/libsanitizer/interception/Makefile.in
@@ -300,6 +300,7 @@ install_sh = @install_sh@
 libdir = @libdir@
 libexecdir = @libexecdir@
 link_libasan = @link_libasan@
+link_libhwasan = @link_libhwasan@
 link_liblsan = @link_liblsan@
 link_libtsan = @link_libtsan@
 link_libubsan = @link_libubsan@
@@ -313,6 +314,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/libsanitizer/libbacktrace/Makefile.in b/libsanitizer/libbacktrace/Makefile.in
index f0e190a81d82ddc86a3e39a5dc41e864190582c0..ba1bcc4b1a6d1ac27e76762219030b39c6242851 100644
--- a/libsanitizer/libbacktrace/Makefile.in
+++ b/libsanitizer/libbacktrace/Makefile.in
@@ -350,6 +350,7 @@ install_sh = @install_sh@
 libdir = @libdir@
 libexecdir = @libexecdir@
 link_libasan = @link_libasan@
+link_libhwasan = @link_libhwasan@
 link_liblsan = @link_liblsan@
 link_libtsan = @link_libtsan@
 link_libubsan = @link_libubsan@
@@ -363,6 +364,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/libsanitizer/libsanitizer.spec.in b/libsanitizer/libsanitizer.spec.in
index a4fa87d8dfc51549b0f932b31a610db1a2e86c29..70a33574d7b1d494c4875cfc41f29606bde2172e 100644
--- a/libsanitizer/libsanitizer.spec.in
+++ b/libsanitizer/libsanitizer.spec.in
@@ -3,6 +3,8 @@
 
 *link_libasan: @link_libasan@
 
+*link_libhwasan: @link_libhwasan@
+
 *link_libtsan: @link_libtsan@
 
 *link_libubsan: @link_libubsan@
diff --git a/libsanitizer/lsan/Makefile.in b/libsanitizer/lsan/Makefile.in
index a11baed30c85327f43f05888017bc5a028c92b1b..68c40849ecb9a4eb8e95035386b37810ca443f74 100644
--- a/libsanitizer/lsan/Makefile.in
+++ b/libsanitizer/lsan/Makefile.in
@@ -345,6 +345,7 @@ install_sh = @install_sh@
 libdir = @libdir@
 libexecdir = @libexecdir@
 link_libasan = @link_libasan@
+link_libhwasan = @link_libhwasan@
 link_liblsan = @link_liblsan@
 link_libtsan = @link_libtsan@
 link_libubsan = @link_libubsan@
@@ -358,6 +359,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/libsanitizer/merge.sh b/libsanitizer/merge.sh
index fa340bedbac89871f9bb24e49218d7d8cf9d8da7..383079965fec34fcd1e6310c832ade078b51820d 100755
--- a/libsanitizer/merge.sh
+++ b/libsanitizer/merge.sh
@@ -69,6 +69,7 @@ CUR_REV=$(get_current_rev)
 echo Current upstream revision: $CUR_REV
 merge include/sanitizer include/sanitizer
 merge lib/asan asan
+merge lib/hwasan hwasan
 merge lib/lsan lsan
 merge lib/tsan/rtl tsan
 merge lib/sanitizer_common sanitizer_common
diff --git a/libsanitizer/sanitizer_common/Makefile.in b/libsanitizer/sanitizer_common/Makefile.in
index d33d2227938b6d261c0f1c3eaaa06d2c075863f0..2b8f7db1f5e16e8b999f2e68330c9f90d5a0345c 100644
--- a/libsanitizer/sanitizer_common/Makefile.in
+++ b/libsanitizer/sanitizer_common/Makefile.in
@@ -365,6 +365,7 @@ install_sh = @install_sh@
 libdir = @libdir@
 libexecdir = @libexecdir@
 link_libasan = @link_libasan@
+link_libhwasan = @link_libhwasan@
 link_liblsan = @link_liblsan@
 link_libtsan = @link_libtsan@
 link_libubsan = @link_libubsan@
@@ -378,6 +379,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/libsanitizer/tsan/Makefile.in b/libsanitizer/tsan/Makefile.in
index cb4f0f9fef07e075c78af7c305cfbb165eea2774..327134e7ce75eb74d3847ea8fa7bca35c4380634 100644
--- a/libsanitizer/tsan/Makefile.in
+++ b/libsanitizer/tsan/Makefile.in
@@ -375,6 +375,7 @@ install_sh = @install_sh@
 libdir = @libdir@
 libexecdir = @libexecdir@
 link_libasan = @link_libasan@
+link_libhwasan = @link_libhwasan@
 link_liblsan = @link_liblsan@
 link_libtsan = @link_libtsan@
 link_libubsan = @link_libubsan@
@@ -388,6 +389,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
diff --git a/libsanitizer/ubsan/Makefile.in b/libsanitizer/ubsan/Makefile.in
index b1ba31a50e6b030ddc8db8489d60b5383bb72c6e..fbda21c705bbaf2e94a1aa87a1b5296f146a8686 100644
--- a/libsanitizer/ubsan/Makefile.in
+++ b/libsanitizer/ubsan/Makefile.in
@@ -339,6 +339,7 @@ install_sh = @install_sh@
 libdir = @libdir@
 libexecdir = @libexecdir@
 link_libasan = @link_libasan@
+link_libhwasan = @link_libhwasan@
 link_liblsan = @link_liblsan@
 link_libtsan = @link_libtsan@
 link_libubsan = @link_libubsan@
@@ -352,6 +353,7 @@ pdfdir = @pdfdir@
 prefix = @prefix@
 program_transform_name = @program_transform_name@
 psdir = @psdir@
+runstatedir = @runstatedir@
 sbindir = @sbindir@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@


[-- Attachment #2: hwasan-implementation01.patch.gz --]
[-- Type: application/gzip, Size: 11137 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [RFC][PATCH 8/X][libsanitizer] Ensure HWASAN required alignment for stack variables
  2019-09-06 14:46 [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Matthew Malcomson
                   ` (3 preceding siblings ...)
  2019-09-06 14:46 ` [RFC][PATCH 7/X][libsanitizer] Add option to bootstrap using HWASAN Matthew Malcomson
@ 2019-09-06 14:46 ` Matthew Malcomson
  2019-09-06 14:46 ` [RFC][PATCH 5/X][libsanitizer] Introduce longjmp/setjmp interceptors to libhwasan Matthew Malcomson
                   ` (12 subsequent siblings)
  17 siblings, 0 replies; 35+ messages in thread
From: Matthew Malcomson @ 2019-09-06 14:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: mliska, dodji, nd, kcc, jakub, dvyukov

[-- Attachment #1: Type: text/plain, Size: 6602 bytes --]

When colouring shadow memory, we need to ensure that each tag granule
is only used by one variable at a time.

This is done by ensuring that ecah coloured variable is aligned to the
tag granule representation size and also ensure that the end of each
variable as an alignment boundary between the end and the start of any
other data stored on the stack.

This patch ensures this by adding alignment requirements in
`align_local_variable` and forcing all stack variable allocation to be
deferred to allow `expand_stack_vars` to ensure the stack pointer is
aligned before allocating any variable for the current frame.

This patch also adds some macros defining how the HWASAN shadow memory
is stored and how a tag is stored in a pointer.

gcc/ChangeLog:

2019-09-06  Matthew Malcomson  <matthew.malcomson@arm.com>

	* asan.h (HWASAN_TAG_SIZE): New macro.
	(HWASAN_TAG_GRANULE_SIZE):New macro.
	(HWASAN_SHIFT):New macro.
	(HWASAN_SHIFT_RTX):New macro.
	(HWASAN_STACK_BACKGROUND):New macro.
	* cfgexpand.c (align_local_variable): Ensure alignment.
	(expand_stack_vars): Ensure alignment.
	(defer_stack_allocation): Ensure all variables are deferred so
	they can be handled by `expand_stack_vars`.



###############     Attachment also inlined for ease of reply    ###############


diff --git a/gcc/asan.h b/gcc/asan.h
index 66c11139b5ccbe307850d0be57e86f96445dd18d..d78f6b821c7d1e859cc53f124e071eac27a5e9b8 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -75,6 +75,41 @@ extern hash_set <tree> *asan_used_labels;
 
 #define ASAN_USE_AFTER_SCOPE_ATTRIBUTE	"use after scope memory"
 
+/* NOTE: The macros below are hard-coded to these values in libhwasan, and
+   hence can't be changed independently here.  */
+/* How many bits are used to store a tag in a pointer.
+   For aarch64 MTE we have 4 bits per colour.
+   AArch64 has a Top-Byte-Ignore feature that allows the use of the top byte of
+   pointers for storing information, HWASAN can use that entire top byte if
+   required.
+   If changing this value, be careful of the predicates/constraints on the
+   addtag<mode>4 patterns in the backend.  */
+#define HWASAN_TAG_SIZE 4
+/* Tag Granule of HWASAN shadow stack.
+   This is the size in real memory that each byte in the shadow memory refers
+   to.  I.e. if a variable is X bytes long in memory then it's colour in shadow
+   memory will span X / HWASAN_TAG_GRANULE_SIZE bytes.
+   On top of this, most variables will need to be aligned to this amount since
+   two variables that are neighbours in memory and share a tag granule would
+   need to share the same colour (as the shared tag granule can only store one
+   colour).  */
+#define HWASAN_TAG_GRANULE_SIZE (1ULL << HWASAN_TAG_SIZE)
+/* How many bits to shift in order to access the tag bits.
+   This approach assumes that the tag is stored in the top N bits of a pointer,
+   and hence that shifting a known amount will leave just the tag bits.  */
+#define HWASAN_SHIFT 56
+#define HWASAN_SHIFT_RTX const_int_rtx[MAX_SAVED_CONST_INT + HWASAN_SHIFT]
+/* Define the tag for the stack background.
+   NOTE: Having a background colour of zero is hard-coded in the runtime
+   library, so we can't really change this.
+   This defines what colour the stack pointer will be and hence what colour all
+   uncoloured parts of the stack are (e.g. spilled registers).
+   It also provides a tag for stack allocation to avoid, since an object stored
+   on the stack will want to have a different colour to the background stack to
+   ensure things like the return address etc can't be affected by accesses
+   through pointer to a user-object.  */
+#define HWASAN_STACK_BACKGROUND 0
+
 /* Various flags for Asan builtins.  */
 enum asan_check_flags
 {
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 7722dcd4004e270551c8bcd4403e53a78ebfdff0..c5585d83c6e155856e7a4278e21c35ee5675bbdd 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -372,7 +372,14 @@ align_local_variable (tree decl)
       align = LOCAL_DECL_ALIGNMENT (decl);
       SET_DECL_ALIGN (decl, align);
     }
-  return align / BITS_PER_UNIT;
+
+  unsigned int ret_align = align / BITS_PER_UNIT;
+
+  if (memory_tagging_p ())
+    ret_align = ret_align > HWASAN_TAG_GRANULE_SIZE
+      ? ret_align
+      : HWASAN_TAG_GRANULE_SIZE;
+  return ret_align;
 }
 
 /* Align given offset BASE with ALIGN.  Truncate up if ALIGN_UP is true,
@@ -1117,6 +1124,29 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
       alignb = stack_vars[i].alignb;
       if (alignb * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT)
 	{
+	  if (memory_tagging_p ())
+	    {
+	      /* Allocate zero bytes to take advantage of the
+		 alloc_stack_frame_space logic of ensuring the stack is aligned
+		 despite having poly_int64's to deal with.
+
+		 There must be no tag granule "shared" between different
+		 objects.  This means that no HWASAN_TAG_GRANULE_SIZE byte
+		 chunk can have more than one object in it.
+
+		 We ensure this by forcing the end of the last bit of data to
+		 be aligned to HWASAN_TAG_GRANULE_SIZE bytes here, and setting
+		 the start of each variable to be aligned to
+		 HWASAN_TAG_GRANULE_SIZE bytes in `align_local_variable`.
+
+		 We can't align just one of the start or end, since there are
+		 untagged things stored on the stack that we have no control on
+		 the alignment (e.g. function parameters which must conform to
+		 ABI requirements) and these can't share a tag granule with a
+		 tagged variable.  */
+	      gcc_assert (stack_vars[i].alignb >= HWASAN_TAG_GRANULE_SIZE);
+	      alloc_stack_frame_space (0, HWASAN_TAG_GRANULE_SIZE);
+	    }
 	  base = virtual_stack_vars_rtx;
 	  /* ASAN description strings don't yet have a syntax for expressing
 	     polynomial offsets.  */
@@ -1545,8 +1575,11 @@ defer_stack_allocation (tree var, bool toplevel)
 
   /* If stack protection is enabled, *all* stack variables must be deferred,
      so that we can re-order the strings to the top of the frame.
-     Similarly for Address Sanitizer.  */
-  if (flag_stack_protect || asan_sanitize_stack_p ())
+     Similarly for Address Sanitizer.
+     When memory tagging we defer all stack variables so we can handle them in
+     one place (handle here meaning ensure aligned and record information on
+     its position on the stack).  */
+  if (flag_stack_protect || asan_sanitize_stack_p () || memory_tagging_p ())
     return true;
 
   unsigned int align = TREE_CODE (var) == SSA_NAME


[-- Attachment #2: hwasan-implementation07.patch --]
[-- Type: text/plain, Size: 5176 bytes --]

diff --git a/gcc/asan.h b/gcc/asan.h
index 66c11139b5ccbe307850d0be57e86f96445dd18d..d78f6b821c7d1e859cc53f124e071eac27a5e9b8 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -75,6 +75,41 @@ extern hash_set <tree> *asan_used_labels;
 
 #define ASAN_USE_AFTER_SCOPE_ATTRIBUTE	"use after scope memory"
 
+/* NOTE: The macros below are hard-coded to these values in libhwasan, and
+   hence can't be changed independently here.  */
+/* How many bits are used to store a tag in a pointer.
+   For aarch64 MTE we have 4 bits per colour.
+   AArch64 has a Top-Byte-Ignore feature that allows the use of the top byte of
+   pointers for storing information, HWASAN can use that entire top byte if
+   required.
+   If changing this value, be careful of the predicates/constraints on the
+   addtag<mode>4 patterns in the backend.  */
+#define HWASAN_TAG_SIZE 4
+/* Tag Granule of HWASAN shadow stack.
+   This is the size in real memory that each byte in the shadow memory refers
+   to.  I.e. if a variable is X bytes long in memory then it's colour in shadow
+   memory will span X / HWASAN_TAG_GRANULE_SIZE bytes.
+   On top of this, most variables will need to be aligned to this amount since
+   two variables that are neighbours in memory and share a tag granule would
+   need to share the same colour (as the shared tag granule can only store one
+   colour).  */
+#define HWASAN_TAG_GRANULE_SIZE (1ULL << HWASAN_TAG_SIZE)
+/* How many bits to shift in order to access the tag bits.
+   This approach assumes that the tag is stored in the top N bits of a pointer,
+   and hence that shifting a known amount will leave just the tag bits.  */
+#define HWASAN_SHIFT 56
+#define HWASAN_SHIFT_RTX const_int_rtx[MAX_SAVED_CONST_INT + HWASAN_SHIFT]
+/* Define the tag for the stack background.
+   NOTE: Having a background colour of zero is hard-coded in the runtime
+   library, so we can't really change this.
+   This defines what colour the stack pointer will be and hence what colour all
+   uncoloured parts of the stack are (e.g. spilled registers).
+   It also provides a tag for stack allocation to avoid, since an object stored
+   on the stack will want to have a different colour to the background stack to
+   ensure things like the return address etc can't be affected by accesses
+   through pointer to a user-object.  */
+#define HWASAN_STACK_BACKGROUND 0
+
 /* Various flags for Asan builtins.  */
 enum asan_check_flags
 {
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 7722dcd4004e270551c8bcd4403e53a78ebfdff0..c5585d83c6e155856e7a4278e21c35ee5675bbdd 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -372,7 +372,14 @@ align_local_variable (tree decl)
       align = LOCAL_DECL_ALIGNMENT (decl);
       SET_DECL_ALIGN (decl, align);
     }
-  return align / BITS_PER_UNIT;
+
+  unsigned int ret_align = align / BITS_PER_UNIT;
+
+  if (memory_tagging_p ())
+    ret_align = ret_align > HWASAN_TAG_GRANULE_SIZE
+      ? ret_align
+      : HWASAN_TAG_GRANULE_SIZE;
+  return ret_align;
 }
 
 /* Align given offset BASE with ALIGN.  Truncate up if ALIGN_UP is true,
@@ -1117,6 +1124,29 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
       alignb = stack_vars[i].alignb;
       if (alignb * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT)
 	{
+	  if (memory_tagging_p ())
+	    {
+	      /* Allocate zero bytes to take advantage of the
+		 alloc_stack_frame_space logic of ensuring the stack is aligned
+		 despite having poly_int64's to deal with.
+
+		 There must be no tag granule "shared" between different
+		 objects.  This means that no HWASAN_TAG_GRANULE_SIZE byte
+		 chunk can have more than one object in it.
+
+		 We ensure this by forcing the end of the last bit of data to
+		 be aligned to HWASAN_TAG_GRANULE_SIZE bytes here, and setting
+		 the start of each variable to be aligned to
+		 HWASAN_TAG_GRANULE_SIZE bytes in `align_local_variable`.
+
+		 We can't align just one of the start or end, since there are
+		 untagged things stored on the stack that we have no control on
+		 the alignment (e.g. function parameters which must conform to
+		 ABI requirements) and these can't share a tag granule with a
+		 tagged variable.  */
+	      gcc_assert (stack_vars[i].alignb >= HWASAN_TAG_GRANULE_SIZE);
+	      alloc_stack_frame_space (0, HWASAN_TAG_GRANULE_SIZE);
+	    }
 	  base = virtual_stack_vars_rtx;
 	  /* ASAN description strings don't yet have a syntax for expressing
 	     polynomial offsets.  */
@@ -1545,8 +1575,11 @@ defer_stack_allocation (tree var, bool toplevel)
 
   /* If stack protection is enabled, *all* stack variables must be deferred,
      so that we can re-order the strings to the top of the frame.
-     Similarly for Address Sanitizer.  */
-  if (flag_stack_protect || asan_sanitize_stack_p ())
+     Similarly for Address Sanitizer.
+     When memory tagging we defer all stack variables so we can handle them in
+     one place (handle here meaning ensure aligned and record information on
+     its position on the stack).  */
+  if (flag_stack_protect || asan_sanitize_stack_p () || memory_tagging_p ())
     return true;
 
   unsigned int align = TREE_CODE (var) == SSA_NAME


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [RFC][PATCH 3/X][libsanitizer] Allow compilation for HWASAN_WITH_INTERCEPTORS=OFF
  2019-09-06 14:46 [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Matthew Malcomson
@ 2019-09-06 14:46 ` Matthew Malcomson
  2019-09-09  9:27   ` Martin Liška
  2019-09-06 14:46 ` [RFC][PATCH 2/X][libsanitizer] Tie the hwasan library into our build system Matthew Malcomson
                   ` (16 subsequent siblings)
  17 siblings, 1 reply; 35+ messages in thread
From: Matthew Malcomson @ 2019-09-06 14:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: mliska, dodji, nd, kcc, jakub, dvyukov

[-- Attachment #1: Type: text/plain, Size: 1410 bytes --]

This is a port of the LLVM-svn commit number 359914, it allows
compilation of the library without using interceptors.

This has been useful for testing.

libsanitizer/ChangeLog:

2019-09-06  Matthew Malcomson  <matthew.malcomson@arm.com>

	* hwasan/hwasan_linux.cc: Allow compilation without
	interceptors.



###############     Attachment also inlined for ease of reply    ###############


diff --git a/libsanitizer/hwasan/hwasan_linux.cc b/libsanitizer/hwasan/hwasan_linux.cc
index eef332fe9f16f36416bc93fc3e90eacf27f687f8..cdb02f161f691dcfe0f6f267a3a478d81cca458b 100644
--- a/libsanitizer/hwasan/hwasan_linux.cc
+++ b/libsanitizer/hwasan/hwasan_linux.cc
@@ -38,7 +38,17 @@
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_procmaps.h"
 
-#if HWASAN_WITH_INTERCEPTORS && !SANITIZER_ANDROID
+// Configurations of HWASAN_WITH_INTERCEPTORS and SANITIZER_ANDROID.
+//
+// HWASAN_WITH_INTERCEPTORS=OFF, SANITIZER_ANDROID=OFF
+//   Not currently tested.
+// HWASAN_WITH_INTERCEPTORS=OFF, SANITIZER_ANDROID=ON
+//   Integration tests downstream exist.
+// HWASAN_WITH_INTERCEPTORS=ON, SANITIZER_ANDROID=OFF
+//    Tested with check-hwasan on x86_64-linux.
+// HWASAN_WITH_INTERCEPTORS=ON, SANITIZER_ANDROID=ON
+//    Tested with check-hwasan on aarch64-linux-android.
+#if !SANITIZER_ANDROID
 THREADLOCAL uptr __hwasan_tls;
 #endif
 


[-- Attachment #2: hwasan-implementation02.patch --]
[-- Type: text/plain, Size: 976 bytes --]

diff --git a/libsanitizer/hwasan/hwasan_linux.cc b/libsanitizer/hwasan/hwasan_linux.cc
index eef332fe9f16f36416bc93fc3e90eacf27f687f8..cdb02f161f691dcfe0f6f267a3a478d81cca458b 100644
--- a/libsanitizer/hwasan/hwasan_linux.cc
+++ b/libsanitizer/hwasan/hwasan_linux.cc
@@ -38,7 +38,17 @@
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_procmaps.h"
 
-#if HWASAN_WITH_INTERCEPTORS && !SANITIZER_ANDROID
+// Configurations of HWASAN_WITH_INTERCEPTORS and SANITIZER_ANDROID.
+//
+// HWASAN_WITH_INTERCEPTORS=OFF, SANITIZER_ANDROID=OFF
+//   Not currently tested.
+// HWASAN_WITH_INTERCEPTORS=OFF, SANITIZER_ANDROID=ON
+//   Integration tests downstream exist.
+// HWASAN_WITH_INTERCEPTORS=ON, SANITIZER_ANDROID=OFF
+//    Tested with check-hwasan on x86_64-linux.
+// HWASAN_WITH_INTERCEPTORS=ON, SANITIZER_ANDROID=ON
+//    Tested with check-hwasan on aarch64-linux-android.
+#if !SANITIZER_ANDROID
 THREADLOCAL uptr __hwasan_tls;
 #endif
 


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC
@ 2019-09-06 14:46 Matthew Malcomson
  2019-09-06 14:46 ` [RFC][PATCH 3/X][libsanitizer] Allow compilation for HWASAN_WITH_INTERCEPTORS=OFF Matthew Malcomson
                   ` (17 more replies)
  0 siblings, 18 replies; 35+ messages in thread
From: Matthew Malcomson @ 2019-09-06 14:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: mliska, dodji, nd, kcc, jakub, dvyukov

[-- Attachment #1: Type: text/plain, Size: 3839 bytes --]

Hello,

This patch series is a WORK-IN-PROGRESS towards porting the LLVM hardware
address sanitizer (HWASAN) in GCC.  The document describing HWASAN can be found
here http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html.

The current patch series is far from complete, but I'm posting the current state
to provide something to discuss at the Cauldron next week.

In its current state, this sanitizer only works on AArch64 with a custom kernel
to allow tagged pointers in system calls.  This is discussed in the below link
https://source.android.com/devices/tech/debug/hwasan -- the custom kernel allows
tagged pointers in syscalls.
I have also not yet put tests into the DejaGNU framework, but instead have a
simple test file from which the tests will eventually come.  That test file is
attached to this email despite not being in the patch series.

Something close to this patch series bootstraps and passes most regression
tests when ~--with-build-config=bootstrap-hwasan~ is used.  The regressions it
doesn't pass are all the other sanitizer tests and all linker plugin tests.
The linker plugin tests fail due to a configuration problem where the library
path is not correctly set.
(I say "something close to this patch series" because I recently made a change
that breaks bootstrap but I believe is the best approach once I've fixed it,
hence for an RFC I'm leaving it in).

HWASAN works by storing a tag in the top bits of every pointer and a colour in
a shadow memory region corresponding to every area of memory.  On every memory
access through a pointer the tag in the pointer is checked against the colour in
shadow memory corresponding to the memory the pointer is accessing.  If the tag
and colour do not match then a fault is signalled.

The instrumentation required for this sanitizer has a large overlap with the
instrumentation required for implementing MTE (which has similar functionality
but checks are automatically done in the hardware and instructions for colouring
shadow memory and for managing tags are provided by the architecture).
https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/arm-a-profile-architecture-2018-developments-armv85a

We hope to use the HWASAN framework to implement MTE tagging on the stack, and
hence I have a "dummy" patch demonstrating the approach envisaged for this.

Though there is still much to implement here, the general approach should be
clear.  Any feedback is welcomed, but I have three main points that I'm
particularly hoping for external opinions.

1) The current approach stores a tag on the RTL representing a given variable,
   in order to implement HWASAN for x86_64 the tag needs to be removed before
   every memory access but not on things like function calls.
   Is there any obvious way to handle removing the tag in these places?
   Maybe something with legitimize_address?
2) The first draft presented here introduces a new RTL expression called
   ADDTAG.  I now believe that a hook would be neater here but haven't yet
   looked into it.  Do people agree?
   (addtag is introduced in the patch titled "Put tags into each stack variable
   pointer", but the reason it's introduced is so the backend can define how
   this gets implemented with a ~define_expand~ and that's only needed for the
   MTE handling as introduced in "Add in MTE stubs")
3) This patch series has not yet had much thought go towards it around command
   line arguments.  I personally quite like the idea of having
   ~-fsanitize=hwaddress~ turn on "checking memory tags against shadow memory
   colour", and MTE being just a hardware acceleration of this ability.
   I suspect this idea wouldn't be liked by all and would like to hear some
   opinions.

Thanks,
Matthew

[-- Attachment #2: testcases.c --]
[-- Type: text/plain, Size: 17443 bytes --]

#include <assert.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>

struct two_values {
    int left;
    int right;
};

struct big_struct {
    int left;
    int right;
    int big_array[100];
};

struct bitmapped_struct {
    unsigned one : 1;
    unsigned two : 1;
    unsigned three : 1;
    unsigned four : 1;
    unsigned five : 1;
    unsigned six : 1;
    unsigned seven : 1;
    unsigned eight : 1;
};

uint8_t
tag_of (void * x) { return ((uintptr_t)x) >> 56; }

/*
   Tests of nested funtions are:
    0) Accessing closed over variables works.
    1) Accesses outside of variables is caught.
    2) Accessing variable out of scope is caught.
 */
int __attribute__ ((noinline))
intermediate (void (*f) (int, uint8_t),
	      uint8_t num)
{
  if (num == 1)
    f (20, 100);
  else
    f (3, 100);
  /* Just return something ... */
  return num % 3;
}

int* __attribute__ ((noinline))
nested_function (uint8_t num)
{
  int big_array[16];
  int other_array[16];
  void store (int index, uint8_t value)
    { big_array[index] = value; }
  return &other_array[intermediate (store, num)];
}

int __attribute__ ((noinline))
test_nested (uint8_t check_mode)
{
  assert (check_mode < 3);
  int *retval = nested_function (check_mode);
  if (check_mode == 0)
    return 0;
  else if (check_mode == 2)
    *retval = 100;

  /* For check_mode anything other than 1 we should have caught an error.  */
  return 1;
}

#include <setjmp.h>
#include <stdio.h>

/*
   Testing longjmp/setjmp should test.

   0) Nothing special happens with the jmp_buf.
   1) Accesses to scopes jmp'd over are caught.
 */
int __attribute__ ((noinline))
uses_longjmp (int **other_array, int num, jmp_buf env)
{
  int internal_array[100] = {0};
  *other_array = &internal_array[0];
  if (num % 2)
    longjmp (env, num);
  else
    return num % 8;
}

int __attribute__ ((noinline))
uses_setjmp (int num)
{
  int big_array[100];
  int *other_array = NULL;
  sigjmp_buf cur_env;
  int temp = 0;
  if ((temp = sigsetjmp (cur_env, 1)) != 0)
    {
      if (other_array != NULL)
	printf ("Value pointed to in other_array[0]: %d\n",
		other_array[0]);
      else
	puts ("other_array was not initialised!");

      printf ("You gave %d arguments.\n", temp);
      return 10;
    }
  else
    {
      return uses_longjmp (&other_array, num, cur_env);
    }
}

int __attribute__ ((noinline))
test_longjmp (uint8_t check_mode)
{
  assert (check_mode < 2);
  if (check_mode)
    {
      uses_setjmp (1);
      return 1;
    }
  else
    nested_function (0);
  return 0;
}

/* Basic tests for stack tagging.

   0) Accesses outside of a variable crash.
   1) Valid accesses work.
*/
int __attribute__ ((noinline))
accessing_pointers (int *left, int *right)
{
  int x = right[2];
  left[3] = right[1];
  return right[1] + left[2];
}

int __attribute__ ((noinline))
using_stack (int num)
{
  int big_array[10];
  int other_array[20];
  accessing_pointers(other_array, big_array);
  return big_array[num];
}

int __attribute__ ((noinline))
test_basic_stack (uint8_t check_mode)
{
  assert (check_mode < 2);
  if (check_mode)
    {
      using_stack (5);
      return 0;
    }
  else
    using_stack (17);
  return 1;
}


/*
   Tests for alloca are:

   0) alloca is given a different tag to other variables.
   1) entire alloca array is accessible with pointer returned.
   2) Outside of alloca array is not accessible (once cross 16 byte alignment).
 */

#include <alloca.h>
int __attribute__ ((noinline))
check_alloca (int num)
{
  int *allocd_array = alloca (num * sizeof(int));
  int other_array[10];
  if (num % 2)
    {
      return allocd_array[num + 2];
    }
  return other_array[12];
}

int __attribute__ ((noinline))
alloca_different_tag (int num)
{
  struct two_values tmp_object = {
      .left = 100,
      .right = num,
  };
  int *big_array = alloca (num * sizeof (int));
  int other_array[100];
  
  uint8_t first_tag = tag_of (&tmp_object);
  uint8_t second_tag = tag_of (big_array);
  uint8_t other_tag = tag_of (other_array);
  assert (first_tag != second_tag);
  assert (second_tag != other_tag);
  assert (first_tag != other_tag);
  return 0;
}

int __attribute__ ((noinline))
using_alloca (int num)
{
  int retval = 0;
  int *big_array = alloca (num * sizeof (int));
  for (int i = 0; i < num; ++i) {
      retval += big_array[i];
  }
  return retval;
}

int __attribute__ ((noinline))
test_alloca (uint8_t check_mode)
{
  assert (check_mode < 3);
  if (check_mode == 1)
    using_alloca (16);
  else if (check_mode == 0)
    alloca_different_tag (check_mode);
  else
    {
      check_alloca (3);
      return 1;
    }
  return 0;
}

/*
   Tests for variable arrays are:

   SEE ABOVE REQUIREMENTS (alloca).
 */
#include <alloca.h>
int __attribute__ ((noinline))
check_vararray (int num)
{
  int var_array[num];
  int other_array[10];
  if (num % 2)
    {
      return var_array[num + 2];
    }
  return other_array[12];
}

int __attribute__ ((noinline))
vararray_different_tag (int num)
{
  struct two_values tmp_object = {
      .left = 100,
      .right = num,
  };
  int big_array[num];
  int other_array[100];
  
  uint8_t first_tag = tag_of (&tmp_object);
  uint8_t second_tag = tag_of (big_array);
  uint8_t other_tag = tag_of (other_array);
  assert (first_tag != second_tag);
  assert (second_tag != other_tag);
  assert (first_tag != other_tag);
  return 0;
}

int __attribute__ ((noinline))
using_vararray (int num)
{
  int retval = 0;
  int big_array[num];
  for (int i = 0; i < num; ++i) {
      retval += big_array[i];
  }
  return retval;
}

int __attribute__ ((noinline))
test_vararray (uint8_t check_mode)
{
  assert (check_mode < 3);
  if (check_mode == 1)
    using_vararray (16);
  else if (check_mode == 0)
    vararray_different_tag (check_mode);
  else
    {
      check_vararray (3);
      return 1;
    }
  return 0;
}

/*
   Tests for RVO

   0) The value is accessible in the given function.
   1) RVO does happen.
   2) The pointer for both caller and callee are the same.
 */

struct big_struct __attribute__ ((noinline))
return_on_stack()
{
  struct big_struct x;
  x.left = 100;
  x.right = 20;
  x.big_array[10] = 30;
  return x;
}

struct big_struct __attribute__ ((noinline))
unnamed_return_on_stack()
{
  return (struct big_struct){ .left = 100, .right = 20, .big_array = {0} };
}


/* Misc tests that I added each time I made a mistake in the implementation and
   broke something.  */

int __attribute__ ((noinline))
two_items_on_stack (int num)
{
  int left_array[100];
  int right_array[200];
  return left_array[num] + right_array[num];
}

int __attribute__ ((noinline))
stack_object_use(int direction)
{
  struct two_values stack_object = {
      .left = 1,
      .right = 2,
  };

  int *ptr = (int *)0;
  if (direction) {
      ptr = &stack_object.left;
  } else {
      ptr = &stack_object.right;
  }

  *ptr = direction;
  if (direction & 2) {
      return stack_object.right;
  } else {
      return stack_object.left;
  }
}

struct two_values __attribute__ ((noinline))
basic_stack_object (int direction)
{
  struct two_values x = {
      .left = 1,
      .right = 2,
  };
  x.left += direction;
  return x;
}

int __attribute__ ((noinline))
set_value_to_random(int *value_p)
{
  int big_array[100];
  *value_p = big_array[10];
  return 1;
}


/* Ensure my instrumentation doesn't crash on unaligned access (an older
   version with a completely different approach didn't handle this well).  */

int __attribute__ ((noinline))
handle_unaligned_access (struct bitmapped_struct *foo)
{
  if (foo->three)
    return foo->four;

  foo->five = 1;
  return 1;
}

/* Handling large aligned variables.
   Large aligned variables take a different code-path through expand_stack_vars
   in cfgexpand.c.  This testcase is just to exercise that code-path.

   The alternate code-path produces a second base-pointer through some
   instructions emitted in the prologue.
   
   Test cases are:
   0) Valid access works without complaint.
   1) Invalid access is caught.  */
int __attribute__ ((noinline))
handle_large_alignment (int num)
{
  int other_array[10];
  int big_array[100] __attribute__ ((aligned (32)));
  return big_array[num] + other_array[num];
}

int __attribute__ ((noinline))
test_large_alignment (uint8_t check_mode)
{
  assert (check_mode < 2);
  if (check_mode)
    {
      handle_large_alignment (11);
      return 1;
    }
  else
    handle_large_alignment (1);
  return 0;
}

/* {{{ This is a reduced testcase from an ICE a while ago.
   At the time I was modifying the GIMPLE and made an assumption that all
   statements used all their operands.
   This test is redundant now, but there's no harm in still compiling it. */
#include <string.h>
#include <stdint.h>

const short DPD2BIN[1024] = {0};
const char  BIN2CHAR[4001] = {0};

char * decimal64ToString(char *string)
{
  char *c;                         /* output pointer in string */
  const uint8_t *u;                /* work */
  int32_t  dpd;                    /* .. */

  u=(const uint8_t *)&BIN2CHAR[DPD2BIN[dpd]*4]; 
  if (string[3]) {memcpy(c, u+1, 4); c+=3;}
  else if (string[4])  {memcpy(c, u+4-*u, 4); c+=string[4];}
  return string;
}

int __attribute__ ((noinline))
variables_same_partition ()
{
  int ret = 0;
    {
      struct bitmapped_struct orig;
      ret = handle_unaligned_access (&orig);
    }
    {
      struct bitmapped_struct other;
      ret += handle_unaligned_access (&other);
    }
  return ret;
}

/* }}} */

/* {{{ Unrecogniseable insn problem.
   This code is reduced from something in the bootstrap that triggered a
   problem where my backend patterns didn't handle very large offsets.  */
#ifndef ASIZE
# define ASIZE 0x10000000000UL
#endif

#include <limits.h>

#if LONG_MAX < 8 * ASIZE
# undef ASIZE
# define ASIZE 4096
#endif

extern void abort (void);

int __attribute__((noinline))
foo (const char *s)
{
  if (!s)
    return 1;
  if (s[0] != 'a')
    abort ();
  s += ASIZE - 1;
  if (s[0] != 'b')
    abort ();
  return 0;
}

int (*fn) (const char *) = foo;

int __attribute__((noinline))
bar (void)
{
  char s[ASIZE];
  s[0] = 'a';
  s[ASIZE - 1] = 'b';
  foo (s);
  foo (s);
  return 0;
}

int __attribute__((noinline))
baz (long i)
{
  if (i)
    return fn (0);
  else
    {
      char s[ASIZE];
      s[0] = 'a';
      s[ASIZE - 1] = 'b';
      foo (s);
      foo (s);
      return fn (0);
    }
}
/* }}} */

/* {{{ Non-constant sizes.
   Code designed to store SVE registers on the stack.
   This is needed to exercise the poly_int64 handling for HWASAN and MTE
   instrumentation. */
int u;

void
foo_sve (int *p)
{
  int i;
  #pragma omp for simd lastprivate(u) schedule (static, 32)
  for (i = 0; i < 1024; i++)
    u = p[i];
}

void
bar_sve (int *p)
{
  int i;
  #pragma omp taskloop simd lastprivate(u)
  for (i = 0; i < 1024; i++)
    u = p[i];
}
/* }}} */

/* An old RTL testcase.  This was originally introduced since it was produced
   somewhere in bootstrap and the compiler ICE'd on it.
   It's only relevant for MTE, since for HWASAN the ADDTAG pattern is converted
   into a plain ADD at expand time.
   Moreover, this pattern only works for MTE, since there is no define_insn
   matching ADDTAG patterns when MTE is not available.  */
// // Apparently clang defines the __GNUC__ macro.
// // That's a little annoying, but the below works for what I need.
// #ifndef __clang__
// int __RTL (startwith ("final"))
// bootstrap_problem ()
// {
//   (function "bootstrap_problem"
//    (insn-chain
//     (block 2
//      (edge-from entry (flags "FALLTHRU"))
//      (cnote 3 [bb 2] NOTE_INSN_BASIC_BLOCK)
//      (cinsn 90 (set (reg:DI x0)
// 		(addtag:DI (reg:DI x0)
// 		 (const_int -16)
// 		 (const_int 1))))
//      (edge-to exit (flags "FALLTHRU"))
//     ) ;; block 2
//    ) ;; insn-chain
//   ) ;; function "bootstrap_problem"
// }
// #endif


int __attribute__((noinline))
very_large_offset (int *p)
{
  char init_array[(uint64_t)0xfefefef];
  char other_array[(uint64_t)0xfefefef];
  return (int)init_array[p[1]] + (int)other_array[p[0]];
}

void __attribute__((noinline))
just_abort() { abort(); }

/* This test is only around for observing what the compiler does, not for
   checking the HWASAN implementation works properly.  HWASAN and MTE do
   nothing special for varargs.  */
void __attribute__((noinline))
varargs_function (size_t numargs, ...)
{
  va_list args;
  va_start (args, numargs);

  while (numargs > 0)
    {
      char *x = va_arg (args, char *);
      printf ("Address of next argument is: %p\n", &x);
      numargs -= 1;
    }
  va_end (args);
}

/* Functions to observe that HWASAN instruments memory builtins in the expected
   manner.  */
void * __attribute__((noinline))
memset_builtin (void *dest, int value, size_t len)
{
  return __builtin_memset (dest, value, len);
}

/* HWASAN avoids strlen because it doesn't know the size of the memory access
   until *after* the function call.  */
size_t __attribute__ ((noinline))
strlen_builtin (char *element)
{
  return __builtin_strlen (element);
}

/* Here to check that the ASAN_POISON stuff works just fine.
   THis mechanism isn't very often used, but I should at least go through the
   code-path once in my testfile.  */
int __attribute__ ((noinline))
access_outside_of_scope ()
{
  int *ptr = 0;

  {
    int a;
    ptr = &a;
    *ptr = 12345;
  }

  return *ptr;
}

int
main (int argc, char *argv[])
{
  printf("outside-scope return value: %d\n", access_outside_of_scope ());
  printf("Returned value of %d\n",
	 uses_setjmp (argc));
  printf ("Value is %d\n",
	  handle_large_alignment (argc));
  printf ("Value is %d\n",
	  check_alloca (argc));
  using_alloca (argc);

  int left[100] = {0};
  memset_builtin (left, 1, 100);

  char *mystring = "hello world!\n";
  printf ("Length of string is: %u\n", strlen_builtin (mystring));
  varargs_function (4, "hello there", (char)1,
		    (char)2);

  int right[100] = {0};
  accessing_pointers (left, right);
  using_stack(argc);

  int num = argc;
  two_items_on_stack(num);

  int direction = argc;
  stack_object_use(direction);
  int *num_addr = &num;
  set_value_to_random(num_addr);
  struct big_struct x;
  x = return_on_stack();
  struct big_struct y;
  y = unnamed_return_on_stack();
  printf("Value is %d ... %d\n", x.left, y.left);
  return 0;
}

/* {{{ Simply checking that HWASAN caught failures behave sensibly when run
   under a multithreaded environment.  */
// #include <pthread.h>
// #include <stdio.h>
// #include <string.h>
// #include <stdarg.h>
// #include <stdbool.h>
// #include <stdint.h>

// void *
// failing_thread_function (void *argument)
// {
//     void * other = (void *)((uint64_t)argument & 0xffffffffffffffULL);
//     int *num = argument;
//     printf ("(should succeed): first number = %d\n", num[0]);
//     printf ("(now should fail):");
//     fflush (stdout);

//     int *othernum = other;
//     printf (" second number = %d\n", othernum[0]);
//     return (void *)1;
// }

// void *
// failing_from_stack (void * argument)
// {
//     int internal_array[16] = {0};
//     printf ("(now should fail):");
//     fflush (stdout);
//     printf (" problem number is %d\n", internal_array[17]);
//     return (void *)1;
// }

// void *
// pthread_stack_is_cleared (void *argument)
// {
//    (void)argument;
//    int internal_array[16] = {0};
//    return (void*)internal_array;
// }

// void *
// successful_thread_function (void * argument)
// {
//     int *deref = (int *)argument;
//     printf ("(should be fine): sum of first two numbers is %d\n",
//             deref[0] + deref[1]);
//     return (void *)0;
// }

// int
// main (int argc, char **argv)
// {
//     int argument[100] = {0};
//     argument[1] = 10;
//     void *(*thread_function) (void *) = NULL;
//     bool access_variable = false;

//     if (argc < 2 || strcmp (argv[1], "success") == 0)
//       thread_function = successful_thread_function;
//     else if (strcmp (argv[1], "external-fail") == 0)
//       thread_function = failing_thread_function;
//     else if (strcmp (argv[1], "internal-fail") == 0)
//       thread_function = failing_from_stack;
//     else
//       {
//         thread_function = pthread_stack_is_cleared;
//         access_variable = true;
//       }

//     pthread_t thread_index;
//     pthread_create (&thread_index, NULL, thread_function, (void*)argument);

//     void *retval;
//     pthread_join (thread_index, &retval);

//     if (access_variable)
//       {
//         printf ("(should fail): ");
//         fflush (stdout);
//         printf ("value left in stack is: %d\n", ((int *)retval)[0]);
//       }

//     return (int)retval;
// }

/* }}} */

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [RFC][PATCH 5/X][libsanitizer] Introduce longjmp/setjmp interceptors to libhwasan
  2019-09-06 14:46 [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Matthew Malcomson
                   ` (4 preceding siblings ...)
  2019-09-06 14:46 ` [RFC][PATCH 8/X][libsanitizer] Ensure HWASAN required alignment for stack variables Matthew Malcomson
@ 2019-09-06 14:46 ` Matthew Malcomson
  2019-09-09 10:02   ` Martin Liška
  2019-09-06 14:46 ` [RFC][PATCH 14/X][libsanitizer] Introduce HWASAN block-scope poisoning Matthew Malcomson
                   ` (11 subsequent siblings)
  17 siblings, 1 reply; 35+ messages in thread
From: Matthew Malcomson @ 2019-09-06 14:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: mliska, dodji, nd, kcc, jakub, dvyukov

[-- Attachment #1: Type: text/plain, Size: 14486 bytes --]

When using hwasan to tag parameters on the stack, we need to ensure that
the shadow stack is cleared upon exit of a function.

If this is not done, then accesses to an untagged memory region (e.g.
parameters passed on the stack) can end up being checked against a
shadow region that was coloured for a variable some time in the past.

Ensuring that the shadow stack is cleared on normal function exit will
be done by adding instrumentation to the function epilogue through the
compiler.
longjmp and setjmp are some abnormal methods of exiting the function
that can't be handled in the compiler since they can be called in
uninstrumented code to unwind past instrumented function frames.

This patch introduces some interceptors for setjmp and longjmp.
This pair of functions only behaves differently to the glibc version by
uncolouring the stack between the point where longjmp was called and the
destination stack pointer.

The file hwasan_interceptors.cc aims to include as little system headers
as possible, since it defines interceptors for system functions and
hence needs to use its own data structures that are independent of the
current platform.  To avoid including signal.h yet still be able to
handle sigsetjmp we manually define a __sigset_t structure and similarly
we define data structures to use for the intercepting setjmp/longjmp.

libsanitizer/ChangeLog:

2019-09-06  Matthew Malcomson  <matthew.malcomson@arm.com>

	* hwasan/Makefile.am: Add hwasan_setjmp.S.
	* hwasan/Makefile.in: Regenerate.
	* hwasan/hwasan_interceptors.cc (_SIGSET_NWORDS):
	(struct __sigset_t): New structure.
	(struct __jmp_buf_tag): New structure.
	(sigprocmask): Declaration of system function.
	(SIG_BLOCK): New.
	(SIG_SETMASK): New.
	(__sigjmp_save): New.
	(__hwasan_internal_longjmp): longjmp that clears shadow tags.
	(siglongjmp): New interceptors.
	(__libc_longjmp): New interceptors.
	(longjmp): New interceptors.
	* hwasan/hwasan_setjmp.S: New file.



###############     Attachment also inlined for ease of reply    ###############


diff --git a/libsanitizer/hwasan/Makefile.am b/libsanitizer/hwasan/Makefile.am
index 3754f435ce0342f5c8051f6ea44273bb811c9659..36c0fc4d9e832dfc81c72d2d05c2b327589daee2 100644
--- a/libsanitizer/hwasan/Makefile.am
+++ b/libsanitizer/hwasan/Makefile.am
@@ -13,6 +13,7 @@ ACLOCAL_AMFLAGS = -I $(top_srcdir) -I $(top_srcdir)/config
 toolexeclib_LTLIBRARIES = libhwasan.la
 
 hwasan_files = \
+	       hwasan_setjmp.S \
 	       hwasan_allocator.cc \
 	       hwasan.cc \
 	       hwasan_dynamic_shadow.cc \
diff --git a/libsanitizer/hwasan/Makefile.in b/libsanitizer/hwasan/Makefile.in
index f89bc9e440502fcf8072d67aa61a4b63cd490b40..472fbf7d8d2a5311db8fe4c14376f9213cdddde4 100644
--- a/libsanitizer/hwasan/Makefile.in
+++ b/libsanitizer/hwasan/Makefile.in
@@ -145,10 +145,10 @@ am__DEPENDENCIES_1 =
 libhwasan_la_DEPENDENCIES =  \
 	$(top_builddir)/sanitizer_common/libsanitizer_common.la \
 	$(am__append_1) $(am__append_2) $(am__DEPENDENCIES_1)
-am__objects_1 = hwasan_allocator.lo hwasan.lo hwasan_dynamic_shadow.lo \
-	hwasan_interceptors.lo hwasan_linux.lo hwasan_new_delete.lo \
-	hwasan_poisoning.lo hwasan_report.lo hwasan_thread.lo \
-	hwasan_thread_list.lo
+am__objects_1 = hwasan_setjmp.lo hwasan_allocator.lo hwasan.lo \
+	hwasan_dynamic_shadow.lo hwasan_interceptors.lo \
+	hwasan_linux.lo hwasan_new_delete.lo hwasan_poisoning.lo \
+	hwasan_report.lo hwasan_thread.lo hwasan_thread_list.lo
 am_libhwasan_la_OBJECTS = $(am__objects_1)
 libhwasan_la_OBJECTS = $(am_libhwasan_la_OBJECTS)
 AM_V_lt = $(am__v_lt_@AM_V@)
@@ -174,6 +174,16 @@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
 depcomp = $(SHELL) $(top_srcdir)/../depcomp
 am__depfiles_maybe = depfiles
 am__mv = mv -f
+CPPASCOMPILE = $(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CCASFLAGS) $(CCASFLAGS)
+LTCPPASCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CCAS) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CCASFLAGS) $(CCASFLAGS)
+AM_V_CPPAS = $(am__v_CPPAS_@AM_V@)
+am__v_CPPAS_ = $(am__v_CPPAS_@AM_DEFAULT_V@)
+am__v_CPPAS_0 = @echo "  CPPAS   " $@;
+am__v_CPPAS_1 = 
 CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
 	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
 LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
@@ -192,6 +202,24 @@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
 am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
 am__v_CXXLD_0 = @echo "  CXXLD   " $@;
 am__v_CXXLD_1 = 
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
 SOURCES = $(libhwasan_la_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
@@ -380,6 +408,7 @@ AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic \
 ACLOCAL_AMFLAGS = -I $(top_srcdir) -I $(top_srcdir)/config
 toolexeclib_LTLIBRARIES = libhwasan.la
 hwasan_files = \
+	       hwasan_setjmp.S \
 	       hwasan_allocator.cc \
 	       hwasan.cc \
 	       hwasan_dynamic_shadow.cc \
@@ -439,7 +468,7 @@ MAKEOVERRIDES =
 all: all-am
 
 .SUFFIXES:
-.SUFFIXES: .cc .lo .o .obj
+.SUFFIXES: .S .cc .lo .o .obj
 $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
 	@for dep in $?; do \
 	  case '$(am__configure_deps)' in \
@@ -522,9 +551,31 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_new_delete.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_poisoning.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_report.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_setjmp.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_thread.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_thread_list.Plo@am__quote@
 
+.S.o:
+@am__fastdepCCAS_TRUE@	$(AM_V_CPPAS)$(CPPASCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCCAS_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@	$(AM_V_CPPAS)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@	DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCCAS_FALSE@	$(AM_V_CPPAS@am__nodep@)$(CPPASCOMPILE) -c -o $@ $<
+
+.S.obj:
+@am__fastdepCCAS_TRUE@	$(AM_V_CPPAS)$(CPPASCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCCAS_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@	$(AM_V_CPPAS)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@	DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCCAS_FALSE@	$(AM_V_CPPAS@am__nodep@)$(CPPASCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.S.lo:
+@am__fastdepCCAS_TRUE@	$(AM_V_CPPAS)$(LTCPPASCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCCAS_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@	$(AM_V_CPPAS)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@	DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCCAS_FALSE@	$(AM_V_CPPAS@am__nodep@)$(LTCPPASCOMPILE) -c -o $@ $<
+
 .cc.o:
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
diff --git a/libsanitizer/hwasan/hwasan_interceptors.cc b/libsanitizer/hwasan/hwasan_interceptors.cc
index 9a0770f563b7948644cb10cdd0f88edc79f786d5..2edfba5d4ba065ca1dd09400c182962ecff5d9ca 100644
--- a/libsanitizer/hwasan/hwasan_interceptors.cc
+++ b/libsanitizer/hwasan/hwasan_interceptors.cc
@@ -284,6 +284,107 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
                                  &HwasanThreadStartFunc, A);
   return res;
 }
+
+
+#if defined(__aarch64__)
+/*
+   Setjmp and longjmp implementations are platform specific, and hence the
+   interception code is platform specific too.  As yet we've only implemented
+   the interception for AArch64.
+ */
+# define _SIGSET_NWORDS	(1024 / (8 * sizeof (unsigned long int)))
+typedef struct
+  {
+    unsigned long int __val[_SIGSET_NWORDS];
+  } __sigset_t;
+
+#undef _SIGSET_NWORDS
+typedef __sigset_t sigset_t;
+typedef unsigned long long __jmp_buf [22];
+struct __jmp_buf_tag
+  {
+    /* NOTE: The machine-dependent definitions of `__sigsetjmp'
+       assume that a `jmp_buf' begins with a `__jmp_buf' and that
+       `__mask_was_saved' follows it.  Do not move these members
+       or add others before it.  */
+    __jmp_buf __jmpbuf;		/* Calling environment.  */
+    int __mask_was_saved;	/* Saved the signal mask?  */
+    __sigset_t __saved_mask;	/* Saved signal mask.  */
+  };
+typedef struct __jmp_buf_tag jmp_buf[1];
+typedef struct __jmp_buf_tag sigjmp_buf[1];
+
+/* Get and/or change the set of blocked signals.  */
+extern "C" int sigprocmask (int __how, const sigset_t *__restrict __set,
+			sigset_t *__restrict __oset);
+#define SIG_BLOCK 0
+#define SIG_SETMASK 2
+extern "C" int __sigjmp_save (sigjmp_buf env, int savemask)
+{
+  env[0].__mask_was_saved = (savemask
+			     && sigprocmask (SIG_BLOCK, (sigset_t *) 0,
+					     (sigset_t *) &env[0].__saved_mask) == 0);
+  return 0;
+}
+
+static void __attribute__ ((always_inline))
+__hwasan_internal_longjmp (__jmp_buf env, int retval)
+{
+  /* Clear all memory tags on the stack between here and where we're going.  */
+  unsigned long long stack_pointer = env[13];
+  /* The stack pointer should never be tagged, so we don't need to clear the
+     tag for this function call.  */
+  __hwasan_handle_longjmp ((void *)stack_pointer);
+
+  /* Run code for handling a longjmp.
+     Need to use a register that isn't going to be loaded from the environment
+     buffer -- hence why we need to specify the register to use.  */
+  register int retval_tmp asm ("x1") = retval;
+  register void *env_address asm ("x0") = &env[0];
+  asm volatile (
+	"ldp	x19, x20, [%0, #0<<3];"
+	"ldp	x21, x22, [%0, #2<<3];"
+	"ldp	x23, x24, [%0, #4<<3];"
+	"ldp	x25, x26, [%0, #6<<3];"
+	"ldp	x27, x28, [%0, #8<<3];"
+	"ldp	x29, x30, [%0, #10<<3];"
+	"ldp	 d8,  d9, [%0, #14<<3];"
+	"ldp	d10, d11, [%0, #16<<3];"
+	"ldp	d12, d13, [%0, #18<<3];"
+	"ldp	d14, d15, [%0, #20<<3];"
+	"ldr	x5, [%0, #13<<3];"
+	"mov	sp, x5;"
+	/* Return the value requested to return through arguments.
+	   This should be in x1 given what we requested above.  */
+	"cmp	%1, #0;"
+	"mov	x0, #1;"
+	"csel	x0, %1, x0, ne;"
+	"br	x30;" : "+r" (env_address) : "r" (retval_tmp));
+}
+
+INTERCEPTOR(void, siglongjmp, sigjmp_buf env, int val)
+{
+  if (env[0].__mask_was_saved)
+    /* Restore the saved signal mask.  */
+    (void) sigprocmask (SIG_SETMASK,
+			(sigset_t *) &env[0].__saved_mask,
+			(sigset_t *) 0);
+  __hwasan_internal_longjmp (env[0].__jmpbuf, val);
+}
+
+INTERCEPTOR(void, __libc_longjmp, jmp_buf env, int val)
+{
+  __hwasan_internal_longjmp (env[0].__jmpbuf, val);
+}
+
+INTERCEPTOR(void, longjmp, jmp_buf env, int val)
+{
+  __hwasan_internal_longjmp (env[0].__jmpbuf, val);
+}
+#undef SIG_BLOCK
+#undef SIG_SETMASK
+
+#endif // __aarch64__
 #endif // HWASAN_WITH_INTERCEPTORS
 
 static void BeforeFork() {
@@ -302,7 +403,6 @@ INTERCEPTOR(int, fork, void) {
   return pid;
 }
 
-
 struct HwasanInterceptorContext {
   bool in_interceptor_scope;
 };
@@ -325,6 +425,11 @@ void InitializeInterceptors() {
   INTERCEPT_FUNCTION(fork);
 
 #if HWASAN_WITH_INTERCEPTORS
+#if defined(__aarch64__)
+  INTERCEPT_FUNCTION(longjmp);
+  INTERCEPT_FUNCTION(__libc_longjmp);
+  INTERCEPT_FUNCTION(siglongjmp);
+#endif
   INTERCEPT_FUNCTION(pthread_create);
 #endif
 
diff --git a/libsanitizer/hwasan/hwasan_setjmp.S b/libsanitizer/hwasan/hwasan_setjmp.S
new file mode 100644
index 0000000000000000000000000000000000000000..56add3e149abcc37ec23b8cdc8f4ba2cbc722c08
--- /dev/null
+++ b/libsanitizer/hwasan/hwasan_setjmp.S
@@ -0,0 +1,52 @@
+// We want to save the context of the calling function.
+// That requires
+// 1) No modification of the link register by this function.
+// 2) No modification of the stack pointer by this function.
+// 3) (no modification of any other saved register, but that's not really going
+// to occur, and hence isn't as much of a worry).
+//
+// There's essentially no way to ensure that the compiler will not modify the
+// stack pointer when compiling a C function.
+// Hence we have to write this function in assembly.
+
+#if HWASAN_WITH_INTERCEPTORS && defined(__aarch64__)
+
+.macro ENTRY symbol
+  .align 2
+  .global \symbol
+  .type  \symbol\(), %function
+\symbol\():
+  .cfi_startproc
+.endm
+
+.macro END symbol
+  .cfi_endproc
+  .size \symbol, .-\symbol
+.endm
+
+ENTRY _setjmp
+mov	x1, #0
+b	1f
+END _setjmp
+
+ENTRY __sigsetjmp
+1:
+  stp	x19, x20, [x0, #0<<3]
+  stp	x21, x22, [x0, #2<<3]
+  stp	x23, x24, [x0, #4<<3]
+  stp	x25, x26, [x0, #6<<3]
+  stp	x27, x28, [x0, #8<<3]
+  stp	x29, x30, [x0, #10<<3]
+  stp	 d8,  d9, [x0, #14<<3]
+  stp	d10, d11, [x0, #16<<3]
+  stp	d12, d13, [x0, #18<<3]
+  stp	d14, d15, [x0, #20<<3]
+  mov	x2,  sp
+  str	x2,  [x0, #13<<3]
+  // We always have the second argument to __sigjmp_save (savemask) set, since
+  // the _setjmp function above has set it for us as `false`.
+  // This function is defined in hwasan_interceptors.cc
+  b	__sigjmp_save
+END __sigsetjmp
+
+#endif


[-- Attachment #2: hwasan-implementation04.patch --]
[-- Type: text/plain, Size: 12085 bytes --]

diff --git a/libsanitizer/hwasan/Makefile.am b/libsanitizer/hwasan/Makefile.am
index 3754f435ce0342f5c8051f6ea44273bb811c9659..36c0fc4d9e832dfc81c72d2d05c2b327589daee2 100644
--- a/libsanitizer/hwasan/Makefile.am
+++ b/libsanitizer/hwasan/Makefile.am
@@ -13,6 +13,7 @@ ACLOCAL_AMFLAGS = -I $(top_srcdir) -I $(top_srcdir)/config
 toolexeclib_LTLIBRARIES = libhwasan.la
 
 hwasan_files = \
+	       hwasan_setjmp.S \
 	       hwasan_allocator.cc \
 	       hwasan.cc \
 	       hwasan_dynamic_shadow.cc \
diff --git a/libsanitizer/hwasan/Makefile.in b/libsanitizer/hwasan/Makefile.in
index f89bc9e440502fcf8072d67aa61a4b63cd490b40..472fbf7d8d2a5311db8fe4c14376f9213cdddde4 100644
--- a/libsanitizer/hwasan/Makefile.in
+++ b/libsanitizer/hwasan/Makefile.in
@@ -145,10 +145,10 @@ am__DEPENDENCIES_1 =
 libhwasan_la_DEPENDENCIES =  \
 	$(top_builddir)/sanitizer_common/libsanitizer_common.la \
 	$(am__append_1) $(am__append_2) $(am__DEPENDENCIES_1)
-am__objects_1 = hwasan_allocator.lo hwasan.lo hwasan_dynamic_shadow.lo \
-	hwasan_interceptors.lo hwasan_linux.lo hwasan_new_delete.lo \
-	hwasan_poisoning.lo hwasan_report.lo hwasan_thread.lo \
-	hwasan_thread_list.lo
+am__objects_1 = hwasan_setjmp.lo hwasan_allocator.lo hwasan.lo \
+	hwasan_dynamic_shadow.lo hwasan_interceptors.lo \
+	hwasan_linux.lo hwasan_new_delete.lo hwasan_poisoning.lo \
+	hwasan_report.lo hwasan_thread.lo hwasan_thread_list.lo
 am_libhwasan_la_OBJECTS = $(am__objects_1)
 libhwasan_la_OBJECTS = $(am_libhwasan_la_OBJECTS)
 AM_V_lt = $(am__v_lt_@AM_V@)
@@ -174,6 +174,16 @@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
 depcomp = $(SHELL) $(top_srcdir)/../depcomp
 am__depfiles_maybe = depfiles
 am__mv = mv -f
+CPPASCOMPILE = $(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CCASFLAGS) $(CCASFLAGS)
+LTCPPASCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CCAS) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CCASFLAGS) $(CCASFLAGS)
+AM_V_CPPAS = $(am__v_CPPAS_@AM_V@)
+am__v_CPPAS_ = $(am__v_CPPAS_@AM_DEFAULT_V@)
+am__v_CPPAS_0 = @echo "  CPPAS   " $@;
+am__v_CPPAS_1 = 
 CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
 	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
 LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
@@ -192,6 +202,24 @@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
 am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
 am__v_CXXLD_0 = @echo "  CXXLD   " $@;
 am__v_CXXLD_1 = 
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
 SOURCES = $(libhwasan_la_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
@@ -380,6 +408,7 @@ AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic \
 ACLOCAL_AMFLAGS = -I $(top_srcdir) -I $(top_srcdir)/config
 toolexeclib_LTLIBRARIES = libhwasan.la
 hwasan_files = \
+	       hwasan_setjmp.S \
 	       hwasan_allocator.cc \
 	       hwasan.cc \
 	       hwasan_dynamic_shadow.cc \
@@ -439,7 +468,7 @@ MAKEOVERRIDES =
 all: all-am
 
 .SUFFIXES:
-.SUFFIXES: .cc .lo .o .obj
+.SUFFIXES: .S .cc .lo .o .obj
 $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
 	@for dep in $?; do \
 	  case '$(am__configure_deps)' in \
@@ -522,9 +551,31 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_new_delete.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_poisoning.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_report.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_setjmp.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_thread.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hwasan_thread_list.Plo@am__quote@
 
+.S.o:
+@am__fastdepCCAS_TRUE@	$(AM_V_CPPAS)$(CPPASCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCCAS_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@	$(AM_V_CPPAS)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@	DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCCAS_FALSE@	$(AM_V_CPPAS@am__nodep@)$(CPPASCOMPILE) -c -o $@ $<
+
+.S.obj:
+@am__fastdepCCAS_TRUE@	$(AM_V_CPPAS)$(CPPASCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCCAS_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@	$(AM_V_CPPAS)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@	DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCCAS_FALSE@	$(AM_V_CPPAS@am__nodep@)$(CPPASCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.S.lo:
+@am__fastdepCCAS_TRUE@	$(AM_V_CPPAS)$(LTCPPASCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCCAS_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@	$(AM_V_CPPAS)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCCAS_FALSE@	DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCCAS_FALSE@	$(AM_V_CPPAS@am__nodep@)$(LTCPPASCOMPILE) -c -o $@ $<
+
 .cc.o:
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
diff --git a/libsanitizer/hwasan/hwasan_interceptors.cc b/libsanitizer/hwasan/hwasan_interceptors.cc
index 9a0770f563b7948644cb10cdd0f88edc79f786d5..2edfba5d4ba065ca1dd09400c182962ecff5d9ca 100644
--- a/libsanitizer/hwasan/hwasan_interceptors.cc
+++ b/libsanitizer/hwasan/hwasan_interceptors.cc
@@ -284,6 +284,107 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
                                  &HwasanThreadStartFunc, A);
   return res;
 }
+
+
+#if defined(__aarch64__)
+/*
+   Setjmp and longjmp implementations are platform specific, and hence the
+   interception code is platform specific too.  As yet we've only implemented
+   the interception for AArch64.
+ */
+# define _SIGSET_NWORDS	(1024 / (8 * sizeof (unsigned long int)))
+typedef struct
+  {
+    unsigned long int __val[_SIGSET_NWORDS];
+  } __sigset_t;
+
+#undef _SIGSET_NWORDS
+typedef __sigset_t sigset_t;
+typedef unsigned long long __jmp_buf [22];
+struct __jmp_buf_tag
+  {
+    /* NOTE: The machine-dependent definitions of `__sigsetjmp'
+       assume that a `jmp_buf' begins with a `__jmp_buf' and that
+       `__mask_was_saved' follows it.  Do not move these members
+       or add others before it.  */
+    __jmp_buf __jmpbuf;		/* Calling environment.  */
+    int __mask_was_saved;	/* Saved the signal mask?  */
+    __sigset_t __saved_mask;	/* Saved signal mask.  */
+  };
+typedef struct __jmp_buf_tag jmp_buf[1];
+typedef struct __jmp_buf_tag sigjmp_buf[1];
+
+/* Get and/or change the set of blocked signals.  */
+extern "C" int sigprocmask (int __how, const sigset_t *__restrict __set,
+			sigset_t *__restrict __oset);
+#define SIG_BLOCK 0
+#define SIG_SETMASK 2
+extern "C" int __sigjmp_save (sigjmp_buf env, int savemask)
+{
+  env[0].__mask_was_saved = (savemask
+			     && sigprocmask (SIG_BLOCK, (sigset_t *) 0,
+					     (sigset_t *) &env[0].__saved_mask) == 0);
+  return 0;
+}
+
+static void __attribute__ ((always_inline))
+__hwasan_internal_longjmp (__jmp_buf env, int retval)
+{
+  /* Clear all memory tags on the stack between here and where we're going.  */
+  unsigned long long stack_pointer = env[13];
+  /* The stack pointer should never be tagged, so we don't need to clear the
+     tag for this function call.  */
+  __hwasan_handle_longjmp ((void *)stack_pointer);
+
+  /* Run code for handling a longjmp.
+     Need to use a register that isn't going to be loaded from the environment
+     buffer -- hence why we need to specify the register to use.  */
+  register int retval_tmp asm ("x1") = retval;
+  register void *env_address asm ("x0") = &env[0];
+  asm volatile (
+	"ldp	x19, x20, [%0, #0<<3];"
+	"ldp	x21, x22, [%0, #2<<3];"
+	"ldp	x23, x24, [%0, #4<<3];"
+	"ldp	x25, x26, [%0, #6<<3];"
+	"ldp	x27, x28, [%0, #8<<3];"
+	"ldp	x29, x30, [%0, #10<<3];"
+	"ldp	 d8,  d9, [%0, #14<<3];"
+	"ldp	d10, d11, [%0, #16<<3];"
+	"ldp	d12, d13, [%0, #18<<3];"
+	"ldp	d14, d15, [%0, #20<<3];"
+	"ldr	x5, [%0, #13<<3];"
+	"mov	sp, x5;"
+	/* Return the value requested to return through arguments.
+	   This should be in x1 given what we requested above.  */
+	"cmp	%1, #0;"
+	"mov	x0, #1;"
+	"csel	x0, %1, x0, ne;"
+	"br	x30;" : "+r" (env_address) : "r" (retval_tmp));
+}
+
+INTERCEPTOR(void, siglongjmp, sigjmp_buf env, int val)
+{
+  if (env[0].__mask_was_saved)
+    /* Restore the saved signal mask.  */
+    (void) sigprocmask (SIG_SETMASK,
+			(sigset_t *) &env[0].__saved_mask,
+			(sigset_t *) 0);
+  __hwasan_internal_longjmp (env[0].__jmpbuf, val);
+}
+
+INTERCEPTOR(void, __libc_longjmp, jmp_buf env, int val)
+{
+  __hwasan_internal_longjmp (env[0].__jmpbuf, val);
+}
+
+INTERCEPTOR(void, longjmp, jmp_buf env, int val)
+{
+  __hwasan_internal_longjmp (env[0].__jmpbuf, val);
+}
+#undef SIG_BLOCK
+#undef SIG_SETMASK
+
+#endif // __aarch64__
 #endif // HWASAN_WITH_INTERCEPTORS
 
 static void BeforeFork() {
@@ -302,7 +403,6 @@ INTERCEPTOR(int, fork, void) {
   return pid;
 }
 
-
 struct HwasanInterceptorContext {
   bool in_interceptor_scope;
 };
@@ -325,6 +425,11 @@ void InitializeInterceptors() {
   INTERCEPT_FUNCTION(fork);
 
 #if HWASAN_WITH_INTERCEPTORS
+#if defined(__aarch64__)
+  INTERCEPT_FUNCTION(longjmp);
+  INTERCEPT_FUNCTION(__libc_longjmp);
+  INTERCEPT_FUNCTION(siglongjmp);
+#endif
   INTERCEPT_FUNCTION(pthread_create);
 #endif
 
diff --git a/libsanitizer/hwasan/hwasan_setjmp.S b/libsanitizer/hwasan/hwasan_setjmp.S
new file mode 100644
index 0000000000000000000000000000000000000000..56add3e149abcc37ec23b8cdc8f4ba2cbc722c08
--- /dev/null
+++ b/libsanitizer/hwasan/hwasan_setjmp.S
@@ -0,0 +1,52 @@
+// We want to save the context of the calling function.
+// That requires
+// 1) No modification of the link register by this function.
+// 2) No modification of the stack pointer by this function.
+// 3) (no modification of any other saved register, but that's not really going
+// to occur, and hence isn't as much of a worry).
+//
+// There's essentially no way to ensure that the compiler will not modify the
+// stack pointer when compiling a C function.
+// Hence we have to write this function in assembly.
+
+#if HWASAN_WITH_INTERCEPTORS && defined(__aarch64__)
+
+.macro ENTRY symbol
+  .align 2
+  .global \symbol
+  .type  \symbol\(), %function
+\symbol\():
+  .cfi_startproc
+.endm
+
+.macro END symbol
+  .cfi_endproc
+  .size \symbol, .-\symbol
+.endm
+
+ENTRY _setjmp
+mov	x1, #0
+b	1f
+END _setjmp
+
+ENTRY __sigsetjmp
+1:
+  stp	x19, x20, [x0, #0<<3]
+  stp	x21, x22, [x0, #2<<3]
+  stp	x23, x24, [x0, #4<<3]
+  stp	x25, x26, [x0, #6<<3]
+  stp	x27, x28, [x0, #8<<3]
+  stp	x29, x30, [x0, #10<<3]
+  stp	 d8,  d9, [x0, #14<<3]
+  stp	d10, d11, [x0, #16<<3]
+  stp	d12, d13, [x0, #18<<3]
+  stp	d14, d15, [x0, #20<<3]
+  mov	x2,  sp
+  str	x2,  [x0, #13<<3]
+  // We always have the second argument to __sigjmp_save (savemask) set, since
+  // the _setjmp function above has set it for us as `false`.
+  // This function is defined in hwasan_interceptors.cc
+  b	__sigjmp_save
+END __sigsetjmp
+
+#endif


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [RFC][PATCH 14/X][libsanitizer] Introduce HWASAN block-scope poisoning
  2019-09-06 14:46 [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Matthew Malcomson
                   ` (5 preceding siblings ...)
  2019-09-06 14:46 ` [RFC][PATCH 5/X][libsanitizer] Introduce longjmp/setjmp interceptors to libhwasan Matthew Malcomson
@ 2019-09-06 14:46 ` Matthew Malcomson
  2019-09-06 14:46 ` [RFC][PATCH 1/X][libsanitizer] Introduce libsanitizer to GCC tree Matthew Malcomson
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 35+ messages in thread
From: Matthew Malcomson @ 2019-09-06 14:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: mliska, dodji, nd, kcc, jakub, dvyukov

[-- Attachment #1: Type: text/plain, Size: 11650 bytes --]

Here we use exactly the same mechanism as ASAN_MARK to poison/unpoison
variables on entry/exit of a block.

In order to simply use the exact same machinery we're using the same
internal functions until the SANOPT pass.  This means that all handling
of ASAN_MARK is the same.
This has the negative that the naming may be a little confusing, but a
positive that handling of the internal function doesn't have to be
duplicated for a function that behaves exactly the same but has a
different name.

gcc/ChangeLog:

2019-09-06  Matthew Malcomson  <matthew.malcomson@arm.com>

	* asan.c (asan_expand_mark_ifn): New.
	(asan_expand_poison_ifn): Add assertion.
	(hwasan_emit_prologue): Add assertion.
	(hwasan_emit_uncolour_frame): Clear hash map of block-scope
	variables.
	(hwasan_extract_tag): New.
	(hwasan_expand_mark_ifn): New.
	(hardware_memory_tagging_p): New.
	* asan.h (hwasan_extract_tag): New.
	(hwasan_expand_mark_ifn): New.
	(enum hwasan_mark_flags): New.
	(hardware_memory_tagging_p): New.
	* cfgexpand.c (expand_stack_vars): Neaten up an if clause.
	* gimple-pretty-print.c (dump_gimple_call_args): Handle
	HWASAN_MARK.
	* gimplify.c (asan_poison_variable): Set alignment for HWASAN.
	(gimplify_function_tree): Record marked variables for both ASAN
	and HWASAN.
	* internal-fn.c (expand_HWASAN_MARK): New.
	(expand_HWASAN_CHOOSE_COLOUR): Use new hwasan_extract_tag
	helper.
	* internal-fn.def (HWASAN_MARK): New.
	* sanopt.c (pass_sanopt::execute): Account for HWASAN.



###############     Attachment also inlined for ease of reply    ###############


diff --git a/gcc/asan.h b/gcc/asan.h
index e4e823080e4ca7489135ee2da9e0727de9bba8ae..6e5ba8be606e9a1eae2afe57f17ccca5562167fd 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -30,12 +30,15 @@ extern void hwasan_increment_tag ();
 extern rtx hwasan_with_tag (rtx, poly_int64);
 extern void hwasan_tag_init ();
 extern rtx hwasan_create_untagged_base (rtx);
+extern rtx hwasan_extract_tag (rtx tagged_pointer);
 extern rtx hwasan_base ();
 extern void hwasan_emit_prologue (rtx *, rtx *, poly_int64 *, uint8_t *, size_t);
 extern rtx_insn *hwasan_emit_uncolour_frame (rtx, rtx, rtx_insn *);
 extern bool hwasan_expand_check_ifn (gimple_stmt_iterator *, bool);
+extern bool hwasan_expand_mark_ifn (gimple_stmt_iterator *);
 extern bool memory_tagging_p (void);
 extern bool gate_hwasan (void);
+extern bool hardware_memory_tagging_p (void);
 extern rtx_insn *asan_emit_stack_protection (rtx, rtx, unsigned int,
 					     HOST_WIDE_INT *, tree *, int);
 extern rtx_insn *asan_emit_allocas_unpoison (rtx, rtx, rtx_insn *);
@@ -142,6 +145,13 @@ enum asan_mark_flags
 #undef DEF
 };
 
+enum hwasan_mark_flags
+{
+#define DEF(X) HWASAN_MARK_##X
+  IFN_ASAN_MARK_FLAGS
+#undef DEF
+};
+
 /* Return true if STMT is ASAN_MARK with FLAG as first argument.  */
 extern bool asan_mark_p (gimple *stmt, enum asan_mark_flags flag);
 
diff --git a/gcc/asan.c b/gcc/asan.c
index fefd28cbd136d74ad3389cf8efbf1949e3815dfd..ad3d5a6451d3ecd9ff79b768c1e9a3fb92272a7e 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -3375,6 +3375,22 @@ asan_expand_mark_ifn (gimple_stmt_iterator *iter)
   unsigned HOST_WIDE_INT size_in_bytes = tree_to_shwi (len);
   gcc_assert (size_in_bytes);
 
+  if (memory_tagging_p ())
+    {
+      /* Here we swap the ASAN_MARK for HWASAN_MARK.
+	 This is because we are using the (possibly temporary) approach to
+	 always emit ASAN_MARK in TREE until here.
+	 That approach means we don't yet have to duplicate all the special
+	 cases for ASAN_MARK and ASAN_POISON with the exact same handling but
+	 called HWASAN_MARK etc.  */
+      gimple *hw_poison_call
+	= gimple_build_call_internal (IFN_HWASAN_MARK, 3,
+				      gimple_call_arg (g, 0),
+				      base, len);
+      gsi_replace (iter, hw_poison_call, false);
+      return false;
+    }
+
   g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
 			   NOP_EXPR, base);
   gimple_set_location (g, loc);
@@ -3673,6 +3689,7 @@ asan_expand_poison_ifn (gimple_stmt_iterator *iter,
 			bool *need_commit_edge_insert,
 			hash_map<tree, tree> &shadow_vars_mapping)
 {
+  gcc_assert (! memory_tagging_p ());
   gimple *g = gsi_stmt (*iter);
   tree poisoned_var = gimple_call_lhs (g);
   if (!poisoned_var || has_zero_uses (poisoned_var))
@@ -3968,6 +3985,7 @@ hwasan_emit_prologue (rtx *bases,
 	}
       else
 	{
+	  gcc_assert (known_ge (end, start));
 	  top = end;
 	  bot = start;
 	}
@@ -4037,6 +4055,12 @@ hwasan_emit_uncolour_frame (rtx dynamic, rtx vars, rtx_insn *before)
   do_pending_stack_adjust ();
   rtx_insn *insns = get_insns ();
   end_sequence ();
+
+  /* Clear the hash_map recording which variables are handled by HWASAN_MARK.
+     The only use in HWASAN is to decide which variables need to be coloured in
+     the prologue and which don't.  */
+  delete asan_handled_variables;
+  asan_handled_variables = NULL;
   return insns;
 }
 
@@ -4052,6 +4076,19 @@ hwasan_create_untagged_base (rtx orig_base)
   return untagged_base;
 }
 
+rtx
+hwasan_extract_tag (rtx tagged_pointer)
+{
+  rtx tag = expand_simple_binop (Pmode,
+				 LSHIFTRT,
+				 tagged_pointer,
+				 HWASAN_SHIFT_RTX,
+				 NULL_RTX,
+				 /* unsignedp = */0,
+				 OPTAB_DIRECT);
+  return gen_lowpart (QImode, tag);
+}
+
 /* Needs to be GTY(()), because cgraph_build_static_cdtor may
    invoke ggc_collect.  */
 static GTY(()) tree hwasan_ctor_statements;
@@ -4166,10 +4203,25 @@ hwasan_expand_check_ifn (gimple_stmt_iterator *iter, bool)
 }
 
 bool
+hwasan_expand_mark_ifn (gimple_stmt_iterator *)
+{
+  /* HWASAN_MARK should only ever be available after the sanopt pass.
+     It might be nicer to have it everywhere in the future, so I"m leaving this
+     function and the declaration in asan.h around in case that's requested
+     upstream.  */
+  gcc_unreachable ();
+}
+
+bool
 gate_hwasan ()
 {
   return memory_tagging_p ();
 }
+bool
+hardware_memory_tagging_p ()
+{
+  return memory_tagging_p () && HARDWARE_MEMORY_TAGGING;
+}
 
 namespace {
 
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 10f79ea619e3ebfdcbe9f5159e174cf2bb08b7d8..52d104857df92bc80db6deb5b18c99ee2caa4151 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -739,6 +739,7 @@ dump_gimple_call_args (pretty_printer *buffer, gcall *gs, dump_flags_t flags)
 	  limit = ARRAY_SIZE (reduction_args);
 	  break;
 
+	case IFN_HWASAN_MARK:
 	case IFN_ASAN_MARK:
 #define DEF(X) #X
 	  static const char *const asan_mark_args[] = {IFN_ASAN_MARK_FLAGS};
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 5bacb255ba75901a3cd95e3b99b1f274216bf85d..d89d81ec112d918912269c90faae468d1d8aa321 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1202,8 +1202,10 @@ asan_poison_variable (tree decl, bool poison, gimple_stmt_iterator *it,
 
   /* It's necessary to have all stack variables aligned to ASAN granularity
      bytes.  */
-  if (DECL_ALIGN_UNIT (decl) <= ASAN_SHADOW_GRANULARITY)
-    SET_DECL_ALIGN (decl, BITS_PER_UNIT * ASAN_SHADOW_GRANULARITY);
+  unsigned shadow_granularity =
+    memory_tagging_p () ? HWASAN_TAG_GRANULE_SIZE : ASAN_SHADOW_GRANULARITY;
+  if (DECL_ALIGN_UNIT (decl) <= shadow_granularity)
+    SET_DECL_ALIGN (decl, BITS_PER_UNIT * shadow_granularity);
 
   HOST_WIDE_INT flags = poison ? ASAN_MARK_POISON : ASAN_MARK_UNPOISON;
 
@@ -13816,7 +13818,7 @@ gimplify_function_tree (tree fndecl)
       && !needs_to_live_in_memory (ret))
     DECL_GIMPLE_REG_P (ret) = 1;
 
-  if (asan_sanitize_use_after_scope () && sanitize_flags_p (SANITIZE_ADDRESS))
+  if (asan_sanitize_use_after_scope ())
     asan_poisoned_variables = new hash_set<tree> ();
   bind = gimplify_body (fndecl, true);
   if (asan_poisoned_variables)
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 4eec9919b520691ab3e73a2920ef8b544cf55dfe..c530fe8951c30987c874df83e74be6d058730134 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -471,11 +471,7 @@ expand_HWASAN_CHOOSE_COLOUR (internal_fn, gcall *gc)
   machine_mode mode = GET_MODE (target);
   gcc_assert (mode == QImode);
 
-  rtx base_tag = expand_simple_binop (Pmode, LSHIFTRT, hwasan_base (),
-				      HWASAN_SHIFT_RTX,
-				      NULL_RTX, /* unsignedp = */0,
-				      OPTAB_DIRECT);
-
+  rtx base_tag = hwasan_extract_tag (hwasan_base ());
   gcc_assert (base_tag);
   rtx tag_offset = const_int_rtx[MAX_SAVED_CONST_INT + hwasan_current_tag ()];
   rtx chosen_tag = expand_simple_binop (QImode, PLUS, base_tag, tag_offset,
@@ -498,6 +494,39 @@ expand_HWASAN_CHOOSE_COLOUR (internal_fn, gcall *gc)
 }
 
 static void
+expand_HWASAN_MARK (internal_fn, gcall *gc)
+{
+  HOST_WIDE_INT flag = tree_to_shwi (gimple_call_arg (gc, 0));
+  bool is_poison = ((asan_mark_flags)flag) == ASAN_MARK_POISON;
+
+  tree base = gimple_call_arg (gc, 1);
+  gcc_checking_assert (TREE_CODE (base) == ADDR_EXPR);
+  rtx base_rtx = expand_normal (base);
+
+  rtx tag = is_poison ? const0_rtx : hwasan_extract_tag (base_rtx);
+  rtx address = hwasan_create_untagged_base (base_rtx);
+
+  tree len = gimple_call_arg (gc, 2);
+  gcc_assert (tree_fits_shwi_p (len));
+  unsigned HOST_WIDE_INT size_in_bytes = tree_to_shwi (len);
+  uint8_t tg_mask = HWASAN_TAG_GRANULE_SIZE - 1;
+  gcc_assert (size_in_bytes);
+  size_in_bytes = (size_in_bytes + tg_mask) & ~tg_mask;
+  rtx size = gen_int_mode (size_in_bytes, Pmode);
+
+  /* TODO Other options (i.e. inline options)  */
+  rtx func = init_one_libfunc ("__hwasan_tag_memory");
+  emit_library_call (func,
+      LCT_NORMAL,
+      VOIDmode,
+      address, ptr_mode,
+      tag, QImode,
+      size, ptr_mode);
+}
+
+/* This should get expanded in the sanopt pass.  */
+
+static void
 expand_ASAN_CHECK (internal_fn, gcall *)
 {
   gcc_unreachable ();
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index ed0c5bc110f16b2cdbc139403dbdbd8ebe7e2823..100f6fbad0af4fefdd0408384374b8fdcde9bee4 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -290,6 +290,7 @@ DEF_INTERNAL_FN (ABNORMAL_DISPATCHER, ECF_NORETURN, NULL)
 DEF_INTERNAL_FN (BUILTIN_EXPECT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (HWASAN_CHOOSE_COLOUR, ECF_LEAF | ECF_NOTHROW, ".")
 DEF_INTERNAL_FN (HWASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, "..R..")
+DEF_INTERNAL_FN (HWASAN_MARK, ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (ASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, "..R..")
 DEF_INTERNAL_FN (ASAN_MARK, ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (ASAN_POISON, ECF_LEAF | ECF_NOTHROW | ECF_NOVOPS, NULL)
diff --git a/gcc/sanopt.c b/gcc/sanopt.c
index 31270153f3cf56bfbad593830de1b9334e7f65d1..29b12a43029cdcce5756354ac12d6d9e963e9ac8 100644
--- a/gcc/sanopt.c
+++ b/gcc/sanopt.c
@@ -1258,6 +1258,12 @@ sanitize_rewrite_addressable_params (function *fun)
 unsigned int
 pass_sanopt::execute (function *fun)
 {
+  /*
+     n.b. ASAN_MARK is used for both HWASAN and ASAN.
+     asan_num_accesses is used to count either HWASAN_CHECK or ASAN_CHECK
+     stuff.  This is fine because you can only have one of these active at a
+     time.
+ */
   basic_block bb;
   int asan_num_accesses = 0;
   bool contains_asan_mark = false;
@@ -1345,6 +1351,9 @@ pass_sanopt::execute (function *fun)
 						    &need_commit_edge_insert,
 						    shadow_vars_mapping);
 		  break;
+		case IFN_HWASAN_MARK:
+		  no_next = hwasan_expand_mark_ifn (&gsi);
+		  break;
 		default:
 		  break;
 		}


[-- Attachment #2: hwasan-implementation13.patch --]
[-- Type: text/plain, Size: 9772 bytes --]

diff --git a/gcc/asan.h b/gcc/asan.h
index e4e823080e4ca7489135ee2da9e0727de9bba8ae..6e5ba8be606e9a1eae2afe57f17ccca5562167fd 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -30,12 +30,15 @@ extern void hwasan_increment_tag ();
 extern rtx hwasan_with_tag (rtx, poly_int64);
 extern void hwasan_tag_init ();
 extern rtx hwasan_create_untagged_base (rtx);
+extern rtx hwasan_extract_tag (rtx tagged_pointer);
 extern rtx hwasan_base ();
 extern void hwasan_emit_prologue (rtx *, rtx *, poly_int64 *, uint8_t *, size_t);
 extern rtx_insn *hwasan_emit_uncolour_frame (rtx, rtx, rtx_insn *);
 extern bool hwasan_expand_check_ifn (gimple_stmt_iterator *, bool);
+extern bool hwasan_expand_mark_ifn (gimple_stmt_iterator *);
 extern bool memory_tagging_p (void);
 extern bool gate_hwasan (void);
+extern bool hardware_memory_tagging_p (void);
 extern rtx_insn *asan_emit_stack_protection (rtx, rtx, unsigned int,
 					     HOST_WIDE_INT *, tree *, int);
 extern rtx_insn *asan_emit_allocas_unpoison (rtx, rtx, rtx_insn *);
@@ -142,6 +145,13 @@ enum asan_mark_flags
 #undef DEF
 };
 
+enum hwasan_mark_flags
+{
+#define DEF(X) HWASAN_MARK_##X
+  IFN_ASAN_MARK_FLAGS
+#undef DEF
+};
+
 /* Return true if STMT is ASAN_MARK with FLAG as first argument.  */
 extern bool asan_mark_p (gimple *stmt, enum asan_mark_flags flag);
 
diff --git a/gcc/asan.c b/gcc/asan.c
index fefd28cbd136d74ad3389cf8efbf1949e3815dfd..ad3d5a6451d3ecd9ff79b768c1e9a3fb92272a7e 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -3375,6 +3375,22 @@ asan_expand_mark_ifn (gimple_stmt_iterator *iter)
   unsigned HOST_WIDE_INT size_in_bytes = tree_to_shwi (len);
   gcc_assert (size_in_bytes);
 
+  if (memory_tagging_p ())
+    {
+      /* Here we swap the ASAN_MARK for HWASAN_MARK.
+	 This is because we are using the (possibly temporary) approach to
+	 always emit ASAN_MARK in TREE until here.
+	 That approach means we don't yet have to duplicate all the special
+	 cases for ASAN_MARK and ASAN_POISON with the exact same handling but
+	 called HWASAN_MARK etc.  */
+      gimple *hw_poison_call
+	= gimple_build_call_internal (IFN_HWASAN_MARK, 3,
+				      gimple_call_arg (g, 0),
+				      base, len);
+      gsi_replace (iter, hw_poison_call, false);
+      return false;
+    }
+
   g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
 			   NOP_EXPR, base);
   gimple_set_location (g, loc);
@@ -3673,6 +3689,7 @@ asan_expand_poison_ifn (gimple_stmt_iterator *iter,
 			bool *need_commit_edge_insert,
 			hash_map<tree, tree> &shadow_vars_mapping)
 {
+  gcc_assert (! memory_tagging_p ());
   gimple *g = gsi_stmt (*iter);
   tree poisoned_var = gimple_call_lhs (g);
   if (!poisoned_var || has_zero_uses (poisoned_var))
@@ -3968,6 +3985,7 @@ hwasan_emit_prologue (rtx *bases,
 	}
       else
 	{
+	  gcc_assert (known_ge (end, start));
 	  top = end;
 	  bot = start;
 	}
@@ -4037,6 +4055,12 @@ hwasan_emit_uncolour_frame (rtx dynamic, rtx vars, rtx_insn *before)
   do_pending_stack_adjust ();
   rtx_insn *insns = get_insns ();
   end_sequence ();
+
+  /* Clear the hash_map recording which variables are handled by HWASAN_MARK.
+     The only use in HWASAN is to decide which variables need to be coloured in
+     the prologue and which don't.  */
+  delete asan_handled_variables;
+  asan_handled_variables = NULL;
   return insns;
 }
 
@@ -4052,6 +4076,19 @@ hwasan_create_untagged_base (rtx orig_base)
   return untagged_base;
 }
 
+rtx
+hwasan_extract_tag (rtx tagged_pointer)
+{
+  rtx tag = expand_simple_binop (Pmode,
+				 LSHIFTRT,
+				 tagged_pointer,
+				 HWASAN_SHIFT_RTX,
+				 NULL_RTX,
+				 /* unsignedp = */0,
+				 OPTAB_DIRECT);
+  return gen_lowpart (QImode, tag);
+}
+
 /* Needs to be GTY(()), because cgraph_build_static_cdtor may
    invoke ggc_collect.  */
 static GTY(()) tree hwasan_ctor_statements;
@@ -4166,10 +4203,25 @@ hwasan_expand_check_ifn (gimple_stmt_iterator *iter, bool)
 }
 
 bool
+hwasan_expand_mark_ifn (gimple_stmt_iterator *)
+{
+  /* HWASAN_MARK should only ever be available after the sanopt pass.
+     It might be nicer to have it everywhere in the future, so I"m leaving this
+     function and the declaration in asan.h around in case that's requested
+     upstream.  */
+  gcc_unreachable ();
+}
+
+bool
 gate_hwasan ()
 {
   return memory_tagging_p ();
 }
+bool
+hardware_memory_tagging_p ()
+{
+  return memory_tagging_p () && HARDWARE_MEMORY_TAGGING;
+}
 
 namespace {
 
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 10f79ea619e3ebfdcbe9f5159e174cf2bb08b7d8..52d104857df92bc80db6deb5b18c99ee2caa4151 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -739,6 +739,7 @@ dump_gimple_call_args (pretty_printer *buffer, gcall *gs, dump_flags_t flags)
 	  limit = ARRAY_SIZE (reduction_args);
 	  break;
 
+	case IFN_HWASAN_MARK:
 	case IFN_ASAN_MARK:
 #define DEF(X) #X
 	  static const char *const asan_mark_args[] = {IFN_ASAN_MARK_FLAGS};
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 5bacb255ba75901a3cd95e3b99b1f274216bf85d..d89d81ec112d918912269c90faae468d1d8aa321 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1202,8 +1202,10 @@ asan_poison_variable (tree decl, bool poison, gimple_stmt_iterator *it,
 
   /* It's necessary to have all stack variables aligned to ASAN granularity
      bytes.  */
-  if (DECL_ALIGN_UNIT (decl) <= ASAN_SHADOW_GRANULARITY)
-    SET_DECL_ALIGN (decl, BITS_PER_UNIT * ASAN_SHADOW_GRANULARITY);
+  unsigned shadow_granularity =
+    memory_tagging_p () ? HWASAN_TAG_GRANULE_SIZE : ASAN_SHADOW_GRANULARITY;
+  if (DECL_ALIGN_UNIT (decl) <= shadow_granularity)
+    SET_DECL_ALIGN (decl, BITS_PER_UNIT * shadow_granularity);
 
   HOST_WIDE_INT flags = poison ? ASAN_MARK_POISON : ASAN_MARK_UNPOISON;
 
@@ -13816,7 +13818,7 @@ gimplify_function_tree (tree fndecl)
       && !needs_to_live_in_memory (ret))
     DECL_GIMPLE_REG_P (ret) = 1;
 
-  if (asan_sanitize_use_after_scope () && sanitize_flags_p (SANITIZE_ADDRESS))
+  if (asan_sanitize_use_after_scope ())
     asan_poisoned_variables = new hash_set<tree> ();
   bind = gimplify_body (fndecl, true);
   if (asan_poisoned_variables)
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 4eec9919b520691ab3e73a2920ef8b544cf55dfe..c530fe8951c30987c874df83e74be6d058730134 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -471,11 +471,7 @@ expand_HWASAN_CHOOSE_COLOUR (internal_fn, gcall *gc)
   machine_mode mode = GET_MODE (target);
   gcc_assert (mode == QImode);
 
-  rtx base_tag = expand_simple_binop (Pmode, LSHIFTRT, hwasan_base (),
-				      HWASAN_SHIFT_RTX,
-				      NULL_RTX, /* unsignedp = */0,
-				      OPTAB_DIRECT);
-
+  rtx base_tag = hwasan_extract_tag (hwasan_base ());
   gcc_assert (base_tag);
   rtx tag_offset = const_int_rtx[MAX_SAVED_CONST_INT + hwasan_current_tag ()];
   rtx chosen_tag = expand_simple_binop (QImode, PLUS, base_tag, tag_offset,
@@ -498,6 +494,39 @@ expand_HWASAN_CHOOSE_COLOUR (internal_fn, gcall *gc)
 }
 
 static void
+expand_HWASAN_MARK (internal_fn, gcall *gc)
+{
+  HOST_WIDE_INT flag = tree_to_shwi (gimple_call_arg (gc, 0));
+  bool is_poison = ((asan_mark_flags)flag) == ASAN_MARK_POISON;
+
+  tree base = gimple_call_arg (gc, 1);
+  gcc_checking_assert (TREE_CODE (base) == ADDR_EXPR);
+  rtx base_rtx = expand_normal (base);
+
+  rtx tag = is_poison ? const0_rtx : hwasan_extract_tag (base_rtx);
+  rtx address = hwasan_create_untagged_base (base_rtx);
+
+  tree len = gimple_call_arg (gc, 2);
+  gcc_assert (tree_fits_shwi_p (len));
+  unsigned HOST_WIDE_INT size_in_bytes = tree_to_shwi (len);
+  uint8_t tg_mask = HWASAN_TAG_GRANULE_SIZE - 1;
+  gcc_assert (size_in_bytes);
+  size_in_bytes = (size_in_bytes + tg_mask) & ~tg_mask;
+  rtx size = gen_int_mode (size_in_bytes, Pmode);
+
+  /* TODO Other options (i.e. inline options)  */
+  rtx func = init_one_libfunc ("__hwasan_tag_memory");
+  emit_library_call (func,
+      LCT_NORMAL,
+      VOIDmode,
+      address, ptr_mode,
+      tag, QImode,
+      size, ptr_mode);
+}
+
+/* This should get expanded in the sanopt pass.  */
+
+static void
 expand_ASAN_CHECK (internal_fn, gcall *)
 {
   gcc_unreachable ();
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index ed0c5bc110f16b2cdbc139403dbdbd8ebe7e2823..100f6fbad0af4fefdd0408384374b8fdcde9bee4 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -290,6 +290,7 @@ DEF_INTERNAL_FN (ABNORMAL_DISPATCHER, ECF_NORETURN, NULL)
 DEF_INTERNAL_FN (BUILTIN_EXPECT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (HWASAN_CHOOSE_COLOUR, ECF_LEAF | ECF_NOTHROW, ".")
 DEF_INTERNAL_FN (HWASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, "..R..")
+DEF_INTERNAL_FN (HWASAN_MARK, ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (ASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, "..R..")
 DEF_INTERNAL_FN (ASAN_MARK, ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (ASAN_POISON, ECF_LEAF | ECF_NOTHROW | ECF_NOVOPS, NULL)
diff --git a/gcc/sanopt.c b/gcc/sanopt.c
index 31270153f3cf56bfbad593830de1b9334e7f65d1..29b12a43029cdcce5756354ac12d6d9e963e9ac8 100644
--- a/gcc/sanopt.c
+++ b/gcc/sanopt.c
@@ -1258,6 +1258,12 @@ sanitize_rewrite_addressable_params (function *fun)
 unsigned int
 pass_sanopt::execute (function *fun)
 {
+  /*
+     n.b. ASAN_MARK is used for both HWASAN and ASAN.
+     asan_num_accesses is used to count either HWASAN_CHECK or ASAN_CHECK
+     stuff.  This is fine because you can only have one of these active at a
+     time.
+ */
   basic_block bb;
   int asan_num_accesses = 0;
   bool contains_asan_mark = false;
@@ -1345,6 +1351,9 @@ pass_sanopt::execute (function *fun)
 						    &need_commit_edge_insert,
 						    shadow_vars_mapping);
 		  break;
+		case IFN_HWASAN_MARK:
+		  no_next = hwasan_expand_mark_ifn (&gsi);
+		  break;
 		default:
 		  break;
 		}


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [RFC][PATCH 4/X][libsanitizer] Pass size and pointer info to error reporting functions
  2019-09-06 14:46 [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Matthew Malcomson
  2019-09-06 14:46 ` [RFC][PATCH 3/X][libsanitizer] Allow compilation for HWASAN_WITH_INTERCEPTORS=OFF Matthew Malcomson
  2019-09-06 14:46 ` [RFC][PATCH 2/X][libsanitizer] Tie the hwasan library into our build system Matthew Malcomson
@ 2019-09-06 14:46 ` Matthew Malcomson
  2019-09-09  9:27   ` Martin Liška
  2019-09-06 14:46 ` [RFC][PATCH 7/X][libsanitizer] Add option to bootstrap using HWASAN Matthew Malcomson
                   ` (14 subsequent siblings)
  17 siblings, 1 reply; 35+ messages in thread
From: Matthew Malcomson @ 2019-09-06 14:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: mliska, dodji, nd, kcc, jakub, dvyukov

[-- Attachment #1: Type: text/plain, Size: 2602 bytes --]

This makes the error reporting for loadN and storeN much better.
In this first draft these are the only functions I will be using and
hence this fix is very useful.

This is taken from upstream LLVM (change made in LLVM svn commit
351730), but is not a direct cherry-pick of a commit since the commit
does not apply cleanly.

libsanitizer/ChangeLog:

2019-09-06  Matthew Malcomson  <matthew.malcomson@arm.com>

	* hwasan/hwasan.cc (CheckAddressSized): Use new sized SigTrap.
	(SigTrap): Record pointer in x0 for error report and add an
	overloaded version that takes both pointer and size.



###############     Attachment also inlined for ease of reply    ###############


diff --git a/libsanitizer/hwasan/hwasan.cc b/libsanitizer/hwasan/hwasan.cc
index 518cd11ff301f1d1cf6f5275ecffdb03d880d8d1..a2ad8f96d847d5c4395da668a40b24f5331dcbd6 100644
--- a/libsanitizer/hwasan/hwasan.cc
+++ b/libsanitizer/hwasan/hwasan.cc
@@ -360,8 +360,8 @@ static void SigTrap(uptr p) {
   (void)p;
   // 0x900 is added to do not interfere with the kernel use of lower values of
   // brk immediate.
-  // FIXME: Add a constraint to put the pointer into x0, the same as x86 branch.
-  asm("brk %0\n\t" ::"n"(0x900 + X));
+  register uptr x0 asm("x0") = p;
+  asm("brk %1\n\t" ::"r"(x0), "n"(0x900 + X));
 #elif defined(__x86_64__)
   // INT3 + NOP DWORD ptr [EAX + X] to pass X to our signal handler, 5 bytes
   // total. The pointer is passed via rdi.
@@ -379,6 +379,25 @@ static void SigTrap(uptr p) {
   // __builtin_unreachable();
 }
 
+template <unsigned X>
+__attribute__((always_inline)) static void SigTrap(uptr p, uptr size) {
+#if defined(__aarch64__)
+  register uptr x0 asm("x0") = p;
+  register uptr x1 asm("x1") = size;
+  asm("brk %2\n\t" ::"r"(x0), "r"(x1), "n"(0x900 + X));
+#elif defined(__x86_64__)
+  // Size is stored in rsi.
+  asm volatile(
+      "int3\n"
+      "nopl %c0(%%rax)\n" ::"n"(0x40 + X),
+      "D"(p), "S"(size));
+#else
+  __builtin_trap();
+#endif
+  // __builtin_unreachable();
+}
+
+
 enum class ErrorAction { Abort, Recover };
 enum class AccessType { Load, Store };
 
@@ -405,7 +424,7 @@ __attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p,
   for (tag_t *t = shadow_first; t <= shadow_last; ++t)
     if (UNLIKELY(ptr_tag != *t)) {
       SigTrap<0x20 * (EA == ErrorAction::Recover) +
-             0x10 * (AT == AccessType::Store) + 0xf>(p);
+             0x10 * (AT == AccessType::Store) + 0xf>(p, sz);
       if (EA == ErrorAction::Abort) __builtin_unreachable();
     }
 }


[-- Attachment #2: hwasan-implementation03.patch --]
[-- Type: text/plain, Size: 1854 bytes --]

diff --git a/libsanitizer/hwasan/hwasan.cc b/libsanitizer/hwasan/hwasan.cc
index 518cd11ff301f1d1cf6f5275ecffdb03d880d8d1..a2ad8f96d847d5c4395da668a40b24f5331dcbd6 100644
--- a/libsanitizer/hwasan/hwasan.cc
+++ b/libsanitizer/hwasan/hwasan.cc
@@ -360,8 +360,8 @@ static void SigTrap(uptr p) {
   (void)p;
   // 0x900 is added to do not interfere with the kernel use of lower values of
   // brk immediate.
-  // FIXME: Add a constraint to put the pointer into x0, the same as x86 branch.
-  asm("brk %0\n\t" ::"n"(0x900 + X));
+  register uptr x0 asm("x0") = p;
+  asm("brk %1\n\t" ::"r"(x0), "n"(0x900 + X));
 #elif defined(__x86_64__)
   // INT3 + NOP DWORD ptr [EAX + X] to pass X to our signal handler, 5 bytes
   // total. The pointer is passed via rdi.
@@ -379,6 +379,25 @@ static void SigTrap(uptr p) {
   // __builtin_unreachable();
 }
 
+template <unsigned X>
+__attribute__((always_inline)) static void SigTrap(uptr p, uptr size) {
+#if defined(__aarch64__)
+  register uptr x0 asm("x0") = p;
+  register uptr x1 asm("x1") = size;
+  asm("brk %2\n\t" ::"r"(x0), "r"(x1), "n"(0x900 + X));
+#elif defined(__x86_64__)
+  // Size is stored in rsi.
+  asm volatile(
+      "int3\n"
+      "nopl %c0(%%rax)\n" ::"n"(0x40 + X),
+      "D"(p), "S"(size));
+#else
+  __builtin_trap();
+#endif
+  // __builtin_unreachable();
+}
+
+
 enum class ErrorAction { Abort, Recover };
 enum class AccessType { Load, Store };
 
@@ -405,7 +424,7 @@ __attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p,
   for (tag_t *t = shadow_first; t <= shadow_last; ++t)
     if (UNLIKELY(ptr_tag != *t)) {
       SigTrap<0x20 * (EA == ErrorAction::Recover) +
-             0x10 * (AT == AccessType::Store) + 0xf>(p);
+             0x10 * (AT == AccessType::Store) + 0xf>(p, sz);
       if (EA == ErrorAction::Abort) __builtin_unreachable();
     }
 }


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [RFC][PATCH 7/X][libsanitizer] Add option to bootstrap using HWASAN
  2019-09-06 14:46 [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Matthew Malcomson
                   ` (2 preceding siblings ...)
  2019-09-06 14:46 ` [RFC][PATCH 4/X][libsanitizer] Pass size and pointer info to error reporting functions Matthew Malcomson
@ 2019-09-06 14:46 ` Matthew Malcomson
  2019-09-06 14:46 ` [RFC][PATCH 8/X][libsanitizer] Ensure HWASAN required alignment for stack variables Matthew Malcomson
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 35+ messages in thread
From: Matthew Malcomson @ 2019-09-06 14:46 UTC (permalink / raw)
  To: gcc-patches; +Cc: mliska, dodji, nd, kcc, jakub, dvyukov

[-- Attachment #1: Type: text/plain, Size: 8705 bytes --]

This is an analogous option to --bootstrap-asan to configure.  It allows
bootstrapping GCC using HWASAN.

For the same reasons as for ASAN we have to avoid using the HWASAN
sanitizer when compiling libiberty and the lto-plugin.

Also add a function to query whether -fsanitize=hwaddress has been
passed.

ChangeLog:

2019-08-29  Matthew Malcomson  <matthew.malcomson@arm.com>

	* configure: Regenerate.
	* configure.ac: Add --bootstrap-hwasan option.

config/ChangeLog:

2019-09-06  Matthew Malcomson  <matthew.malcomson@arm.com>

	* bootstrap-hwasan.mk: New file.

gcc/ChangeLog:

2019-09-06  Matthew Malcomson  <matthew.malcomson@arm.com>

	* asan.c (memory_tagging_p): New function.
	* asan.h (memory_tagging_p): New declaration.

libiberty/ChangeLog:

2019-09-06  Matthew Malcomson  <matthew.malcomson@arm.com>

	* configure: Regenerate.
	* configure.ac: Avoid using sanitizer.

lto-plugin/ChangeLog:

2019-09-06  Matthew Malcomson  <matthew.malcomson@arm.com>

	* Makefile.am: Avoid using sanitizer.
	* Makefile.in: Regenerate.



###############     Attachment also inlined for ease of reply    ###############


diff --git a/config/bootstrap-hwasan.mk b/config/bootstrap-hwasan.mk
new file mode 100644
index 0000000000000000000000000000000000000000..4f60bed3fd6e98b47a3a38aea6eba2a7c320da25
--- /dev/null
+++ b/config/bootstrap-hwasan.mk
@@ -0,0 +1,8 @@
+# This option enables -fsanitize=hwaddress for stage2 and stage3.
+
+STAGE2_CFLAGS += -fsanitize=hwaddress
+STAGE3_CFLAGS += -fsanitize=hwaddress
+POSTSTAGE1_LDFLAGS += -fsanitize=hwaddress -static-libhwasan \
+		      -B$$r/prev-$(TARGET_SUBDIR)/libsanitizer/ \
+		      -B$$r/prev-$(TARGET_SUBDIR)/libsanitizer/hwasan/ \
+		      -B$$r/prev-$(TARGET_SUBDIR)/libsanitizer/hwasan/.libs
diff --git a/configure b/configure
index abd93a990a947f9e7f07d530d14f0ab8720ffa4c..b97737c857b4d6a02570f7007465a292b86c3936 100755
--- a/configure
+++ b/configure
@@ -754,6 +754,7 @@ infodir
 docdir
 oldincludedir
 includedir
+runstatedir
 localstatedir
 sharedstatedir
 sysconfdir
@@ -919,6 +920,7 @@ datadir='${datarootdir}'
 sysconfdir='${prefix}/etc'
 sharedstatedir='${prefix}/com'
 localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
 includedir='${prefix}/include'
 oldincludedir='/usr/include'
 docdir='${datarootdir}/doc/${PACKAGE}'
@@ -1171,6 +1173,15 @@ do
   | -silent | --silent | --silen | --sile | --sil)
     silent=yes ;;
 
+  -runstatedir | --runstatedir | --runstatedi | --runstated \
+  | --runstate | --runstat | --runsta | --runst | --runs \
+  | --run | --ru | --r)
+    ac_prev=runstatedir ;;
+  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+  | --run=* | --ru=* | --r=*)
+    runstatedir=$ac_optarg ;;
+
   -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
     ac_prev=sbindir ;;
   -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1308,7 +1319,7 @@ fi
 for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
 		datadir sysconfdir sharedstatedir localstatedir includedir \
 		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
-		libdir localedir mandir
+		libdir localedir mandir runstatedir
 do
   eval ac_val=\$$ac_var
   # Remove trailing slashes.
@@ -1468,6 +1479,7 @@ Fine tuning of the installation directories:
   --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
   --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
   --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
   --libdir=DIR            object code libraries [EPREFIX/lib]
   --includedir=DIR        C header files [PREFIX/include]
   --oldincludedir=DIR     C header files for non-gcc [/usr/include]
@@ -7189,7 +7201,7 @@ fi
 # or bootstrap-ubsan, bootstrap it.
 if echo " ${target_configdirs} " | grep " libsanitizer " > /dev/null 2>&1; then
   case "$BUILD_CONFIG" in
-    *bootstrap-asan* | *bootstrap-ubsan* )
+    *bootstrap-hwasan* | *bootstrap-asan* | *bootstrap-ubsan* )
       bootstrap_target_libs=${bootstrap_target_libs}target-libsanitizer,
       bootstrap_fixincludes=yes
       ;;
diff --git a/configure.ac b/configure.ac
index 9db4fd14aa238f346dbe3ec1e7ef134741498048..836fd457c43f482bc80b2032954f4f98cd978a3e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2702,7 +2702,7 @@ fi
 # or bootstrap-ubsan, bootstrap it.
 if echo " ${target_configdirs} " | grep " libsanitizer " > /dev/null 2>&1; then
   case "$BUILD_CONFIG" in
-    *bootstrap-asan* | *bootstrap-ubsan* )
+    *bootstrap-hwasan* | *bootstrap-asan* | *bootstrap-ubsan* )
       bootstrap_target_libs=${bootstrap_target_libs}target-libsanitizer,
       bootstrap_fixincludes=yes
       ;;
diff --git a/gcc/asan.h b/gcc/asan.h
index 7675f18a84ee3f187ba4cb40db0ce232f3958762..66c11139b5ccbe307850d0be57e86f96445dd18d 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -33,7 +33,7 @@ extern bool asan_expand_check_ifn (gimple_stmt_iterator *, bool);
 extern bool asan_expand_mark_ifn (gimple_stmt_iterator *);
 extern bool asan_expand_poison_ifn (gimple_stmt_iterator *, bool *,
 				    hash_map<tree, tree> &);
-
+extern bool memory_tagging_p (void);
 extern gimple_stmt_iterator create_cond_insert_point
      (gimple_stmt_iterator *, bool, bool, bool, basic_block *, basic_block *);
 
diff --git a/gcc/asan.c b/gcc/asan.c
index 3b800b26b6991c5a79116a7de838751b04db496a..42e990675e740bd37dad0704fd34b7a04740121e 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -1351,6 +1351,15 @@ asan_redzone_buffer::flush_if_full (void)
     flush_redzone_payload ();
 }
 
+/* Returns whether we are tagging pointers and checking those tags on memory
+   access.  This is true when checking with either in software or hardware
+   (hardware e.g. with the AArch64 memtag extension).  */
+bool
+memory_tagging_p ()
+{
+    return sanitize_flags_p (SANITIZE_HWADDRESS);
+}
+
 /* Insert code to protect stack vars.  The prologue sequence should be emitted
    directly, epilogue sequence returned.  BASE is the register holding the
    stack base, against which OFFSETS array offsets are relative to, OFFSETS
diff --git a/libiberty/configure b/libiberty/configure
index 7a34dabec32b0b383bd33f07811757335f4dd39c..cb2dd4ff5295598343cc18b3a79a86a778f2261d 100755
--- a/libiberty/configure
+++ b/libiberty/configure
@@ -5261,6 +5261,7 @@ fi
 NOASANFLAG=
 case " ${CFLAGS} " in
   *\ -fsanitize=address\ *) NOASANFLAG=-fno-sanitize=address ;;
+  *\ -fsanitize=hwaddress\ *) NOASANFLAG=-fno-sanitize=hwaddress ;;
 esac
 
 
diff --git a/libiberty/configure.ac b/libiberty/configure.ac
index f1ce76010c9acde79c5dc46686a78b2e2f19244e..043237628b79cbf37d07359b59c5ffe17a7a22ef 100644
--- a/libiberty/configure.ac
+++ b/libiberty/configure.ac
@@ -240,6 +240,7 @@ AC_SUBST(PICFLAG)
 NOASANFLAG=
 case " ${CFLAGS} " in
   *\ -fsanitize=address\ *) NOASANFLAG=-fno-sanitize=address ;;
+  *\ -fsanitize=hwaddress\ *) NOASANFLAG=-fno-sanitize=hwaddress ;;
 esac
 AC_SUBST(NOASANFLAG)
 
diff --git a/lto-plugin/Makefile.am b/lto-plugin/Makefile.am
index 28dc21014b2e86988fa88adabd63ce6092e18e02..34aa397d785e3cc9b6975de460d065900364c3ff 100644
--- a/lto-plugin/Makefile.am
+++ b/lto-plugin/Makefile.am
@@ -11,8 +11,8 @@ AM_CPPFLAGS = -I$(top_srcdir)/../include $(DEFS)
 AM_CFLAGS = @ac_lto_plugin_warn_cflags@
 AM_LDFLAGS = @ac_lto_plugin_ldflags@
 AM_LIBTOOLFLAGS = --tag=disable-static
-override CFLAGS := $(filter-out -fsanitize=address,$(CFLAGS))
-override LDFLAGS := $(filter-out -fsanitize=address,$(LDFLAGS))
+override CFLAGS := $(filter-out -fsanitize=address -fsanitize=hwaddress,$(CFLAGS))
+override LDFLAGS := $(filter-out -fsanitize=address -fsanitize=hwaddress,$(LDFLAGS))
 
 libexecsub_LTLIBRARIES = liblto_plugin.la
 gcc_build_dir = @gcc_build_dir@
diff --git a/lto-plugin/Makefile.in b/lto-plugin/Makefile.in
index 8dd6e40ac9dddab39fe1752f9a70e6834ab3c926..7acfc047eff6f86f8d38287e6ffb6533c4c13500 100644
--- a/lto-plugin/Makefile.in
+++ b/lto-plugin/Makefile.in
@@ -672,8 +672,8 @@ uninstall-am: uninstall-libexecsubLTLIBRARIES
 
 .PRECIOUS: Makefile
 
-override CFLAGS := $(filter-out -fsanitize=address,$(CFLAGS))
-override LDFLAGS := $(filter-out -fsanitize=address,$(LDFLAGS))
+override CFLAGS := $(filter-out -fsanitize=address -fsanitize=hwaddress,$(CFLAGS))
+override LDFLAGS := $(filter-out -fsanitize=address -fsanitize=hwaddress,$(LDFLAGS))
 
 all-local: $(in_gcc_libs)
 


[-- Attachment #2: hwasan-implementation06.patch --]
[-- Type: text/plain, Size: 7361 bytes --]

diff --git a/config/bootstrap-hwasan.mk b/config/bootstrap-hwasan.mk
new file mode 100644
index 0000000000000000000000000000000000000000..4f60bed3fd6e98b47a3a38aea6eba2a7c320da25
--- /dev/null
+++ b/config/bootstrap-hwasan.mk
@@ -0,0 +1,8 @@
+# This option enables -fsanitize=hwaddress for stage2 and stage3.
+
+STAGE2_CFLAGS += -fsanitize=hwaddress
+STAGE3_CFLAGS += -fsanitize=hwaddress
+POSTSTAGE1_LDFLAGS += -fsanitize=hwaddress -static-libhwasan \
+		      -B$$r/prev-$(TARGET_SUBDIR)/libsanitizer/ \
+		      -B$$r/prev-$(TARGET_SUBDIR)/libsanitizer/hwasan/ \
+		      -B$$r/prev-$(TARGET_SUBDIR)/libsanitizer/hwasan/.libs
diff --git a/configure b/configure
index abd93a990a947f9e7f07d530d14f0ab8720ffa4c..b97737c857b4d6a02570f7007465a292b86c3936 100755
--- a/configure
+++ b/configure
@@ -754,6 +754,7 @@ infodir
 docdir
 oldincludedir
 includedir
+runstatedir
 localstatedir
 sharedstatedir
 sysconfdir
@@ -919,6 +920,7 @@ datadir='${datarootdir}'
 sysconfdir='${prefix}/etc'
 sharedstatedir='${prefix}/com'
 localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
 includedir='${prefix}/include'
 oldincludedir='/usr/include'
 docdir='${datarootdir}/doc/${PACKAGE}'
@@ -1171,6 +1173,15 @@ do
   | -silent | --silent | --silen | --sile | --sil)
     silent=yes ;;
 
+  -runstatedir | --runstatedir | --runstatedi | --runstated \
+  | --runstate | --runstat | --runsta | --runst | --runs \
+  | --run | --ru | --r)
+    ac_prev=runstatedir ;;
+  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+  | --run=* | --ru=* | --r=*)
+    runstatedir=$ac_optarg ;;
+
   -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
     ac_prev=sbindir ;;
   -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1308,7 +1319,7 @@ fi
 for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
 		datadir sysconfdir sharedstatedir localstatedir includedir \
 		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
-		libdir localedir mandir
+		libdir localedir mandir runstatedir
 do
   eval ac_val=\$$ac_var
   # Remove trailing slashes.
@@ -1468,6 +1479,7 @@ Fine tuning of the installation directories:
   --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
   --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
   --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
   --libdir=DIR            object code libraries [EPREFIX/lib]
   --includedir=DIR        C header files [PREFIX/include]
   --oldincludedir=DIR     C header files for non-gcc [/usr/include]
@@ -7189,7 +7201,7 @@ fi
 # or bootstrap-ubsan, bootstrap it.
 if echo " ${target_configdirs} " | grep " libsanitizer " > /dev/null 2>&1; then
   case "$BUILD_CONFIG" in
-    *bootstrap-asan* | *bootstrap-ubsan* )
+    *bootstrap-hwasan* | *bootstrap-asan* | *bootstrap-ubsan* )
       bootstrap_target_libs=${bootstrap_target_libs}target-libsanitizer,
       bootstrap_fixincludes=yes
       ;;
diff --git a/configure.ac b/configure.ac
index 9db4fd14aa238f346dbe3ec1e7ef134741498048..836fd457c43f482bc80b2032954f4f98cd978a3e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2702,7 +2702,7 @@ fi
 # or bootstrap-ubsan, bootstrap it.
 if echo " ${target_configdirs} " | grep " libsanitizer " > /dev/null 2>&1; then
   case "$BUILD_CONFIG" in
-    *bootstrap-asan* | *bootstrap-ubsan* )
+    *bootstrap-hwasan* | *bootstrap-asan* | *bootstrap-ubsan* )
       bootstrap_target_libs=${bootstrap_target_libs}target-libsanitizer,
       bootstrap_fixincludes=yes
       ;;
diff --git a/gcc/asan.h b/gcc/asan.h
index 7675f18a84ee3f187ba4cb40db0ce232f3958762..66c11139b5ccbe307850d0be57e86f96445dd18d 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -33,7 +33,7 @@ extern bool asan_expand_check_ifn (gimple_stmt_iterator *, bool);
 extern bool asan_expand_mark_ifn (gimple_stmt_iterator *);
 extern bool asan_expand_poison_ifn (gimple_stmt_iterator *, bool *,
 				    hash_map<tree, tree> &);
-
+extern bool memory_tagging_p (void);
 extern gimple_stmt_iterator create_cond_insert_point
      (gimple_stmt_iterator *, bool, bool, bool, basic_block *, basic_block *);
 
diff --git a/gcc/asan.c b/gcc/asan.c
index 3b800b26b6991c5a79116a7de838751b04db496a..42e990675e740bd37dad0704fd34b7a04740121e 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -1351,6 +1351,15 @@ asan_redzone_buffer::flush_if_full (void)
     flush_redzone_payload ();
 }
 
+/* Returns whether we are tagging pointers and checking those tags on memory
+   access.  This is true when checking with either in software or hardware
+   (hardware e.g. with the AArch64 memtag extension).  */
+bool
+memory_tagging_p ()
+{
+    return sanitize_flags_p (SANITIZE_HWADDRESS);
+}
+
 /* Insert code to protect stack vars.  The prologue sequence should be emitted
    directly, epilogue sequence returned.  BASE is the register holding the
    stack base, against which OFFSETS array offsets are relative to, OFFSETS
diff --git a/libiberty/configure b/libiberty/configure
index 7a34dabec32b0b383bd33f07811757335f4dd39c..cb2dd4ff5295598343cc18b3a79a86a778f2261d 100755
--- a/libiberty/configure
+++ b/libiberty/configure
@@ -5261,6 +5261,7 @@ fi
 NOASANFLAG=
 case " ${CFLAGS} " in
   *\ -fsanitize=address\ *) NOASANFLAG=-fno-sanitize=address ;;
+  *\ -fsanitize=hwaddress\ *) NOASANFLAG=-fno-sanitize=hwaddress ;;
 esac
 
 
diff --git a/libiberty/configure.ac b/libiberty/configure.ac
index f1ce76010c9acde79c5dc46686a78b2e2f19244e..043237628b79cbf37d07359b59c5ffe17a7a22ef 100644
--- a/libiberty/configure.ac
+++ b/libiberty/configure.ac
@@ -240,6 +240,7 @@ AC_SUBST(PICFLAG)
 NOASANFLAG=
 case " ${CFLAGS} " in
   *\ -fsanitize=address\ *) NOASANFLAG=-fno-sanitize=address ;;
+  *\ -fsanitize=hwaddress\ *) NOASANFLAG=-fno-sanitize=hwaddress ;;
 esac
 AC_SUBST(NOASANFLAG)
 
diff --git a/lto-plugin/Makefile.am b/lto-plugin/Makefile.am
index 28dc21014b2e86988fa88adabd63ce6092e18e02..34aa397d785e3cc9b6975de460d065900364c3ff 100644
--- a/lto-plugin/Makefile.am
+++ b/lto-plugin/Makefile.am
@@ -11,8 +11,8 @@ AM_CPPFLAGS = -I$(top_srcdir)/../include $(DEFS)
 AM_CFLAGS = @ac_lto_plugin_warn_cflags@
 AM_LDFLAGS = @ac_lto_plugin_ldflags@
 AM_LIBTOOLFLAGS = --tag=disable-static
-override CFLAGS := $(filter-out -fsanitize=address,$(CFLAGS))
-override LDFLAGS := $(filter-out -fsanitize=address,$(LDFLAGS))
+override CFLAGS := $(filter-out -fsanitize=address -fsanitize=hwaddress,$(CFLAGS))
+override LDFLAGS := $(filter-out -fsanitize=address -fsanitize=hwaddress,$(LDFLAGS))
 
 libexecsub_LTLIBRARIES = liblto_plugin.la
 gcc_build_dir = @gcc_build_dir@
diff --git a/lto-plugin/Makefile.in b/lto-plugin/Makefile.in
index 8dd6e40ac9dddab39fe1752f9a70e6834ab3c926..7acfc047eff6f86f8d38287e6ffb6533c4c13500 100644
--- a/lto-plugin/Makefile.in
+++ b/lto-plugin/Makefile.in
@@ -672,8 +672,8 @@ uninstall-am: uninstall-libexecsubLTLIBRARIES
 
 .PRECIOUS: Makefile
 
-override CFLAGS := $(filter-out -fsanitize=address,$(CFLAGS))
-override LDFLAGS := $(filter-out -fsanitize=address,$(LDFLAGS))
+override CFLAGS := $(filter-out -fsanitize=address -fsanitize=hwaddress,$(CFLAGS))
+override LDFLAGS := $(filter-out -fsanitize=address -fsanitize=hwaddress,$(LDFLAGS))
 
 all-local: $(in_gcc_libs)
 


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [RFC][PATCH 13/X][libsanitizer] Instrument known builtin function calls
  2019-09-06 14:46 [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Matthew Malcomson
                   ` (7 preceding siblings ...)
  2019-09-06 14:46 ` [RFC][PATCH 1/X][libsanitizer] Introduce libsanitizer to GCC tree Matthew Malcomson
@ 2019-09-06 14:47 ` Matthew Malcomson
  2019-09-06 14:47 ` [RFC][PATCH 10/X][libsanitizer] Colour the shadow stack for each stack variable Matthew Malcomson
                   ` (8 subsequent siblings)
  17 siblings, 0 replies; 35+ messages in thread
From: Matthew Malcomson @ 2019-09-06 14:47 UTC (permalink / raw)
  To: gcc-patches; +Cc: mliska, dodji, nd, kcc, jakub, dvyukov

[-- Attachment #1: Type: text/plain, Size: 15029 bytes --]

Handle all builtin functions that we know use memory accesses.
This commit uses the machinery added for ASAN to identify builtin
functions that access memory.

The main differences between the approaches for HWASAN and ASAN are:
1) libhwasan intercepts much less builtin functions.
2) Alloca needs to be transformed differently (instead of adding
   redzones it needs to colour shadow memory and return a tagged
   pointer).
3) stack_restore needs to uncolour the shadow stack between the current
   position and where it's going.
4) `noreturn` functions can not be handled by simply unpoisoning the
   entire shadow stack -- there is no "always valid" colour.

For hardware implemented checking such as AArch64's memory tagging
extension alloca and stack_restore will need to be handled by hooks in
the backend rather than transformation at the gimple level.  This will
allow architecture specific handling of such stack modifications.

gcc/ChangeLog:

2019-09-06  Matthew Malcomson  <matthew.malcomson@arm.com>

	* asan.c (handle_builtin_stack_restore): Handle HWASAN.
	(handle_builtin_alloca): Handle HWASAN.
	(get_mem_refs_of_builtin_call): Avoid strlen for HWASAN.
	(maybe_instrument_call): HWASAN avoids ASAN_HANDLE_NO_RETURN.
	(initialize_sanitizer_builtins): Define new function type.
	(hwasan_base): New.
	* asan.h (hwasan_base): New decl.
	* builtin-types.def (BT_FN_PTR_CONST_PTR_UINT8): New type.
	* internal-fn.c (expand_HWASAN_CHOOSE_COLOUR): New.
	* internal-fn.def (HWASAN_CHOOSE_COLOUR): New.
	* sanitizer.def (BUILT_IN_HWASAN_HANDLE_LONGJMP): New.
	(BUILT_IN_HWASAN_TAG_PTR): New.



###############     Attachment also inlined for ease of reply    ###############


diff --git a/gcc/asan.h b/gcc/asan.h
index 68ea1b4afaf9195553251a987df33788421fa142..e4e823080e4ca7489135ee2da9e0727de9bba8ae 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -30,6 +30,7 @@ extern void hwasan_increment_tag ();
 extern rtx hwasan_with_tag (rtx, poly_int64);
 extern void hwasan_tag_init ();
 extern rtx hwasan_create_untagged_base (rtx);
+extern rtx hwasan_base ();
 extern void hwasan_emit_prologue (rtx *, rtx *, poly_int64 *, uint8_t *, size_t);
 extern rtx_insn *hwasan_emit_uncolour_frame (rtx, rtx, rtx_insn *);
 extern bool hwasan_expand_check_ifn (gimple_stmt_iterator *, bool);
diff --git a/gcc/asan.c b/gcc/asan.c
index ae1f8a0d28e911c2ff30be8ea9f4001923983cb1..fefd28cbd136d74ad3389cf8efbf1949e3815dfd 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -579,15 +579,28 @@ get_last_alloca_addr ()
 static void
 handle_builtin_stack_restore (gcall *call, gimple_stmt_iterator *iter)
 {
-  if (!iter || !asan_sanitize_allocas_p ())
+  if (!iter
+      || !(asan_sanitize_allocas_p () || memory_tagging_p ()))
     return;
 
-  tree last_alloca = get_last_alloca_addr ();
   tree restored_stack = gimple_call_arg (call, 0);
-  tree fn = builtin_decl_implicit (BUILT_IN_ASAN_ALLOCAS_UNPOISON);
-  gimple *g = gimple_build_call (fn, 2, last_alloca, restored_stack);
-  gsi_insert_before (iter, g, GSI_SAME_STMT);
-  g = gimple_build_assign (last_alloca, restored_stack);
+
+  gimple *g;
+
+  if (memory_tagging_p ())
+    {
+      tree fn = builtin_decl_implicit (BUILT_IN_HWASAN_HANDLE_LONGJMP);
+      g = gimple_build_call (fn, 1, restored_stack);
+    }
+  else
+    {
+      tree last_alloca = get_last_alloca_addr ();
+      tree fn = builtin_decl_implicit (BUILT_IN_ASAN_ALLOCAS_UNPOISON);
+      g = gimple_build_call (fn, 2, last_alloca, restored_stack);
+      gsi_insert_before (iter, g, GSI_SAME_STMT);
+      g = gimple_build_assign (last_alloca, restored_stack);
+    }
+
   gsi_insert_before (iter, g, GSI_SAME_STMT);
 }
 
@@ -617,14 +630,12 @@ handle_builtin_stack_restore (gcall *call, gimple_stmt_iterator *iter)
 static void
 handle_builtin_alloca (gcall *call, gimple_stmt_iterator *iter)
 {
-  if (!iter || !asan_sanitize_allocas_p ())
+  if (!iter
+      || !(asan_sanitize_allocas_p () || memory_tagging_p ()))
     return;
 
   gassign *g;
   gcall *gg;
-  const HOST_WIDE_INT redzone_mask = ASAN_RED_ZONE_SIZE - 1;
-
-  tree last_alloca = get_last_alloca_addr ();
   tree callee = gimple_call_fndecl (call);
   tree old_size = gimple_call_arg (call, 0);
   tree ptr_type = gimple_call_lhs (call) ? TREE_TYPE (gimple_call_lhs (call))
@@ -634,6 +645,86 @@ handle_builtin_alloca (gcall *call, gimple_stmt_iterator *iter)
     = DECL_FUNCTION_CODE (callee) == BUILT_IN_ALLOCA
       ? 0 : tree_to_uhwi (gimple_call_arg (call, 1));
 
+  if (memory_tagging_p ())
+    {
+      /*
+	 HWASAN needs a different expansion.
+
+	 addr = __builtin_alloca (size, align);
+
+	 should be replaced by
+
+	 new_size = size rounded up to HWASAN_TAG_GRANULE_SIZE byte alignment;
+	 untagged_addr = __builtin_alloca (new_size, align);
+	 colour = __hwasan_choose_alloca_colour ();
+	 addr = __hwasan_tag_pointer (untagged_addr, colour);
+	 __hwasan_tag_memory (addr, colour, new_size);
+	*/
+      /* Ensure alignment at least HWASAN_TAG_GRANULE_SIZE bytes so we start on
+	 a tag granule. aarch64 already has an alignment of 16 bytes by
+	 default which is the same as HWASAN_TAG_GRANULE_SIZE at the moment. */
+      align = align > HWASAN_TAG_GRANULE_SIZE ? align : HWASAN_TAG_GRANULE_SIZE;
+
+      /* tree new_size = (old_size + 15) & ~15;  */
+      uint8_t tg_mask = HWASAN_TAG_GRANULE_SIZE - 1;
+      tree old_size = gimple_call_arg (call, 0);
+      tree tree_mask = build_int_cst (size_type_node, tg_mask);
+      g = gimple_build_assign (make_ssa_name (size_type_node), PLUS_EXPR,
+			       old_size, tree_mask);
+      gsi_insert_before (iter, g, GSI_SAME_STMT);
+      tree oversize = gimple_assign_lhs (g);
+
+      g = gimple_build_assign (make_ssa_name (size_type_node), BIT_NOT_EXPR,
+			       tree_mask);
+      tree mask = gimple_assign_lhs (g);
+      gsi_insert_before (iter, g, GSI_SAME_STMT);
+
+      g = gimple_build_assign (make_ssa_name (size_type_node), BIT_AND_EXPR,
+			       oversize, mask);
+      gsi_insert_before (iter, g, GSI_SAME_STMT);
+      tree new_size = gimple_assign_lhs (g);
+
+      /* emit the alloca call */
+      tree fn = builtin_decl_implicit (BUILT_IN_ALLOCA_WITH_ALIGN);
+      gg = gimple_build_call (fn, 2, new_size,
+			      build_int_cst (size_type_node, align));
+      tree untagged_addr = make_ssa_name (ptr_type, gg);
+      gimple_call_set_lhs (gg, untagged_addr);
+      gsi_insert_before (iter, gg, GSI_SAME_STMT);
+
+      /* Insert code choosing the tag.
+	 Here we use an internal function so we can choose the colour at expand
+	 time.  We want this so the decision is made after stack variables have
+	 been assigned their colour (i.e. once the tag_offset variable has been
+	 set to one after the last stack variables tag).  */
+
+      gg = gimple_build_call_internal (IFN_HWASAN_CHOOSE_COLOUR, 0);
+      tree colour = make_ssa_name (unsigned_char_type_node, gg);
+      gimple_call_set_lhs (gg, colour);
+      gsi_insert_before (iter, gg, GSI_SAME_STMT);
+
+      /* Insert code adding tag to pointer.  */
+      fn = builtin_decl_implicit (BUILT_IN_HWASAN_TAG_PTR);
+      gg = gimple_build_call (fn, 2, untagged_addr, colour);
+      tree addr = make_ssa_name (ptr_type, gg);
+      gimple_call_set_lhs (gg, addr);
+      gsi_insert_before (iter, gg, GSI_SAME_STMT);
+
+      /* Insert code colouring shadow memory.
+	 NOTE: require using `untagged_addr` here.  */
+      fn = builtin_decl_implicit (BUILT_IN_HWASAN_TAG_MEM);
+      gg = gimple_build_call (fn, 3, untagged_addr, colour, new_size);
+      gsi_insert_before (iter, gg, GSI_SAME_STMT);
+
+      /* Finally, replace old alloca ptr with NEW_ALLOCA.  */
+      replace_call_with_value (iter, addr);
+      return;
+    }
+
+  tree last_alloca = get_last_alloca_addr ();
+  const HOST_WIDE_INT redzone_mask = ASAN_RED_ZONE_SIZE - 1;
+
+
   /* If ALIGN > ASAN_RED_ZONE_SIZE, we embed left redzone into first ALIGN
      bytes of allocated space.  Otherwise, align alloca to ASAN_RED_ZONE_SIZE
      manually.  */
@@ -786,6 +877,33 @@ get_mem_refs_of_builtin_call (gcall *call,
       break;
 
     case BUILT_IN_STRLEN:
+      /*
+	 Special case strlen here because its length is taken from its return
+	 value.
+
+	 The approach taken by the sanitizers is to check a memory access
+	 before it's taken.  For ASAN strlen is intercepted by libasan, so no
+	 check is inserted by the compiler.
+
+	 This function still returns `true` and provides a length to the rest
+	 of the ASAN pass in order to record what areas have been checked,
+	 avoiding superfluous checks later on.
+
+	 HWASAN does not intercept any of these internal functions.
+	 This means that checks for memory accesses must be inserted by the
+	 compiler.
+	 strlen is a special case, because we can tell the length from the
+	 return of the function, but that is not known until after the function
+	 has returned.
+
+	 Hence we can't check the memory access before it happens.
+	 We could check the memory access after it has already happened, but
+	 for now I'm choosing to just ignore `strlen` calls.
+	 This decision was simply made because that means the special case is
+	 limited to this one case of this one function.
+	*/
+      if (memory_tagging_p ())
+	return false;
       source0 = gimple_call_arg (call, 0);
       len = gimple_call_lhs (call);
       break;
@@ -2493,8 +2611,6 @@ maybe_instrument_assignment (gimple_stmt_iterator *iter)
 static bool
 maybe_instrument_call (gimple_stmt_iterator *iter)
 {
-  if (memory_tagging_p ())
-    return false;
   gimple *stmt = gsi_stmt (*iter);
   bool is_builtin = gimple_call_builtin_p (stmt, BUILT_IN_NORMAL);
 
@@ -2516,10 +2632,13 @@ maybe_instrument_call (gimple_stmt_iterator *iter)
 	      break;
 	    }
 	}
-      tree decl = builtin_decl_implicit (BUILT_IN_ASAN_HANDLE_NO_RETURN);
-      gimple *g = gimple_build_call (decl, 0);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_insert_before (iter, g, GSI_SAME_STMT);
+      if (! memory_tagging_p ())
+	{
+	  tree decl = builtin_decl_implicit (BUILT_IN_ASAN_HANDLE_NO_RETURN);
+	  gimple *g = gimple_build_call (decl, 0);
+	  gimple_set_location (g, gimple_location (stmt));
+	  gsi_insert_before (iter, g, GSI_SAME_STMT);
+	}
     }
 
   bool instrumented = false;
@@ -2918,6 +3037,9 @@ initialize_sanitizer_builtins (void)
     = build_function_type_list (void_type_node, uint64_type_node,
 				ptr_type_node, NULL_TREE);
 
+  tree BT_FN_PTR_CONST_PTR_UINT8
+    = build_function_type_list (ptr_type_node, const_ptr_type_node,
+				unsigned_char_type_node, NULL_TREE);
   tree BT_FN_VOID_PTR_UINT8_SIZE
     = build_function_type_list (void_type_node, ptr_type_node,
 				unsigned_char_type_node, size_type_node,
@@ -3749,6 +3871,14 @@ hwasan_record_base (rtx base)
 }
 
 uint8_t hwasan_current_tag () { return tag_offset; }
+rtx
+hwasan_base ()
+{
+  if (! hwasan_base_ptr)
+    hwasan_record_base (gen_reg_rtx (Pmode));
+
+  return hwasan_base_ptr;
+}
 
 void
 hwasan_increment_tag ()
diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def
index d05f597b6434f39fe95d4f28dd2ef3ed463dd925..00592b1eea76164471e281c8922893937cf9bb2e 100644
--- a/gcc/builtin-types.def
+++ b/gcc/builtin-types.def
@@ -493,6 +493,7 @@ DEF_FUNCTION_TYPE_2 (BT_FN_INT_FEXCEPT_T_PTR_INT, BT_INT, BT_FEXCEPT_T_PTR,
 		     BT_INT)
 DEF_FUNCTION_TYPE_2 (BT_FN_INT_CONST_FEXCEPT_T_PTR_INT, BT_INT,
 		     BT_CONST_FEXCEPT_T_PTR, BT_INT)
+DEF_FUNCTION_TYPE_2 (BT_FN_PTR_CONST_PTR_UINT8, BT_PTR, BT_CONST_PTR, BT_UINT8)
 
 DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR)
 
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 80f94f141bfd92e9f6af13a6df76f0c9ac053fdc..4eec9919b520691ab3e73a2920ef8b544cf55dfe 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -462,6 +462,42 @@ expand_HWASAN_CHECK (internal_fn, gcall *)
 }
 
 static void
+expand_HWASAN_CHOOSE_COLOUR (internal_fn, gcall *gc)
+{
+  /* TODO Use shared function somewhere so that MTE can use the same basic
+     functionality when it needs to get a tag for alloca.  */
+  tree colour = gimple_call_lhs (gc);
+  rtx target = expand_expr (colour, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+  machine_mode mode = GET_MODE (target);
+  gcc_assert (mode == QImode);
+
+  rtx base_tag = expand_simple_binop (Pmode, LSHIFTRT, hwasan_base (),
+				      HWASAN_SHIFT_RTX,
+				      NULL_RTX, /* unsignedp = */0,
+				      OPTAB_DIRECT);
+
+  gcc_assert (base_tag);
+  rtx tag_offset = const_int_rtx[MAX_SAVED_CONST_INT + hwasan_current_tag ()];
+  rtx chosen_tag = expand_simple_binop (QImode, PLUS, base_tag, tag_offset,
+					target, /* unsignedp = */1,
+					OPTAB_WIDEN);
+
+  gcc_assert (chosen_tag);
+  /* TODO truncate target */
+  if (chosen_tag != target)
+    {
+      rtx temp = chosen_tag;
+      machine_mode ret_mode = GET_MODE (chosen_tag);
+      if (ret_mode != mode)
+	temp = simplify_gen_unary (TRUNCATE, mode, chosen_tag, ret_mode);
+
+      emit_move_insn (target, temp);
+    }
+
+  hwasan_increment_tag ();
+}
+
+static void
 expand_ASAN_CHECK (internal_fn, gcall *)
 {
   gcc_unreachable ();
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index c683e5d8e5c607f18909bda4d97b58421cb7c2a4..ed0c5bc110f16b2cdbc139403dbdbd8ebe7e2823 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -288,6 +288,7 @@ DEF_INTERNAL_FN (UBSAN_PTR, ECF_LEAF | ECF_NOTHROW, ".R.")
 DEF_INTERNAL_FN (UBSAN_OBJECT_SIZE, ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (ABNORMAL_DISPATCHER, ECF_NORETURN, NULL)
 DEF_INTERNAL_FN (BUILTIN_EXPECT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
+DEF_INTERNAL_FN (HWASAN_CHOOSE_COLOUR, ECF_LEAF | ECF_NOTHROW, ".")
 DEF_INTERNAL_FN (HWASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, "..R..")
 DEF_INTERNAL_FN (ASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, "..R..")
 DEF_INTERNAL_FN (ASAN_MARK, ECF_LEAF | ECF_NOTHROW, NULL)
diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def
index 0edf349cc23e846608b89d54a1024b9d99de9c4d..b6944f3e365bcd9ecd319bbf66bada32f87ad249 100644
--- a/gcc/sanitizer.def
+++ b/gcc/sanitizer.def
@@ -187,6 +187,10 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_LOADN, "__hwasan_loadN",
 		      BT_FN_VOID_PTR_PTRMODE, ATTR_TMPURE_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_STOREN, "__hwasan_storeN",
 		      BT_FN_VOID_PTR_PTRMODE, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_HANDLE_LONGJMP, "__hwasan_handle_longjmp",
+		      BT_FN_VOID_CONST_PTR, ATTR_NOTHROW_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_TAG_PTR, "__hwasan_tag_pointer",
+		      BT_FN_PTR_CONST_PTR_UINT8, ATTR_TMPURE_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_TAG_MEM, "__hwasan_tag_memory",
 		      BT_FN_VOID_PTR_UINT8_SIZE, ATTR_NOTHROW_LIST)
 


[-- Attachment #2: hwasan-implementation12.patch --]
[-- Type: text/plain, Size: 12975 bytes --]

diff --git a/gcc/asan.h b/gcc/asan.h
index 68ea1b4afaf9195553251a987df33788421fa142..e4e823080e4ca7489135ee2da9e0727de9bba8ae 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -30,6 +30,7 @@ extern void hwasan_increment_tag ();
 extern rtx hwasan_with_tag (rtx, poly_int64);
 extern void hwasan_tag_init ();
 extern rtx hwasan_create_untagged_base (rtx);
+extern rtx hwasan_base ();
 extern void hwasan_emit_prologue (rtx *, rtx *, poly_int64 *, uint8_t *, size_t);
 extern rtx_insn *hwasan_emit_uncolour_frame (rtx, rtx, rtx_insn *);
 extern bool hwasan_expand_check_ifn (gimple_stmt_iterator *, bool);
diff --git a/gcc/asan.c b/gcc/asan.c
index ae1f8a0d28e911c2ff30be8ea9f4001923983cb1..fefd28cbd136d74ad3389cf8efbf1949e3815dfd 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -579,15 +579,28 @@ get_last_alloca_addr ()
 static void
 handle_builtin_stack_restore (gcall *call, gimple_stmt_iterator *iter)
 {
-  if (!iter || !asan_sanitize_allocas_p ())
+  if (!iter
+      || !(asan_sanitize_allocas_p () || memory_tagging_p ()))
     return;
 
-  tree last_alloca = get_last_alloca_addr ();
   tree restored_stack = gimple_call_arg (call, 0);
-  tree fn = builtin_decl_implicit (BUILT_IN_ASAN_ALLOCAS_UNPOISON);
-  gimple *g = gimple_build_call (fn, 2, last_alloca, restored_stack);
-  gsi_insert_before (iter, g, GSI_SAME_STMT);
-  g = gimple_build_assign (last_alloca, restored_stack);
+
+  gimple *g;
+
+  if (memory_tagging_p ())
+    {
+      tree fn = builtin_decl_implicit (BUILT_IN_HWASAN_HANDLE_LONGJMP);
+      g = gimple_build_call (fn, 1, restored_stack);
+    }
+  else
+    {
+      tree last_alloca = get_last_alloca_addr ();
+      tree fn = builtin_decl_implicit (BUILT_IN_ASAN_ALLOCAS_UNPOISON);
+      g = gimple_build_call (fn, 2, last_alloca, restored_stack);
+      gsi_insert_before (iter, g, GSI_SAME_STMT);
+      g = gimple_build_assign (last_alloca, restored_stack);
+    }
+
   gsi_insert_before (iter, g, GSI_SAME_STMT);
 }
 
@@ -617,14 +630,12 @@ handle_builtin_stack_restore (gcall *call, gimple_stmt_iterator *iter)
 static void
 handle_builtin_alloca (gcall *call, gimple_stmt_iterator *iter)
 {
-  if (!iter || !asan_sanitize_allocas_p ())
+  if (!iter
+      || !(asan_sanitize_allocas_p () || memory_tagging_p ()))
     return;
 
   gassign *g;
   gcall *gg;
-  const HOST_WIDE_INT redzone_mask = ASAN_RED_ZONE_SIZE - 1;
-
-  tree last_alloca = get_last_alloca_addr ();
   tree callee = gimple_call_fndecl (call);
   tree old_size = gimple_call_arg (call, 0);
   tree ptr_type = gimple_call_lhs (call) ? TREE_TYPE (gimple_call_lhs (call))
@@ -634,6 +645,86 @@ handle_builtin_alloca (gcall *call, gimple_stmt_iterator *iter)
     = DECL_FUNCTION_CODE (callee) == BUILT_IN_ALLOCA
       ? 0 : tree_to_uhwi (gimple_call_arg (call, 1));
 
+  if (memory_tagging_p ())
+    {
+      /*
+	 HWASAN needs a different expansion.
+
+	 addr = __builtin_alloca (size, align);
+
+	 should be replaced by
+
+	 new_size = size rounded up to HWASAN_TAG_GRANULE_SIZE byte alignment;
+	 untagged_addr = __builtin_alloca (new_size, align);
+	 colour = __hwasan_choose_alloca_colour ();
+	 addr = __hwasan_tag_pointer (untagged_addr, colour);
+	 __hwasan_tag_memory (addr, colour, new_size);
+	*/
+      /* Ensure alignment at least HWASAN_TAG_GRANULE_SIZE bytes so we start on
+	 a tag granule. aarch64 already has an alignment of 16 bytes by
+	 default which is the same as HWASAN_TAG_GRANULE_SIZE at the moment. */
+      align = align > HWASAN_TAG_GRANULE_SIZE ? align : HWASAN_TAG_GRANULE_SIZE;
+
+      /* tree new_size = (old_size + 15) & ~15;  */
+      uint8_t tg_mask = HWASAN_TAG_GRANULE_SIZE - 1;
+      tree old_size = gimple_call_arg (call, 0);
+      tree tree_mask = build_int_cst (size_type_node, tg_mask);
+      g = gimple_build_assign (make_ssa_name (size_type_node), PLUS_EXPR,
+			       old_size, tree_mask);
+      gsi_insert_before (iter, g, GSI_SAME_STMT);
+      tree oversize = gimple_assign_lhs (g);
+
+      g = gimple_build_assign (make_ssa_name (size_type_node), BIT_NOT_EXPR,
+			       tree_mask);
+      tree mask = gimple_assign_lhs (g);
+      gsi_insert_before (iter, g, GSI_SAME_STMT);
+
+      g = gimple_build_assign (make_ssa_name (size_type_node), BIT_AND_EXPR,
+			       oversize, mask);
+      gsi_insert_before (iter, g, GSI_SAME_STMT);
+      tree new_size = gimple_assign_lhs (g);
+
+      /* emit the alloca call */
+      tree fn = builtin_decl_implicit (BUILT_IN_ALLOCA_WITH_ALIGN);
+      gg = gimple_build_call (fn, 2, new_size,
+			      build_int_cst (size_type_node, align));
+      tree untagged_addr = make_ssa_name (ptr_type, gg);
+      gimple_call_set_lhs (gg, untagged_addr);
+      gsi_insert_before (iter, gg, GSI_SAME_STMT);
+
+      /* Insert code choosing the tag.
+	 Here we use an internal function so we can choose the colour at expand
+	 time.  We want this so the decision is made after stack variables have
+	 been assigned their colour (i.e. once the tag_offset variable has been
+	 set to one after the last stack variables tag).  */
+
+      gg = gimple_build_call_internal (IFN_HWASAN_CHOOSE_COLOUR, 0);
+      tree colour = make_ssa_name (unsigned_char_type_node, gg);
+      gimple_call_set_lhs (gg, colour);
+      gsi_insert_before (iter, gg, GSI_SAME_STMT);
+
+      /* Insert code adding tag to pointer.  */
+      fn = builtin_decl_implicit (BUILT_IN_HWASAN_TAG_PTR);
+      gg = gimple_build_call (fn, 2, untagged_addr, colour);
+      tree addr = make_ssa_name (ptr_type, gg);
+      gimple_call_set_lhs (gg, addr);
+      gsi_insert_before (iter, gg, GSI_SAME_STMT);
+
+      /* Insert code colouring shadow memory.
+	 NOTE: require using `untagged_addr` here.  */
+      fn = builtin_decl_implicit (BUILT_IN_HWASAN_TAG_MEM);
+      gg = gimple_build_call (fn, 3, untagged_addr, colour, new_size);
+      gsi_insert_before (iter, gg, GSI_SAME_STMT);
+
+      /* Finally, replace old alloca ptr with NEW_ALLOCA.  */
+      replace_call_with_value (iter, addr);
+      return;
+    }
+
+  tree last_alloca = get_last_alloca_addr ();
+  const HOST_WIDE_INT redzone_mask = ASAN_RED_ZONE_SIZE - 1;
+
+
   /* If ALIGN > ASAN_RED_ZONE_SIZE, we embed left redzone into first ALIGN
      bytes of allocated space.  Otherwise, align alloca to ASAN_RED_ZONE_SIZE
      manually.  */
@@ -786,6 +877,33 @@ get_mem_refs_of_builtin_call (gcall *call,
       break;
 
     case BUILT_IN_STRLEN:
+      /*
+	 Special case strlen here because its length is taken from its return
+	 value.
+
+	 The approach taken by the sanitizers is to check a memory access
+	 before it's taken.  For ASAN strlen is intercepted by libasan, so no
+	 check is inserted by the compiler.
+
+	 This function still returns `true` and provides a length to the rest
+	 of the ASAN pass in order to record what areas have been checked,
+	 avoiding superfluous checks later on.
+
+	 HWASAN does not intercept any of these internal functions.
+	 This means that checks for memory accesses must be inserted by the
+	 compiler.
+	 strlen is a special case, because we can tell the length from the
+	 return of the function, but that is not known until after the function
+	 has returned.
+
+	 Hence we can't check the memory access before it happens.
+	 We could check the memory access after it has already happened, but
+	 for now I'm choosing to just ignore `strlen` calls.
+	 This decision was simply made because that means the special case is
+	 limited to this one case of this one function.
+	*/
+      if (memory_tagging_p ())
+	return false;
       source0 = gimple_call_arg (call, 0);
       len = gimple_call_lhs (call);
       break;
@@ -2493,8 +2611,6 @@ maybe_instrument_assignment (gimple_stmt_iterator *iter)
 static bool
 maybe_instrument_call (gimple_stmt_iterator *iter)
 {
-  if (memory_tagging_p ())
-    return false;
   gimple *stmt = gsi_stmt (*iter);
   bool is_builtin = gimple_call_builtin_p (stmt, BUILT_IN_NORMAL);
 
@@ -2516,10 +2632,13 @@ maybe_instrument_call (gimple_stmt_iterator *iter)
 	      break;
 	    }
 	}
-      tree decl = builtin_decl_implicit (BUILT_IN_ASAN_HANDLE_NO_RETURN);
-      gimple *g = gimple_build_call (decl, 0);
-      gimple_set_location (g, gimple_location (stmt));
-      gsi_insert_before (iter, g, GSI_SAME_STMT);
+      if (! memory_tagging_p ())
+	{
+	  tree decl = builtin_decl_implicit (BUILT_IN_ASAN_HANDLE_NO_RETURN);
+	  gimple *g = gimple_build_call (decl, 0);
+	  gimple_set_location (g, gimple_location (stmt));
+	  gsi_insert_before (iter, g, GSI_SAME_STMT);
+	}
     }
 
   bool instrumented = false;
@@ -2918,6 +3037,9 @@ initialize_sanitizer_builtins (void)
     = build_function_type_list (void_type_node, uint64_type_node,
 				ptr_type_node, NULL_TREE);
 
+  tree BT_FN_PTR_CONST_PTR_UINT8
+    = build_function_type_list (ptr_type_node, const_ptr_type_node,
+				unsigned_char_type_node, NULL_TREE);
   tree BT_FN_VOID_PTR_UINT8_SIZE
     = build_function_type_list (void_type_node, ptr_type_node,
 				unsigned_char_type_node, size_type_node,
@@ -3749,6 +3871,14 @@ hwasan_record_base (rtx base)
 }
 
 uint8_t hwasan_current_tag () { return tag_offset; }
+rtx
+hwasan_base ()
+{
+  if (! hwasan_base_ptr)
+    hwasan_record_base (gen_reg_rtx (Pmode));
+
+  return hwasan_base_ptr;
+}
 
 void
 hwasan_increment_tag ()
diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def
index d05f597b6434f39fe95d4f28dd2ef3ed463dd925..00592b1eea76164471e281c8922893937cf9bb2e 100644
--- a/gcc/builtin-types.def
+++ b/gcc/builtin-types.def
@@ -493,6 +493,7 @@ DEF_FUNCTION_TYPE_2 (BT_FN_INT_FEXCEPT_T_PTR_INT, BT_INT, BT_FEXCEPT_T_PTR,
 		     BT_INT)
 DEF_FUNCTION_TYPE_2 (BT_FN_INT_CONST_FEXCEPT_T_PTR_INT, BT_INT,
 		     BT_CONST_FEXCEPT_T_PTR, BT_INT)
+DEF_FUNCTION_TYPE_2 (BT_FN_PTR_CONST_PTR_UINT8, BT_PTR, BT_CONST_PTR, BT_UINT8)
 
 DEF_POINTER_TYPE (BT_PTR_FN_VOID_PTR_PTR, BT_FN_VOID_PTR_PTR)
 
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 80f94f141bfd92e9f6af13a6df76f0c9ac053fdc..4eec9919b520691ab3e73a2920ef8b544cf55dfe 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -462,6 +462,42 @@ expand_HWASAN_CHECK (internal_fn, gcall *)
 }
 
 static void
+expand_HWASAN_CHOOSE_COLOUR (internal_fn, gcall *gc)
+{
+  /* TODO Use shared function somewhere so that MTE can use the same basic
+     functionality when it needs to get a tag for alloca.  */
+  tree colour = gimple_call_lhs (gc);
+  rtx target = expand_expr (colour, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+  machine_mode mode = GET_MODE (target);
+  gcc_assert (mode == QImode);
+
+  rtx base_tag = expand_simple_binop (Pmode, LSHIFTRT, hwasan_base (),
+				      HWASAN_SHIFT_RTX,
+				      NULL_RTX, /* unsignedp = */0,
+				      OPTAB_DIRECT);
+
+  gcc_assert (base_tag);
+  rtx tag_offset = const_int_rtx[MAX_SAVED_CONST_INT + hwasan_current_tag ()];
+  rtx chosen_tag = expand_simple_binop (QImode, PLUS, base_tag, tag_offset,
+					target, /* unsignedp = */1,
+					OPTAB_WIDEN);
+
+  gcc_assert (chosen_tag);
+  /* TODO truncate target */
+  if (chosen_tag != target)
+    {
+      rtx temp = chosen_tag;
+      machine_mode ret_mode = GET_MODE (chosen_tag);
+      if (ret_mode != mode)
+	temp = simplify_gen_unary (TRUNCATE, mode, chosen_tag, ret_mode);
+
+      emit_move_insn (target, temp);
+    }
+
+  hwasan_increment_tag ();
+}
+
+static void
 expand_ASAN_CHECK (internal_fn, gcall *)
 {
   gcc_unreachable ();
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index c683e5d8e5c607f18909bda4d97b58421cb7c2a4..ed0c5bc110f16b2cdbc139403dbdbd8ebe7e2823 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -288,6 +288,7 @@ DEF_INTERNAL_FN (UBSAN_PTR, ECF_LEAF | ECF_NOTHROW, ".R.")
 DEF_INTERNAL_FN (UBSAN_OBJECT_SIZE, ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (ABNORMAL_DISPATCHER, ECF_NORETURN, NULL)
 DEF_INTERNAL_FN (BUILTIN_EXPECT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
+DEF_INTERNAL_FN (HWASAN_CHOOSE_COLOUR, ECF_LEAF | ECF_NOTHROW, ".")
 DEF_INTERNAL_FN (HWASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, "..R..")
 DEF_INTERNAL_FN (ASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, "..R..")
 DEF_INTERNAL_FN (ASAN_MARK, ECF_LEAF | ECF_NOTHROW, NULL)
diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def
index 0edf349cc23e846608b89d54a1024b9d99de9c4d..b6944f3e365bcd9ecd319bbf66bada32f87ad249 100644
--- a/gcc/sanitizer.def
+++ b/gcc/sanitizer.def
@@ -187,6 +187,10 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_LOADN, "__hwasan_loadN",
 		      BT_FN_VOID_PTR_PTRMODE, ATTR_TMPURE_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_STOREN, "__hwasan_storeN",
 		      BT_FN_VOID_PTR_PTRMODE, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_HANDLE_LONGJMP, "__hwasan_handle_longjmp",
+		      BT_FN_VOID_CONST_PTR, ATTR_NOTHROW_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_TAG_PTR, "__hwasan_tag_pointer",
+		      BT_FN_PTR_CONST_PTR_UINT8, ATTR_TMPURE_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_TAG_MEM, "__hwasan_tag_memory",
 		      BT_FN_VOID_PTR_UINT8_SIZE, ATTR_NOTHROW_LIST)
 


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [RFC][PATCH 16/X][libsanitizer] Build libhwasan with interceptors
  2019-09-06 14:46 [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Matthew Malcomson
                   ` (11 preceding siblings ...)
  2019-09-06 14:47 ` [RFC][PATCH 11/X][libsanitizer] Uncolour stack frame on function exit Matthew Malcomson
@ 2019-09-06 14:47 ` Matthew Malcomson
  2019-09-06 14:47 ` [RFC][PATCH 12/X][libsanitizer] Check pointer tags match address tags Matthew Malcomson
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 35+ messages in thread
From: Matthew Malcomson @ 2019-09-06 14:47 UTC (permalink / raw)
  To: gcc-patches; +Cc: mliska, dodji, nd, kcc, jakub, dvyukov

[-- Attachment #1: Type: text/plain, Size: 2267 bytes --]

This builds the library in the way designed for userspace rather than
for kernel space.  This means intercepting allocation routines so they
now tag memory at the same time, and intercepting setjmp/longjmp so that
it clears tags on the stack when called.

libsanitizer/ChangeLog:

2019-09-06  Matthew Malcomson  <matthew.malcomson@arm.com>

	* hwasan/Makefile.am: Set HWASAN_WITH_INTERCEPTORS macro.
	* hwasan/Makefile.in: Regenerate.



###############     Attachment also inlined for ease of reply    ###############


diff --git a/libsanitizer/hwasan/Makefile.am b/libsanitizer/hwasan/Makefile.am
index 36c0fc4d9e832dfc81c72d2d05c2b327589daee2..4d9f6b9bfb6ce81fa26d028ba37be055ad0d645f 100644
--- a/libsanitizer/hwasan/Makefile.am
+++ b/libsanitizer/hwasan/Makefile.am
@@ -3,7 +3,7 @@ AM_CPPFLAGS = -I $(top_srcdir)/include -I $(top_srcdir)
 # May be used by toolexeclibdir.
 gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 
-DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DCAN_SANITIZE_UB=0
+DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DCAN_SANITIZE_UB=0 -DHWASAN_WITH_INTERCEPTORS=1
 AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long  -fPIC -fno-builtin -fno-exceptions -fno-rtti -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros -fno-ipa-icf
 AM_CXXFLAGS += $(LIBSTDCXX_RAW_CXX_CXXFLAGS)
 AM_CXXFLAGS += -std=gnu++11
diff --git a/libsanitizer/hwasan/Makefile.in b/libsanitizer/hwasan/Makefile.in
index 472fbf7d8d2a5311db8fe4c14376f9213cdddde4..5fec6788f2c87c86812b6ac81f7705608f49b4e0 100644
--- a/libsanitizer/hwasan/Makefile.in
+++ b/libsanitizer/hwasan/Makefile.in
@@ -270,7 +270,7 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DCAN_SANITIZE_UB=0
+DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DCAN_SANITIZE_UB=0 -DHWASAN_WITH_INTERCEPTORS=1
 DEPDIR = @DEPDIR@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@


[-- Attachment #2: hwasan-implementation15.patch --]
[-- Type: text/plain, Size: 1702 bytes --]

diff --git a/libsanitizer/hwasan/Makefile.am b/libsanitizer/hwasan/Makefile.am
index 36c0fc4d9e832dfc81c72d2d05c2b327589daee2..4d9f6b9bfb6ce81fa26d028ba37be055ad0d645f 100644
--- a/libsanitizer/hwasan/Makefile.am
+++ b/libsanitizer/hwasan/Makefile.am
@@ -3,7 +3,7 @@ AM_CPPFLAGS = -I $(top_srcdir)/include -I $(top_srcdir)
 # May be used by toolexeclibdir.
 gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
 
-DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DCAN_SANITIZE_UB=0
+DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DCAN_SANITIZE_UB=0 -DHWASAN_WITH_INTERCEPTORS=1
 AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long  -fPIC -fno-builtin -fno-exceptions -fno-rtti -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros -fno-ipa-icf
 AM_CXXFLAGS += $(LIBSTDCXX_RAW_CXX_CXXFLAGS)
 AM_CXXFLAGS += -std=gnu++11
diff --git a/libsanitizer/hwasan/Makefile.in b/libsanitizer/hwasan/Makefile.in
index 472fbf7d8d2a5311db8fe4c14376f9213cdddde4..5fec6788f2c87c86812b6ac81f7705608f49b4e0 100644
--- a/libsanitizer/hwasan/Makefile.in
+++ b/libsanitizer/hwasan/Makefile.in
@@ -270,7 +270,7 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DCAN_SANITIZE_UB=0
+DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DCAN_SANITIZE_UB=0 -DHWASAN_WITH_INTERCEPTORS=1
 DEPDIR = @DEPDIR@
 DSYMUTIL = @DSYMUTIL@
 DUMPBIN = @DUMPBIN@


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [RFC][PATCH 15/X][libsanitizer] Add in MTE stubs
  2019-09-06 14:46 [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Matthew Malcomson
                   ` (9 preceding siblings ...)
  2019-09-06 14:47 ` [RFC][PATCH 10/X][libsanitizer] Colour the shadow stack for each stack variable Matthew Malcomson
@ 2019-09-06 14:47 ` Matthew Malcomson
  2019-09-06 14:47 ` [RFC][PATCH 11/X][libsanitizer] Uncolour stack frame on function exit Matthew Malcomson
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 35+ messages in thread
From: Matthew Malcomson @ 2019-09-06 14:47 UTC (permalink / raw)
  To: gcc-patches; +Cc: mliska, dodji, nd, kcc, jakub, dvyukov

[-- Attachment #1: Type: text/plain, Size: 31459 bytes --]

This patch in the series is just for demonstration, here we add stubs
where MTE would be implemented.

At the moment all implementations are dummies of some sort, the assembly
generated uses `mov` instead of `irg`, `add` instead of `addg`, and
`sub` instead of `subg`.  This should mean the binaries do all the same
actions except ignoring tags.

For a hardware implementation of memory tagging checks are done
automatically so adding HWASAN_CHECK is not needed.  This means that the
`hwasan` pass is no longer needed.
Similarly, the `sanopt` pass is not run when compiling for hardware
memory tagging since it provides no benefit without the HWASAN_CHECK
functions.

This patch also gives backends extra control over how a tag is stored in
a pointer and how many real-memory bytes is represented by each byte in
the shadow space.

gcc/ChangeLog:

2019-09-06  Matthew Malcomson  <matthew.malcomson@arm.com>

	* asan.c (hwasan_increment_tag): Avoid special handling around
	background tag for hardwawre implementation.
	(hwasan_copy_tag): New.
	(hwasan_tag_init): Choose initialisation value based on
	hardware/software tagging.
	(hwasan_emit_prologue): Account for hardware checking.
	(hwasan_emit_uncolour_frame): Account for hardware checking.
	(hwasan_finish_file): Assert not called for hardware checking.
	(hwasan_expand_check_ifn): Assert not called for hardware
	checking.
	(gate_hwasan): Don't run when have hardware checking.
	* asan.h (hwasan_copy_tag): New decl.
	(HWASAN_TAG_SIZE): Use backend hook if hardware checking.
	(HWASAN_TAG_GRANULE_SIZE): Use backend hook if hardware
	checking.
	* builtins.c (expand_builtin_alloca): Extra TODO comment.
	(expand_stack_restore): Extra TODO comment.
	* cfgexpand.c (expand_stack_vars): Only record untagged bases
	for hardware checking.
	* config/aarch64/aarch64.c (aarch64_tag_memory): Add dummy hook.
	(aarch64_gentag): Add dummy hook.
	(TARGET_MEMTAG_TAG): New.
	(TARGET_MEMTAG_GENTAG): New.
	* config/aarch64/aarch64.h (AARCH64_ISA_MEMTAG): New macro.
	(HARDWARE_MEMORY_TAGGING): Test for MTE.
	* config/aarch64/aarch64.md (random_tag,
	plain_offset_tag<mode>): New.
	(addtag<mode>4): Implement for MTE.
	* config/aarch64/predicates.md (aarch64_MTE_value_offset): New
	predicate.
	* defaults.h (HARDWARE_MEMORY_TAGGING):
	* doc/tm.texi: Document new hooks.
	* doc/tm.texi.in: Document new hooks.
	* internal-fn.c (expand_HWASAN_MARK): Account for hardware
	checking.
	* sanopt.c (sanitize_asan_mark_unpoison):
	* target.def (targetm.memtag.tag_size): New.
	(targetm.memtag.granule_size): New.
	(targetm.memtag.copy_tag): New.
	(targetm.memtag.tag): New.
	* targhooks.c (default_memtag_tag_size): New.
	(default_memtag_granule_size): New.
	(default_memtag_copy_tag): New.
	* targhooks.h (default_memtag_tag_size): New decl.
	(default_memtag_granule_size): New decl.
	(default_memtag_copy_tag): New decl.



###############     Attachment also inlined for ease of reply    ###############


diff --git a/gcc/asan.h b/gcc/asan.h
index 6e5ba8be606e9a1eae2afe57f17ccca5562167fd..2d697158a15e7e3078902c4fb742819f90b9a0c4 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -27,10 +27,10 @@ extern void hwasan_finish_file (void);
 extern void hwasan_record_base (rtx);
 extern uint8_t hwasan_current_tag ();
 extern void hwasan_increment_tag ();
+extern rtx hwasan_extract_tag (rtx);
 extern rtx hwasan_with_tag (rtx, poly_int64);
 extern void hwasan_tag_init ();
 extern rtx hwasan_create_untagged_base (rtx);
-extern rtx hwasan_extract_tag (rtx tagged_pointer);
 extern rtx hwasan_base ();
 extern void hwasan_emit_prologue (rtx *, rtx *, poly_int64 *, uint8_t *, size_t);
 extern rtx_insn *hwasan_emit_uncolour_frame (rtx, rtx, rtx_insn *);
@@ -100,7 +100,7 @@ extern hash_set <tree> *asan_used_labels;
    required.
    If changing this value, be careful of the predicates/constraints on the
    addtag<mode>4 patterns in the backend.  */
-#define HWASAN_TAG_SIZE 4
+#define HWASAN_TAG_SIZE (HARDWARE_MEMORY_TAGGING ? targetm.memtag.tag_size () : 4)
 /* Tag Granule of HWASAN shadow stack.
    This is the size in real memory that each byte in the shadow memory refers
    to.  I.e. if a variable is X bytes long in memory then it's colour in shadow
@@ -109,12 +109,12 @@ extern hash_set <tree> *asan_used_labels;
    two variables that are neighbours in memory and share a tag granule would
    need to share the same colour (as the shared tag granule can only store one
    colour).  */
-#define HWASAN_TAG_GRANULE_SIZE (1ULL << HWASAN_TAG_SIZE)
-/* How many bits to shift in order to access the tag bits.
-   This approach assumes that the tag is stored in the top N bits of a pointer,
-   and hence that shifting a known amount will leave just the tag bits.  */
-#define HWASAN_SHIFT 56
-#define HWASAN_SHIFT_RTX const_int_rtx[MAX_SAVED_CONST_INT + HWASAN_SHIFT]
+#define HWASAN_TAG_GRANULE_SIZE (HARDWARE_MEMORY_TAGGING ? targetm.memtag.granule_size () : (1ULL << HWASAN_TAG_SIZE))
+
+/*
+   The following HWASAN_* macros are only used when HARDWARE_MEMORY_TAGGING is
+   false, which is why we don't define anything for the case where it's true.
+ */
 /* Define the tag for the stack background.
    NOTE: Having a background colour of zero is hard-coded in the runtime
    library, so we can't really change this.
@@ -125,6 +125,11 @@ extern hash_set <tree> *asan_used_labels;
    ensure things like the return address etc can't be affected by accesses
    through pointer to a user-object.  */
 #define HWASAN_STACK_BACKGROUND 0
+/* How many bits to shift in order to access the tag bits.
+   This approach assumes that the tag is stored in the top N bits of a pointer,
+   and hence that shifting a known amount will leave just the tag bits.  */
+#define HWASAN_SHIFT 56
+#define HWASAN_SHIFT_RTX const_int_rtx[MAX_SAVED_CONST_INT + HWASAN_SHIFT]
 
 /* Various flags for Asan builtins.  */
 enum asan_check_flags
diff --git a/gcc/asan.c b/gcc/asan.c
index ad3d5a6451d3ecd9ff79b768c1e9a3fb92272a7e..5fc8e36865e5c442e7e68aa481c6899fde3ad16a 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -3914,7 +3914,7 @@ hwasan_increment_tag ()
 
      That's a help when debugging -- every variable should have a non-zero
      colour.  */
-  if (tag_offset == HWASAN_STACK_BACKGROUND)
+  if (! HARDWARE_MEMORY_TAGGING && tag_offset == HWASAN_STACK_BACKGROUND)
     tag_offset += 1;
 }
 
@@ -3947,7 +3947,9 @@ hwasan_tag_init ()
   asan_used_labels = NULL;
 
   hwasan_base_ptr = NULL_RTX;
-  tag_offset = HWASAN_STACK_BACKGROUND + 1;
+  tag_offset = HARDWARE_MEMORY_TAGGING
+    ? 0
+    : HWASAN_STACK_BACKGROUND + 1;
 }
 
 void
@@ -3958,7 +3960,8 @@ hwasan_emit_prologue (rtx *bases,
 		      size_t length)
 {
   /*
-    NOTE: bases contains both the tagged and untagged base.
+    NOTE: When running the software emulation we record both the tagged and
+    untagged bases.
     This allows us to get both the original frame tag and the untagged variable
     pointer with a minimal of extra instructions.
 
@@ -3969,8 +3972,8 @@ hwasan_emit_prologue (rtx *bases,
     pointers in __hwasan_tag_memory.  We need the tagged base pointer to obtain
     the base tag for an offset.
 
-    We also will need the tagged base pointer for MTE, since the ADDTAG
-    instruction takes a tagged pointer.
+    We need the tagged base pointer for MTE, since the ADDTAG instruction takes
+    a tagged pointer.
  */
   for (size_t i = 0; (i * 2) + 1 < length; i++)
     {
@@ -4002,19 +4005,29 @@ hwasan_emit_prologue (rtx *bases,
 	gcc_assert (tmp % HWASAN_TAG_GRANULE_SIZE == 0);
 
       /* TODO Other options (i.e. inline options)  */
-      /* TODO At the moment we don't generate a random base tag for each
-         frame.  When that happens we will need to generate the tag by
-         adding tags[i] to the frame tag fetched from `bases[i]`.  */
-      rtx ret = init_one_libfunc ("__hwasan_tag_memory");
-      emit_library_call (ret,
-	  LCT_NORMAL,
-	  VOIDmode,
-	  plus_constant (ptr_mode, untagged_bases[i], bot),
-	  ptr_mode,
-	  const_int_rtx[MAX_SAVED_CONST_INT + tags[i]],
-	  QImode,
-	  gen_int_mode (size, ptr_mode),
-	  ptr_mode);
+      if (! HARDWARE_MEMORY_TAGGING )
+	{
+	  /* TODO At the moment we don't generate a random base tag for each
+	     frame.  When that happens we will need to generate the tag by
+	     adding tags[i] to the frame tag fetched from `bases[i]`.  */
+	  rtx ret = init_one_libfunc ("__hwasan_tag_memory");
+	  emit_library_call (ret,
+			     LCT_NORMAL,
+			     VOIDmode,
+			     plus_constant (ptr_mode, untagged_bases[i], bot),
+			     ptr_mode,
+			     const_int_rtx[MAX_SAVED_CONST_INT + tags[i]],
+			     QImode,
+			     gen_int_mode (size, ptr_mode),
+			     ptr_mode);
+	}
+      else
+	{
+	  targetm.memtag.tag (bases[i],
+			      bot,
+			      tags[i],
+			      gen_int_mode (size, ptr_mode));
+	}
     }
 }
 
@@ -4046,11 +4059,19 @@ hwasan_emit_uncolour_frame (rtx dynamic, rtx vars, rtx_insn *before)
 				  NULL_RTX, /* unsignedp = */0, OPTAB_DIRECT);
 
   /* TODO Other options (i.e. inline options)  */
-  rtx ret = init_one_libfunc ("__hwasan_tag_memory");
-  emit_library_call (ret, LCT_NORMAL, VOIDmode,
-      bot_rtx, ptr_mode,
-      const0_rtx, QImode,
-      size_rtx, ptr_mode);
+  if (! HARDWARE_MEMORY_TAGGING )
+    {
+      rtx ret = init_one_libfunc ("__hwasan_tag_memory");
+      emit_library_call (ret, LCT_NORMAL, VOIDmode,
+			 bot_rtx, ptr_mode,
+			 const0_rtx, QImode,
+			 size_rtx, ptr_mode);
+    }
+  else
+    {
+      targetm.memtag.copy_tag (bot_rtx, stack_pointer_rtx);
+      targetm.memtag.tag (bot_rtx, 0, 0, size_rtx);
+    }
 
   do_pending_stack_adjust ();
   rtx_insn *insns = get_insns ();
@@ -4096,6 +4117,7 @@ static GTY(()) tree hwasan_ctor_statements;
 void
 hwasan_finish_file (void)
 {
+  gcc_assert (! HARDWARE_MEMORY_TAGGING);
   /* Avoid instrumenting code in the hwasan constructors/destructors.  */
   flag_sanitize &= ~SANITIZE_HWADDRESS;
   /* TODO Only do this if in userspace.
@@ -4113,6 +4135,7 @@ hwasan_finish_file (void)
 bool
 hwasan_expand_check_ifn (gimple_stmt_iterator *iter, bool)
 {
+  gcc_assert (! HARDWARE_MEMORY_TAGGING);
   // TODO For now only implementing the function when using calls.
   // This is a little easier, and means I can rely on the library
   // implementation while checking my instrumentation code for now.
@@ -4215,7 +4238,7 @@ hwasan_expand_mark_ifn (gimple_stmt_iterator *)
 bool
 gate_hwasan ()
 {
-  return memory_tagging_p ();
+  return memory_tagging_p () && ! HARDWARE_MEMORY_TAGGING;
 }
 bool
 hardware_memory_tagging_p ()
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 3f32754c4d35fc34af7c53156d2a356f69a94a8f..544d07b67a74875fdd93b152b5720f58a10931a1 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -5312,6 +5312,17 @@ expand_builtin_frame_address (tree fndecl, tree exp)
 static rtx
 expand_builtin_alloca (tree exp)
 {
+  /* TODO For hardware memory tagging we will need to call the backend to tag
+     this memory since the `hwasan` pass will not be run.
+
+     The `hwasan` pass is mainly to add HWASAN_CHECK internal functions where
+     checks should be made.  With hardware memory tagging the checks are done
+     automatically by the architecture.
+
+     The `hwasan` pass also modifies the behaviour of the alloca builtin
+     function in a target-independent manner, but when memory tagging is
+     handled by the backend it is more convenient to handle the tagging in the
+     alloca hook.  */
   rtx op0;
   rtx result;
   unsigned int align;
@@ -6932,6 +6943,9 @@ expand_builtin_set_thread_pointer (tree exp)
 static void
 expand_stack_restore (tree var)
 {
+  /* TODO If memory tagging is enabled through the hardware we need to uncolour
+     the stack from where we are to where we're going. (i.e. colour in the
+     background stack colour).  */
   rtx_insn *prev;
   rtx sa = expand_normal (var);
 
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 9f0872b32354cbc3186f3f2d2600f711a46926d1..061f00c2e1cf5d1b86fb3dd03d27fd0bf905721a 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -1041,6 +1041,8 @@ struct stack_vars_data
      ASAN records HOST_WIDE_INT offsets (that was enough before the
      introduction of SVE vectors) which  */
   auto_vec<poly_int64> hwasan_vec;
+  /* HWASAN needs to record untagged base pointers when there isn't hardware
+     memory tagging enabled by the architecture.  */
   auto_vec<rtx> hwasan_untagged_base_vec;
   auto_vec<rtx> hwasan_base_vec;
 
@@ -1174,7 +1176,8 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
 	      gcc_assert (stack_vars[i].alignb >= HWASAN_TAG_GRANULE_SIZE);
 	      offset = alloc_stack_frame_space (0, HWASAN_TAG_GRANULE_SIZE);
 	      data->hwasan_vec.safe_push (offset);
-	      data->hwasan_untagged_base_vec.safe_push (virtual_stack_vars_rtx);
+	      if (! HARDWARE_MEMORY_TAGGING)
+		data->hwasan_untagged_base_vec.safe_push (virtual_stack_vars_rtx);
 	    }
 	  /* ASAN description strings don't yet have a syntax for expressing
 	     polynomial offsets.  */
@@ -1290,10 +1293,18 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
 		 requirement means that the alignment requirement is greater
 		 than the required alignment for tags.
 		*/
-	      if (!large_untagged_base)
-		large_untagged_base = hwasan_create_untagged_base (large_base);
 	      data->hwasan_vec.safe_push (large_alloc);
-	      data->hwasan_untagged_base_vec.safe_push (large_untagged_base);
+
+	      if (! HARDWARE_MEMORY_TAGGING )
+	      {
+		/* We only need to record the untagged bases for HWASAN, since
+		   the runtime library for that doesn't accept tagged pointers.
+		   For hardware implementations of memory tagging there is no
+		   use of recording these untagged versions.  */
+		if (!large_untagged_base)
+		  large_untagged_base = hwasan_create_untagged_base (large_base);
+		data->hwasan_untagged_base_vec.safe_push (large_untagged_base);
+	      }
 	    }
 	  offset = large_alloc;
 	  large_alloc += stack_vars[i].size;
diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
index 7bd3bf525dd71347a12ed9cd2227bc2cd6e9cc55..8ea219f25ecb13d26e5d84ee45e8ced61c3e72a9 100644
--- a/gcc/config/aarch64/aarch64.h
+++ b/gcc/config/aarch64/aarch64.h
@@ -235,6 +235,7 @@ extern unsigned aarch64_architecture_version;
 #define AARCH64_ISA_F16FML	   (aarch64_isa_flags & AARCH64_FL_F16FML)
 #define AARCH64_ISA_RCPC8_4	   (aarch64_isa_flags & AARCH64_FL_RCPC8_4)
 #define AARCH64_ISA_V8_5	   (aarch64_isa_flags & AARCH64_FL_V8_5)
+#define AARCH64_ISA_MEMTAG	   (aarch64_isa_flags & AARCH64_FL_MEMTAG)
 
 /* Crypto is an optional extension to AdvSIMD.  */
 #define TARGET_CRYPTO (TARGET_SIMD && AARCH64_ISA_CRYPTO)
@@ -509,6 +510,10 @@ extern unsigned aarch64_architecture_version;
 #define EH_RETURN_STACKADJ_RTX	gen_rtx_REG (Pmode, R4_REGNUM)
 #define EH_RETURN_HANDLER_RTX  aarch64_eh_return_handler_rtx ()
 
+/* We have memory tag checking if we have the MEMTAG extension enabled and
+   hence want to handle that and colouring memory ourselves.  */
+#define HARDWARE_MEMORY_TAGGING AARCH64_ISA_MEMTAG
+
 /* Don't use __builtin_setjmp until we've defined it.  */
 #undef DONT_USE_BUILTIN_SETJMP
 #define DONT_USE_BUILTIN_SETJMP 1
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 8a290dcd9046be4775627dec0e9b3bf826ce3770..444021f81191a2eee3e50a4fcb4ae6ccb33182ab 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -18772,6 +18772,22 @@ aarch64_stack_protect_guard (void)
   return NULL_TREE;
 }
 
+/* Implement TARGET_MEMTAG_TAG for AArch64. This is only available when
+   AARCH64_ISA_MEMTAG is available.  TODO Eventually we would just want
+   something to emit a loop of STG or ST2G.  Currently unimplemented.  */
+void
+aarch64_tag_memory (rtx tagged_start, poly_int64 address_offset, uint8_t tag_offset,
+		    rtx size)
+{
+  return;
+}
+
+void
+aarch64_gentag (rtx a, rtx b)
+{
+  emit_insn (gen_random_tag (a, b));
+}
+
 /* Implement TARGET_ASM_FILE_END for AArch64.  This adds the AArch64 GNU NOTE
    section at the end if needed.  */
 #define GNU_PROPERTY_AARCH64_FEATURE_1_AND	0xc0000000
@@ -19336,6 +19352,14 @@ aarch64_libgcc_floating_mode_supported_p
 #undef TARGET_GET_MULTILIB_ABI_NAME
 #define TARGET_GET_MULTILIB_ABI_NAME aarch64_get_multilib_abi_name
 
+#ifdef AARCH64_ISA_MEMTAG
+#undef TARGET_MEMTAG_TAG
+#define TARGET_MEMTAG_TAG aarch64_tag_memory
+
+#undef TARGET_MEMTAG_GENTAG
+#define TARGET_MEMTAG_GENTAG aarch64_gentag
+#endif
+
 #if CHECKING_P
 #undef TARGET_RUN_TARGET_SELFTESTS
 #define TARGET_RUN_TARGET_SELFTESTS selftest::aarch64_run_selftests
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index cb0d3ae6bbf3ed439c7b27683726f4c30b04777d..70a927b6b70e4e498d962c5e9cf1344f2661e377 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -231,6 +231,7 @@ (define_c_enum "unspec" [
     UNSPEC_REV_SUBREG
     UNSPEC_SPECULATION_TRACKER
     UNSPEC_COPYSIGN
+    UNSPEC_GENTAG
 ])
 
 (define_c_enum "unspecv" [
@@ -409,6 +410,30 @@ (define_expand "cbranch<mode>4"
   "
 )
 
+;; TODO
+;;    Need to put in some sort of random tag here.
+;;    At the moment skipping it because I don't know what instructions to use.
+;;    (plus, starting at zero means that I can know what to expect during
+;;    development.
+(define_insn "random_tag"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(unspec:DI [(match_operand:DI 1 "register_operand" "r")] UNSPEC_GENTAG))]
+  ""
+  ;; "AARCH64_ISA_MEMTAG"
+  "mov\\t%0, %1 // irg\\t%0, %1"
+)
+
+(define_insn "plain_offset_tag<mode>"
+  [(set (match_operand:GPI 0 "register_operand" "=r,r")
+    (addtag:GPI (match_operand:GPI 1 "register_operand" "r,r")
+     (match_operand:GPI 2 "aarch64_MTE_value_offset" "I,J")
+     (match_operand:GPI 3 "aarch64_MTE_tag_offset" "i,i")))]
+  "AARCH64_ISA_MEMTAG"
+  "@
+  add\\t%0, %1, %2     // addg\\t%0, %1, %2, %3
+  sub\\t%0, %1, #%n2   // subg\\t%0, %1, #%n2, %3"
+)
+
 (define_expand "addtag<mode>4"
   [(set (match_operand:GPI 0 "register_operand" "")
     (addtag:GPI (match_operand:GPI 1 "register_operand" "")
@@ -417,13 +442,41 @@ (define_expand "addtag<mode>4"
   ""
 {
   gcc_assert (can_create_pseudo_p ());
-  /* Simply add the two values as a constant and use that.  The adddi pattern
-     will handle the fact that the integer is out of range for ADD.  */
-  poly_int64 val = rtx_to_poly_int64 (operands[2]);
-  val += ((uint64_t)INTVAL(operands[3]) << 56);
-  emit_insn (gen_add<mode>3 (operands[0], operands[1],
-			     immed_wide_int_const (val, <MODE>mode)));
-  DONE;
+
+  if (!AARCH64_ISA_MEMTAG)
+    {
+      /* TODO
+	  Need to look into what the most efficient code sequence is.
+	  Right now just want something to work so I can bootstrap again and
+	  check for mistakes.
+
+	  This is a code sequence that would be emitted *many* times, so we
+	  want it as small as possible.
+	*/
+    /* Simply add the two values as a constant and use that.  The adddi
+       pattern will handle the fact that the integer is out of the
+       representable range.  */
+      poly_int64 val = rtx_to_poly_int64 (operands[2]);
+      val += ((uint64_t)INTVAL(operands[3]) << 56);
+      emit_insn (gen_add<mode>3 (operands[0], operands[1],
+				 immed_wide_int_const (val, <MODE>mode)));
+      DONE;
+    }
+  else if (!aarch64_MTE_value_offset (operands[2], <MODE>mode))
+    {
+      /* Must always be able to create a pseudo register.
+	 This pattern requires the ability to generate new pseudo registers,
+	 since there's no way to handle a constant that's too large other than
+         adding that constant into the current register.
+         If we had a too-large constant at the point where we can't create a
+         pseudo register, then using the basic `plus` pattern would end up with
+         a `plus` pattern that has a too-large constant, which would fail there
+         instead of here. */
+      rtx newreg = gen_reg_rtx (<MODE>mode);
+      emit_insn (gen_add<mode>3 (newreg, operands[1], operands[2]));
+      operands[2] = const0_rtx;
+      operands[1] = newreg;
+    }
 })
 
 (define_expand "cbranchcc4"
diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md
index e2aa0290f833fbffedec1d8dab219f72eb17419e..0edfb6de7d1ddb466d114b7510e58499117061c5 100644
--- a/gcc/config/aarch64/predicates.md
+++ b/gcc/config/aarch64/predicates.md
@@ -141,6 +141,13 @@ (define_predicate "aarch64_MTE_tag_offset"
   (and (match_code "const_int")
        (match_test "IN_RANGE (INTVAL (op), 0, 16)")))
 
+;; TODO
+;;    Will have to change the constant from 4096 to 64 when switching to addg.
+(define_predicate "aarch64_MTE_value_offset"
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (INTVAL (op), -4096, 4096)")))
+
+
 (define_predicate "aarch64_pluslong_strict_immedate"
   (and (match_operand 0 "aarch64_pluslong_immediate")
        (not (match_operand 0 "aarch64_plus_immediate"))))
diff --git a/gcc/defaults.h b/gcc/defaults.h
index b7534256119bd7834f2fa9d5f32863822d3b393a..b47fe6b35554091c9f3228169ad1f6ff4c692b14 100644
--- a/gcc/defaults.h
+++ b/gcc/defaults.h
@@ -1294,6 +1294,16 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define EH_RETURN_HANDLER_RTX NULL
 #endif
 
+/* Indicate whether this backend has automatic access checks for tagged
+   pointers (i.e. HWASAN) if so then HWASAN memory tagging can be implemented
+   with much less instrumentation.
+   If a backend advertises that they have this it must also handle tagging
+   shadow memory themselves by implementing TARGET_MEMORY_TAG and avoiding the
+   background stack colour automatically in the addtag pattern.  */
+#ifndef HARDWARE_MEMORY_TAGGING
+#define HARDWARE_MEMORY_TAGGING 0
+#endif
+
 #ifdef GCC_INSN_FLAGS_H
 /* Dependent default target macro definitions
 
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 67d79a23799cd3057f7d91bd538c7ee76c836f82..7f0cc257a6634e3b0a2013b7fb9ffa4083f19038 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -2968,6 +2968,30 @@ This hook defines the machine mode to use for the boolean result of  conditional
 A target hook which lets a backend compute the set of pressure classes to  be used by those optimization passes which take register pressure into  account, as opposed to letting IRA compute them.  It returns the number of  register classes stored in the array @var{pressure_classes}.
 @end deftypefn
 
+@deftypefn {Target Hook} uint8_t TARGET_MEMTAG_TAG_SIZE ()
+Return the size in bits of a tag for this platform.
+@end deftypefn
+
+@deftypefn {Target Hook} uint8_t TARGET_MEMTAG_GRANULE_SIZE ()
+Return how many bytes in real memory each byte in shadow memory represents.
+I.e. one byte in shadow memory being colour 1 implies the assocaiated
+targetm.memtag.granule_size () bytes in real memory must all be accessed by
+pointers tagged as 1.
+@end deftypefn
+
+@deftypefn {Target Hook} void TARGET_MEMTAG_COPY_TAG (rtx @var{to}, rtx @var{from})
+Emit insns to copy the tag in FROM to TO.
+@end deftypefn
+
+@deftypefn {Target Hook} void TARGET_MEMTAG_TAG (rtx @var{tagged_start}, poly_int64 @var{address_offset}, uint8_t @var{tag_offset}, rtx @var{size})
+This function should emit an RTX to colour memory.
+It's given arguments TAGGED_START, ADDRESS_OFFSET, TAG_OFFSET, SIZE, where
+TAGGED_START and SIZE are RTL expressions, ADDRESS_OFFSET is a poly_int64
+and TAG_OFFSET is a uint8_t.
+It should emit RTL to colour "shadow memory" for the relevant range the
+colour of the tag it was given.
+@end deftypefn
+
 @deftypefn {Target Hook} void TARGET_MEMTAG_GENTAG (rtx @var{base}, rtx @var{untagged})
 Set the BASE argument to UNTAGGED with some random tag.
 This function is used to generate a tagged base for the current stack frame.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index e1ec503befadb4061fbd3b95e55757fe22d33c39..6c77c09fca161dc3ade98d81b16c1b01af3c0bc7 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2370,6 +2370,14 @@ in the reload pass.
 
 @hook TARGET_COMPUTE_PRESSURE_CLASSES
 
+@hook TARGET_MEMTAG_TAG_SIZE
+
+@hook TARGET_MEMTAG_GRANULE_SIZE
+
+@hook TARGET_MEMTAG_COPY_TAG
+
+@hook TARGET_MEMTAG_TAG
+
 @hook TARGET_MEMTAG_GENTAG
 
 @node Stack and Calling
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index c530fe8951c30987c874df83e74be6d058730134..a58a55ad59b2ad7a6b93e2f5f2bbb40b8da51c5e 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -503,9 +503,6 @@ expand_HWASAN_MARK (internal_fn, gcall *gc)
   gcc_checking_assert (TREE_CODE (base) == ADDR_EXPR);
   rtx base_rtx = expand_normal (base);
 
-  rtx tag = is_poison ? const0_rtx : hwasan_extract_tag (base_rtx);
-  rtx address = hwasan_create_untagged_base (base_rtx);
-
   tree len = gimple_call_arg (gc, 2);
   gcc_assert (tree_fits_shwi_p (len));
   unsigned HOST_WIDE_INT size_in_bytes = tree_to_shwi (len);
@@ -515,13 +512,24 @@ expand_HWASAN_MARK (internal_fn, gcall *gc)
   rtx size = gen_int_mode (size_in_bytes, Pmode);
 
   /* TODO Other options (i.e. inline options)  */
-  rtx func = init_one_libfunc ("__hwasan_tag_memory");
-  emit_library_call (func,
-      LCT_NORMAL,
-      VOIDmode,
-      address, ptr_mode,
-      tag, QImode,
-      size, ptr_mode);
+  if (! HARDWARE_MEMORY_TAGGING )
+    {
+      rtx func = init_one_libfunc ("__hwasan_tag_memory");
+      rtx address = hwasan_create_untagged_base (base_rtx);
+      rtx tag = is_poison ? const0_rtx : hwasan_extract_tag (base_rtx);
+      emit_library_call (func,
+			 LCT_NORMAL,
+			 VOIDmode,
+			 address, ptr_mode,
+			 tag, QImode,
+			 size, ptr_mode);
+    }
+  else
+    {
+      if (is_poison)
+	targetm.memtag.copy_tag (base_rtx, stack_pointer_rtx);
+      targetm.memtag.tag (base_rtx, 0, 0, size);
+    }
 }
 
 /* This should get expanded in the sanopt pass.  */
diff --git a/gcc/target.def b/gcc/target.def
index 5326cb070dec78f19bfe0844a9d5e50c69e7dcc1..e0c543254538c802e1e0a059e1a3e60a045a0cdf 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -6709,6 +6709,34 @@ HOOK_VECTOR_END (mode_switching)
 HOOK_VECTOR (TARGET_MEMTAG_, memtag)
 
 DEFHOOK
+(tag_size,
+ "Return the size in bits of a tag for this platform.",
+ uint8_t, (), default_memtag_tag_size)
+
+DEFHOOK
+(granule_size,
+ "Return how many bytes in real memory each byte in shadow memory represents.\n\
+I.e. one byte in shadow memory being colour 1 implies the assocaiated\n\
+targetm.memtag.granule_size () bytes in real memory must all be accessed by\n\
+pointers tagged as 1.",
+uint8_t, (), default_memtag_granule_size)
+
+DEFHOOK
+(copy_tag,
+ "Emit insns to copy the tag in FROM to TO.",
+void, (rtx to, rtx from), default_memtag_copy_tag)
+
+DEFHOOK
+(tag,
+ "This function should emit an RTX to colour memory.\n\
+It's given arguments TAGGED_START, ADDRESS_OFFSET, TAG_OFFSET, SIZE, where\n\
+TAGGED_START and SIZE are RTL expressions, ADDRESS_OFFSET is a poly_int64\n\
+and TAG_OFFSET is a uint8_t.\n\
+It should emit RTL to colour \"shadow memory\" for the relevant range the\n\
+colour of the tag it was given.",
+  void, (rtx tagged_start, poly_int64 address_offset, uint8_t tag_offset, rtx size), NULL)
+
+DEFHOOK
 (gentag,
  "Set the BASE argument to UNTAGGED with some random tag.\n\
 This function is used to generate a tagged base for the current stack frame.",
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index 493ff3bb29263f8360bea0f7ead1092b4d0c646a..1c09bbad964b7705eea493a828d5906ad07481b6 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -288,5 +288,8 @@ extern rtx default_speculation_safe_value (machine_mode, rtx, rtx, rtx);
 extern void default_remove_extra_call_preserved_regs (rtx_insn *,
 						      HARD_REG_SET *);
 
+extern uint8_t default_memtag_tag_size ();
+extern uint8_t default_memtag_granule_size ();
 extern void default_memtag_gentag (rtx, rtx);
+extern void default_memtag_copy_tag (rtx, rtx);
 #endif /* GCC_TARGHOOKS_H */
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index 58ec711ce81ee67d692e81d2616bd3422f6bd092..bf078295cbd9514778454cef775dd288fd502641 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -70,6 +70,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "varasm.h"
 #include "flags.h"
 #include "explow.h"
+#include "expmed.h"
 #include "calls.h"
 #include "expr.h"
 #include "output.h"
@@ -83,6 +84,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "real.h"
 #include "langhooks.h"
 #include "sbitmap.h"
+#include "attribs.h"
+#include "asan.h"
 
 bool
 default_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED,
@@ -2391,6 +2394,18 @@ default_remove_extra_call_preserved_regs (rtx_insn *, HARD_REG_SET *)
 {
 }
 
+uint8_t
+default_memtag_tag_size ()
+{
+  return 4;
+}
+
+uint8_t
+default_memtag_granule_size ()
+{
+  return 1ULL << default_memtag_tag_size ();
+}
+
 void
 default_memtag_gentag (rtx base, rtx untagged)
 {
@@ -2402,5 +2417,40 @@ default_memtag_gentag (rtx base, rtx untagged)
   emit_move_insn (base, untagged);
 }
 
+void
+default_memtag_copy_tag (rtx to, rtx from)
+{
+  /* TODO: For AArch64 this can cause a problem in LRA if the `to`
+     RTX eventually resolves to being the stack pointer.
+     This happens because the instruction that gets emitted from
+     `store_bit_field` corresponds to a pattern that can't handle the stack
+     pointer and LRA can't figure out to use a temporary register in the `bfi`
+     instruction's place.
+
+     This doesn't cause a problem at the moment since there's currently no way
+     the stack pointer should be given to this function.  The hook is only used
+     when poisoning variables with HWASAN_MARK, and in that function the `to`
+     RTX should always be pointing to a tagged variable on the stack (since
+     the variable is tagged it can't be the stack pointer since that is
+     untagged).
+
+     Eventually we will be generating random tags as the "start" tag for each
+     frame.  When this happens we can no longer avoid the background colour at
+     compile time since we will not know what offset to avoid.
+     This will mean we no longer avoid a `tag_offset` of 0, and hence
+     `hwasan_with_tag` could emit simple PLUS statements.
+
+     When that happens, the last variable on the stack could very well have
+     a zero tag offset and somewhere else in the compiler could optimise that
+     to simply use the stack pointer.
+
+     That would trigger an ICE due to LRA being unable to reload the
+     `insv_regdi` pattern.
+
+     This is another thing that needs to be fixed but I'll deal with later.  */
+  rtx temp = hwasan_extract_tag (from);
+  store_bit_field (to, 8, 56, 0, 0,
+		   QImode, temp, false);
+}
 
 #include "gt-targhooks.h"


[-- Attachment #2: hwasan-implementation14.patch --]
[-- Type: text/plain, Size: 27735 bytes --]

diff --git a/gcc/asan.h b/gcc/asan.h
index 6e5ba8be606e9a1eae2afe57f17ccca5562167fd..2d697158a15e7e3078902c4fb742819f90b9a0c4 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -27,10 +27,10 @@ extern void hwasan_finish_file (void);
 extern void hwasan_record_base (rtx);
 extern uint8_t hwasan_current_tag ();
 extern void hwasan_increment_tag ();
+extern rtx hwasan_extract_tag (rtx);
 extern rtx hwasan_with_tag (rtx, poly_int64);
 extern void hwasan_tag_init ();
 extern rtx hwasan_create_untagged_base (rtx);
-extern rtx hwasan_extract_tag (rtx tagged_pointer);
 extern rtx hwasan_base ();
 extern void hwasan_emit_prologue (rtx *, rtx *, poly_int64 *, uint8_t *, size_t);
 extern rtx_insn *hwasan_emit_uncolour_frame (rtx, rtx, rtx_insn *);
@@ -100,7 +100,7 @@ extern hash_set <tree> *asan_used_labels;
    required.
    If changing this value, be careful of the predicates/constraints on the
    addtag<mode>4 patterns in the backend.  */
-#define HWASAN_TAG_SIZE 4
+#define HWASAN_TAG_SIZE (HARDWARE_MEMORY_TAGGING ? targetm.memtag.tag_size () : 4)
 /* Tag Granule of HWASAN shadow stack.
    This is the size in real memory that each byte in the shadow memory refers
    to.  I.e. if a variable is X bytes long in memory then it's colour in shadow
@@ -109,12 +109,12 @@ extern hash_set <tree> *asan_used_labels;
    two variables that are neighbours in memory and share a tag granule would
    need to share the same colour (as the shared tag granule can only store one
    colour).  */
-#define HWASAN_TAG_GRANULE_SIZE (1ULL << HWASAN_TAG_SIZE)
-/* How many bits to shift in order to access the tag bits.
-   This approach assumes that the tag is stored in the top N bits of a pointer,
-   and hence that shifting a known amount will leave just the tag bits.  */
-#define HWASAN_SHIFT 56
-#define HWASAN_SHIFT_RTX const_int_rtx[MAX_SAVED_CONST_INT + HWASAN_SHIFT]
+#define HWASAN_TAG_GRANULE_SIZE (HARDWARE_MEMORY_TAGGING ? targetm.memtag.granule_size () : (1ULL << HWASAN_TAG_SIZE))
+
+/*
+   The following HWASAN_* macros are only used when HARDWARE_MEMORY_TAGGING is
+   false, which is why we don't define anything for the case where it's true.
+ */
 /* Define the tag for the stack background.
    NOTE: Having a background colour of zero is hard-coded in the runtime
    library, so we can't really change this.
@@ -125,6 +125,11 @@ extern hash_set <tree> *asan_used_labels;
    ensure things like the return address etc can't be affected by accesses
    through pointer to a user-object.  */
 #define HWASAN_STACK_BACKGROUND 0
+/* How many bits to shift in order to access the tag bits.
+   This approach assumes that the tag is stored in the top N bits of a pointer,
+   and hence that shifting a known amount will leave just the tag bits.  */
+#define HWASAN_SHIFT 56
+#define HWASAN_SHIFT_RTX const_int_rtx[MAX_SAVED_CONST_INT + HWASAN_SHIFT]
 
 /* Various flags for Asan builtins.  */
 enum asan_check_flags
diff --git a/gcc/asan.c b/gcc/asan.c
index ad3d5a6451d3ecd9ff79b768c1e9a3fb92272a7e..5fc8e36865e5c442e7e68aa481c6899fde3ad16a 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -3914,7 +3914,7 @@ hwasan_increment_tag ()
 
      That's a help when debugging -- every variable should have a non-zero
      colour.  */
-  if (tag_offset == HWASAN_STACK_BACKGROUND)
+  if (! HARDWARE_MEMORY_TAGGING && tag_offset == HWASAN_STACK_BACKGROUND)
     tag_offset += 1;
 }
 
@@ -3947,7 +3947,9 @@ hwasan_tag_init ()
   asan_used_labels = NULL;
 
   hwasan_base_ptr = NULL_RTX;
-  tag_offset = HWASAN_STACK_BACKGROUND + 1;
+  tag_offset = HARDWARE_MEMORY_TAGGING
+    ? 0
+    : HWASAN_STACK_BACKGROUND + 1;
 }
 
 void
@@ -3958,7 +3960,8 @@ hwasan_emit_prologue (rtx *bases,
 		      size_t length)
 {
   /*
-    NOTE: bases contains both the tagged and untagged base.
+    NOTE: When running the software emulation we record both the tagged and
+    untagged bases.
     This allows us to get both the original frame tag and the untagged variable
     pointer with a minimal of extra instructions.
 
@@ -3969,8 +3972,8 @@ hwasan_emit_prologue (rtx *bases,
     pointers in __hwasan_tag_memory.  We need the tagged base pointer to obtain
     the base tag for an offset.
 
-    We also will need the tagged base pointer for MTE, since the ADDTAG
-    instruction takes a tagged pointer.
+    We need the tagged base pointer for MTE, since the ADDTAG instruction takes
+    a tagged pointer.
  */
   for (size_t i = 0; (i * 2) + 1 < length; i++)
     {
@@ -4002,19 +4005,29 @@ hwasan_emit_prologue (rtx *bases,
 	gcc_assert (tmp % HWASAN_TAG_GRANULE_SIZE == 0);
 
       /* TODO Other options (i.e. inline options)  */
-      /* TODO At the moment we don't generate a random base tag for each
-         frame.  When that happens we will need to generate the tag by
-         adding tags[i] to the frame tag fetched from `bases[i]`.  */
-      rtx ret = init_one_libfunc ("__hwasan_tag_memory");
-      emit_library_call (ret,
-	  LCT_NORMAL,
-	  VOIDmode,
-	  plus_constant (ptr_mode, untagged_bases[i], bot),
-	  ptr_mode,
-	  const_int_rtx[MAX_SAVED_CONST_INT + tags[i]],
-	  QImode,
-	  gen_int_mode (size, ptr_mode),
-	  ptr_mode);
+      if (! HARDWARE_MEMORY_TAGGING )
+	{
+	  /* TODO At the moment we don't generate a random base tag for each
+	     frame.  When that happens we will need to generate the tag by
+	     adding tags[i] to the frame tag fetched from `bases[i]`.  */
+	  rtx ret = init_one_libfunc ("__hwasan_tag_memory");
+	  emit_library_call (ret,
+			     LCT_NORMAL,
+			     VOIDmode,
+			     plus_constant (ptr_mode, untagged_bases[i], bot),
+			     ptr_mode,
+			     const_int_rtx[MAX_SAVED_CONST_INT + tags[i]],
+			     QImode,
+			     gen_int_mode (size, ptr_mode),
+			     ptr_mode);
+	}
+      else
+	{
+	  targetm.memtag.tag (bases[i],
+			      bot,
+			      tags[i],
+			      gen_int_mode (size, ptr_mode));
+	}
     }
 }
 
@@ -4046,11 +4059,19 @@ hwasan_emit_uncolour_frame (rtx dynamic, rtx vars, rtx_insn *before)
 				  NULL_RTX, /* unsignedp = */0, OPTAB_DIRECT);
 
   /* TODO Other options (i.e. inline options)  */
-  rtx ret = init_one_libfunc ("__hwasan_tag_memory");
-  emit_library_call (ret, LCT_NORMAL, VOIDmode,
-      bot_rtx, ptr_mode,
-      const0_rtx, QImode,
-      size_rtx, ptr_mode);
+  if (! HARDWARE_MEMORY_TAGGING )
+    {
+      rtx ret = init_one_libfunc ("__hwasan_tag_memory");
+      emit_library_call (ret, LCT_NORMAL, VOIDmode,
+			 bot_rtx, ptr_mode,
+			 const0_rtx, QImode,
+			 size_rtx, ptr_mode);
+    }
+  else
+    {
+      targetm.memtag.copy_tag (bot_rtx, stack_pointer_rtx);
+      targetm.memtag.tag (bot_rtx, 0, 0, size_rtx);
+    }
 
   do_pending_stack_adjust ();
   rtx_insn *insns = get_insns ();
@@ -4096,6 +4117,7 @@ static GTY(()) tree hwasan_ctor_statements;
 void
 hwasan_finish_file (void)
 {
+  gcc_assert (! HARDWARE_MEMORY_TAGGING);
   /* Avoid instrumenting code in the hwasan constructors/destructors.  */
   flag_sanitize &= ~SANITIZE_HWADDRESS;
   /* TODO Only do this if in userspace.
@@ -4113,6 +4135,7 @@ hwasan_finish_file (void)
 bool
 hwasan_expand_check_ifn (gimple_stmt_iterator *iter, bool)
 {
+  gcc_assert (! HARDWARE_MEMORY_TAGGING);
   // TODO For now only implementing the function when using calls.
   // This is a little easier, and means I can rely on the library
   // implementation while checking my instrumentation code for now.
@@ -4215,7 +4238,7 @@ hwasan_expand_mark_ifn (gimple_stmt_iterator *)
 bool
 gate_hwasan ()
 {
-  return memory_tagging_p ();
+  return memory_tagging_p () && ! HARDWARE_MEMORY_TAGGING;
 }
 bool
 hardware_memory_tagging_p ()
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 3f32754c4d35fc34af7c53156d2a356f69a94a8f..544d07b67a74875fdd93b152b5720f58a10931a1 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -5312,6 +5312,17 @@ expand_builtin_frame_address (tree fndecl, tree exp)
 static rtx
 expand_builtin_alloca (tree exp)
 {
+  /* TODO For hardware memory tagging we will need to call the backend to tag
+     this memory since the `hwasan` pass will not be run.
+
+     The `hwasan` pass is mainly to add HWASAN_CHECK internal functions where
+     checks should be made.  With hardware memory tagging the checks are done
+     automatically by the architecture.
+
+     The `hwasan` pass also modifies the behaviour of the alloca builtin
+     function in a target-independent manner, but when memory tagging is
+     handled by the backend it is more convenient to handle the tagging in the
+     alloca hook.  */
   rtx op0;
   rtx result;
   unsigned int align;
@@ -6932,6 +6943,9 @@ expand_builtin_set_thread_pointer (tree exp)
 static void
 expand_stack_restore (tree var)
 {
+  /* TODO If memory tagging is enabled through the hardware we need to uncolour
+     the stack from where we are to where we're going. (i.e. colour in the
+     background stack colour).  */
   rtx_insn *prev;
   rtx sa = expand_normal (var);
 
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 9f0872b32354cbc3186f3f2d2600f711a46926d1..061f00c2e1cf5d1b86fb3dd03d27fd0bf905721a 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -1041,6 +1041,8 @@ struct stack_vars_data
      ASAN records HOST_WIDE_INT offsets (that was enough before the
      introduction of SVE vectors) which  */
   auto_vec<poly_int64> hwasan_vec;
+  /* HWASAN needs to record untagged base pointers when there isn't hardware
+     memory tagging enabled by the architecture.  */
   auto_vec<rtx> hwasan_untagged_base_vec;
   auto_vec<rtx> hwasan_base_vec;
 
@@ -1174,7 +1176,8 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
 	      gcc_assert (stack_vars[i].alignb >= HWASAN_TAG_GRANULE_SIZE);
 	      offset = alloc_stack_frame_space (0, HWASAN_TAG_GRANULE_SIZE);
 	      data->hwasan_vec.safe_push (offset);
-	      data->hwasan_untagged_base_vec.safe_push (virtual_stack_vars_rtx);
+	      if (! HARDWARE_MEMORY_TAGGING)
+		data->hwasan_untagged_base_vec.safe_push (virtual_stack_vars_rtx);
 	    }
 	  /* ASAN description strings don't yet have a syntax for expressing
 	     polynomial offsets.  */
@@ -1290,10 +1293,18 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
 		 requirement means that the alignment requirement is greater
 		 than the required alignment for tags.
 		*/
-	      if (!large_untagged_base)
-		large_untagged_base = hwasan_create_untagged_base (large_base);
 	      data->hwasan_vec.safe_push (large_alloc);
-	      data->hwasan_untagged_base_vec.safe_push (large_untagged_base);
+
+	      if (! HARDWARE_MEMORY_TAGGING )
+	      {
+		/* We only need to record the untagged bases for HWASAN, since
+		   the runtime library for that doesn't accept tagged pointers.
+		   For hardware implementations of memory tagging there is no
+		   use of recording these untagged versions.  */
+		if (!large_untagged_base)
+		  large_untagged_base = hwasan_create_untagged_base (large_base);
+		data->hwasan_untagged_base_vec.safe_push (large_untagged_base);
+	      }
 	    }
 	  offset = large_alloc;
 	  large_alloc += stack_vars[i].size;
diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
index 7bd3bf525dd71347a12ed9cd2227bc2cd6e9cc55..8ea219f25ecb13d26e5d84ee45e8ced61c3e72a9 100644
--- a/gcc/config/aarch64/aarch64.h
+++ b/gcc/config/aarch64/aarch64.h
@@ -235,6 +235,7 @@ extern unsigned aarch64_architecture_version;
 #define AARCH64_ISA_F16FML	   (aarch64_isa_flags & AARCH64_FL_F16FML)
 #define AARCH64_ISA_RCPC8_4	   (aarch64_isa_flags & AARCH64_FL_RCPC8_4)
 #define AARCH64_ISA_V8_5	   (aarch64_isa_flags & AARCH64_FL_V8_5)
+#define AARCH64_ISA_MEMTAG	   (aarch64_isa_flags & AARCH64_FL_MEMTAG)
 
 /* Crypto is an optional extension to AdvSIMD.  */
 #define TARGET_CRYPTO (TARGET_SIMD && AARCH64_ISA_CRYPTO)
@@ -509,6 +510,10 @@ extern unsigned aarch64_architecture_version;
 #define EH_RETURN_STACKADJ_RTX	gen_rtx_REG (Pmode, R4_REGNUM)
 #define EH_RETURN_HANDLER_RTX  aarch64_eh_return_handler_rtx ()
 
+/* We have memory tag checking if we have the MEMTAG extension enabled and
+   hence want to handle that and colouring memory ourselves.  */
+#define HARDWARE_MEMORY_TAGGING AARCH64_ISA_MEMTAG
+
 /* Don't use __builtin_setjmp until we've defined it.  */
 #undef DONT_USE_BUILTIN_SETJMP
 #define DONT_USE_BUILTIN_SETJMP 1
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 8a290dcd9046be4775627dec0e9b3bf826ce3770..444021f81191a2eee3e50a4fcb4ae6ccb33182ab 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -18772,6 +18772,22 @@ aarch64_stack_protect_guard (void)
   return NULL_TREE;
 }
 
+/* Implement TARGET_MEMTAG_TAG for AArch64. This is only available when
+   AARCH64_ISA_MEMTAG is available.  TODO Eventually we would just want
+   something to emit a loop of STG or ST2G.  Currently unimplemented.  */
+void
+aarch64_tag_memory (rtx tagged_start, poly_int64 address_offset, uint8_t tag_offset,
+		    rtx size)
+{
+  return;
+}
+
+void
+aarch64_gentag (rtx a, rtx b)
+{
+  emit_insn (gen_random_tag (a, b));
+}
+
 /* Implement TARGET_ASM_FILE_END for AArch64.  This adds the AArch64 GNU NOTE
    section at the end if needed.  */
 #define GNU_PROPERTY_AARCH64_FEATURE_1_AND	0xc0000000
@@ -19336,6 +19352,14 @@ aarch64_libgcc_floating_mode_supported_p
 #undef TARGET_GET_MULTILIB_ABI_NAME
 #define TARGET_GET_MULTILIB_ABI_NAME aarch64_get_multilib_abi_name
 
+#ifdef AARCH64_ISA_MEMTAG
+#undef TARGET_MEMTAG_TAG
+#define TARGET_MEMTAG_TAG aarch64_tag_memory
+
+#undef TARGET_MEMTAG_GENTAG
+#define TARGET_MEMTAG_GENTAG aarch64_gentag
+#endif
+
 #if CHECKING_P
 #undef TARGET_RUN_TARGET_SELFTESTS
 #define TARGET_RUN_TARGET_SELFTESTS selftest::aarch64_run_selftests
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index cb0d3ae6bbf3ed439c7b27683726f4c30b04777d..70a927b6b70e4e498d962c5e9cf1344f2661e377 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -231,6 +231,7 @@ (define_c_enum "unspec" [
     UNSPEC_REV_SUBREG
     UNSPEC_SPECULATION_TRACKER
     UNSPEC_COPYSIGN
+    UNSPEC_GENTAG
 ])
 
 (define_c_enum "unspecv" [
@@ -409,6 +410,30 @@ (define_expand "cbranch<mode>4"
   "
 )
 
+;; TODO
+;;    Need to put in some sort of random tag here.
+;;    At the moment skipping it because I don't know what instructions to use.
+;;    (plus, starting at zero means that I can know what to expect during
+;;    development.
+(define_insn "random_tag"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+	(unspec:DI [(match_operand:DI 1 "register_operand" "r")] UNSPEC_GENTAG))]
+  ""
+  ;; "AARCH64_ISA_MEMTAG"
+  "mov\\t%0, %1 // irg\\t%0, %1"
+)
+
+(define_insn "plain_offset_tag<mode>"
+  [(set (match_operand:GPI 0 "register_operand" "=r,r")
+    (addtag:GPI (match_operand:GPI 1 "register_operand" "r,r")
+     (match_operand:GPI 2 "aarch64_MTE_value_offset" "I,J")
+     (match_operand:GPI 3 "aarch64_MTE_tag_offset" "i,i")))]
+  "AARCH64_ISA_MEMTAG"
+  "@
+  add\\t%0, %1, %2     // addg\\t%0, %1, %2, %3
+  sub\\t%0, %1, #%n2   // subg\\t%0, %1, #%n2, %3"
+)
+
 (define_expand "addtag<mode>4"
   [(set (match_operand:GPI 0 "register_operand" "")
     (addtag:GPI (match_operand:GPI 1 "register_operand" "")
@@ -417,13 +442,41 @@ (define_expand "addtag<mode>4"
   ""
 {
   gcc_assert (can_create_pseudo_p ());
-  /* Simply add the two values as a constant and use that.  The adddi pattern
-     will handle the fact that the integer is out of range for ADD.  */
-  poly_int64 val = rtx_to_poly_int64 (operands[2]);
-  val += ((uint64_t)INTVAL(operands[3]) << 56);
-  emit_insn (gen_add<mode>3 (operands[0], operands[1],
-			     immed_wide_int_const (val, <MODE>mode)));
-  DONE;
+
+  if (!AARCH64_ISA_MEMTAG)
+    {
+      /* TODO
+	  Need to look into what the most efficient code sequence is.
+	  Right now just want something to work so I can bootstrap again and
+	  check for mistakes.
+
+	  This is a code sequence that would be emitted *many* times, so we
+	  want it as small as possible.
+	*/
+    /* Simply add the two values as a constant and use that.  The adddi
+       pattern will handle the fact that the integer is out of the
+       representable range.  */
+      poly_int64 val = rtx_to_poly_int64 (operands[2]);
+      val += ((uint64_t)INTVAL(operands[3]) << 56);
+      emit_insn (gen_add<mode>3 (operands[0], operands[1],
+				 immed_wide_int_const (val, <MODE>mode)));
+      DONE;
+    }
+  else if (!aarch64_MTE_value_offset (operands[2], <MODE>mode))
+    {
+      /* Must always be able to create a pseudo register.
+	 This pattern requires the ability to generate new pseudo registers,
+	 since there's no way to handle a constant that's too large other than
+         adding that constant into the current register.
+         If we had a too-large constant at the point where we can't create a
+         pseudo register, then using the basic `plus` pattern would end up with
+         a `plus` pattern that has a too-large constant, which would fail there
+         instead of here. */
+      rtx newreg = gen_reg_rtx (<MODE>mode);
+      emit_insn (gen_add<mode>3 (newreg, operands[1], operands[2]));
+      operands[2] = const0_rtx;
+      operands[1] = newreg;
+    }
 })
 
 (define_expand "cbranchcc4"
diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md
index e2aa0290f833fbffedec1d8dab219f72eb17419e..0edfb6de7d1ddb466d114b7510e58499117061c5 100644
--- a/gcc/config/aarch64/predicates.md
+++ b/gcc/config/aarch64/predicates.md
@@ -141,6 +141,13 @@ (define_predicate "aarch64_MTE_tag_offset"
   (and (match_code "const_int")
        (match_test "IN_RANGE (INTVAL (op), 0, 16)")))
 
+;; TODO
+;;    Will have to change the constant from 4096 to 64 when switching to addg.
+(define_predicate "aarch64_MTE_value_offset"
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (INTVAL (op), -4096, 4096)")))
+
+
 (define_predicate "aarch64_pluslong_strict_immedate"
   (and (match_operand 0 "aarch64_pluslong_immediate")
        (not (match_operand 0 "aarch64_plus_immediate"))))
diff --git a/gcc/defaults.h b/gcc/defaults.h
index b7534256119bd7834f2fa9d5f32863822d3b393a..b47fe6b35554091c9f3228169ad1f6ff4c692b14 100644
--- a/gcc/defaults.h
+++ b/gcc/defaults.h
@@ -1294,6 +1294,16 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #define EH_RETURN_HANDLER_RTX NULL
 #endif
 
+/* Indicate whether this backend has automatic access checks for tagged
+   pointers (i.e. HWASAN) if so then HWASAN memory tagging can be implemented
+   with much less instrumentation.
+   If a backend advertises that they have this it must also handle tagging
+   shadow memory themselves by implementing TARGET_MEMORY_TAG and avoiding the
+   background stack colour automatically in the addtag pattern.  */
+#ifndef HARDWARE_MEMORY_TAGGING
+#define HARDWARE_MEMORY_TAGGING 0
+#endif
+
 #ifdef GCC_INSN_FLAGS_H
 /* Dependent default target macro definitions
 
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 67d79a23799cd3057f7d91bd538c7ee76c836f82..7f0cc257a6634e3b0a2013b7fb9ffa4083f19038 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -2968,6 +2968,30 @@ This hook defines the machine mode to use for the boolean result of  conditional
 A target hook which lets a backend compute the set of pressure classes to  be used by those optimization passes which take register pressure into  account, as opposed to letting IRA compute them.  It returns the number of  register classes stored in the array @var{pressure_classes}.
 @end deftypefn
 
+@deftypefn {Target Hook} uint8_t TARGET_MEMTAG_TAG_SIZE ()
+Return the size in bits of a tag for this platform.
+@end deftypefn
+
+@deftypefn {Target Hook} uint8_t TARGET_MEMTAG_GRANULE_SIZE ()
+Return how many bytes in real memory each byte in shadow memory represents.
+I.e. one byte in shadow memory being colour 1 implies the assocaiated
+targetm.memtag.granule_size () bytes in real memory must all be accessed by
+pointers tagged as 1.
+@end deftypefn
+
+@deftypefn {Target Hook} void TARGET_MEMTAG_COPY_TAG (rtx @var{to}, rtx @var{from})
+Emit insns to copy the tag in FROM to TO.
+@end deftypefn
+
+@deftypefn {Target Hook} void TARGET_MEMTAG_TAG (rtx @var{tagged_start}, poly_int64 @var{address_offset}, uint8_t @var{tag_offset}, rtx @var{size})
+This function should emit an RTX to colour memory.
+It's given arguments TAGGED_START, ADDRESS_OFFSET, TAG_OFFSET, SIZE, where
+TAGGED_START and SIZE are RTL expressions, ADDRESS_OFFSET is a poly_int64
+and TAG_OFFSET is a uint8_t.
+It should emit RTL to colour "shadow memory" for the relevant range the
+colour of the tag it was given.
+@end deftypefn
+
 @deftypefn {Target Hook} void TARGET_MEMTAG_GENTAG (rtx @var{base}, rtx @var{untagged})
 Set the BASE argument to UNTAGGED with some random tag.
 This function is used to generate a tagged base for the current stack frame.
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index e1ec503befadb4061fbd3b95e55757fe22d33c39..6c77c09fca161dc3ade98d81b16c1b01af3c0bc7 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2370,6 +2370,14 @@ in the reload pass.
 
 @hook TARGET_COMPUTE_PRESSURE_CLASSES
 
+@hook TARGET_MEMTAG_TAG_SIZE
+
+@hook TARGET_MEMTAG_GRANULE_SIZE
+
+@hook TARGET_MEMTAG_COPY_TAG
+
+@hook TARGET_MEMTAG_TAG
+
 @hook TARGET_MEMTAG_GENTAG
 
 @node Stack and Calling
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index c530fe8951c30987c874df83e74be6d058730134..a58a55ad59b2ad7a6b93e2f5f2bbb40b8da51c5e 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -503,9 +503,6 @@ expand_HWASAN_MARK (internal_fn, gcall *gc)
   gcc_checking_assert (TREE_CODE (base) == ADDR_EXPR);
   rtx base_rtx = expand_normal (base);
 
-  rtx tag = is_poison ? const0_rtx : hwasan_extract_tag (base_rtx);
-  rtx address = hwasan_create_untagged_base (base_rtx);
-
   tree len = gimple_call_arg (gc, 2);
   gcc_assert (tree_fits_shwi_p (len));
   unsigned HOST_WIDE_INT size_in_bytes = tree_to_shwi (len);
@@ -515,13 +512,24 @@ expand_HWASAN_MARK (internal_fn, gcall *gc)
   rtx size = gen_int_mode (size_in_bytes, Pmode);
 
   /* TODO Other options (i.e. inline options)  */
-  rtx func = init_one_libfunc ("__hwasan_tag_memory");
-  emit_library_call (func,
-      LCT_NORMAL,
-      VOIDmode,
-      address, ptr_mode,
-      tag, QImode,
-      size, ptr_mode);
+  if (! HARDWARE_MEMORY_TAGGING )
+    {
+      rtx func = init_one_libfunc ("__hwasan_tag_memory");
+      rtx address = hwasan_create_untagged_base (base_rtx);
+      rtx tag = is_poison ? const0_rtx : hwasan_extract_tag (base_rtx);
+      emit_library_call (func,
+			 LCT_NORMAL,
+			 VOIDmode,
+			 address, ptr_mode,
+			 tag, QImode,
+			 size, ptr_mode);
+    }
+  else
+    {
+      if (is_poison)
+	targetm.memtag.copy_tag (base_rtx, stack_pointer_rtx);
+      targetm.memtag.tag (base_rtx, 0, 0, size);
+    }
 }
 
 /* This should get expanded in the sanopt pass.  */
diff --git a/gcc/target.def b/gcc/target.def
index 5326cb070dec78f19bfe0844a9d5e50c69e7dcc1..e0c543254538c802e1e0a059e1a3e60a045a0cdf 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -6709,6 +6709,34 @@ HOOK_VECTOR_END (mode_switching)
 HOOK_VECTOR (TARGET_MEMTAG_, memtag)
 
 DEFHOOK
+(tag_size,
+ "Return the size in bits of a tag for this platform.",
+ uint8_t, (), default_memtag_tag_size)
+
+DEFHOOK
+(granule_size,
+ "Return how many bytes in real memory each byte in shadow memory represents.\n\
+I.e. one byte in shadow memory being colour 1 implies the assocaiated\n\
+targetm.memtag.granule_size () bytes in real memory must all be accessed by\n\
+pointers tagged as 1.",
+uint8_t, (), default_memtag_granule_size)
+
+DEFHOOK
+(copy_tag,
+ "Emit insns to copy the tag in FROM to TO.",
+void, (rtx to, rtx from), default_memtag_copy_tag)
+
+DEFHOOK
+(tag,
+ "This function should emit an RTX to colour memory.\n\
+It's given arguments TAGGED_START, ADDRESS_OFFSET, TAG_OFFSET, SIZE, where\n\
+TAGGED_START and SIZE are RTL expressions, ADDRESS_OFFSET is a poly_int64\n\
+and TAG_OFFSET is a uint8_t.\n\
+It should emit RTL to colour \"shadow memory\" for the relevant range the\n\
+colour of the tag it was given.",
+  void, (rtx tagged_start, poly_int64 address_offset, uint8_t tag_offset, rtx size), NULL)
+
+DEFHOOK
 (gentag,
  "Set the BASE argument to UNTAGGED with some random tag.\n\
 This function is used to generate a tagged base for the current stack frame.",
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index 493ff3bb29263f8360bea0f7ead1092b4d0c646a..1c09bbad964b7705eea493a828d5906ad07481b6 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -288,5 +288,8 @@ extern rtx default_speculation_safe_value (machine_mode, rtx, rtx, rtx);
 extern void default_remove_extra_call_preserved_regs (rtx_insn *,
 						      HARD_REG_SET *);
 
+extern uint8_t default_memtag_tag_size ();
+extern uint8_t default_memtag_granule_size ();
 extern void default_memtag_gentag (rtx, rtx);
+extern void default_memtag_copy_tag (rtx, rtx);
 #endif /* GCC_TARGHOOKS_H */
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index 58ec711ce81ee67d692e81d2616bd3422f6bd092..bf078295cbd9514778454cef775dd288fd502641 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -70,6 +70,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "varasm.h"
 #include "flags.h"
 #include "explow.h"
+#include "expmed.h"
 #include "calls.h"
 #include "expr.h"
 #include "output.h"
@@ -83,6 +84,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "real.h"
 #include "langhooks.h"
 #include "sbitmap.h"
+#include "attribs.h"
+#include "asan.h"
 
 bool
 default_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED,
@@ -2391,6 +2394,18 @@ default_remove_extra_call_preserved_regs (rtx_insn *, HARD_REG_SET *)
 {
 }
 
+uint8_t
+default_memtag_tag_size ()
+{
+  return 4;
+}
+
+uint8_t
+default_memtag_granule_size ()
+{
+  return 1ULL << default_memtag_tag_size ();
+}
+
 void
 default_memtag_gentag (rtx base, rtx untagged)
 {
@@ -2402,5 +2417,40 @@ default_memtag_gentag (rtx base, rtx untagged)
   emit_move_insn (base, untagged);
 }
 
+void
+default_memtag_copy_tag (rtx to, rtx from)
+{
+  /* TODO: For AArch64 this can cause a problem in LRA if the `to`
+     RTX eventually resolves to being the stack pointer.
+     This happens because the instruction that gets emitted from
+     `store_bit_field` corresponds to a pattern that can't handle the stack
+     pointer and LRA can't figure out to use a temporary register in the `bfi`
+     instruction's place.
+
+     This doesn't cause a problem at the moment since there's currently no way
+     the stack pointer should be given to this function.  The hook is only used
+     when poisoning variables with HWASAN_MARK, and in that function the `to`
+     RTX should always be pointing to a tagged variable on the stack (since
+     the variable is tagged it can't be the stack pointer since that is
+     untagged).
+
+     Eventually we will be generating random tags as the "start" tag for each
+     frame.  When this happens we can no longer avoid the background colour at
+     compile time since we will not know what offset to avoid.
+     This will mean we no longer avoid a `tag_offset` of 0, and hence
+     `hwasan_with_tag` could emit simple PLUS statements.
+
+     When that happens, the last variable on the stack could very well have
+     a zero tag offset and somewhere else in the compiler could optimise that
+     to simply use the stack pointer.
+
+     That would trigger an ICE due to LRA being unable to reload the
+     `insv_regdi` pattern.
+
+     This is another thing that needs to be fixed but I'll deal with later.  */
+  rtx temp = hwasan_extract_tag (from);
+  store_bit_field (to, 8, 56, 0, 0,
+		   QImode, temp, false);
+}
 
 #include "gt-targhooks.h"


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [RFC][PATCH 9/X][libsanitizer] Put tags into each stack variable pointer
  2019-09-06 14:46 [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Matthew Malcomson
                   ` (14 preceding siblings ...)
  2019-09-06 14:47 ` [RFC][PATCH 6/X][libsanitizer] Add -fsanitize=hwaddress flags Matthew Malcomson
@ 2019-09-06 14:47 ` Matthew Malcomson
  2019-09-09 10:47 ` [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Martin Liška
  2019-09-23  8:02 ` Martin Liška
  17 siblings, 0 replies; 35+ messages in thread
From: Matthew Malcomson @ 2019-09-06 14:47 UTC (permalink / raw)
  To: gcc-patches; +Cc: mliska, dodji, nd, kcc, jakub, dvyukov

[-- Attachment #1: Type: text/plain, Size: 23287 bytes --]

This patch makes sure that every pointer to a stack variable includes a
tag of some sort on it.

The way tagging works is:
  1) For every new stack frame, a random tag is generated.
  2) A base register is formed from the stack pointer value and this
     random tag.
  3) References to stack variables are now formed with RTL describing an
     offset from this base in both tag and value.

The random tag generation is handled by a backend hook.  This is
currently a dummy that keeps the tag of the original pointer.
Using a dummy means that every stack frame has the initial colour of
zero and variables are coloured with incrementing tags from 1, which
makes debugging a bit easier.

We have a more complicated method of handling the tag&value offsets than
is needed for HWASAN.  This complexity is added to allow for backend
specific requirements when the HWASAN framework is adapted to hardware
memory tagging such as AArch64 MTE.

The tag and value increments are handled by emitting a new RTL
expression ADDTAG.  This new expression is a ternary operator returning
the final pointer from operands of the initial pointer plus a tag offset
and value offset.

This expression can then be expanded in the backend in whatever manner
is needed.  The flexibility of being able to use define_expand instead
of define_insn is needed for MTE, since that needs a temporary register
when the value offset is too large.

(NOTE I am looking into another method to allow backend specific
expansion of the tag addition -- by using a hook in force_operand and
hwasan_with_tag -- the method of adding a new RTL expression is under
flux).

gcc/ChangeLog:

2019-09-06  Matthew Malcomson  <matthew.malcomson@arm.com>

	* asan.c (hwasan_record_base): New function.
	(hwasan_increment_tag):New function.
	(hwasan_with_tag):New function.
	(hwasan_tag_init):New function.
	* asan.h (hwasan_record_base): New declaration.
	(hwasan_increment_tag): New declaration.
	(hwasan_with_tag): New declaration.
	(hwasan_tag_init): New declaration.
	* cfgexpand.c (expand_one_stack_var_at): Account for tags in
	variables when using HWASAN.
	(expand_stack_vars): Ensure variables are offset from a tagged
	base.
	(expand_one_stack_var_1): Pass new argument to
	expand_one_stack_var_at.
	(init_vars_expansion): Initialise hwasan internal variables when
	starting variable expansion.
	* config/aarch64/aarch64.md (addtag): Define new addtag pattern.
	* config/aarch64/predicates.md (aarch64_MTE_add_temp): New
	predicate.
	(aarch64_MTE_tag_offset): New predicate.
	* doc/tm.texi (TARGET_MEMTAG_GENTAG): Document.
	* doc/tm.texi.in (TARGET_MEMTAG_GENTAG): Document.
	* dwarf2out.c (is_based_loc): Handle ADDTAG.
	(mem_loc_descriptor): Handle ADDTAG.
	* explow.c (memory_address_addr_space): Handle ADDTAG.
	(get_dynamic_stack_base): Parametrise stack vars RTX base.
	* explow.h (get_dynamic_stack_base): New declaration.
	* expr.c (force_operand): Account for ADDTAG.
	* optabs.def (OPTAB_NL): New ADDTAG optab.
	* rtl.def (ADDTAG): New ADDTAG RTX.
	* simplify-rtx.c (simplify_ternary_operation): Account for
	ADDTAG.
	* target.def (TARGET_MEMTAG_GENTAG): Introduce new hook.
	* targhooks.c (default_memtag_gentag): Define default hook.
	* targhooks.h (default_memtag_gentag): Declare default hook.



###############     Attachment also inlined for ease of reply    ###############


diff --git a/gcc/asan.h b/gcc/asan.h
index d78f6b821c7d1e859cc53f124e071eac27a5e9b8..127c24aa6b0e4e6d0ba332004145ec498034c955 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -23,6 +23,11 @@ along with GCC; see the file COPYING3.  If not see
 
 extern void asan_function_start (void);
 extern void asan_finish_file (void);
+extern void hwasan_record_base (rtx);
+extern void hwasan_increment_tag ();
+extern rtx hwasan_with_tag (rtx, poly_int64);
+extern void hwasan_tag_init ();
+extern bool memory_tagging_p (void);
 extern rtx_insn *asan_emit_stack_protection (rtx, rtx, unsigned int,
 					     HOST_WIDE_INT *, tree *, int);
 extern rtx_insn *asan_emit_allocas_unpoison (rtx, rtx, rtx_insn *);
@@ -33,7 +38,7 @@ extern bool asan_expand_check_ifn (gimple_stmt_iterator *, bool);
 extern bool asan_expand_mark_ifn (gimple_stmt_iterator *);
 extern bool asan_expand_poison_ifn (gimple_stmt_iterator *, bool *,
 				    hash_map<tree, tree> &);
-extern bool memory_tagging_p (void);
+
 extern gimple_stmt_iterator create_cond_insert_point
      (gimple_stmt_iterator *, bool, bool, bool, basic_block *, basic_block *);
 
diff --git a/gcc/asan.c b/gcc/asan.c
index 42e990675e740bd37dad0704fd34b7a04740121e..a6ff503ceec294f2c09b0bd723a3d8043e4de6a1 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -257,6 +257,9 @@ hash_set<tree> *asan_handled_variables = NULL;
 
 hash_set <tree> *asan_used_labels = NULL;
 
+static uint8_t tag_offset = 0;
+static rtx hwasan_base_ptr = NULL_RTX;
+
 /* Sets shadow offset to value in string VAL.  */
 
 bool
@@ -3692,4 +3695,69 @@ make_pass_asan_O0 (gcc::context *ctxt)
   return new pass_asan_O0 (ctxt);
 }
 
+void
+hwasan_record_base (rtx base)
+{
+  /* Initialise base colour of the base register.
+     This has to be done as soon as the stack is getting expanded to ensure
+     anything emitted with `get_dynamic_stack_base` will use the value set here
+     instead of using a register without a value.
+     This is important for large aligned values.  */
+  targetm.memtag.gentag (base, virtual_stack_vars_rtx);
+  hwasan_base_ptr = base;
+}
+
+void
+hwasan_increment_tag ()
+{
+  uint8_t tag_bits = HWASAN_TAG_SIZE;
+  tag_offset = (tag_offset + 1) % (1 << tag_bits);
+  /* TODO Having the offset at STACK_BACKGROUND is not a problem, it's having
+     offset + base at STACK_BACKGROUND.
+
+     Eventually, the base will be randomly generated on every function entry
+     and there will be no way to tell at compile time what tag that base will
+     be.
+
+     For now the base is always zero, which means we can use this clause to
+     avoid allocating any object a tag of the stack background.
+
+     That's a help when debugging -- every variable should have a non-zero
+     colour.  */
+  if (tag_offset == HWASAN_STACK_BACKGROUND)
+    tag_offset += 1;
+}
+
+rtx
+hwasan_with_tag (rtx base, poly_int64 offset)
+{
+  gcc_assert (tag_offset < (1 << HWASAN_TAG_SIZE));
+  rtx x;
+
+  /* No point incrementing the tag by a value of zero.  */
+  if (tag_offset)
+    x = gen_rtx_ADDTAG (
+			Pmode,
+			base,
+			gen_int_mode (offset, Pmode),
+			const_int_rtx[MAX_SAVED_CONST_INT + tag_offset]);
+  else
+    x = plus_constant (Pmode, base, offset);
+
+  return x;
+}
+
+/* Clear internal state for the next function.
+   This function is called after the stack has been expanded in
+   `expand_stack_vars`.  */
+void
+hwasan_tag_init ()
+{
+  delete asan_used_labels;
+  asan_used_labels = NULL;
+
+  hwasan_base_ptr = NULL_RTX;
+  tag_offset = HWASAN_STACK_BACKGROUND + 1;
+}
+
 #include "gt-asan.h"
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index c5585d83c6e155856e7a4278e21c35ee5675bbdd..10739bc25940374c686c191ca76b1dfe8f000562 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -987,7 +987,7 @@ dump_stack_var_partition (void)
 
 static void
 expand_one_stack_var_at (tree decl, rtx base, unsigned base_align,
-			 poly_int64 offset)
+			 poly_int64 offset, rtx stack_base)
 {
   unsigned align;
   rtx x;
@@ -995,7 +995,11 @@ expand_one_stack_var_at (tree decl, rtx base, unsigned base_align,
   /* If this fails, we've overflowed the stack frame.  Error nicely?  */
   gcc_assert (known_eq (offset, trunc_int_for_mode (offset, Pmode)));
 
-  x = plus_constant (Pmode, base, offset);
+  if (memory_tagging_p ())
+    x = hwasan_with_tag (base, offset);
+  else
+    x = plus_constant (Pmode, base, offset);
+
   x = gen_rtx_MEM (TREE_CODE (decl) == SSA_NAME
 		   ? TYPE_MODE (TREE_TYPE (decl))
 		   : DECL_MODE (SSAVAR (decl)), x);
@@ -1005,7 +1009,7 @@ expand_one_stack_var_at (tree decl, rtx base, unsigned base_align,
       /* Set alignment we actually gave this decl if it isn't an SSA name.
          If it is we generate stack slots only accidentally so it isn't as
 	 important, we'll simply use the alignment that is already set.  */
-      if (base == virtual_stack_vars_rtx)
+      if (base == stack_base)
 	offset -= frame_phase;
       align = known_alignment (offset);
       align *= BITS_PER_UNIT;
@@ -1096,6 +1100,12 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
 	}
     }
 
+  if (memory_tagging_p () && data->asan_base == NULL)
+    {
+      data->asan_base = gen_reg_rtx (Pmode);
+      hwasan_record_base (data->asan_base);
+    }
+
   for (si = 0; si < n; ++si)
     {
       rtx base;
@@ -1121,6 +1131,7 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
       if (pred && !pred (i))
 	continue;
 
+      base = memory_tagging_p () ? data->asan_base : virtual_stack_vars_rtx;
       alignb = stack_vars[i].alignb;
       if (alignb * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT)
 	{
@@ -1147,7 +1158,6 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
 	      gcc_assert (stack_vars[i].alignb >= HWASAN_TAG_GRANULE_SIZE);
 	      alloc_stack_frame_space (0, HWASAN_TAG_GRANULE_SIZE);
 	    }
-	  base = virtual_stack_vars_rtx;
 	  /* ASAN description strings don't yet have a syntax for expressing
 	     polynomial offsets.  */
 	  HOST_WIDE_INT prev_offset;
@@ -1238,22 +1248,39 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
 	     space.  */
 	  if (maybe_ne (large_size, 0U) && ! large_allocation_done)
 	    {
-	      poly_int64 loffset;
 	      rtx large_allocsize;
+	      poly_int64 loffset;
 
 	      large_allocsize = gen_int_mode (large_size, Pmode);
 	      get_dynamic_stack_size (&large_allocsize, 0, large_align, NULL);
 	      loffset = alloc_stack_frame_space
 		(rtx_to_poly_int64 (large_allocsize),
 		 PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT);
-	      large_base = get_dynamic_stack_base (loffset, large_align);
+	      large_base = get_dynamic_stack_base (loffset, large_align, base);
 	      large_allocation_done = true;
 	    }
-	  gcc_assert (large_base != NULL);
 
+	  gcc_assert (large_base != NULL);
 	  large_alloc = aligned_upper_bound (large_alloc, alignb);
 	  offset = large_alloc;
 	  large_alloc += stack_vars[i].size;
+	  if (memory_tagging_p ())
+	    {
+	      /*
+		 The fact that these are all aligned objects means that we
+		 don't need to handle alignment of the object for tagging.
+
+		 However, we do need to ensure that the sizes we colour are
+		 also HWASAN_TAG_GRANULE_SIZE byte aligned.
+
+		 This clause is where we ensure that by rounding the size up.
+		 We know there will be no overlaps, since we know the start of
+		 the next object will be aligned to something greater than
+		 HWASAN_TAG_GRANULE_SIZE bytes.
+		 */
+	      poly_int64 align_again =
+		aligned_upper_bound (large_alloc, HWASAN_TAG_GRANULE_SIZE);
+	    }
 
 	  base = large_base;
 	  base_align = large_align;
@@ -1265,8 +1292,13 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
 	{
 	  expand_one_stack_var_at (stack_vars[j].decl,
 				   base, base_align,
-				   offset);
+				   offset,
+				   memory_tagging_p ()
+				   ? data->asan_base
+				   : virtual_stack_vars_rtx);
 	}
+      if (memory_tagging_p ())
+	hwasan_increment_tag ();
     }
 
   gcc_assert (known_eq (large_alloc, large_size));
@@ -1362,7 +1394,8 @@ expand_one_stack_var_1 (tree var)
   offset = alloc_stack_frame_space (size, byte_align);
 
   expand_one_stack_var_at (var, virtual_stack_vars_rtx,
-			   crtl->max_used_stack_slot_alignment, offset);
+			   crtl->max_used_stack_slot_alignment, offset,
+			   virtual_stack_vars_rtx);
 }
 
 /* Wrapper for expand_one_stack_var_1 that checks SSA_NAMEs are
@@ -1964,6 +1997,8 @@ init_vars_expansion (void)
   /* Initialize local stack smashing state.  */
   has_protected_decls = false;
   has_short_buffer = false;
+  if (memory_tagging_p ())
+    hwasan_tag_init ();
 }
 
 /* Free up stack variable graph data.  */
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 5a1894063a1ed2db1cc947c9c449d48808ed96ae..cb0d3ae6bbf3ed439c7b27683726f4c30b04777d 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -409,6 +409,23 @@ (define_expand "cbranch<mode>4"
   "
 )
 
+(define_expand "addtag<mode>4"
+  [(set (match_operand:GPI 0 "register_operand" "")
+    (addtag:GPI (match_operand:GPI 1 "register_operand" "")
+     (match_operand:GPI 2 "aarch64_MTE_add_temp" "")
+     (match_operand:GPI 3 "aarch64_MTE_tag_offset" "")))]
+  ""
+{
+  gcc_assert (can_create_pseudo_p ());
+  /* Simply add the two values as a constant and use that.  The adddi pattern
+     will handle the fact that the integer is out of range for ADD.  */
+  poly_int64 val = rtx_to_poly_int64 (operands[2]);
+  val += ((uint64_t)INTVAL(operands[3]) << 56);
+  emit_insn (gen_add<mode>3 (operands[0], operands[1],
+			     immed_wide_int_const (val, <MODE>mode)));
+  DONE;
+})
+
 (define_expand "cbranchcc4"
   [(set (pc) (if_then_else
 	      (match_operator 0 "aarch64_comparison_operator"
diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md
index 10100ca830a0cd753ef5759e3ce09914b1046d26..e2aa0290f833fbffedec1d8dab219f72eb17419e 100644
--- a/gcc/config/aarch64/predicates.md
+++ b/gcc/config/aarch64/predicates.md
@@ -134,6 +134,13 @@ (define_predicate "aarch64_pluslong_immediate"
   (and (match_code "const_int")
        (match_test "(INTVAL (op) < 0xffffff && INTVAL (op) > -0xffffff)")))
 
+(define_predicate "aarch64_MTE_add_temp"
+  (ior (match_code "const_int") (match_code "const_poly_int")))
+
+(define_predicate "aarch64_MTE_tag_offset"
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (INTVAL (op), 0, 16)")))
+
 (define_predicate "aarch64_pluslong_strict_immedate"
   (and (match_operand 0 "aarch64_pluslong_immediate")
        (not (match_operand 0 "aarch64_plus_immediate"))))
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 622e8cf240fbf4834a7a39317aff844989b8b65f..67d79a23799cd3057f7d91bd538c7ee76c836f82 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -2968,6 +2968,11 @@ This hook defines the machine mode to use for the boolean result of  conditional
 A target hook which lets a backend compute the set of pressure classes to  be used by those optimization passes which take register pressure into  account, as opposed to letting IRA compute them.  It returns the number of  register classes stored in the array @var{pressure_classes}.
 @end deftypefn
 
+@deftypefn {Target Hook} void TARGET_MEMTAG_GENTAG (rtx @var{base}, rtx @var{untagged})
+Set the BASE argument to UNTAGGED with some random tag.
+This function is used to generate a tagged base for the current stack frame.
+@end deftypefn
+
 @node Stack and Calling
 @section Stack Layout and Calling Conventions
 @cindex calling conventions
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 17560fce6b7a2cb0148e4dbac565eca588d5302e..e1ec503befadb4061fbd3b95e55757fe22d33c39 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2370,6 +2370,8 @@ in the reload pass.
 
 @hook TARGET_COMPUTE_PRESSURE_CLASSES
 
+@hook TARGET_MEMTAG_GENTAG
+
 @node Stack and Calling
 @section Stack Layout and Calling Conventions
 @cindex calling conventions
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 5979ac68fa86bf24fd096ad7754be05b59bc92f6..18364bbf8ee6e374678dcc9370750e297fb6daa2 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -14424,7 +14424,7 @@ based_loc_descr (rtx reg, poly_int64 offset,
 static inline int
 is_based_loc (const_rtx rtl)
 {
-  return (GET_CODE (rtl) == PLUS
+  return ((GET_CODE (rtl) == PLUS || GET_CODE (rtl) == ADDTAG)
 	  && ((REG_P (XEXP (rtl, 0))
 	       && REGNO (XEXP (rtl, 0)) < FIRST_PSEUDO_REGISTER
 	       && CONST_INT_P (XEXP (rtl, 1)))));
@@ -15877,6 +15877,7 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
 
       /* fall through */
 
+    case ADDTAG:
     case PLUS:
     plus:
       if (is_based_loc (rtl)
diff --git a/gcc/explow.h b/gcc/explow.h
index 5110ad82d6a024fda1d3a3eaf80de40c5e6ad3b6..333948e0c69a1b1132e9a1d06707dc63f1226262 100644
--- a/gcc/explow.h
+++ b/gcc/explow.h
@@ -102,7 +102,7 @@ extern rtx allocate_dynamic_stack_space (rtx, unsigned, unsigned,
 extern void get_dynamic_stack_size (rtx *, unsigned, unsigned, HOST_WIDE_INT *);
 
 /* Returns the address of the dynamic stack space without allocating it.  */
-extern rtx get_dynamic_stack_base (poly_int64, unsigned);
+extern rtx get_dynamic_stack_base (poly_int64, unsigned, rtx);
 
 /* Return an rtx doing runtime alignment to REQUIRED_ALIGN on TARGET.  */
 extern rtx align_dynamic_address (rtx, unsigned);
diff --git a/gcc/explow.c b/gcc/explow.c
index ba06458ebdc64db0859127df880742ae1007bd8c..07665b28a1ff3a0067f3bc559eb4508e0f3a96e4 100644
--- a/gcc/explow.c
+++ b/gcc/explow.c
@@ -477,7 +477,8 @@ memory_address_addr_space (machine_mode mode, rtx x, addr_space_t as)
 	    }
 	}
 
-      else if (GET_CODE (x) == MULT || GET_CODE (x) == MINUS)
+      else if (GET_CODE (x) == MULT || GET_CODE (x) == MINUS
+	       || GET_CODE (x) == ADDTAG)
 	x = force_operand (x, NULL_RTX);
 
       /* If we have a register that's an invalid address,
@@ -1586,10 +1587,15 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
    OFFSET is the offset of the area into the virtual stack vars area.
 
    REQUIRED_ALIGN is the alignment (in bits) required for the region
-   of memory.  */
+   of memory.
+
+   BASE is the rtx of the base of this virtual stack vars area.
+   The only time this is not `virtual_stack_vars_rtx` is when tagging pointers
+   on the stack.
+   */
 
 rtx
-get_dynamic_stack_base (poly_int64 offset, unsigned required_align)
+get_dynamic_stack_base (poly_int64 offset, unsigned required_align, rtx base)
 {
   rtx target;
 
@@ -1597,7 +1603,7 @@ get_dynamic_stack_base (poly_int64 offset, unsigned required_align)
     crtl->preferred_stack_boundary = PREFERRED_STACK_BOUNDARY;
 
   target = gen_reg_rtx (Pmode);
-  emit_move_insn (target, virtual_stack_vars_rtx);
+  emit_move_insn (target, base);
   target = expand_binop (Pmode, add_optab, target,
 			 gen_int_mode (offset, Pmode),
 			 NULL_RTX, 1, OPTAB_LIB_WIDEN);
diff --git a/gcc/expr.c b/gcc/expr.c
index c78bc74c0d9f9005f284741863652852a295125b..fa4ee4e2068c26328e651c04f838b354225e4970 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -7464,6 +7464,16 @@ force_operand (rtx value, rtx target)
       return subtarget;
     }
 
+  if (code == ADDTAG)
+    {
+      /* Instead of just letting an ADD_TAG go through directly, call the
+         expand_ternary_op() function to ensure it gets expanded as the backend
+         requires.  */
+      return expand_ternary_op (GET_MODE (value), addtag_optab,
+				XEXP (value, 0), XEXP (value, 1),
+				XEXP (value, 2), target, 0);
+
+    }
   if (ARITHMETIC_P (value))
     {
       op2 = XEXP (value, 1);
diff --git a/gcc/optabs.def b/gcc/optabs.def
index 8af3a2f43fd99a36b69999d3fb50b9a6d5379964..7c73fc18bce72f88a7427359d966a5d9a8d51c05 100644
--- a/gcc/optabs.def
+++ b/gcc/optabs.def
@@ -99,6 +99,8 @@ OPTAB_CD (while_ult_optab, "while_ult$a$b")
 OPTAB_NL(add_optab, "add$P$a3", PLUS, "add", '3', gen_int_fp_fixed_libfunc)
 OPTAB_NX(add_optab, "add$F$a3")
 OPTAB_NX(add_optab, "add$Q$a3")
+/* TODO Currently don"t know what the gen_int_fp_fixed_libfunc field is for. */
+OPTAB_NL(addtag_optab, "addtag$P$a4", ADDTAG, "addtag", '4', gen_int_fp_fixed_libfunc)
 OPTAB_VL(addv_optab, "addv$I$a3", PLUS, "add", '3', gen_intv_fp_libfunc)
 OPTAB_VX(addv_optab, "add$F$a3")
 OPTAB_NL(ssadd_optab, "ssadd$Q$a3", SS_PLUS, "ssadd", '3', gen_signed_fixed_libfunc)
diff --git a/gcc/rtl.def b/gcc/rtl.def
index f4c9d946cb5aedb74b4cc9181987762151231855..4d6879481b5565248b8a3b188de58a7184547231 100644
--- a/gcc/rtl.def
+++ b/gcc/rtl.def
@@ -471,6 +471,14 @@ DEF_RTL_EXPR(COMPARE, "compare", "ee", RTX_BIN_ARITH)
 /* plus */
 DEF_RTL_EXPR(PLUS, "plus", "ee", RTX_COMM_ARITH)
 
+/* add_tag. This is used for memory tagging instructions.
+    Operands:
+      0:  Original
+      1:  Offset
+      2:  Tag Offset  */
+
+DEF_RTL_EXPR(ADDTAG, "addtag", "eee", RTX_TERNARY)
+
 /* Operand 0 minus operand 1.  */
 DEF_RTL_EXPR(MINUS, "minus", "ee", RTX_BIN_ARITH)
 
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index 89a46a933facaded1b23a84fa9a0924595b01e5a..91bf885e9e26459743caf11c91fa160585179905 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -5699,6 +5699,9 @@ simplify_ternary_operation (enum rtx_code code, machine_mode mode,
 
   switch (code)
     {
+    case ADDTAG:
+      return NULL_RTX;
+
     case FMA:
       /* Simplify negations around the multiplication.  */
       /* -a * -b + c  =>  a * b + c.  */
diff --git a/gcc/target.def b/gcc/target.def
index 7d52102c8153b4c86f6541da5e04c39251c2d42f..5326cb070dec78f19bfe0844a9d5e50c69e7dcc1 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -6705,6 +6705,18 @@ DEFHOOK
 HOOK_VECTOR_END (mode_switching)
 
 #undef HOOK_PREFIX
+#define HOOK_PREFIX "TARGET_MEMTAG_"
+HOOK_VECTOR (TARGET_MEMTAG_, memtag)
+
+DEFHOOK
+(gentag,
+ "Set the BASE argument to UNTAGGED with some random tag.\n\
+This function is used to generate a tagged base for the current stack frame.",
+  void, (rtx base, rtx untagged),
+  default_memtag_gentag)
+
+HOOK_VECTOR_END (memtag)
+#undef HOOK_PREFIX
 #define HOOK_PREFIX "TARGET_"
 
 #define DEF_TARGET_INSN(NAME, PROTO) \
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index 229aacd7b6597d75774e82594cfa332f37afcf3c..493ff3bb29263f8360bea0f7ead1092b4d0c646a 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -288,4 +288,5 @@ extern rtx default_speculation_safe_value (machine_mode, rtx, rtx, rtx);
 extern void default_remove_extra_call_preserved_regs (rtx_insn *,
 						      HARD_REG_SET *);
 
+extern void default_memtag_gentag (rtx, rtx);
 #endif /* GCC_TARGHOOKS_H */
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index b27111639f4960426ff2fc39a10ddc9237deaf61..58ec711ce81ee67d692e81d2616bd3422f6bd092 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -2391,4 +2391,16 @@ default_remove_extra_call_preserved_regs (rtx_insn *, HARD_REG_SET *)
 {
 }
 
+void
+default_memtag_gentag (rtx base, rtx untagged)
+{
+  /* TODO This function should emit instructions to calculate a random tag and
+     insert it into the `base` rtx.  At the moment we have a dummy function
+     that keeps `base` without a tag.  That helps for debugging since it means
+     variables are tagged starting from 1 in each function frame, which is
+     a bit easier to view.  */
+  emit_move_insn (base, untagged);
+}
+
+
 #include "gt-targhooks.h"


[-- Attachment #2: hwasan-implementation08.patch --]
[-- Type: text/plain, Size: 19331 bytes --]

diff --git a/gcc/asan.h b/gcc/asan.h
index d78f6b821c7d1e859cc53f124e071eac27a5e9b8..127c24aa6b0e4e6d0ba332004145ec498034c955 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -23,6 +23,11 @@ along with GCC; see the file COPYING3.  If not see
 
 extern void asan_function_start (void);
 extern void asan_finish_file (void);
+extern void hwasan_record_base (rtx);
+extern void hwasan_increment_tag ();
+extern rtx hwasan_with_tag (rtx, poly_int64);
+extern void hwasan_tag_init ();
+extern bool memory_tagging_p (void);
 extern rtx_insn *asan_emit_stack_protection (rtx, rtx, unsigned int,
 					     HOST_WIDE_INT *, tree *, int);
 extern rtx_insn *asan_emit_allocas_unpoison (rtx, rtx, rtx_insn *);
@@ -33,7 +38,7 @@ extern bool asan_expand_check_ifn (gimple_stmt_iterator *, bool);
 extern bool asan_expand_mark_ifn (gimple_stmt_iterator *);
 extern bool asan_expand_poison_ifn (gimple_stmt_iterator *, bool *,
 				    hash_map<tree, tree> &);
-extern bool memory_tagging_p (void);
+
 extern gimple_stmt_iterator create_cond_insert_point
      (gimple_stmt_iterator *, bool, bool, bool, basic_block *, basic_block *);
 
diff --git a/gcc/asan.c b/gcc/asan.c
index 42e990675e740bd37dad0704fd34b7a04740121e..a6ff503ceec294f2c09b0bd723a3d8043e4de6a1 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -257,6 +257,9 @@ hash_set<tree> *asan_handled_variables = NULL;
 
 hash_set <tree> *asan_used_labels = NULL;
 
+static uint8_t tag_offset = 0;
+static rtx hwasan_base_ptr = NULL_RTX;
+
 /* Sets shadow offset to value in string VAL.  */
 
 bool
@@ -3692,4 +3695,69 @@ make_pass_asan_O0 (gcc::context *ctxt)
   return new pass_asan_O0 (ctxt);
 }
 
+void
+hwasan_record_base (rtx base)
+{
+  /* Initialise base colour of the base register.
+     This has to be done as soon as the stack is getting expanded to ensure
+     anything emitted with `get_dynamic_stack_base` will use the value set here
+     instead of using a register without a value.
+     This is important for large aligned values.  */
+  targetm.memtag.gentag (base, virtual_stack_vars_rtx);
+  hwasan_base_ptr = base;
+}
+
+void
+hwasan_increment_tag ()
+{
+  uint8_t tag_bits = HWASAN_TAG_SIZE;
+  tag_offset = (tag_offset + 1) % (1 << tag_bits);
+  /* TODO Having the offset at STACK_BACKGROUND is not a problem, it's having
+     offset + base at STACK_BACKGROUND.
+
+     Eventually, the base will be randomly generated on every function entry
+     and there will be no way to tell at compile time what tag that base will
+     be.
+
+     For now the base is always zero, which means we can use this clause to
+     avoid allocating any object a tag of the stack background.
+
+     That's a help when debugging -- every variable should have a non-zero
+     colour.  */
+  if (tag_offset == HWASAN_STACK_BACKGROUND)
+    tag_offset += 1;
+}
+
+rtx
+hwasan_with_tag (rtx base, poly_int64 offset)
+{
+  gcc_assert (tag_offset < (1 << HWASAN_TAG_SIZE));
+  rtx x;
+
+  /* No point incrementing the tag by a value of zero.  */
+  if (tag_offset)
+    x = gen_rtx_ADDTAG (
+			Pmode,
+			base,
+			gen_int_mode (offset, Pmode),
+			const_int_rtx[MAX_SAVED_CONST_INT + tag_offset]);
+  else
+    x = plus_constant (Pmode, base, offset);
+
+  return x;
+}
+
+/* Clear internal state for the next function.
+   This function is called after the stack has been expanded in
+   `expand_stack_vars`.  */
+void
+hwasan_tag_init ()
+{
+  delete asan_used_labels;
+  asan_used_labels = NULL;
+
+  hwasan_base_ptr = NULL_RTX;
+  tag_offset = HWASAN_STACK_BACKGROUND + 1;
+}
+
 #include "gt-asan.h"
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index c5585d83c6e155856e7a4278e21c35ee5675bbdd..10739bc25940374c686c191ca76b1dfe8f000562 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -987,7 +987,7 @@ dump_stack_var_partition (void)
 
 static void
 expand_one_stack_var_at (tree decl, rtx base, unsigned base_align,
-			 poly_int64 offset)
+			 poly_int64 offset, rtx stack_base)
 {
   unsigned align;
   rtx x;
@@ -995,7 +995,11 @@ expand_one_stack_var_at (tree decl, rtx base, unsigned base_align,
   /* If this fails, we've overflowed the stack frame.  Error nicely?  */
   gcc_assert (known_eq (offset, trunc_int_for_mode (offset, Pmode)));
 
-  x = plus_constant (Pmode, base, offset);
+  if (memory_tagging_p ())
+    x = hwasan_with_tag (base, offset);
+  else
+    x = plus_constant (Pmode, base, offset);
+
   x = gen_rtx_MEM (TREE_CODE (decl) == SSA_NAME
 		   ? TYPE_MODE (TREE_TYPE (decl))
 		   : DECL_MODE (SSAVAR (decl)), x);
@@ -1005,7 +1009,7 @@ expand_one_stack_var_at (tree decl, rtx base, unsigned base_align,
       /* Set alignment we actually gave this decl if it isn't an SSA name.
          If it is we generate stack slots only accidentally so it isn't as
 	 important, we'll simply use the alignment that is already set.  */
-      if (base == virtual_stack_vars_rtx)
+      if (base == stack_base)
 	offset -= frame_phase;
       align = known_alignment (offset);
       align *= BITS_PER_UNIT;
@@ -1096,6 +1100,12 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
 	}
     }
 
+  if (memory_tagging_p () && data->asan_base == NULL)
+    {
+      data->asan_base = gen_reg_rtx (Pmode);
+      hwasan_record_base (data->asan_base);
+    }
+
   for (si = 0; si < n; ++si)
     {
       rtx base;
@@ -1121,6 +1131,7 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
       if (pred && !pred (i))
 	continue;
 
+      base = memory_tagging_p () ? data->asan_base : virtual_stack_vars_rtx;
       alignb = stack_vars[i].alignb;
       if (alignb * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT)
 	{
@@ -1147,7 +1158,6 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
 	      gcc_assert (stack_vars[i].alignb >= HWASAN_TAG_GRANULE_SIZE);
 	      alloc_stack_frame_space (0, HWASAN_TAG_GRANULE_SIZE);
 	    }
-	  base = virtual_stack_vars_rtx;
 	  /* ASAN description strings don't yet have a syntax for expressing
 	     polynomial offsets.  */
 	  HOST_WIDE_INT prev_offset;
@@ -1238,22 +1248,39 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
 	     space.  */
 	  if (maybe_ne (large_size, 0U) && ! large_allocation_done)
 	    {
-	      poly_int64 loffset;
 	      rtx large_allocsize;
+	      poly_int64 loffset;
 
 	      large_allocsize = gen_int_mode (large_size, Pmode);
 	      get_dynamic_stack_size (&large_allocsize, 0, large_align, NULL);
 	      loffset = alloc_stack_frame_space
 		(rtx_to_poly_int64 (large_allocsize),
 		 PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT);
-	      large_base = get_dynamic_stack_base (loffset, large_align);
+	      large_base = get_dynamic_stack_base (loffset, large_align, base);
 	      large_allocation_done = true;
 	    }
-	  gcc_assert (large_base != NULL);
 
+	  gcc_assert (large_base != NULL);
 	  large_alloc = aligned_upper_bound (large_alloc, alignb);
 	  offset = large_alloc;
 	  large_alloc += stack_vars[i].size;
+	  if (memory_tagging_p ())
+	    {
+	      /*
+		 The fact that these are all aligned objects means that we
+		 don't need to handle alignment of the object for tagging.
+
+		 However, we do need to ensure that the sizes we colour are
+		 also HWASAN_TAG_GRANULE_SIZE byte aligned.
+
+		 This clause is where we ensure that by rounding the size up.
+		 We know there will be no overlaps, since we know the start of
+		 the next object will be aligned to something greater than
+		 HWASAN_TAG_GRANULE_SIZE bytes.
+		 */
+	      poly_int64 align_again =
+		aligned_upper_bound (large_alloc, HWASAN_TAG_GRANULE_SIZE);
+	    }
 
 	  base = large_base;
 	  base_align = large_align;
@@ -1265,8 +1292,13 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
 	{
 	  expand_one_stack_var_at (stack_vars[j].decl,
 				   base, base_align,
-				   offset);
+				   offset,
+				   memory_tagging_p ()
+				   ? data->asan_base
+				   : virtual_stack_vars_rtx);
 	}
+      if (memory_tagging_p ())
+	hwasan_increment_tag ();
     }
 
   gcc_assert (known_eq (large_alloc, large_size));
@@ -1362,7 +1394,8 @@ expand_one_stack_var_1 (tree var)
   offset = alloc_stack_frame_space (size, byte_align);
 
   expand_one_stack_var_at (var, virtual_stack_vars_rtx,
-			   crtl->max_used_stack_slot_alignment, offset);
+			   crtl->max_used_stack_slot_alignment, offset,
+			   virtual_stack_vars_rtx);
 }
 
 /* Wrapper for expand_one_stack_var_1 that checks SSA_NAMEs are
@@ -1964,6 +1997,8 @@ init_vars_expansion (void)
   /* Initialize local stack smashing state.  */
   has_protected_decls = false;
   has_short_buffer = false;
+  if (memory_tagging_p ())
+    hwasan_tag_init ();
 }
 
 /* Free up stack variable graph data.  */
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 5a1894063a1ed2db1cc947c9c449d48808ed96ae..cb0d3ae6bbf3ed439c7b27683726f4c30b04777d 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -409,6 +409,23 @@ (define_expand "cbranch<mode>4"
   "
 )
 
+(define_expand "addtag<mode>4"
+  [(set (match_operand:GPI 0 "register_operand" "")
+    (addtag:GPI (match_operand:GPI 1 "register_operand" "")
+     (match_operand:GPI 2 "aarch64_MTE_add_temp" "")
+     (match_operand:GPI 3 "aarch64_MTE_tag_offset" "")))]
+  ""
+{
+  gcc_assert (can_create_pseudo_p ());
+  /* Simply add the two values as a constant and use that.  The adddi pattern
+     will handle the fact that the integer is out of range for ADD.  */
+  poly_int64 val = rtx_to_poly_int64 (operands[2]);
+  val += ((uint64_t)INTVAL(operands[3]) << 56);
+  emit_insn (gen_add<mode>3 (operands[0], operands[1],
+			     immed_wide_int_const (val, <MODE>mode)));
+  DONE;
+})
+
 (define_expand "cbranchcc4"
   [(set (pc) (if_then_else
 	      (match_operator 0 "aarch64_comparison_operator"
diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md
index 10100ca830a0cd753ef5759e3ce09914b1046d26..e2aa0290f833fbffedec1d8dab219f72eb17419e 100644
--- a/gcc/config/aarch64/predicates.md
+++ b/gcc/config/aarch64/predicates.md
@@ -134,6 +134,13 @@ (define_predicate "aarch64_pluslong_immediate"
   (and (match_code "const_int")
        (match_test "(INTVAL (op) < 0xffffff && INTVAL (op) > -0xffffff)")))
 
+(define_predicate "aarch64_MTE_add_temp"
+  (ior (match_code "const_int") (match_code "const_poly_int")))
+
+(define_predicate "aarch64_MTE_tag_offset"
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (INTVAL (op), 0, 16)")))
+
 (define_predicate "aarch64_pluslong_strict_immedate"
   (and (match_operand 0 "aarch64_pluslong_immediate")
        (not (match_operand 0 "aarch64_plus_immediate"))))
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 622e8cf240fbf4834a7a39317aff844989b8b65f..67d79a23799cd3057f7d91bd538c7ee76c836f82 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -2968,6 +2968,11 @@ This hook defines the machine mode to use for the boolean result of  conditional
 A target hook which lets a backend compute the set of pressure classes to  be used by those optimization passes which take register pressure into  account, as opposed to letting IRA compute them.  It returns the number of  register classes stored in the array @var{pressure_classes}.
 @end deftypefn
 
+@deftypefn {Target Hook} void TARGET_MEMTAG_GENTAG (rtx @var{base}, rtx @var{untagged})
+Set the BASE argument to UNTAGGED with some random tag.
+This function is used to generate a tagged base for the current stack frame.
+@end deftypefn
+
 @node Stack and Calling
 @section Stack Layout and Calling Conventions
 @cindex calling conventions
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 17560fce6b7a2cb0148e4dbac565eca588d5302e..e1ec503befadb4061fbd3b95e55757fe22d33c39 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -2370,6 +2370,8 @@ in the reload pass.
 
 @hook TARGET_COMPUTE_PRESSURE_CLASSES
 
+@hook TARGET_MEMTAG_GENTAG
+
 @node Stack and Calling
 @section Stack Layout and Calling Conventions
 @cindex calling conventions
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 5979ac68fa86bf24fd096ad7754be05b59bc92f6..18364bbf8ee6e374678dcc9370750e297fb6daa2 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -14424,7 +14424,7 @@ based_loc_descr (rtx reg, poly_int64 offset,
 static inline int
 is_based_loc (const_rtx rtl)
 {
-  return (GET_CODE (rtl) == PLUS
+  return ((GET_CODE (rtl) == PLUS || GET_CODE (rtl) == ADDTAG)
 	  && ((REG_P (XEXP (rtl, 0))
 	       && REGNO (XEXP (rtl, 0)) < FIRST_PSEUDO_REGISTER
 	       && CONST_INT_P (XEXP (rtl, 1)))));
@@ -15877,6 +15877,7 @@ mem_loc_descriptor (rtx rtl, machine_mode mode,
 
       /* fall through */
 
+    case ADDTAG:
     case PLUS:
     plus:
       if (is_based_loc (rtl)
diff --git a/gcc/explow.h b/gcc/explow.h
index 5110ad82d6a024fda1d3a3eaf80de40c5e6ad3b6..333948e0c69a1b1132e9a1d06707dc63f1226262 100644
--- a/gcc/explow.h
+++ b/gcc/explow.h
@@ -102,7 +102,7 @@ extern rtx allocate_dynamic_stack_space (rtx, unsigned, unsigned,
 extern void get_dynamic_stack_size (rtx *, unsigned, unsigned, HOST_WIDE_INT *);
 
 /* Returns the address of the dynamic stack space without allocating it.  */
-extern rtx get_dynamic_stack_base (poly_int64, unsigned);
+extern rtx get_dynamic_stack_base (poly_int64, unsigned, rtx);
 
 /* Return an rtx doing runtime alignment to REQUIRED_ALIGN on TARGET.  */
 extern rtx align_dynamic_address (rtx, unsigned);
diff --git a/gcc/explow.c b/gcc/explow.c
index ba06458ebdc64db0859127df880742ae1007bd8c..07665b28a1ff3a0067f3bc559eb4508e0f3a96e4 100644
--- a/gcc/explow.c
+++ b/gcc/explow.c
@@ -477,7 +477,8 @@ memory_address_addr_space (machine_mode mode, rtx x, addr_space_t as)
 	    }
 	}
 
-      else if (GET_CODE (x) == MULT || GET_CODE (x) == MINUS)
+      else if (GET_CODE (x) == MULT || GET_CODE (x) == MINUS
+	       || GET_CODE (x) == ADDTAG)
 	x = force_operand (x, NULL_RTX);
 
       /* If we have a register that's an invalid address,
@@ -1586,10 +1587,15 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
    OFFSET is the offset of the area into the virtual stack vars area.
 
    REQUIRED_ALIGN is the alignment (in bits) required for the region
-   of memory.  */
+   of memory.
+
+   BASE is the rtx of the base of this virtual stack vars area.
+   The only time this is not `virtual_stack_vars_rtx` is when tagging pointers
+   on the stack.
+   */
 
 rtx
-get_dynamic_stack_base (poly_int64 offset, unsigned required_align)
+get_dynamic_stack_base (poly_int64 offset, unsigned required_align, rtx base)
 {
   rtx target;
 
@@ -1597,7 +1603,7 @@ get_dynamic_stack_base (poly_int64 offset, unsigned required_align)
     crtl->preferred_stack_boundary = PREFERRED_STACK_BOUNDARY;
 
   target = gen_reg_rtx (Pmode);
-  emit_move_insn (target, virtual_stack_vars_rtx);
+  emit_move_insn (target, base);
   target = expand_binop (Pmode, add_optab, target,
 			 gen_int_mode (offset, Pmode),
 			 NULL_RTX, 1, OPTAB_LIB_WIDEN);
diff --git a/gcc/expr.c b/gcc/expr.c
index c78bc74c0d9f9005f284741863652852a295125b..fa4ee4e2068c26328e651c04f838b354225e4970 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -7464,6 +7464,16 @@ force_operand (rtx value, rtx target)
       return subtarget;
     }
 
+  if (code == ADDTAG)
+    {
+      /* Instead of just letting an ADD_TAG go through directly, call the
+         expand_ternary_op() function to ensure it gets expanded as the backend
+         requires.  */
+      return expand_ternary_op (GET_MODE (value), addtag_optab,
+				XEXP (value, 0), XEXP (value, 1),
+				XEXP (value, 2), target, 0);
+
+    }
   if (ARITHMETIC_P (value))
     {
       op2 = XEXP (value, 1);
diff --git a/gcc/optabs.def b/gcc/optabs.def
index 8af3a2f43fd99a36b69999d3fb50b9a6d5379964..7c73fc18bce72f88a7427359d966a5d9a8d51c05 100644
--- a/gcc/optabs.def
+++ b/gcc/optabs.def
@@ -99,6 +99,8 @@ OPTAB_CD (while_ult_optab, "while_ult$a$b")
 OPTAB_NL(add_optab, "add$P$a3", PLUS, "add", '3', gen_int_fp_fixed_libfunc)
 OPTAB_NX(add_optab, "add$F$a3")
 OPTAB_NX(add_optab, "add$Q$a3")
+/* TODO Currently don"t know what the gen_int_fp_fixed_libfunc field is for. */
+OPTAB_NL(addtag_optab, "addtag$P$a4", ADDTAG, "addtag", '4', gen_int_fp_fixed_libfunc)
 OPTAB_VL(addv_optab, "addv$I$a3", PLUS, "add", '3', gen_intv_fp_libfunc)
 OPTAB_VX(addv_optab, "add$F$a3")
 OPTAB_NL(ssadd_optab, "ssadd$Q$a3", SS_PLUS, "ssadd", '3', gen_signed_fixed_libfunc)
diff --git a/gcc/rtl.def b/gcc/rtl.def
index f4c9d946cb5aedb74b4cc9181987762151231855..4d6879481b5565248b8a3b188de58a7184547231 100644
--- a/gcc/rtl.def
+++ b/gcc/rtl.def
@@ -471,6 +471,14 @@ DEF_RTL_EXPR(COMPARE, "compare", "ee", RTX_BIN_ARITH)
 /* plus */
 DEF_RTL_EXPR(PLUS, "plus", "ee", RTX_COMM_ARITH)
 
+/* add_tag. This is used for memory tagging instructions.
+    Operands:
+      0:  Original
+      1:  Offset
+      2:  Tag Offset  */
+
+DEF_RTL_EXPR(ADDTAG, "addtag", "eee", RTX_TERNARY)
+
 /* Operand 0 minus operand 1.  */
 DEF_RTL_EXPR(MINUS, "minus", "ee", RTX_BIN_ARITH)
 
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index 89a46a933facaded1b23a84fa9a0924595b01e5a..91bf885e9e26459743caf11c91fa160585179905 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -5699,6 +5699,9 @@ simplify_ternary_operation (enum rtx_code code, machine_mode mode,
 
   switch (code)
     {
+    case ADDTAG:
+      return NULL_RTX;
+
     case FMA:
       /* Simplify negations around the multiplication.  */
       /* -a * -b + c  =>  a * b + c.  */
diff --git a/gcc/target.def b/gcc/target.def
index 7d52102c8153b4c86f6541da5e04c39251c2d42f..5326cb070dec78f19bfe0844a9d5e50c69e7dcc1 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -6705,6 +6705,18 @@ DEFHOOK
 HOOK_VECTOR_END (mode_switching)
 
 #undef HOOK_PREFIX
+#define HOOK_PREFIX "TARGET_MEMTAG_"
+HOOK_VECTOR (TARGET_MEMTAG_, memtag)
+
+DEFHOOK
+(gentag,
+ "Set the BASE argument to UNTAGGED with some random tag.\n\
+This function is used to generate a tagged base for the current stack frame.",
+  void, (rtx base, rtx untagged),
+  default_memtag_gentag)
+
+HOOK_VECTOR_END (memtag)
+#undef HOOK_PREFIX
 #define HOOK_PREFIX "TARGET_"
 
 #define DEF_TARGET_INSN(NAME, PROTO) \
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index 229aacd7b6597d75774e82594cfa332f37afcf3c..493ff3bb29263f8360bea0f7ead1092b4d0c646a 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -288,4 +288,5 @@ extern rtx default_speculation_safe_value (machine_mode, rtx, rtx, rtx);
 extern void default_remove_extra_call_preserved_regs (rtx_insn *,
 						      HARD_REG_SET *);
 
+extern void default_memtag_gentag (rtx, rtx);
 #endif /* GCC_TARGHOOKS_H */
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index b27111639f4960426ff2fc39a10ddc9237deaf61..58ec711ce81ee67d692e81d2616bd3422f6bd092 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -2391,4 +2391,16 @@ default_remove_extra_call_preserved_regs (rtx_insn *, HARD_REG_SET *)
 {
 }
 
+void
+default_memtag_gentag (rtx base, rtx untagged)
+{
+  /* TODO This function should emit instructions to calculate a random tag and
+     insert it into the `base` rtx.  At the moment we have a dummy function
+     that keeps `base` without a tag.  That helps for debugging since it means
+     variables are tagged starting from 1 in each function frame, which is
+     a bit easier to view.  */
+  emit_move_insn (base, untagged);
+}
+
+
 #include "gt-targhooks.h"


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [RFC][PATCH 12/X][libsanitizer] Check pointer tags match address tags
  2019-09-06 14:46 [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Matthew Malcomson
                   ` (12 preceding siblings ...)
  2019-09-06 14:47 ` [RFC][PATCH 16/X][libsanitizer] Build libhwasan with interceptors Matthew Malcomson
@ 2019-09-06 14:47 ` Matthew Malcomson
  2019-09-06 14:47 ` [RFC][PATCH 6/X][libsanitizer] Add -fsanitize=hwaddress flags Matthew Malcomson
                   ` (3 subsequent siblings)
  17 siblings, 0 replies; 35+ messages in thread
From: Matthew Malcomson @ 2019-09-06 14:47 UTC (permalink / raw)
  To: gcc-patches; +Cc: mliska, dodji, nd, kcc, jakub, dvyukov

[-- Attachment #1: Type: text/plain, Size: 18568 bytes --]

This adds the `hwasan` pass that puts HWASAN_CHECK internal functions
around memory accesses to check that tags in the pointer being used
match the tag stored in shadow memory for the memory region being used.

These internal functions are expanded into actual checks in the sanopt
pass that happens just before expansion into RTL.

We use the same mechanism that currently inserts ASAN_CHECK internal
functions to insert the new HWASAN_CHECK functions.  Instrumenting
builtin function calls is not yet handled and will be in a later patch
in this series.

As yet we always terminate the program on a tag mismatch, and always
check tags via a library call to libhwasan.  Allowing a program to
continue from tag mismatch, and implementing inline checks are intended
for a later revision.

gcc/ChangeLog:

2019-09-06  Matthew Malcomson  <matthew.malcomson@arm.com>

	* asan.c (build_check_stmt): Generate HWASAN_CHECK for HWASAN.
	(instrument_derefs): Avoid checking global variables for HWASAN.
	(maybe_instrument_call): Temporarily avoid for HWASAN.
	(hwasan_instrument): New.
	(hwasan_expand_check_ifn): New.
	(gate_hwasan): New.
	(class pass_hwasan): New.
	(make_pass_hwasan): New.
	(class pass_hwasan_O0): New.
	(make_pass_hwasan_O0): New.
	* asan.h (hwasan_expand_check_ifn): New.
	(gate_hwasan): New.
	(asan_intercepted_p): No memory function is intercepted by
	libhwasan.
	(asan_sanitize_use_after_scope): True for memory tagging.
	* internal-fn.c (expand_HWASAN_CHECK): New.
	* internal-fn.def (HWASAN_CHECK): New.
	* passes.def (hwasan): New pass.
	* sanitizer.def (BUILT_IN_HWASAN_LOADN): New builtin.
	(BUILT_IN_HWASAN_STOREN): New builtin.
	* sanopt.c (sanopt_optimize_walker): Account for HWASAN_CHECK.
	(pass_sanopt::execute): Account for HWASAN_CHECK.
	* tree-pass.h (make_pass_hwasan, make_pass_hwasan_O0): New decl.



###############     Attachment also inlined for ease of reply    ###############


diff --git a/gcc/asan.h b/gcc/asan.h
index c5492ce35980d0b26d4707f96482b69dc76a525a..68ea1b4afaf9195553251a987df33788421fa142 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -32,7 +32,9 @@ extern void hwasan_tag_init ();
 extern rtx hwasan_create_untagged_base (rtx);
 extern void hwasan_emit_prologue (rtx *, rtx *, poly_int64 *, uint8_t *, size_t);
 extern rtx_insn *hwasan_emit_uncolour_frame (rtx, rtx, rtx_insn *);
+extern bool hwasan_expand_check_ifn (gimple_stmt_iterator *, bool);
 extern bool memory_tagging_p (void);
+extern bool gate_hwasan (void);
 extern rtx_insn *asan_emit_stack_protection (rtx, rtx, unsigned int,
 					     HOST_WIDE_INT *, tree *, int);
 extern rtx_insn *asan_emit_allocas_unpoison (rtx, rtx, rtx_insn *);
@@ -188,6 +190,9 @@ extern hash_set<tree> *asan_handled_variables;
 static inline bool
 asan_intercepted_p (enum built_in_function fcode)
 {
+  if (memory_tagging_p ())
+    return false;
+
   return fcode == BUILT_IN_INDEX
 	 || fcode == BUILT_IN_MEMCHR
 	 || fcode == BUILT_IN_MEMCMP
@@ -216,7 +221,8 @@ asan_intercepted_p (enum built_in_function fcode)
 static inline bool
 asan_sanitize_use_after_scope (void)
 {
-  return (flag_sanitize_address_use_after_scope && asan_sanitize_stack_p ());
+  return (flag_sanitize_address_use_after_scope &&
+	  (asan_sanitize_stack_p () || memory_tagging_p ()));
 }
 
 /* Return true if DECL should be guarded on the stack.  */
diff --git a/gcc/asan.c b/gcc/asan.c
index 0e74e32ae6ca4e130b3f13abe110364b119def46..ae1f8a0d28e911c2ff30be8ea9f4001923983cb1 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -2177,7 +2177,13 @@ build_check_stmt (location_t loc, tree base, tree len,
   if (is_scalar_access)
     flags |= ASAN_CHECK_SCALAR_ACCESS;
 
-  g = gimple_build_call_internal (IFN_ASAN_CHECK, 4,
+  enum internal_fn fn;
+  if (memory_tagging_p ())
+    fn = IFN_HWASAN_CHECK;
+  else
+    fn = IFN_ASAN_CHECK;
+
+  g = gimple_build_call_internal (fn, 4,
 				  build_int_cst (integer_type_node, flags),
 				  base, len,
 				  build_int_cst (integer_type_node,
@@ -2201,10 +2207,13 @@ static void
 instrument_derefs (gimple_stmt_iterator *iter, tree t,
 		   location_t location, bool is_store)
 {
-  if (is_store && !ASAN_INSTRUMENT_WRITES)
-    return;
-  if (!is_store && !ASAN_INSTRUMENT_READS)
-    return;
+  if (! memory_tagging_p ())
+    {
+    if (is_store && !ASAN_INSTRUMENT_WRITES)
+      return;
+    if (!is_store && !ASAN_INSTRUMENT_READS)
+      return;
+    }
 
   tree type, base;
   HOST_WIDE_INT size_in_bytes;
@@ -2248,10 +2257,21 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t,
       return;
     }
 
+  /* TODO Understand when this can happen.
+      What's the point of ignoring these parts?
+      I guess non-byte sizes would be awkward to instrument?
+      When would this occur?  */
   if (!multiple_p (bitpos, BITS_PER_UNIT)
       || maybe_ne (bitsize, size_in_bytes * BITS_PER_UNIT))
     return;
 
+  /* TODO What are we checking, and why are we not instrumenting that?
+      If the "object" is stored in a register then do nothing?
+      If the "object" is a register then do nothing?
+
+      The second one makes a lot of sense, but I can"t just assume that"s
+      what"s being checked.
+    */
   if (VAR_P (inner) && DECL_HARD_REGISTER (inner))
     return;
 
@@ -2264,7 +2284,8 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t,
     {
       if (DECL_THREAD_LOCAL_P (inner))
 	return;
-      if (!ASAN_GLOBALS && is_global_var (inner))
+      if ((memory_tagging_p () || !ASAN_GLOBALS)
+	  && is_global_var (inner))
         return;
       if (!TREE_STATIC (inner))
 	{
@@ -2472,6 +2493,8 @@ maybe_instrument_assignment (gimple_stmt_iterator *iter)
 static bool
 maybe_instrument_call (gimple_stmt_iterator *iter)
 {
+  if (memory_tagging_p ())
+    return false;
   gimple *stmt = gsi_stmt (*iter);
   bool is_builtin = gimple_call_builtin_p (stmt, BUILT_IN_NORMAL);
 
@@ -3702,6 +3725,17 @@ make_pass_asan_O0 (gcc::context *ctxt)
   return new pass_asan_O0 (ctxt);
 }
 
+/*  HWASAN  */
+static unsigned int
+hwasan_instrument (void)
+{
+  if (shadow_ptr_types[0] == NULL_TREE)
+    asan_init_shadow_ptr_types ();
+  transform_statements ();
+  last_alloca_addr = NULL_TREE;
+  return 0;
+}
+
 void
 hwasan_record_base (rtx base)
 {
@@ -3909,4 +3943,176 @@ hwasan_finish_file (void)
   flag_sanitize |= SANITIZE_HWADDRESS;
 }
 
+bool
+hwasan_expand_check_ifn (gimple_stmt_iterator *iter, bool)
+{
+  // TODO For now only implementing the function when using calls.
+  // This is a little easier, and means I can rely on the library
+  // implementation while checking my instrumentation code for now.
+
+  gimple *g = gsi_stmt (*iter);
+  location_t loc = gimple_location (g);
+  bool recover_p = false;
+  (void)recover_p; // UNUSED for now (will be used to determine action)
+
+  HOST_WIDE_INT flags = tree_to_shwi (gimple_call_arg (g, 0));
+  gcc_assert (flags < ASAN_CHECK_LAST);
+  bool is_scalar_access = (flags & ASAN_CHECK_SCALAR_ACCESS) != 0;
+  bool is_store = (flags & ASAN_CHECK_STORE) != 0;
+  bool is_non_zero_len = (flags & ASAN_CHECK_NON_ZERO_LEN) != 0;
+
+  tree base = gimple_call_arg (g, 1);
+  tree len = gimple_call_arg (g, 2);
+
+  /* TODO align is unused for HWASAN_CHECK, but I pass the argument anyway
+   * because that way I need to write less code.  */
+  /* HOST_WIDE_INT align = tree_to_shwi (gimple_call_arg (g, 3));  */
+
+  unsigned HOST_WIDE_INT size_in_bytes
+    = is_scalar_access && tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
+  (void)size_in_bytes; // UNUSED for now (will be used to determine action)
+
+  gimple_stmt_iterator gsi = *iter;
+
+  if (!is_non_zero_len)
+    {
+      /* So, the length of the memory area to hwasan-protect is
+	 non-constant.  Let's guard the generated instrumentation code
+	 like:
+
+	 if (len != 0)
+	   {
+	     // hwasan instrumentation code goes here.
+	   }
+	 // falltrough instructions, starting with *ITER.  */
+
+      g = gimple_build_cond (NE_EXPR,
+			    len,
+			    build_int_cst (TREE_TYPE (len), 0),
+			    NULL_TREE, NULL_TREE);
+      gimple_set_location (g, loc);
+
+      basic_block then_bb, fallthrough_bb;
+      insert_if_then_before_iter (as_a <gcond *> (g), iter,
+				  /*then_more_likely_p=*/true,
+				  &then_bb, &fallthrough_bb);
+      /* Note that fallthrough_bb starts with the statement that was
+	pointed to by ITER.  */
+
+      /* The 'then block' of the 'if (len != 0) condition is where
+	we'll generate the hwasan instrumentation code now.  */
+      gsi = gsi_last_bb (then_bb);
+    }
+
+  /* Instrument using callbacks.  */
+  g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+			   NOP_EXPR, base);
+  gimple_set_location (g, loc);
+  gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+  tree base_addr = gimple_assign_lhs (g);
+
+  /* TODO Here we only ever use the LOADN/STOREN functions for checking.
+     This means we always terminate the program on tag mismatch, always use
+     a function call instead of an inline check, and never have the nicer error
+     messages that come from size-specific checking.
+
+     This is much quicker to code for now, all other options will be
+     implemented later.  */
+  enum built_in_function fun_enum =
+    is_store ? BUILT_IN_HWASAN_STOREN : BUILT_IN_HWASAN_LOADN;
+  tree fun = builtin_decl_implicit (fun_enum);
+  g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+			   NOP_EXPR, len);
+  gimple_set_location (g, loc);
+  gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+  tree sz_arg = gimple_assign_lhs (g);
+  g = gimple_build_call (fun, 2, base_addr, sz_arg);
+  gimple_set_location (g, loc);
+  gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+
+  gsi_remove (iter, true);
+  *iter = gsi;
+  return false;
+}
+
+bool
+gate_hwasan ()
+{
+  return memory_tagging_p ();
+}
+
+namespace {
+
+const pass_data pass_data_hwasan =
+{
+  GIMPLE_PASS, /* type */
+  "hwasan", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  ( PROP_ssa | PROP_cfg | PROP_gimple_leh ), /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_update_ssa, /* todo_flags_finish */
+};
+
+class pass_hwasan : public gimple_opt_pass
+{
+public:
+  pass_hwasan (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_hwasan, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  opt_pass * clone () { return new pass_hwasan (m_ctxt); }
+  virtual bool gate (function *) { return gate_hwasan (); }
+  virtual unsigned int execute (function *) { return hwasan_instrument (); }
+
+}; // class pass_asan
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_hwasan (gcc::context *ctxt)
+{
+  return new pass_hwasan (ctxt);
+}
+
+namespace {
+
+const pass_data pass_data_hwasan_O0 =
+{
+  GIMPLE_PASS, /* type */
+  "hwasan_O0", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  ( PROP_ssa | PROP_cfg | PROP_gimple_leh ), /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_update_ssa, /* todo_flags_finish */
+};
+
+class pass_hwasan_O0 : public gimple_opt_pass
+{
+public:
+  pass_hwasan_O0 (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_hwasan_O0, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  opt_pass * clone () { return new pass_hwasan_O0 (m_ctxt); }
+  virtual bool gate (function *) { return !optimize && gate_hwasan (); }
+  virtual unsigned int execute (function *) { return hwasan_instrument (); }
+
+}; // class pass_asan
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_hwasan_O0 (gcc::context *ctxt)
+{
+  return new pass_hwasan_O0 (ctxt);
+}
+
 #include "gt-asan.h"
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 04081f36c4d31ecfba4099e50412345c67e1f58f..80f94f141bfd92e9f6af13a6df76f0c9ac053fdc 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -456,6 +456,12 @@ expand_UBSAN_OBJECT_SIZE (internal_fn, gcall *)
 /* This should get expanded in the sanopt pass.  */
 
 static void
+expand_HWASAN_CHECK (internal_fn, gcall *)
+{
+  gcc_unreachable ();
+}
+
+static void
 expand_ASAN_CHECK (internal_fn, gcall *)
 {
   gcc_unreachable ();
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index 016301a58d83d7128817824d7c7ef92825c7e03e..c683e5d8e5c607f18909bda4d97b58421cb7c2a4 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -288,6 +288,7 @@ DEF_INTERNAL_FN (UBSAN_PTR, ECF_LEAF | ECF_NOTHROW, ".R.")
 DEF_INTERNAL_FN (UBSAN_OBJECT_SIZE, ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (ABNORMAL_DISPATCHER, ECF_NORETURN, NULL)
 DEF_INTERNAL_FN (BUILTIN_EXPECT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
+DEF_INTERNAL_FN (HWASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, "..R..")
 DEF_INTERNAL_FN (ASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, "..R..")
 DEF_INTERNAL_FN (ASAN_MARK, ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (ASAN_POISON, ECF_LEAF | ECF_NOTHROW | ECF_NOVOPS, NULL)
diff --git a/gcc/passes.def b/gcc/passes.def
index ad2efabd3853d8d20562f66f4c5bb34694ec80f2..11c9fb20b042d55a7d52da4feda633dc5cd3052a 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -246,6 +246,7 @@ along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_sink_code);
       NEXT_PASS (pass_sancov);
       NEXT_PASS (pass_asan);
+      NEXT_PASS (pass_hwasan);
       NEXT_PASS (pass_tsan);
       NEXT_PASS (pass_dce);
       /* Pass group that runs when 1) enabled, 2) there are loops
@@ -362,6 +363,7 @@ along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_dce);
       NEXT_PASS (pass_sancov);
       NEXT_PASS (pass_asan);
+      NEXT_PASS (pass_hwasan);
       NEXT_PASS (pass_tsan);
       /* ???  We do want some kind of loop invariant motion, but we possibly
          need to adjust LIM to be more friendly towards preserving accurate
@@ -387,6 +389,7 @@ along with GCC; see the file COPYING3.  If not see
   NEXT_PASS (pass_sancov_O0);
   NEXT_PASS (pass_lower_switch_O0);
   NEXT_PASS (pass_asan_O0);
+  NEXT_PASS (pass_hwasan_O0);
   NEXT_PASS (pass_tsan_O0);
   NEXT_PASS (pass_sanopt);
   NEXT_PASS (pass_cleanup_eh);
diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def
index 7bd50715f24a2cb154b578e2abdea4e8fcdb2107..0edf349cc23e846608b89d54a1024b9d99de9c4d 100644
--- a/gcc/sanitizer.def
+++ b/gcc/sanitizer.def
@@ -183,6 +183,10 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_POINTER_SUBTRACT, "__sanitizer_ptr_sub",
 /* Hardware Address Sanitizer.  */
 DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_INIT, "__hwasan_init",
 		      BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_LOADN, "__hwasan_loadN",
+		      BT_FN_VOID_PTR_PTRMODE, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_STOREN, "__hwasan_storeN",
+		      BT_FN_VOID_PTR_PTRMODE, ATTR_TMPURE_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_TAG_MEM, "__hwasan_tag_memory",
 		      BT_FN_VOID_PTR_UINT8_SIZE, ATTR_NOTHROW_LIST)
 
diff --git a/gcc/sanopt.c b/gcc/sanopt.c
index 5cb98e1b50e4e1644072bd18d74797c3cac43c3f..31270153f3cf56bfbad593830de1b9334e7f65d1 100644
--- a/gcc/sanopt.c
+++ b/gcc/sanopt.c
@@ -772,7 +772,8 @@ sanopt_optimize_walker (basic_block bb, struct sanopt_ctx *ctx)
   basic_block son;
   gimple_stmt_iterator gsi;
   sanopt_info *info = (sanopt_info *) bb->aux;
-  bool asan_check_optimize = (flag_sanitize & SANITIZE_ADDRESS) != 0;
+  bool asan_check_optimize =
+    ((flag_sanitize & SANITIZE_ADDRESS) != 0) || memory_tagging_p ();
 
   for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
     {
@@ -802,6 +803,7 @@ sanopt_optimize_walker (basic_block bb, struct sanopt_ctx *ctx)
       if (asan_check_optimize
 	  && gimple_call_builtin_p (stmt, BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT))
 	{
+	  gcc_assert (!memory_tagging_p ());
 	  use_operand_p use;
 	  gimple *use_stmt;
 	  if (single_imm_use (gimple_vdef (stmt), &use, &use_stmt))
@@ -830,6 +832,7 @@ sanopt_optimize_walker (basic_block bb, struct sanopt_ctx *ctx)
 	  case IFN_UBSAN_PTR:
 	    remove = maybe_optimize_ubsan_ptr_ifn (ctx, stmt);
 	    break;
+	  case IFN_HWASAN_CHECK:
 	  case IFN_ASAN_CHECK:
 	    if (asan_check_optimize)
 	      remove = maybe_optimize_asan_check_ifn (ctx, stmt);
@@ -1262,10 +1265,11 @@ pass_sanopt::execute (function *fun)
   /* Try to remove redundant checks.  */
   if (optimize
       && (flag_sanitize
-	  & (SANITIZE_NULL | SANITIZE_ALIGNMENT
+	  & (SANITIZE_NULL | SANITIZE_ALIGNMENT | SANITIZE_HWADDRESS
 	     | SANITIZE_ADDRESS | SANITIZE_VPTR | SANITIZE_POINTER_OVERFLOW)))
     asan_num_accesses = sanopt_optimize (fun, &contains_asan_mark);
-  else if (flag_sanitize & SANITIZE_ADDRESS)
+  else if (flag_sanitize & SANITIZE_ADDRESS
+	   || memory_tagging_p ())
     {
       gimple_stmt_iterator gsi;
       FOR_EACH_BB_FN (bb, fun)
@@ -1285,7 +1289,7 @@ pass_sanopt::execute (function *fun)
       sanitize_asan_mark_poison ();
     }
 
-  if (asan_sanitize_stack_p ())
+  if (asan_sanitize_stack_p () || memory_tagging_p ())
     sanitize_rewrite_addressable_params (fun);
 
   bool use_calls = ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD < INT_MAX
@@ -1327,6 +1331,9 @@ pass_sanopt::execute (function *fun)
 		case IFN_UBSAN_VPTR:
 		  no_next = ubsan_expand_vptr_ifn (&gsi);
 		  break;
+		case IFN_HWASAN_CHECK:
+		  no_next = hwasan_expand_check_ifn (&gsi, use_calls);
+		  break;
 		case IFN_ASAN_CHECK:
 		  no_next = asan_expand_check_ifn (&gsi, use_calls);
 		  break;
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 3a0b3805d24dbd50141d4145563861e4ae3768f3..01ebd03205e57ee3a63d3344da8098160c081002 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -341,6 +341,8 @@ extern void register_pass (opt_pass* pass, pass_positioning_ops pos,
 
 extern gimple_opt_pass *make_pass_asan (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_asan_O0 (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_hwasan (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_hwasan_O0 (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_tsan (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_tsan_O0 (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_sancov (gcc::context *ctxt);


[-- Attachment #2: hwasan-implementation11.patch --]
[-- Type: text/plain, Size: 16144 bytes --]

diff --git a/gcc/asan.h b/gcc/asan.h
index c5492ce35980d0b26d4707f96482b69dc76a525a..68ea1b4afaf9195553251a987df33788421fa142 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -32,7 +32,9 @@ extern void hwasan_tag_init ();
 extern rtx hwasan_create_untagged_base (rtx);
 extern void hwasan_emit_prologue (rtx *, rtx *, poly_int64 *, uint8_t *, size_t);
 extern rtx_insn *hwasan_emit_uncolour_frame (rtx, rtx, rtx_insn *);
+extern bool hwasan_expand_check_ifn (gimple_stmt_iterator *, bool);
 extern bool memory_tagging_p (void);
+extern bool gate_hwasan (void);
 extern rtx_insn *asan_emit_stack_protection (rtx, rtx, unsigned int,
 					     HOST_WIDE_INT *, tree *, int);
 extern rtx_insn *asan_emit_allocas_unpoison (rtx, rtx, rtx_insn *);
@@ -188,6 +190,9 @@ extern hash_set<tree> *asan_handled_variables;
 static inline bool
 asan_intercepted_p (enum built_in_function fcode)
 {
+  if (memory_tagging_p ())
+    return false;
+
   return fcode == BUILT_IN_INDEX
 	 || fcode == BUILT_IN_MEMCHR
 	 || fcode == BUILT_IN_MEMCMP
@@ -216,7 +221,8 @@ asan_intercepted_p (enum built_in_function fcode)
 static inline bool
 asan_sanitize_use_after_scope (void)
 {
-  return (flag_sanitize_address_use_after_scope && asan_sanitize_stack_p ());
+  return (flag_sanitize_address_use_after_scope &&
+	  (asan_sanitize_stack_p () || memory_tagging_p ()));
 }
 
 /* Return true if DECL should be guarded on the stack.  */
diff --git a/gcc/asan.c b/gcc/asan.c
index 0e74e32ae6ca4e130b3f13abe110364b119def46..ae1f8a0d28e911c2ff30be8ea9f4001923983cb1 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -2177,7 +2177,13 @@ build_check_stmt (location_t loc, tree base, tree len,
   if (is_scalar_access)
     flags |= ASAN_CHECK_SCALAR_ACCESS;
 
-  g = gimple_build_call_internal (IFN_ASAN_CHECK, 4,
+  enum internal_fn fn;
+  if (memory_tagging_p ())
+    fn = IFN_HWASAN_CHECK;
+  else
+    fn = IFN_ASAN_CHECK;
+
+  g = gimple_build_call_internal (fn, 4,
 				  build_int_cst (integer_type_node, flags),
 				  base, len,
 				  build_int_cst (integer_type_node,
@@ -2201,10 +2207,13 @@ static void
 instrument_derefs (gimple_stmt_iterator *iter, tree t,
 		   location_t location, bool is_store)
 {
-  if (is_store && !ASAN_INSTRUMENT_WRITES)
-    return;
-  if (!is_store && !ASAN_INSTRUMENT_READS)
-    return;
+  if (! memory_tagging_p ())
+    {
+    if (is_store && !ASAN_INSTRUMENT_WRITES)
+      return;
+    if (!is_store && !ASAN_INSTRUMENT_READS)
+      return;
+    }
 
   tree type, base;
   HOST_WIDE_INT size_in_bytes;
@@ -2248,10 +2257,21 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t,
       return;
     }
 
+  /* TODO Understand when this can happen.
+      What's the point of ignoring these parts?
+      I guess non-byte sizes would be awkward to instrument?
+      When would this occur?  */
   if (!multiple_p (bitpos, BITS_PER_UNIT)
       || maybe_ne (bitsize, size_in_bytes * BITS_PER_UNIT))
     return;
 
+  /* TODO What are we checking, and why are we not instrumenting that?
+      If the "object" is stored in a register then do nothing?
+      If the "object" is a register then do nothing?
+
+      The second one makes a lot of sense, but I can"t just assume that"s
+      what"s being checked.
+    */
   if (VAR_P (inner) && DECL_HARD_REGISTER (inner))
     return;
 
@@ -2264,7 +2284,8 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t,
     {
       if (DECL_THREAD_LOCAL_P (inner))
 	return;
-      if (!ASAN_GLOBALS && is_global_var (inner))
+      if ((memory_tagging_p () || !ASAN_GLOBALS)
+	  && is_global_var (inner))
         return;
       if (!TREE_STATIC (inner))
 	{
@@ -2472,6 +2493,8 @@ maybe_instrument_assignment (gimple_stmt_iterator *iter)
 static bool
 maybe_instrument_call (gimple_stmt_iterator *iter)
 {
+  if (memory_tagging_p ())
+    return false;
   gimple *stmt = gsi_stmt (*iter);
   bool is_builtin = gimple_call_builtin_p (stmt, BUILT_IN_NORMAL);
 
@@ -3702,6 +3725,17 @@ make_pass_asan_O0 (gcc::context *ctxt)
   return new pass_asan_O0 (ctxt);
 }
 
+/*  HWASAN  */
+static unsigned int
+hwasan_instrument (void)
+{
+  if (shadow_ptr_types[0] == NULL_TREE)
+    asan_init_shadow_ptr_types ();
+  transform_statements ();
+  last_alloca_addr = NULL_TREE;
+  return 0;
+}
+
 void
 hwasan_record_base (rtx base)
 {
@@ -3909,4 +3943,176 @@ hwasan_finish_file (void)
   flag_sanitize |= SANITIZE_HWADDRESS;
 }
 
+bool
+hwasan_expand_check_ifn (gimple_stmt_iterator *iter, bool)
+{
+  // TODO For now only implementing the function when using calls.
+  // This is a little easier, and means I can rely on the library
+  // implementation while checking my instrumentation code for now.
+
+  gimple *g = gsi_stmt (*iter);
+  location_t loc = gimple_location (g);
+  bool recover_p = false;
+  (void)recover_p; // UNUSED for now (will be used to determine action)
+
+  HOST_WIDE_INT flags = tree_to_shwi (gimple_call_arg (g, 0));
+  gcc_assert (flags < ASAN_CHECK_LAST);
+  bool is_scalar_access = (flags & ASAN_CHECK_SCALAR_ACCESS) != 0;
+  bool is_store = (flags & ASAN_CHECK_STORE) != 0;
+  bool is_non_zero_len = (flags & ASAN_CHECK_NON_ZERO_LEN) != 0;
+
+  tree base = gimple_call_arg (g, 1);
+  tree len = gimple_call_arg (g, 2);
+
+  /* TODO align is unused for HWASAN_CHECK, but I pass the argument anyway
+   * because that way I need to write less code.  */
+  /* HOST_WIDE_INT align = tree_to_shwi (gimple_call_arg (g, 3));  */
+
+  unsigned HOST_WIDE_INT size_in_bytes
+    = is_scalar_access && tree_fits_shwi_p (len) ? tree_to_shwi (len) : -1;
+  (void)size_in_bytes; // UNUSED for now (will be used to determine action)
+
+  gimple_stmt_iterator gsi = *iter;
+
+  if (!is_non_zero_len)
+    {
+      /* So, the length of the memory area to hwasan-protect is
+	 non-constant.  Let's guard the generated instrumentation code
+	 like:
+
+	 if (len != 0)
+	   {
+	     // hwasan instrumentation code goes here.
+	   }
+	 // falltrough instructions, starting with *ITER.  */
+
+      g = gimple_build_cond (NE_EXPR,
+			    len,
+			    build_int_cst (TREE_TYPE (len), 0),
+			    NULL_TREE, NULL_TREE);
+      gimple_set_location (g, loc);
+
+      basic_block then_bb, fallthrough_bb;
+      insert_if_then_before_iter (as_a <gcond *> (g), iter,
+				  /*then_more_likely_p=*/true,
+				  &then_bb, &fallthrough_bb);
+      /* Note that fallthrough_bb starts with the statement that was
+	pointed to by ITER.  */
+
+      /* The 'then block' of the 'if (len != 0) condition is where
+	we'll generate the hwasan instrumentation code now.  */
+      gsi = gsi_last_bb (then_bb);
+    }
+
+  /* Instrument using callbacks.  */
+  g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+			   NOP_EXPR, base);
+  gimple_set_location (g, loc);
+  gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+  tree base_addr = gimple_assign_lhs (g);
+
+  /* TODO Here we only ever use the LOADN/STOREN functions for checking.
+     This means we always terminate the program on tag mismatch, always use
+     a function call instead of an inline check, and never have the nicer error
+     messages that come from size-specific checking.
+
+     This is much quicker to code for now, all other options will be
+     implemented later.  */
+  enum built_in_function fun_enum =
+    is_store ? BUILT_IN_HWASAN_STOREN : BUILT_IN_HWASAN_LOADN;
+  tree fun = builtin_decl_implicit (fun_enum);
+  g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
+			   NOP_EXPR, len);
+  gimple_set_location (g, loc);
+  gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+  tree sz_arg = gimple_assign_lhs (g);
+  g = gimple_build_call (fun, 2, base_addr, sz_arg);
+  gimple_set_location (g, loc);
+  gsi_insert_after (&gsi, g, GSI_NEW_STMT);
+
+  gsi_remove (iter, true);
+  *iter = gsi;
+  return false;
+}
+
+bool
+gate_hwasan ()
+{
+  return memory_tagging_p ();
+}
+
+namespace {
+
+const pass_data pass_data_hwasan =
+{
+  GIMPLE_PASS, /* type */
+  "hwasan", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  ( PROP_ssa | PROP_cfg | PROP_gimple_leh ), /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_update_ssa, /* todo_flags_finish */
+};
+
+class pass_hwasan : public gimple_opt_pass
+{
+public:
+  pass_hwasan (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_hwasan, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  opt_pass * clone () { return new pass_hwasan (m_ctxt); }
+  virtual bool gate (function *) { return gate_hwasan (); }
+  virtual unsigned int execute (function *) { return hwasan_instrument (); }
+
+}; // class pass_asan
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_hwasan (gcc::context *ctxt)
+{
+  return new pass_hwasan (ctxt);
+}
+
+namespace {
+
+const pass_data pass_data_hwasan_O0 =
+{
+  GIMPLE_PASS, /* type */
+  "hwasan_O0", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE, /* tv_id */
+  ( PROP_ssa | PROP_cfg | PROP_gimple_leh ), /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_update_ssa, /* todo_flags_finish */
+};
+
+class pass_hwasan_O0 : public gimple_opt_pass
+{
+public:
+  pass_hwasan_O0 (gcc::context *ctxt)
+    : gimple_opt_pass (pass_data_hwasan_O0, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  opt_pass * clone () { return new pass_hwasan_O0 (m_ctxt); }
+  virtual bool gate (function *) { return !optimize && gate_hwasan (); }
+  virtual unsigned int execute (function *) { return hwasan_instrument (); }
+
+}; // class pass_asan
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_hwasan_O0 (gcc::context *ctxt)
+{
+  return new pass_hwasan_O0 (ctxt);
+}
+
 #include "gt-asan.h"
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 04081f36c4d31ecfba4099e50412345c67e1f58f..80f94f141bfd92e9f6af13a6df76f0c9ac053fdc 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -456,6 +456,12 @@ expand_UBSAN_OBJECT_SIZE (internal_fn, gcall *)
 /* This should get expanded in the sanopt pass.  */
 
 static void
+expand_HWASAN_CHECK (internal_fn, gcall *)
+{
+  gcc_unreachable ();
+}
+
+static void
 expand_ASAN_CHECK (internal_fn, gcall *)
 {
   gcc_unreachable ();
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index 016301a58d83d7128817824d7c7ef92825c7e03e..c683e5d8e5c607f18909bda4d97b58421cb7c2a4 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -288,6 +288,7 @@ DEF_INTERNAL_FN (UBSAN_PTR, ECF_LEAF | ECF_NOTHROW, ".R.")
 DEF_INTERNAL_FN (UBSAN_OBJECT_SIZE, ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (ABNORMAL_DISPATCHER, ECF_NORETURN, NULL)
 DEF_INTERNAL_FN (BUILTIN_EXPECT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
+DEF_INTERNAL_FN (HWASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, "..R..")
 DEF_INTERNAL_FN (ASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, "..R..")
 DEF_INTERNAL_FN (ASAN_MARK, ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (ASAN_POISON, ECF_LEAF | ECF_NOTHROW | ECF_NOVOPS, NULL)
diff --git a/gcc/passes.def b/gcc/passes.def
index ad2efabd3853d8d20562f66f4c5bb34694ec80f2..11c9fb20b042d55a7d52da4feda633dc5cd3052a 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -246,6 +246,7 @@ along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_sink_code);
       NEXT_PASS (pass_sancov);
       NEXT_PASS (pass_asan);
+      NEXT_PASS (pass_hwasan);
       NEXT_PASS (pass_tsan);
       NEXT_PASS (pass_dce);
       /* Pass group that runs when 1) enabled, 2) there are loops
@@ -362,6 +363,7 @@ along with GCC; see the file COPYING3.  If not see
       NEXT_PASS (pass_dce);
       NEXT_PASS (pass_sancov);
       NEXT_PASS (pass_asan);
+      NEXT_PASS (pass_hwasan);
       NEXT_PASS (pass_tsan);
       /* ???  We do want some kind of loop invariant motion, but we possibly
          need to adjust LIM to be more friendly towards preserving accurate
@@ -387,6 +389,7 @@ along with GCC; see the file COPYING3.  If not see
   NEXT_PASS (pass_sancov_O0);
   NEXT_PASS (pass_lower_switch_O0);
   NEXT_PASS (pass_asan_O0);
+  NEXT_PASS (pass_hwasan_O0);
   NEXT_PASS (pass_tsan_O0);
   NEXT_PASS (pass_sanopt);
   NEXT_PASS (pass_cleanup_eh);
diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def
index 7bd50715f24a2cb154b578e2abdea4e8fcdb2107..0edf349cc23e846608b89d54a1024b9d99de9c4d 100644
--- a/gcc/sanitizer.def
+++ b/gcc/sanitizer.def
@@ -183,6 +183,10 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_POINTER_SUBTRACT, "__sanitizer_ptr_sub",
 /* Hardware Address Sanitizer.  */
 DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_INIT, "__hwasan_init",
 		      BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_LOADN, "__hwasan_loadN",
+		      BT_FN_VOID_PTR_PTRMODE, ATTR_TMPURE_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_STOREN, "__hwasan_storeN",
+		      BT_FN_VOID_PTR_PTRMODE, ATTR_TMPURE_NOTHROW_LEAF_LIST)
 DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_TAG_MEM, "__hwasan_tag_memory",
 		      BT_FN_VOID_PTR_UINT8_SIZE, ATTR_NOTHROW_LIST)
 
diff --git a/gcc/sanopt.c b/gcc/sanopt.c
index 5cb98e1b50e4e1644072bd18d74797c3cac43c3f..31270153f3cf56bfbad593830de1b9334e7f65d1 100644
--- a/gcc/sanopt.c
+++ b/gcc/sanopt.c
@@ -772,7 +772,8 @@ sanopt_optimize_walker (basic_block bb, struct sanopt_ctx *ctx)
   basic_block son;
   gimple_stmt_iterator gsi;
   sanopt_info *info = (sanopt_info *) bb->aux;
-  bool asan_check_optimize = (flag_sanitize & SANITIZE_ADDRESS) != 0;
+  bool asan_check_optimize =
+    ((flag_sanitize & SANITIZE_ADDRESS) != 0) || memory_tagging_p ();
 
   for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
     {
@@ -802,6 +803,7 @@ sanopt_optimize_walker (basic_block bb, struct sanopt_ctx *ctx)
       if (asan_check_optimize
 	  && gimple_call_builtin_p (stmt, BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT))
 	{
+	  gcc_assert (!memory_tagging_p ());
 	  use_operand_p use;
 	  gimple *use_stmt;
 	  if (single_imm_use (gimple_vdef (stmt), &use, &use_stmt))
@@ -830,6 +832,7 @@ sanopt_optimize_walker (basic_block bb, struct sanopt_ctx *ctx)
 	  case IFN_UBSAN_PTR:
 	    remove = maybe_optimize_ubsan_ptr_ifn (ctx, stmt);
 	    break;
+	  case IFN_HWASAN_CHECK:
 	  case IFN_ASAN_CHECK:
 	    if (asan_check_optimize)
 	      remove = maybe_optimize_asan_check_ifn (ctx, stmt);
@@ -1262,10 +1265,11 @@ pass_sanopt::execute (function *fun)
   /* Try to remove redundant checks.  */
   if (optimize
       && (flag_sanitize
-	  & (SANITIZE_NULL | SANITIZE_ALIGNMENT
+	  & (SANITIZE_NULL | SANITIZE_ALIGNMENT | SANITIZE_HWADDRESS
 	     | SANITIZE_ADDRESS | SANITIZE_VPTR | SANITIZE_POINTER_OVERFLOW)))
     asan_num_accesses = sanopt_optimize (fun, &contains_asan_mark);
-  else if (flag_sanitize & SANITIZE_ADDRESS)
+  else if (flag_sanitize & SANITIZE_ADDRESS
+	   || memory_tagging_p ())
     {
       gimple_stmt_iterator gsi;
       FOR_EACH_BB_FN (bb, fun)
@@ -1285,7 +1289,7 @@ pass_sanopt::execute (function *fun)
       sanitize_asan_mark_poison ();
     }
 
-  if (asan_sanitize_stack_p ())
+  if (asan_sanitize_stack_p () || memory_tagging_p ())
     sanitize_rewrite_addressable_params (fun);
 
   bool use_calls = ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD < INT_MAX
@@ -1327,6 +1331,9 @@ pass_sanopt::execute (function *fun)
 		case IFN_UBSAN_VPTR:
 		  no_next = ubsan_expand_vptr_ifn (&gsi);
 		  break;
+		case IFN_HWASAN_CHECK:
+		  no_next = hwasan_expand_check_ifn (&gsi, use_calls);
+		  break;
 		case IFN_ASAN_CHECK:
 		  no_next = asan_expand_check_ifn (&gsi, use_calls);
 		  break;
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 3a0b3805d24dbd50141d4145563861e4ae3768f3..01ebd03205e57ee3a63d3344da8098160c081002 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -341,6 +341,8 @@ extern void register_pass (opt_pass* pass, pass_positioning_ops pos,
 
 extern gimple_opt_pass *make_pass_asan (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_asan_O0 (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_hwasan (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_hwasan_O0 (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_tsan (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_tsan_O0 (gcc::context *ctxt);
 extern gimple_opt_pass *make_pass_sancov (gcc::context *ctxt);


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [RFC][PATCH 10/X][libsanitizer] Colour the shadow stack for each stack variable
  2019-09-06 14:46 [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Matthew Malcomson
                   ` (8 preceding siblings ...)
  2019-09-06 14:47 ` [RFC][PATCH 13/X][libsanitizer] Instrument known builtin function calls Matthew Malcomson
@ 2019-09-06 14:47 ` Matthew Malcomson
  2019-09-06 14:47 ` [RFC][PATCH 15/X][libsanitizer] Add in MTE stubs Matthew Malcomson
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 35+ messages in thread
From: Matthew Malcomson @ 2019-09-06 14:47 UTC (permalink / raw)
  To: gcc-patches; +Cc: mliska, dodji, nd, kcc, jakub, dvyukov

[-- Attachment #1: Type: text/plain, Size: 14468 bytes --]

On entry to each function we colour the relevant shadow stack region for
each stack variable the colour to match the tag added to each pointer
for that variable.

We currently only use the library option for this, in the future inline
options will be added and configured in the same way as ASAN.

This is the first patch where we use the HWASAN shadow space, so we need
to add in the libhwasan initialisation code that creates this shadow
memory region into the binary we produce.  This instrumentation is  done
in `compile_file`.

gcc/ChangeLog:

2019-09-06  Matthew Malcomson  <matthew.malcomson@arm.com>

	* asan.c (initialize_sanitizer_builtins): Define new builtins.
	(ATTR_NOTHROW_LIST): New macro.
	(hwasan_current_tag): New.
	(hwasan_emit_prologue): New.
	(hwasan_create_untagged_base): New.
	(hwasan_finish_file): New.
	* asan.h (hwasan_finish_file): New.
	(hwasan_current_tag): New.
	(hwasan_create_untagged_base): New.
	(hwasan_emit_prologue): New.
	* builtin-types.def (BT_FN_VOID_PTR_UINT8_SIZE): New.
	* builtins.def (DEF_SANITIZER_BUILTIN): Enable for HWASAN.
	* cfgexpand.c (struct stack_vars_data):
	(expand_stack_vars): Record offsets for hwasan.
	(expand_used_vars): Call function to emit prologue.
	* sanitizer.def (BUILT_IN_HWASAN_INIT): New.
	(BUILT_IN_HWASAN_TAG_MEM): New.
	* toplev.c (compile_file): Emit libhwasan initialisation.



###############     Attachment also inlined for ease of reply    ###############


diff --git a/gcc/asan.h b/gcc/asan.h
index 127c24aa6b0e4e6d0ba332004145ec498034c955..028afdd2e7d16245c6cbbe106b7ccb9c5034d542 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -23,10 +23,14 @@ along with GCC; see the file COPYING3.  If not see
 
 extern void asan_function_start (void);
 extern void asan_finish_file (void);
+extern void hwasan_finish_file (void);
 extern void hwasan_record_base (rtx);
+extern uint8_t hwasan_current_tag ();
 extern void hwasan_increment_tag ();
 extern rtx hwasan_with_tag (rtx, poly_int64);
 extern void hwasan_tag_init ();
+extern rtx hwasan_create_untagged_base (rtx);
+extern void hwasan_emit_prologue (rtx *, rtx *, poly_int64 *, uint8_t *, size_t);
 extern bool memory_tagging_p (void);
 extern rtx_insn *asan_emit_stack_protection (rtx, rtx, unsigned int,
 					     HOST_WIDE_INT *, tree *, int);
diff --git a/gcc/asan.c b/gcc/asan.c
index a6ff503ceec294f2c09b0bd723a3d8043e4de6a1..d361b4b562f75cb0c2e081218073eacb3704f8d0 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -2895,6 +2895,11 @@ initialize_sanitizer_builtins (void)
     = build_function_type_list (void_type_node, uint64_type_node,
 				ptr_type_node, NULL_TREE);
 
+  tree BT_FN_VOID_PTR_UINT8_SIZE
+    = build_function_type_list (void_type_node, ptr_type_node,
+				unsigned_char_type_node, size_type_node,
+				NULL_TREE);
+
   tree BT_FN_BOOL_VPTR_PTR_IX_INT_INT[5];
   tree BT_FN_IX_CONST_VPTR_INT[5];
   tree BT_FN_IX_VPTR_IX_INT[5];
@@ -2945,6 +2950,8 @@ initialize_sanitizer_builtins (void)
 #define BT_FN_I16_CONST_VPTR_INT BT_FN_IX_CONST_VPTR_INT[4]
 #define BT_FN_I16_VPTR_I16_INT BT_FN_IX_VPTR_IX_INT[4]
 #define BT_FN_VOID_VPTR_I16_INT BT_FN_VOID_VPTR_IX_INT[4]
+#undef ATTR_NOTHROW_LIST
+#define ATTR_NOTHROW_LIST ECF_NOTHROW
 #undef ATTR_NOTHROW_LEAF_LIST
 #define ATTR_NOTHROW_LEAF_LIST ECF_NOTHROW | ECF_LEAF
 #undef ATTR_TMPURE_NOTHROW_LEAF_LIST
@@ -3707,6 +3714,8 @@ hwasan_record_base (rtx base)
   hwasan_base_ptr = base;
 }
 
+uint8_t hwasan_current_tag () { return tag_offset; }
+
 void
 hwasan_increment_tag ()
 {
@@ -3760,4 +3769,104 @@ hwasan_tag_init ()
   tag_offset = HWASAN_STACK_BACKGROUND + 1;
 }
 
+void
+hwasan_emit_prologue (rtx *bases,
+		      rtx *untagged_bases,
+		      poly_int64 *offsets,
+		      uint8_t *tags,
+		      size_t length)
+{
+  /*
+    NOTE: bases contains both the tagged and untagged base.
+    This allows us to get both the original frame tag and the untagged variable
+    pointer with a minimal of extra instructions.
+
+    We fetch the untagged variable pointer from the offset to the untagged base
+    and fetch the "base" tag from the tagged base.
+
+    We need the untagged base pointer since libhwasan only accepts untagged
+    pointers in __hwasan_tag_memory.  We need the tagged base pointer to obtain
+    the base tag for an offset.
+
+    We also will need the tagged base pointer for MTE, since the ADDTAG
+    instruction takes a tagged pointer.
+ */
+  for (size_t i = 0; (i * 2) + 1 < length; i++)
+    {
+      poly_int64 start = offsets[i * 2];
+      poly_int64 end = offsets[(i * 2) + 1];
+
+      poly_int64 bot, top;
+      if (known_ge (start, end))
+	{
+	  top = start;
+	  bot = end;
+	}
+      else
+	{
+	  top = end;
+	  bot = start;
+	}
+      poly_int64 size = (top - bot);
+
+      /* Can't check that all poly_int64's are aligned, but still nice
+	 to check when we can.  */
+      HOST_WIDE_INT tmp;
+      if (top.is_constant (&tmp))
+	gcc_assert (tmp % HWASAN_TAG_GRANULE_SIZE == 0);
+      if (bot.is_constant (&tmp))
+	gcc_assert (tmp % HWASAN_TAG_GRANULE_SIZE == 0);
+      if (size.is_constant (&tmp))
+	gcc_assert (tmp % HWASAN_TAG_GRANULE_SIZE == 0);
+
+      /* TODO Other options (i.e. inline options)  */
+      /* TODO At the moment we don't generate a random base tag for each
+         frame.  When that happens we will need to generate the tag by
+         adding tags[i] to the frame tag fetched from `bases[i]`.  */
+      rtx ret = init_one_libfunc ("__hwasan_tag_memory");
+      emit_library_call (ret,
+	  LCT_NORMAL,
+	  VOIDmode,
+	  plus_constant (ptr_mode, untagged_bases[i], bot),
+	  ptr_mode,
+	  const_int_rtx[MAX_SAVED_CONST_INT + tags[i]],
+	  QImode,
+	  gen_int_mode (size, ptr_mode),
+	  ptr_mode);
+    }
+}
+
+rtx
+hwasan_create_untagged_base (rtx orig_base)
+{
+  rtx untagged_base = gen_reg_rtx (Pmode);
+  rtx tag_mask = gen_int_mode ((1ULL << HWASAN_SHIFT) - 1, Pmode);
+  untagged_base = expand_binop (Pmode, and_optab,
+				orig_base, tag_mask,
+				untagged_base, true, OPTAB_DIRECT);
+  gcc_assert (untagged_base);
+  return untagged_base;
+}
+
+/* Needs to be GTY(()), because cgraph_build_static_cdtor may
+   invoke ggc_collect.  */
+static GTY(()) tree hwasan_ctor_statements;
+
+void
+hwasan_finish_file (void)
+{
+  /* Avoid instrumenting code in the hwasan constructors/destructors.  */
+  flag_sanitize &= ~SANITIZE_HWADDRESS;
+  /* TODO Only do this if in userspace.
+      For kernel space will have to look more closely into this.
+      May want to look at `asan_finish_file` for what ASAN does in this
+      situation.  */
+
+  int priority = MAX_RESERVED_INIT_PRIORITY - 1;
+  tree fn = builtin_decl_implicit (BUILT_IN_HWASAN_INIT);
+  append_to_statement_list (build_call_expr (fn, 0), &hwasan_ctor_statements);
+  cgraph_build_static_cdtor ('I', hwasan_ctor_statements, priority);
+  flag_sanitize |= SANITIZE_HWADDRESS;
+}
+
 #include "gt-asan.h"
diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def
index e5c9e063c480d1392b6c2b395ec9d029b6d94209..d05f597b6434f39fe95d4f28dd2ef3ed463dd925 100644
--- a/gcc/builtin-types.def
+++ b/gcc/builtin-types.def
@@ -625,6 +625,8 @@ DEF_FUNCTION_TYPE_3 (BT_FN_VOID_UINT32_UINT32_PTR,
 DEF_FUNCTION_TYPE_3 (BT_FN_VOID_SIZE_SIZE_PTR, BT_VOID, BT_SIZE, BT_SIZE,
 		     BT_PTR)
 DEF_FUNCTION_TYPE_3 (BT_FN_UINT_UINT_PTR_PTR, BT_UINT, BT_UINT, BT_PTR, BT_PTR)
+DEF_FUNCTION_TYPE_3 (BT_FN_VOID_PTR_UINT8_SIZE, BT_VOID, BT_PTR, BT_UINT8,
+		     BT_SIZE)
 
 DEF_FUNCTION_TYPE_4 (BT_FN_SIZE_CONST_PTR_SIZE_SIZE_FILEPTR,
 		     BT_SIZE, BT_CONST_PTR, BT_SIZE, BT_SIZE, BT_FILEPTR)
diff --git a/gcc/builtins.def b/gcc/builtins.def
index c92292aeab9da21cb8268e6483078a6be9e49d95..e067ebc7f7003bcdf7df4d52db18c31762623285 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -237,6 +237,7 @@ along with GCC; see the file COPYING3.  If not see
   DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE,    \
 	       true, true, true, ATTRS, true, \
 	      (flag_sanitize & (SANITIZE_ADDRESS | SANITIZE_THREAD \
+				| SANITIZE_HWADDRESS \
 				| SANITIZE_UNDEFINED \
 				| SANITIZE_UNDEFINED_NONDEFAULT) \
 	       || flag_sanitize_coverage))
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 10739bc25940374c686c191ca76b1dfe8f000562..aacf210facc462675a980ee87bd38d4a7d94ad09 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -1034,9 +1034,24 @@ struct stack_vars_data
      The vector is in reversed, highest offset pairs come first.  */
   auto_vec<HOST_WIDE_INT> asan_vec;
 
+  /* HWASAN records the poly_int64 since it needs to act on everything recorded
+     to the stack (as anything not properly coloured would end up causing a
+     falut of some sort).
+
+     ASAN records HOST_WIDE_INT offsets (that was enough before the
+     introduction of SVE vectors) which  */
+  auto_vec<poly_int64> hwasan_vec;
+  auto_vec<rtx> hwasan_untagged_base_vec;
+  auto_vec<rtx> hwasan_base_vec;
+
   /* Vector of partition representative decls in between the paddings.  */
   auto_vec<tree> asan_decl_vec;
 
+  /* Vector of tag offsets representing the colour of each stack variable.
+     Each offset determines the difference between the randomly generated
+     colour for the current frame and the colour for this stack variable.  */
+  auto_vec<uint8_t> hwasan_colour_vec;
+
   /* Base pseudo register for Address Sanitizer protected automatic vars.  */
   rtx asan_base;
 
@@ -1054,6 +1069,7 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
   size_t si, i, j, n = stack_vars_num;
   poly_uint64 large_size = 0, large_alloc = 0;
   rtx large_base = NULL;
+  rtx large_untagged_base = NULL;
   unsigned large_align = 0;
   bool large_allocation_done = false;
   tree decl;
@@ -1110,7 +1126,7 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
     {
       rtx base;
       unsigned base_align, alignb;
-      poly_int64 offset;
+      poly_int64 offset = 0;
 
       i = stack_vars_sorted[si];
 
@@ -1156,7 +1172,9 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
 		 ABI requirements) and these can't share a tag granule with a
 		 tagged variable.  */
 	      gcc_assert (stack_vars[i].alignb >= HWASAN_TAG_GRANULE_SIZE);
-	      alloc_stack_frame_space (0, HWASAN_TAG_GRANULE_SIZE);
+	      offset = alloc_stack_frame_space (0, HWASAN_TAG_GRANULE_SIZE);
+	      data->hwasan_vec.safe_push (offset);
+	      data->hwasan_untagged_base_vec.safe_push (virtual_stack_vars_rtx);
 	    }
 	  /* ASAN description strings don't yet have a syntax for expressing
 	     polynomial offsets.  */
@@ -1237,6 +1255,9 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
 	      offset = alloc_stack_frame_space (stack_vars[i].size, alignb);
 	      base_align = crtl->max_used_stack_slot_alignment;
 	    }
+
+	  if (memory_tagging_p ())
+	    data->hwasan_vec.safe_push (offset);
 	}
       else
 	{
@@ -1262,6 +1283,18 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
 
 	  gcc_assert (large_base != NULL);
 	  large_alloc = aligned_upper_bound (large_alloc, alignb);
+	  if (memory_tagging_p ())
+	    {
+	      /*
+		 For now we just assume that an object with a large alignment
+		 requirement means that the alignment requirement is greater
+		 than the required alignment for tags.
+		*/
+	      if (!large_untagged_base)
+		large_untagged_base = hwasan_create_untagged_base (large_base);
+	      data->hwasan_vec.safe_push (large_alloc);
+	      data->hwasan_untagged_base_vec.safe_push (large_untagged_base);
+	    }
 	  offset = large_alloc;
 	  large_alloc += stack_vars[i].size;
 	  if (memory_tagging_p ())
@@ -1280,6 +1313,7 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
 		 */
 	      poly_int64 align_again =
 		aligned_upper_bound (large_alloc, HWASAN_TAG_GRANULE_SIZE);
+	      data->hwasan_vec.safe_push (align_again);
 	    }
 
 	  base = large_base;
@@ -1297,8 +1331,15 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
 				   ? data->asan_base
 				   : virtual_stack_vars_rtx);
 	}
+
       if (memory_tagging_p ())
-	hwasan_increment_tag ();
+	{
+	  /* Record the tag for this object in `data` so the prologue knows
+	     what colour to put in the shadow memory during cfgexpand.c.  */
+	  data->hwasan_base_vec.safe_push (base);
+	  data->hwasan_colour_vec.safe_push (hwasan_current_tag ());
+	  hwasan_increment_tag ();
+	}
     }
 
   gcc_assert (known_eq (large_alloc, large_size));
@@ -2358,6 +2399,13 @@ expand_used_vars (void)
 	}
 
       expand_stack_vars (NULL, &data);
+
+      if (memory_tagging_p ())
+	hwasan_emit_prologue (data.hwasan_base_vec.address (),
+			      data.hwasan_untagged_base_vec.address (),
+			      data.hwasan_vec.address (),
+			      data.hwasan_colour_vec.address (),
+			      data.hwasan_vec.length ());
     }
 
   if (asan_sanitize_allocas_p () && cfun->calls_alloca)
diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def
index 374d15007d868363d9b4fbf467e1e462abbca61a..7bd50715f24a2cb154b578e2abdea4e8fcdb2107 100644
--- a/gcc/sanitizer.def
+++ b/gcc/sanitizer.def
@@ -180,6 +180,12 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_POINTER_COMPARE, "__sanitizer_ptr_cmp",
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_POINTER_SUBTRACT, "__sanitizer_ptr_sub",
 		      BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
 
+/* Hardware Address Sanitizer.  */
+DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_INIT, "__hwasan_init",
+		      BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_TAG_MEM, "__hwasan_tag_memory",
+		      BT_FN_VOID_PTR_UINT8_SIZE, ATTR_NOTHROW_LIST)
+
 /* Thread Sanitizer */
 DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_INIT, "__tsan_init", 
 		      BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
diff --git a/gcc/toplev.c b/gcc/toplev.c
index d300ac2ec894ee947156616e71796d55d9d04307..93484f87690b8d54d93abe0a67cdf51c4a9a3ee1 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -508,6 +508,9 @@ compile_file (void)
       if (flag_sanitize & SANITIZE_THREAD)
 	tsan_finish_file ();
 
+      if (gate_hwasan ())
+	hwasan_finish_file ();
+
       omp_finish_file ();
 
       hsa_output_brig ();


[-- Attachment #2: hwasan-implementation09.patch --]
[-- Type: text/plain, Size: 12645 bytes --]

diff --git a/gcc/asan.h b/gcc/asan.h
index 127c24aa6b0e4e6d0ba332004145ec498034c955..028afdd2e7d16245c6cbbe106b7ccb9c5034d542 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -23,10 +23,14 @@ along with GCC; see the file COPYING3.  If not see
 
 extern void asan_function_start (void);
 extern void asan_finish_file (void);
+extern void hwasan_finish_file (void);
 extern void hwasan_record_base (rtx);
+extern uint8_t hwasan_current_tag ();
 extern void hwasan_increment_tag ();
 extern rtx hwasan_with_tag (rtx, poly_int64);
 extern void hwasan_tag_init ();
+extern rtx hwasan_create_untagged_base (rtx);
+extern void hwasan_emit_prologue (rtx *, rtx *, poly_int64 *, uint8_t *, size_t);
 extern bool memory_tagging_p (void);
 extern rtx_insn *asan_emit_stack_protection (rtx, rtx, unsigned int,
 					     HOST_WIDE_INT *, tree *, int);
diff --git a/gcc/asan.c b/gcc/asan.c
index a6ff503ceec294f2c09b0bd723a3d8043e4de6a1..d361b4b562f75cb0c2e081218073eacb3704f8d0 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -2895,6 +2895,11 @@ initialize_sanitizer_builtins (void)
     = build_function_type_list (void_type_node, uint64_type_node,
 				ptr_type_node, NULL_TREE);
 
+  tree BT_FN_VOID_PTR_UINT8_SIZE
+    = build_function_type_list (void_type_node, ptr_type_node,
+				unsigned_char_type_node, size_type_node,
+				NULL_TREE);
+
   tree BT_FN_BOOL_VPTR_PTR_IX_INT_INT[5];
   tree BT_FN_IX_CONST_VPTR_INT[5];
   tree BT_FN_IX_VPTR_IX_INT[5];
@@ -2945,6 +2950,8 @@ initialize_sanitizer_builtins (void)
 #define BT_FN_I16_CONST_VPTR_INT BT_FN_IX_CONST_VPTR_INT[4]
 #define BT_FN_I16_VPTR_I16_INT BT_FN_IX_VPTR_IX_INT[4]
 #define BT_FN_VOID_VPTR_I16_INT BT_FN_VOID_VPTR_IX_INT[4]
+#undef ATTR_NOTHROW_LIST
+#define ATTR_NOTHROW_LIST ECF_NOTHROW
 #undef ATTR_NOTHROW_LEAF_LIST
 #define ATTR_NOTHROW_LEAF_LIST ECF_NOTHROW | ECF_LEAF
 #undef ATTR_TMPURE_NOTHROW_LEAF_LIST
@@ -3707,6 +3714,8 @@ hwasan_record_base (rtx base)
   hwasan_base_ptr = base;
 }
 
+uint8_t hwasan_current_tag () { return tag_offset; }
+
 void
 hwasan_increment_tag ()
 {
@@ -3760,4 +3769,104 @@ hwasan_tag_init ()
   tag_offset = HWASAN_STACK_BACKGROUND + 1;
 }
 
+void
+hwasan_emit_prologue (rtx *bases,
+		      rtx *untagged_bases,
+		      poly_int64 *offsets,
+		      uint8_t *tags,
+		      size_t length)
+{
+  /*
+    NOTE: bases contains both the tagged and untagged base.
+    This allows us to get both the original frame tag and the untagged variable
+    pointer with a minimal of extra instructions.
+
+    We fetch the untagged variable pointer from the offset to the untagged base
+    and fetch the "base" tag from the tagged base.
+
+    We need the untagged base pointer since libhwasan only accepts untagged
+    pointers in __hwasan_tag_memory.  We need the tagged base pointer to obtain
+    the base tag for an offset.
+
+    We also will need the tagged base pointer for MTE, since the ADDTAG
+    instruction takes a tagged pointer.
+ */
+  for (size_t i = 0; (i * 2) + 1 < length; i++)
+    {
+      poly_int64 start = offsets[i * 2];
+      poly_int64 end = offsets[(i * 2) + 1];
+
+      poly_int64 bot, top;
+      if (known_ge (start, end))
+	{
+	  top = start;
+	  bot = end;
+	}
+      else
+	{
+	  top = end;
+	  bot = start;
+	}
+      poly_int64 size = (top - bot);
+
+      /* Can't check that all poly_int64's are aligned, but still nice
+	 to check when we can.  */
+      HOST_WIDE_INT tmp;
+      if (top.is_constant (&tmp))
+	gcc_assert (tmp % HWASAN_TAG_GRANULE_SIZE == 0);
+      if (bot.is_constant (&tmp))
+	gcc_assert (tmp % HWASAN_TAG_GRANULE_SIZE == 0);
+      if (size.is_constant (&tmp))
+	gcc_assert (tmp % HWASAN_TAG_GRANULE_SIZE == 0);
+
+      /* TODO Other options (i.e. inline options)  */
+      /* TODO At the moment we don't generate a random base tag for each
+         frame.  When that happens we will need to generate the tag by
+         adding tags[i] to the frame tag fetched from `bases[i]`.  */
+      rtx ret = init_one_libfunc ("__hwasan_tag_memory");
+      emit_library_call (ret,
+	  LCT_NORMAL,
+	  VOIDmode,
+	  plus_constant (ptr_mode, untagged_bases[i], bot),
+	  ptr_mode,
+	  const_int_rtx[MAX_SAVED_CONST_INT + tags[i]],
+	  QImode,
+	  gen_int_mode (size, ptr_mode),
+	  ptr_mode);
+    }
+}
+
+rtx
+hwasan_create_untagged_base (rtx orig_base)
+{
+  rtx untagged_base = gen_reg_rtx (Pmode);
+  rtx tag_mask = gen_int_mode ((1ULL << HWASAN_SHIFT) - 1, Pmode);
+  untagged_base = expand_binop (Pmode, and_optab,
+				orig_base, tag_mask,
+				untagged_base, true, OPTAB_DIRECT);
+  gcc_assert (untagged_base);
+  return untagged_base;
+}
+
+/* Needs to be GTY(()), because cgraph_build_static_cdtor may
+   invoke ggc_collect.  */
+static GTY(()) tree hwasan_ctor_statements;
+
+void
+hwasan_finish_file (void)
+{
+  /* Avoid instrumenting code in the hwasan constructors/destructors.  */
+  flag_sanitize &= ~SANITIZE_HWADDRESS;
+  /* TODO Only do this if in userspace.
+      For kernel space will have to look more closely into this.
+      May want to look at `asan_finish_file` for what ASAN does in this
+      situation.  */
+
+  int priority = MAX_RESERVED_INIT_PRIORITY - 1;
+  tree fn = builtin_decl_implicit (BUILT_IN_HWASAN_INIT);
+  append_to_statement_list (build_call_expr (fn, 0), &hwasan_ctor_statements);
+  cgraph_build_static_cdtor ('I', hwasan_ctor_statements, priority);
+  flag_sanitize |= SANITIZE_HWADDRESS;
+}
+
 #include "gt-asan.h"
diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def
index e5c9e063c480d1392b6c2b395ec9d029b6d94209..d05f597b6434f39fe95d4f28dd2ef3ed463dd925 100644
--- a/gcc/builtin-types.def
+++ b/gcc/builtin-types.def
@@ -625,6 +625,8 @@ DEF_FUNCTION_TYPE_3 (BT_FN_VOID_UINT32_UINT32_PTR,
 DEF_FUNCTION_TYPE_3 (BT_FN_VOID_SIZE_SIZE_PTR, BT_VOID, BT_SIZE, BT_SIZE,
 		     BT_PTR)
 DEF_FUNCTION_TYPE_3 (BT_FN_UINT_UINT_PTR_PTR, BT_UINT, BT_UINT, BT_PTR, BT_PTR)
+DEF_FUNCTION_TYPE_3 (BT_FN_VOID_PTR_UINT8_SIZE, BT_VOID, BT_PTR, BT_UINT8,
+		     BT_SIZE)
 
 DEF_FUNCTION_TYPE_4 (BT_FN_SIZE_CONST_PTR_SIZE_SIZE_FILEPTR,
 		     BT_SIZE, BT_CONST_PTR, BT_SIZE, BT_SIZE, BT_FILEPTR)
diff --git a/gcc/builtins.def b/gcc/builtins.def
index c92292aeab9da21cb8268e6483078a6be9e49d95..e067ebc7f7003bcdf7df4d52db18c31762623285 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -237,6 +237,7 @@ along with GCC; see the file COPYING3.  If not see
   DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE,    \
 	       true, true, true, ATTRS, true, \
 	      (flag_sanitize & (SANITIZE_ADDRESS | SANITIZE_THREAD \
+				| SANITIZE_HWADDRESS \
 				| SANITIZE_UNDEFINED \
 				| SANITIZE_UNDEFINED_NONDEFAULT) \
 	       || flag_sanitize_coverage))
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index 10739bc25940374c686c191ca76b1dfe8f000562..aacf210facc462675a980ee87bd38d4a7d94ad09 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -1034,9 +1034,24 @@ struct stack_vars_data
      The vector is in reversed, highest offset pairs come first.  */
   auto_vec<HOST_WIDE_INT> asan_vec;
 
+  /* HWASAN records the poly_int64 since it needs to act on everything recorded
+     to the stack (as anything not properly coloured would end up causing a
+     falut of some sort).
+
+     ASAN records HOST_WIDE_INT offsets (that was enough before the
+     introduction of SVE vectors) which  */
+  auto_vec<poly_int64> hwasan_vec;
+  auto_vec<rtx> hwasan_untagged_base_vec;
+  auto_vec<rtx> hwasan_base_vec;
+
   /* Vector of partition representative decls in between the paddings.  */
   auto_vec<tree> asan_decl_vec;
 
+  /* Vector of tag offsets representing the colour of each stack variable.
+     Each offset determines the difference between the randomly generated
+     colour for the current frame and the colour for this stack variable.  */
+  auto_vec<uint8_t> hwasan_colour_vec;
+
   /* Base pseudo register for Address Sanitizer protected automatic vars.  */
   rtx asan_base;
 
@@ -1054,6 +1069,7 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
   size_t si, i, j, n = stack_vars_num;
   poly_uint64 large_size = 0, large_alloc = 0;
   rtx large_base = NULL;
+  rtx large_untagged_base = NULL;
   unsigned large_align = 0;
   bool large_allocation_done = false;
   tree decl;
@@ -1110,7 +1126,7 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
     {
       rtx base;
       unsigned base_align, alignb;
-      poly_int64 offset;
+      poly_int64 offset = 0;
 
       i = stack_vars_sorted[si];
 
@@ -1156,7 +1172,9 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
 		 ABI requirements) and these can't share a tag granule with a
 		 tagged variable.  */
 	      gcc_assert (stack_vars[i].alignb >= HWASAN_TAG_GRANULE_SIZE);
-	      alloc_stack_frame_space (0, HWASAN_TAG_GRANULE_SIZE);
+	      offset = alloc_stack_frame_space (0, HWASAN_TAG_GRANULE_SIZE);
+	      data->hwasan_vec.safe_push (offset);
+	      data->hwasan_untagged_base_vec.safe_push (virtual_stack_vars_rtx);
 	    }
 	  /* ASAN description strings don't yet have a syntax for expressing
 	     polynomial offsets.  */
@@ -1237,6 +1255,9 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
 	      offset = alloc_stack_frame_space (stack_vars[i].size, alignb);
 	      base_align = crtl->max_used_stack_slot_alignment;
 	    }
+
+	  if (memory_tagging_p ())
+	    data->hwasan_vec.safe_push (offset);
 	}
       else
 	{
@@ -1262,6 +1283,18 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
 
 	  gcc_assert (large_base != NULL);
 	  large_alloc = aligned_upper_bound (large_alloc, alignb);
+	  if (memory_tagging_p ())
+	    {
+	      /*
+		 For now we just assume that an object with a large alignment
+		 requirement means that the alignment requirement is greater
+		 than the required alignment for tags.
+		*/
+	      if (!large_untagged_base)
+		large_untagged_base = hwasan_create_untagged_base (large_base);
+	      data->hwasan_vec.safe_push (large_alloc);
+	      data->hwasan_untagged_base_vec.safe_push (large_untagged_base);
+	    }
 	  offset = large_alloc;
 	  large_alloc += stack_vars[i].size;
 	  if (memory_tagging_p ())
@@ -1280,6 +1313,7 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
 		 */
 	      poly_int64 align_again =
 		aligned_upper_bound (large_alloc, HWASAN_TAG_GRANULE_SIZE);
+	      data->hwasan_vec.safe_push (align_again);
 	    }
 
 	  base = large_base;
@@ -1297,8 +1331,15 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data)
 				   ? data->asan_base
 				   : virtual_stack_vars_rtx);
 	}
+
       if (memory_tagging_p ())
-	hwasan_increment_tag ();
+	{
+	  /* Record the tag for this object in `data` so the prologue knows
+	     what colour to put in the shadow memory during cfgexpand.c.  */
+	  data->hwasan_base_vec.safe_push (base);
+	  data->hwasan_colour_vec.safe_push (hwasan_current_tag ());
+	  hwasan_increment_tag ();
+	}
     }
 
   gcc_assert (known_eq (large_alloc, large_size));
@@ -2358,6 +2399,13 @@ expand_used_vars (void)
 	}
 
       expand_stack_vars (NULL, &data);
+
+      if (memory_tagging_p ())
+	hwasan_emit_prologue (data.hwasan_base_vec.address (),
+			      data.hwasan_untagged_base_vec.address (),
+			      data.hwasan_vec.address (),
+			      data.hwasan_colour_vec.address (),
+			      data.hwasan_vec.length ());
     }
 
   if (asan_sanitize_allocas_p () && cfun->calls_alloca)
diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def
index 374d15007d868363d9b4fbf467e1e462abbca61a..7bd50715f24a2cb154b578e2abdea4e8fcdb2107 100644
--- a/gcc/sanitizer.def
+++ b/gcc/sanitizer.def
@@ -180,6 +180,12 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_POINTER_COMPARE, "__sanitizer_ptr_cmp",
 DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_POINTER_SUBTRACT, "__sanitizer_ptr_sub",
 		      BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST)
 
+/* Hardware Address Sanitizer.  */
+DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_INIT, "__hwasan_init",
+		      BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_HWASAN_TAG_MEM, "__hwasan_tag_memory",
+		      BT_FN_VOID_PTR_UINT8_SIZE, ATTR_NOTHROW_LIST)
+
 /* Thread Sanitizer */
 DEF_SANITIZER_BUILTIN(BUILT_IN_TSAN_INIT, "__tsan_init", 
 		      BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST)
diff --git a/gcc/toplev.c b/gcc/toplev.c
index d300ac2ec894ee947156616e71796d55d9d04307..93484f87690b8d54d93abe0a67cdf51c4a9a3ee1 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -508,6 +508,9 @@ compile_file (void)
       if (flag_sanitize & SANITIZE_THREAD)
 	tsan_finish_file ();
 
+      if (gate_hwasan ())
+	hwasan_finish_file ();
+
       omp_finish_file ();
 
       hsa_output_brig ();


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [RFC][PATCH 11/X][libsanitizer] Uncolour stack frame on function exit
  2019-09-06 14:46 [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Matthew Malcomson
                   ` (10 preceding siblings ...)
  2019-09-06 14:47 ` [RFC][PATCH 15/X][libsanitizer] Add in MTE stubs Matthew Malcomson
@ 2019-09-06 14:47 ` Matthew Malcomson
  2019-09-06 14:47 ` [RFC][PATCH 16/X][libsanitizer] Build libhwasan with interceptors Matthew Malcomson
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 35+ messages in thread
From: Matthew Malcomson @ 2019-09-06 14:47 UTC (permalink / raw)
  To: gcc-patches; +Cc: mliska, dodji, nd, kcc, jakub, dvyukov

[-- Attachment #1: Type: text/plain, Size: 3514 bytes --]

When exiting a function we need to ensure the shadow stack for this
function has no remaining colour.  Without clearing the shadow stack
area for this function pointer checks to later function calls could
check untagged areas (such as parameters passed on the stack) against
a shadow stack area with left-over colour causing a false-positive.

Here we ensure that the entire stack frame is cleared on function exit.

gcc/ChangeLog:

2019-09-06  Matthew Malcomson  <matthew.malcomson@arm.com>

	* asan.c (hwasan_emit_uncolour_frame): New.
	* asan.h (hwasan_emit_uncolour_frame): New.
	* cfgexpand.c (expand_used_vars): Uncolour shadow frame on
	function exit.



###############     Attachment also inlined for ease of reply    ###############


diff --git a/gcc/asan.h b/gcc/asan.h
index 028afdd2e7d16245c6cbbe106b7ccb9c5034d542..c5492ce35980d0b26d4707f96482b69dc76a525a 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -31,6 +31,7 @@ extern rtx hwasan_with_tag (rtx, poly_int64);
 extern void hwasan_tag_init ();
 extern rtx hwasan_create_untagged_base (rtx);
 extern void hwasan_emit_prologue (rtx *, rtx *, poly_int64 *, uint8_t *, size_t);
+extern rtx_insn *hwasan_emit_uncolour_frame (rtx, rtx, rtx_insn *);
 extern bool memory_tagging_p (void);
 extern rtx_insn *asan_emit_stack_protection (rtx, rtx, unsigned int,
 					     HOST_WIDE_INT *, tree *, int);
diff --git a/gcc/asan.c b/gcc/asan.c
index d361b4b562f75cb0c2e081218073eacb3704f8d0..0e74e32ae6ca4e130b3f13abe110364b119def46 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -3836,6 +3836,46 @@ hwasan_emit_prologue (rtx *bases,
     }
 }
 
+rtx_insn *
+hwasan_emit_uncolour_frame (rtx dynamic, rtx vars, rtx_insn *before)
+{
+  if (before)
+    push_to_sequence (before);
+  else
+    start_sequence ();
+
+  dynamic = convert_memory_address (ptr_mode, dynamic);
+  vars = convert_memory_address (ptr_mode, vars);
+
+  rtx top_rtx;
+  rtx bot_rtx;
+  if (STACK_GROWS_DOWNWARD)
+    {
+      top_rtx = vars;
+      bot_rtx = dynamic;
+    }
+  else
+    {
+      top_rtx = dynamic;
+      bot_rtx = vars;
+    }
+
+  rtx size_rtx = expand_simple_binop (Pmode, MINUS, top_rtx, bot_rtx,
+				  NULL_RTX, /* unsignedp = */0, OPTAB_DIRECT);
+
+  /* TODO Other options (i.e. inline options)  */
+  rtx ret = init_one_libfunc ("__hwasan_tag_memory");
+  emit_library_call (ret, LCT_NORMAL, VOIDmode,
+      bot_rtx, ptr_mode,
+      const0_rtx, QImode,
+      size_rtx, ptr_mode);
+
+  do_pending_stack_adjust ();
+  rtx_insn *insns = get_insns ();
+  end_sequence ();
+  return insns;
+}
+
 rtx
 hwasan_create_untagged_base (rtx orig_base)
 {
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index aacf210facc462675a980ee87bd38d4a7d94ad09..9f0872b32354cbc3186f3f2d2600f711a46926d1 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -2412,6 +2412,14 @@ expand_used_vars (void)
     var_end_seq = asan_emit_allocas_unpoison (virtual_stack_dynamic_rtx,
 					      virtual_stack_vars_rtx,
 					      var_end_seq);
+  /* Here we uncolour the entire frame for this function.
+     We need to uncolour *something* if either we have coloured some local
+     variables or we have coloured some alloca objects.  */
+  else if (memory_tagging_p ()
+	   && (cfun->calls_alloca || stack_vars_num > 0))
+    var_end_seq = hwasan_emit_uncolour_frame (virtual_stack_dynamic_rtx,
+					      virtual_stack_vars_rtx,
+					      var_end_seq);
 
   fini_vars_expansion ();
 


[-- Attachment #2: hwasan-implementation10.patch --]
[-- Type: text/plain, Size: 2664 bytes --]

diff --git a/gcc/asan.h b/gcc/asan.h
index 028afdd2e7d16245c6cbbe106b7ccb9c5034d542..c5492ce35980d0b26d4707f96482b69dc76a525a 100644
--- a/gcc/asan.h
+++ b/gcc/asan.h
@@ -31,6 +31,7 @@ extern rtx hwasan_with_tag (rtx, poly_int64);
 extern void hwasan_tag_init ();
 extern rtx hwasan_create_untagged_base (rtx);
 extern void hwasan_emit_prologue (rtx *, rtx *, poly_int64 *, uint8_t *, size_t);
+extern rtx_insn *hwasan_emit_uncolour_frame (rtx, rtx, rtx_insn *);
 extern bool memory_tagging_p (void);
 extern rtx_insn *asan_emit_stack_protection (rtx, rtx, unsigned int,
 					     HOST_WIDE_INT *, tree *, int);
diff --git a/gcc/asan.c b/gcc/asan.c
index d361b4b562f75cb0c2e081218073eacb3704f8d0..0e74e32ae6ca4e130b3f13abe110364b119def46 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -3836,6 +3836,46 @@ hwasan_emit_prologue (rtx *bases,
     }
 }
 
+rtx_insn *
+hwasan_emit_uncolour_frame (rtx dynamic, rtx vars, rtx_insn *before)
+{
+  if (before)
+    push_to_sequence (before);
+  else
+    start_sequence ();
+
+  dynamic = convert_memory_address (ptr_mode, dynamic);
+  vars = convert_memory_address (ptr_mode, vars);
+
+  rtx top_rtx;
+  rtx bot_rtx;
+  if (STACK_GROWS_DOWNWARD)
+    {
+      top_rtx = vars;
+      bot_rtx = dynamic;
+    }
+  else
+    {
+      top_rtx = dynamic;
+      bot_rtx = vars;
+    }
+
+  rtx size_rtx = expand_simple_binop (Pmode, MINUS, top_rtx, bot_rtx,
+				  NULL_RTX, /* unsignedp = */0, OPTAB_DIRECT);
+
+  /* TODO Other options (i.e. inline options)  */
+  rtx ret = init_one_libfunc ("__hwasan_tag_memory");
+  emit_library_call (ret, LCT_NORMAL, VOIDmode,
+      bot_rtx, ptr_mode,
+      const0_rtx, QImode,
+      size_rtx, ptr_mode);
+
+  do_pending_stack_adjust ();
+  rtx_insn *insns = get_insns ();
+  end_sequence ();
+  return insns;
+}
+
 rtx
 hwasan_create_untagged_base (rtx orig_base)
 {
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index aacf210facc462675a980ee87bd38d4a7d94ad09..9f0872b32354cbc3186f3f2d2600f711a46926d1 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -2412,6 +2412,14 @@ expand_used_vars (void)
     var_end_seq = asan_emit_allocas_unpoison (virtual_stack_dynamic_rtx,
 					      virtual_stack_vars_rtx,
 					      var_end_seq);
+  /* Here we uncolour the entire frame for this function.
+     We need to uncolour *something* if either we have coloured some local
+     variables or we have coloured some alloca objects.  */
+  else if (memory_tagging_p ()
+	   && (cfun->calls_alloca || stack_vars_num > 0))
+    var_end_seq = hwasan_emit_uncolour_frame (virtual_stack_dynamic_rtx,
+					      virtual_stack_vars_rtx,
+					      var_end_seq);
 
   fini_vars_expansion ();
 


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [RFC][PATCH 6/X][libsanitizer] Add -fsanitize=hwaddress flags
  2019-09-06 14:46 [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Matthew Malcomson
                   ` (13 preceding siblings ...)
  2019-09-06 14:47 ` [RFC][PATCH 12/X][libsanitizer] Check pointer tags match address tags Matthew Malcomson
@ 2019-09-06 14:47 ` Matthew Malcomson
  2019-09-09 10:06   ` Martin Liška
  2019-09-06 14:47 ` [RFC][PATCH 9/X][libsanitizer] Put tags into each stack variable pointer Matthew Malcomson
                   ` (2 subsequent siblings)
  17 siblings, 1 reply; 35+ messages in thread
From: Matthew Malcomson @ 2019-09-06 14:47 UTC (permalink / raw)
  To: gcc-patches; +Cc: mliska, dodji, nd, kcc, jakub, dvyukov

[-- Attachment #1: Type: text/plain, Size: 7744 bytes --]

This flag can't be used at the same time as any of the other sanitizers.
We add an equivalent flag to -static-libasan in -static-libhwasan to
ensure static linking.

gcc/ChangeLog:

2019-09-06  Matthew Malcomson  <matthew.malcomson@arm.com>

	* common.opt (static-libhwasan): New cli option.
	* config/gnu-user.h (LIBHWASAN_EARLY_SPEC): hwasan equivalent of
	asan command line flags.
	* flag-types.h (enum sanitize_code): SANITIZE_HWADDRESS member.
	* gcc.c (STATIC_LIBHWASAN_LIBS): New macro.
	(LIBHWASAN_SPEC): New macro.
	(LIBHWASAN_EARLY_SPEC): New macro.
	(SANITIZER_EARLY_SPEC): Update to include hwasan.
	(SANITIZER_SPEC): Update to include hwasan.
	(sanitize_spec_function): Use hwasan.
	* opts.c (finish_options): Add conflict between hwasan and tsan,
	also between hwasan and asan.
	(sanitizer_opts): New option structure for -fsanitize=hwaddress.



###############     Attachment also inlined for ease of reply    ###############


diff --git a/gcc/common.opt b/gcc/common.opt
index d342c4f3749a39df086236162636f14f91bcd8a0..527aada305097b54c927fd094e3ab82220459c2c 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -3273,6 +3273,9 @@ Driver
 static-libasan
 Driver
 
+static-libhwasan
+Driver
+
 static-libtsan
 Driver
 
diff --git a/gcc/config/gnu-user.h b/gcc/config/gnu-user.h
index 055a4f0afeca4a6339fd156db1bf1daf1aae0994..1e4b921afb62f22892aee0ca37e96983112a8134 100644
--- a/gcc/config/gnu-user.h
+++ b/gcc/config/gnu-user.h
@@ -129,14 +129,18 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 /* Link -lasan early on the command line.  For -static-libasan, don't link
    it for -shared link, the executable should be compiled with -static-libasan
    in that case, and for executable link with --{,no-}whole-archive around
-   it to force everything into the executable.  And similarly for -ltsan
-   and -llsan.  */
+   it to force everything into the executable.  And similarly for -ltsan,
+   -lhwasan, and -llsan.  */
 #if defined(HAVE_LD_STATIC_DYNAMIC)
 #undef LIBASAN_EARLY_SPEC
 #define LIBASAN_EARLY_SPEC "%{!shared:libasan_preinit%O%s} " \
   "%{static-libasan:%{!shared:" \
   LD_STATIC_OPTION " --whole-archive -lasan --no-whole-archive " \
   LD_DYNAMIC_OPTION "}}%{!static-libasan:-lasan}"
+#undef LIBHWASAN_EARLY_SPEC
+#define LIBHWASAN_EARLY_SPEC "%{static-libhwasan:%{!shared:" \
+  LD_STATIC_OPTION " --whole-archive -lhwasan --no-whole-archive " \
+  LD_DYNAMIC_OPTION "}}%{!static-libhwasan:-lhwasan}"
 #undef LIBTSAN_EARLY_SPEC
 #define LIBTSAN_EARLY_SPEC "%{!shared:libtsan_preinit%O%s} " \
   "%{static-libtsan:%{!shared:" \
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index a2103282d469db31ad157a87572068d943061c8c..fcc3dd45862b1b64b38a13702f7840ba461aea20 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -256,6 +256,7 @@ enum sanitize_code {
   SANITIZE_BUILTIN = 1UL << 25,
   SANITIZE_POINTER_COMPARE = 1UL << 26,
   SANITIZE_POINTER_SUBTRACT = 1UL << 27,
+  SANITIZE_HWADDRESS = 1UL << 28,
   SANITIZE_SHIFT = SANITIZE_SHIFT_BASE | SANITIZE_SHIFT_EXPONENT,
   SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
 		       | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 7ebdf1f225b49769af3047c852ad3b72d6912fc0..c3d939af1a0fac87a8de95dff3960f2175aecf6d 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -708,6 +708,24 @@ proper position among the other output files.  */
 #define LIBASAN_EARLY_SPEC ""
 #endif
 
+#ifndef LIBHWASAN_SPEC
+#define STATIC_LIBHWASAN_LIBS \
+  " %{static-libhwasan|static:%:include(libsanitizer.spec)%(link_libhwasan)}"
+#ifdef LIBHWASAN_EARLY_SPEC
+#define LIBHWASAN_SPEC STATIC_LIBHWASAN_LIBS
+#elif defined(HAVE_LD_STATIC_DYNAMIC)
+#define LIBHWASAN_SPEC "%{static-libhwasan:" LD_STATIC_OPTION \
+		     "} -lhwasan %{static-libhwasan:" LD_DYNAMIC_OPTION "}" \
+		     STATIC_LIBHWASAN_LIBS
+#else
+#define LIBHWASAN_SPEC "-lhwasan" STATIC_LIBHWASAN_LIBS
+#endif
+#endif
+
+#ifndef LIBHWASAN_EARLY_SPEC
+#define LIBHWASAN_EARLY_SPEC ""
+#endif
+
 #ifndef LIBTSAN_SPEC
 #define STATIC_LIBTSAN_LIBS \
   " %{static-libtsan|static:%:include(libsanitizer.spec)%(link_libtsan)}"
@@ -982,6 +1000,7 @@ proper position among the other output files.  */
 #ifndef SANITIZER_EARLY_SPEC
 #define SANITIZER_EARLY_SPEC "\
 %{!nostdlib:%{!r:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_EARLY_SPEC "} \
+    %{%:sanitize(hwaddress):" LIBHWASAN_EARLY_SPEC "} \
     %{%:sanitize(thread):" LIBTSAN_EARLY_SPEC "} \
     %{%:sanitize(leak):" LIBLSAN_EARLY_SPEC "}}}}"
 #endif
@@ -991,6 +1010,8 @@ proper position among the other output files.  */
 #define SANITIZER_SPEC "\
 %{!nostdlib:%{!r:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_SPEC "\
     %{static:%ecannot specify -static with -fsanitize=address}}\
+    %{%:sanitize(hwaddress):" LIBHWASAN_SPEC "\
+	%{static:%ecannot specify -static with -fsanitize=hwaddress}}\
     %{%:sanitize(thread):" LIBTSAN_SPEC "\
     %{static:%ecannot specify -static with -fsanitize=thread}}\
     %{%:sanitize(undefined):" LIBUBSAN_SPEC "}\
@@ -9387,6 +9408,8 @@ sanitize_spec_function (int argc, const char **argv)
 
   if (strcmp (argv[0], "address") == 0)
     return (flag_sanitize & SANITIZE_USER_ADDRESS) ? "" : NULL;
+  if (strcmp (argv[0], "hwaddress") == 0)
+    return (flag_sanitize & SANITIZE_HWADDRESS) ? "" : NULL;
   if (strcmp (argv[0], "kernel-address") == 0)
     return (flag_sanitize & SANITIZE_KERNEL_ADDRESS) ? "" : NULL;
   if (strcmp (argv[0], "thread") == 0)
diff --git a/gcc/opts.c b/gcc/opts.c
index 879ab17c3620ca6e002b46f4f833ed2b4c0f5432..aedb1db6c00a139f575a341559006d9c3871d233 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -1174,6 +1174,20 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
     error_at (loc,
 	      "%<-fsanitize=leak%> is incompatible with %<-fsanitize=thread%>");
 
+  /* HWASan and ASan conflict with each other.  */
+  if ((opts->x_flag_sanitize & SANITIZE_ADDRESS)
+      && (opts->x_flag_sanitize & SANITIZE_HWADDRESS))
+    error_at (loc,
+	      "%<-fsanitize=hwaddress%> is incompatible with both"
+	      "%<-fsanitize=address%> and %<-fsanitize=kernel-address%>");
+
+  /* And with TSan.  */
+  if ((opts->x_flag_sanitize & SANITIZE_HWADDRESS)
+      && (opts->x_flag_sanitize & SANITIZE_THREAD))
+    error_at (loc,
+	      "%<-fsanitize=hwaddress%> is incompatible with "
+	      "%<-fsanitize=thread%>");
+
   /* Check error recovery for -fsanitize-recover option.  */
   for (int i = 0; sanitizer_opts[i].name != NULL; ++i)
     if ((opts->x_flag_sanitize_recover & sanitizer_opts[i].flag)
@@ -1193,7 +1207,8 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
 
   /* Enable -fsanitize-address-use-after-scope if address sanitizer is
      enabled.  */
-  if ((opts->x_flag_sanitize & SANITIZE_USER_ADDRESS)
+  if (((opts->x_flag_sanitize & SANITIZE_USER_ADDRESS)
+       || (opts->x_flag_sanitize & SANITIZE_HWADDRESS))
       && !opts_set->x_flag_sanitize_address_use_after_scope)
     opts->x_flag_sanitize_address_use_after_scope = true;
 
@@ -1752,6 +1767,8 @@ const struct sanitizer_opts_s sanitizer_opts[] =
 #define SANITIZER_OPT(name, flags, recover) \
     { #name, flags, sizeof #name - 1, recover }
   SANITIZER_OPT (address, (SANITIZE_ADDRESS | SANITIZE_USER_ADDRESS), true),
+  // TODO Look into this properly
+  SANITIZER_OPT (hwaddress, (SANITIZE_HWADDRESS), false),
   SANITIZER_OPT (kernel-address, (SANITIZE_ADDRESS | SANITIZE_KERNEL_ADDRESS),
 		 true),
   SANITIZER_OPT (pointer-compare, SANITIZE_POINTER_COMPARE, true),


[-- Attachment #2: hwasan-implementation05.patch --]
[-- Type: text/plain, Size: 6622 bytes --]

diff --git a/gcc/common.opt b/gcc/common.opt
index d342c4f3749a39df086236162636f14f91bcd8a0..527aada305097b54c927fd094e3ab82220459c2c 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -3273,6 +3273,9 @@ Driver
 static-libasan
 Driver
 
+static-libhwasan
+Driver
+
 static-libtsan
 Driver
 
diff --git a/gcc/config/gnu-user.h b/gcc/config/gnu-user.h
index 055a4f0afeca4a6339fd156db1bf1daf1aae0994..1e4b921afb62f22892aee0ca37e96983112a8134 100644
--- a/gcc/config/gnu-user.h
+++ b/gcc/config/gnu-user.h
@@ -129,14 +129,18 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 /* Link -lasan early on the command line.  For -static-libasan, don't link
    it for -shared link, the executable should be compiled with -static-libasan
    in that case, and for executable link with --{,no-}whole-archive around
-   it to force everything into the executable.  And similarly for -ltsan
-   and -llsan.  */
+   it to force everything into the executable.  And similarly for -ltsan,
+   -lhwasan, and -llsan.  */
 #if defined(HAVE_LD_STATIC_DYNAMIC)
 #undef LIBASAN_EARLY_SPEC
 #define LIBASAN_EARLY_SPEC "%{!shared:libasan_preinit%O%s} " \
   "%{static-libasan:%{!shared:" \
   LD_STATIC_OPTION " --whole-archive -lasan --no-whole-archive " \
   LD_DYNAMIC_OPTION "}}%{!static-libasan:-lasan}"
+#undef LIBHWASAN_EARLY_SPEC
+#define LIBHWASAN_EARLY_SPEC "%{static-libhwasan:%{!shared:" \
+  LD_STATIC_OPTION " --whole-archive -lhwasan --no-whole-archive " \
+  LD_DYNAMIC_OPTION "}}%{!static-libhwasan:-lhwasan}"
 #undef LIBTSAN_EARLY_SPEC
 #define LIBTSAN_EARLY_SPEC "%{!shared:libtsan_preinit%O%s} " \
   "%{static-libtsan:%{!shared:" \
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index a2103282d469db31ad157a87572068d943061c8c..fcc3dd45862b1b64b38a13702f7840ba461aea20 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -256,6 +256,7 @@ enum sanitize_code {
   SANITIZE_BUILTIN = 1UL << 25,
   SANITIZE_POINTER_COMPARE = 1UL << 26,
   SANITIZE_POINTER_SUBTRACT = 1UL << 27,
+  SANITIZE_HWADDRESS = 1UL << 28,
   SANITIZE_SHIFT = SANITIZE_SHIFT_BASE | SANITIZE_SHIFT_EXPONENT,
   SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
 		       | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 7ebdf1f225b49769af3047c852ad3b72d6912fc0..c3d939af1a0fac87a8de95dff3960f2175aecf6d 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -708,6 +708,24 @@ proper position among the other output files.  */
 #define LIBASAN_EARLY_SPEC ""
 #endif
 
+#ifndef LIBHWASAN_SPEC
+#define STATIC_LIBHWASAN_LIBS \
+  " %{static-libhwasan|static:%:include(libsanitizer.spec)%(link_libhwasan)}"
+#ifdef LIBHWASAN_EARLY_SPEC
+#define LIBHWASAN_SPEC STATIC_LIBHWASAN_LIBS
+#elif defined(HAVE_LD_STATIC_DYNAMIC)
+#define LIBHWASAN_SPEC "%{static-libhwasan:" LD_STATIC_OPTION \
+		     "} -lhwasan %{static-libhwasan:" LD_DYNAMIC_OPTION "}" \
+		     STATIC_LIBHWASAN_LIBS
+#else
+#define LIBHWASAN_SPEC "-lhwasan" STATIC_LIBHWASAN_LIBS
+#endif
+#endif
+
+#ifndef LIBHWASAN_EARLY_SPEC
+#define LIBHWASAN_EARLY_SPEC ""
+#endif
+
 #ifndef LIBTSAN_SPEC
 #define STATIC_LIBTSAN_LIBS \
   " %{static-libtsan|static:%:include(libsanitizer.spec)%(link_libtsan)}"
@@ -982,6 +1000,7 @@ proper position among the other output files.  */
 #ifndef SANITIZER_EARLY_SPEC
 #define SANITIZER_EARLY_SPEC "\
 %{!nostdlib:%{!r:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_EARLY_SPEC "} \
+    %{%:sanitize(hwaddress):" LIBHWASAN_EARLY_SPEC "} \
     %{%:sanitize(thread):" LIBTSAN_EARLY_SPEC "} \
     %{%:sanitize(leak):" LIBLSAN_EARLY_SPEC "}}}}"
 #endif
@@ -991,6 +1010,8 @@ proper position among the other output files.  */
 #define SANITIZER_SPEC "\
 %{!nostdlib:%{!r:%{!nodefaultlibs:%{%:sanitize(address):" LIBASAN_SPEC "\
     %{static:%ecannot specify -static with -fsanitize=address}}\
+    %{%:sanitize(hwaddress):" LIBHWASAN_SPEC "\
+	%{static:%ecannot specify -static with -fsanitize=hwaddress}}\
     %{%:sanitize(thread):" LIBTSAN_SPEC "\
     %{static:%ecannot specify -static with -fsanitize=thread}}\
     %{%:sanitize(undefined):" LIBUBSAN_SPEC "}\
@@ -9387,6 +9408,8 @@ sanitize_spec_function (int argc, const char **argv)
 
   if (strcmp (argv[0], "address") == 0)
     return (flag_sanitize & SANITIZE_USER_ADDRESS) ? "" : NULL;
+  if (strcmp (argv[0], "hwaddress") == 0)
+    return (flag_sanitize & SANITIZE_HWADDRESS) ? "" : NULL;
   if (strcmp (argv[0], "kernel-address") == 0)
     return (flag_sanitize & SANITIZE_KERNEL_ADDRESS) ? "" : NULL;
   if (strcmp (argv[0], "thread") == 0)
diff --git a/gcc/opts.c b/gcc/opts.c
index 879ab17c3620ca6e002b46f4f833ed2b4c0f5432..aedb1db6c00a139f575a341559006d9c3871d233 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -1174,6 +1174,20 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
     error_at (loc,
 	      "%<-fsanitize=leak%> is incompatible with %<-fsanitize=thread%>");
 
+  /* HWASan and ASan conflict with each other.  */
+  if ((opts->x_flag_sanitize & SANITIZE_ADDRESS)
+      && (opts->x_flag_sanitize & SANITIZE_HWADDRESS))
+    error_at (loc,
+	      "%<-fsanitize=hwaddress%> is incompatible with both"
+	      "%<-fsanitize=address%> and %<-fsanitize=kernel-address%>");
+
+  /* And with TSan.  */
+  if ((opts->x_flag_sanitize & SANITIZE_HWADDRESS)
+      && (opts->x_flag_sanitize & SANITIZE_THREAD))
+    error_at (loc,
+	      "%<-fsanitize=hwaddress%> is incompatible with "
+	      "%<-fsanitize=thread%>");
+
   /* Check error recovery for -fsanitize-recover option.  */
   for (int i = 0; sanitizer_opts[i].name != NULL; ++i)
     if ((opts->x_flag_sanitize_recover & sanitizer_opts[i].flag)
@@ -1193,7 +1207,8 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
 
   /* Enable -fsanitize-address-use-after-scope if address sanitizer is
      enabled.  */
-  if ((opts->x_flag_sanitize & SANITIZE_USER_ADDRESS)
+  if (((opts->x_flag_sanitize & SANITIZE_USER_ADDRESS)
+       || (opts->x_flag_sanitize & SANITIZE_HWADDRESS))
       && !opts_set->x_flag_sanitize_address_use_after_scope)
     opts->x_flag_sanitize_address_use_after_scope = true;
 
@@ -1752,6 +1767,8 @@ const struct sanitizer_opts_s sanitizer_opts[] =
 #define SANITIZER_OPT(name, flags, recover) \
     { #name, flags, sizeof #name - 1, recover }
   SANITIZER_OPT (address, (SANITIZE_ADDRESS | SANITIZE_USER_ADDRESS), true),
+  // TODO Look into this properly
+  SANITIZER_OPT (hwaddress, (SANITIZE_HWADDRESS), false),
   SANITIZER_OPT (kernel-address, (SANITIZE_ADDRESS | SANITIZE_KERNEL_ADDRESS),
 		 true),
   SANITIZER_OPT (pointer-compare, SANITIZE_POINTER_COMPARE, true),


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC][PATCH 1/X][libsanitizer] Introduce libsanitizer to GCC tree
  2019-09-06 14:46 ` [RFC][PATCH 1/X][libsanitizer] Introduce libsanitizer to GCC tree Matthew Malcomson
@ 2019-09-09  9:26   ` Martin Liška
  0 siblings, 0 replies; 35+ messages in thread
From: Martin Liška @ 2019-09-09  9:26 UTC (permalink / raw)
  To: Matthew Malcomson, gcc-patches; +Cc: dodji, nd, kcc, jakub, dvyukov

On 9/6/19 4:46 PM, Matthew Malcomson wrote:

Hello.

> We have taken the libsanitizer library from the same SVN revision as
> the other sanitizer libraries are taken from (SVN revision 345033 as
> mentioned in libsanitizer/MERGE).

Note that I updated the libsanitizer in the meantime to r368656. That said
I guess the patch does not correspond to what's the content of the newly
added hwasan/* files.

I would probably recommend to start with the change to merge.sh:
+merge lib/hwasan hwasan 

and then run the script to update to latest libsanitizer version.

Martin

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC][PATCH 4/X][libsanitizer] Pass size and pointer info to error reporting functions
  2019-09-06 14:46 ` [RFC][PATCH 4/X][libsanitizer] Pass size and pointer info to error reporting functions Matthew Malcomson
@ 2019-09-09  9:27   ` Martin Liška
  0 siblings, 0 replies; 35+ messages in thread
From: Martin Liška @ 2019-09-09  9:27 UTC (permalink / raw)
  To: Matthew Malcomson, gcc-patches; +Cc: dodji, nd, kcc, jakub, dvyukov

On 9/6/19 4:46 PM, Matthew Malcomson wrote:
> This is taken from upstream LLVM (change made in LLVM svn commit
> 351730), but is not a direct cherry-pick of a commit since the commit
> does not apply cleanly.

As mentioned in the previous email, the cherry-pick will not be
needed any longer.

Martin

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC][PATCH 3/X][libsanitizer] Allow compilation for HWASAN_WITH_INTERCEPTORS=OFF
  2019-09-06 14:46 ` [RFC][PATCH 3/X][libsanitizer] Allow compilation for HWASAN_WITH_INTERCEPTORS=OFF Matthew Malcomson
@ 2019-09-09  9:27   ` Martin Liška
  0 siblings, 0 replies; 35+ messages in thread
From: Martin Liška @ 2019-09-09  9:27 UTC (permalink / raw)
  To: Matthew Malcomson, gcc-patches; +Cc: dodji, nd, kcc, jakub, dvyukov

On 9/6/19 4:46 PM, Matthew Malcomson wrote:
> This is a port of the LLVM-svn commit number 359914, it allows
> compilation of the library without using interceptors.

As mentioned in the previous email, the cherry-pick will not be
needed any longer.

Martin

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC][PATCH 5/X][libsanitizer] Introduce longjmp/setjmp interceptors to libhwasan
  2019-09-06 14:46 ` [RFC][PATCH 5/X][libsanitizer] Introduce longjmp/setjmp interceptors to libhwasan Matthew Malcomson
@ 2019-09-09 10:02   ` Martin Liška
  2019-09-09 10:29     ` Matthew Malcomson
  0 siblings, 1 reply; 35+ messages in thread
From: Martin Liška @ 2019-09-09 10:02 UTC (permalink / raw)
  To: Matthew Malcomson, gcc-patches; +Cc: dodji, nd, kcc, jakub, dvyukov

Hi.

On 9/6/19 4:46 PM, Matthew Malcomson wrote:
> Ensuring that the shadow stack is cleared on normal function exit will
> be done by adding instrumentation to the function epilogue through the
> compiler.
> longjmp and setjmp are some abnormal methods of exiting the function
> that can't be handled in the compiler since they can be called in
> uninstrumented code to unwind past instrumented function frames.

I'm curious why you are adding a new code that is not part of libsanitizer runtime?
Does it mean the current LLVM implementation does not properly handle setjmp and
longjmp?

Note that rule of thumb is that we need to upstream all libsanitizer
changes before we merge libsanitizer. We are doing that in order to not
have a bug difference against upstream libsanitizer.

Martin

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC][PATCH 6/X][libsanitizer] Add -fsanitize=hwaddress flags
  2019-09-06 14:47 ` [RFC][PATCH 6/X][libsanitizer] Add -fsanitize=hwaddress flags Matthew Malcomson
@ 2019-09-09 10:06   ` Martin Liška
  2019-09-09 10:18     ` Matthew Malcomson
  0 siblings, 1 reply; 35+ messages in thread
From: Martin Liška @ 2019-09-09 10:06 UTC (permalink / raw)
  To: Matthew Malcomson, gcc-patches; +Cc: dodji, nd, kcc, jakub, dvyukov

On 9/6/19 4:46 PM, Matthew Malcomson wrote:
> This flag can't be used at the same time as any of the other sanitizers.
> We add an equivalent flag to -static-libasan in -static-libhwasan to
> ensure static linking.

Hello.

You're introducing new option argument -fsanitize=hwaddress. However,
clang is using 'hwasan':
https://github.com/llvm-mirror/clang/blob/master/lib/Driver/ToolChains/CommonArgs.cpp#L625

I would align it with the existing clang's option.

Thanks,
Martin

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC][PATCH 6/X][libsanitizer] Add -fsanitize=hwaddress flags
  2019-09-09 10:06   ` Martin Liška
@ 2019-09-09 10:18     ` Matthew Malcomson
  2019-09-09 10:20       ` Martin Liška
  0 siblings, 1 reply; 35+ messages in thread
From: Matthew Malcomson @ 2019-09-09 10:18 UTC (permalink / raw)
  To: Martin Liška, gcc-patches; +Cc: dodji, nd, kcc, jakub, dvyukov

On 09/09/19 11:06, Martin Liška wrote:
> On 9/6/19 4:46 PM, Matthew Malcomson wrote:
>> This flag can't be used at the same time as any of the other sanitizers.
>> We add an equivalent flag to -static-libasan in -static-libhwasan to
>> ensure static linking.
> 
> Hello.
> 
> You're introducing new option argument -fsanitize=hwaddress. However,
> clang is using 'hwasan':
> https://github.com/llvm-mirror/clang/blob/master/lib/Driver/ToolChains/CommonArgs.cpp#L625
> 
> I would align it with the existing clang's option.
> 
> Thanks,
> Martin
> 

Hi there,

I don't believe that's where this particular option is defined.
I think it's here.
https://github.com/llvm-mirror/clang/blob/master/include/clang/Basic/Sanitizers.def#L53

I took the `hwaddress' argument from what my local build of clang accepted.

(Helpfully enough, finding that option also shows the option that clang 
uses for the AArch64 memtag extension, which I've been meaning to get 
around to finding for a while ;-] )

Cheers,
Matthew.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC][PATCH 6/X][libsanitizer] Add -fsanitize=hwaddress flags
  2019-09-09 10:18     ` Matthew Malcomson
@ 2019-09-09 10:20       ` Martin Liška
  0 siblings, 0 replies; 35+ messages in thread
From: Martin Liška @ 2019-09-09 10:20 UTC (permalink / raw)
  To: Matthew Malcomson, gcc-patches; +Cc: dodji, nd, kcc, jakub, dvyukov

On 9/9/19 12:17 PM, Matthew Malcomson wrote:
> On 09/09/19 11:06, Martin Liška wrote:
>> On 9/6/19 4:46 PM, Matthew Malcomson wrote:
>>> This flag can't be used at the same time as any of the other sanitizers.
>>> We add an equivalent flag to -static-libasan in -static-libhwasan to
>>> ensure static linking.
>>
>> Hello.
>>
>> You're introducing new option argument -fsanitize=hwaddress. However,
>> clang is using 'hwasan':
>> https://github.com/llvm-mirror/clang/blob/master/lib/Driver/ToolChains/CommonArgs.cpp#L625
>>
>> I would align it with the existing clang's option.
>>
>> Thanks,
>> Martin
>>
> 
> Hi there,
> 
> I don't believe that's where this particular option is defined.
> I think it's here.
> https://github.com/llvm-mirror/clang/blob/master/include/clang/Basic/Sanitizers.def#L53

Ah, you are right. Sorry for the noise :)

Martin

> 
> I took the `hwaddress' argument from what my local build of clang accepted.
> 
> (Helpfully enough, finding that option also shows the option that clang 
> uses for the AArch64 memtag extension, which I've been meaning to get 
> around to finding for a while ;-] )
> 
> Cheers,
> Matthew.
> 

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC][PATCH 5/X][libsanitizer] Introduce longjmp/setjmp interceptors to libhwasan
  2019-09-09 10:02   ` Martin Liška
@ 2019-09-09 10:29     ` Matthew Malcomson
  2019-09-09 10:49       ` Martin Liška
  0 siblings, 1 reply; 35+ messages in thread
From: Matthew Malcomson @ 2019-09-09 10:29 UTC (permalink / raw)
  To: Martin Liška, gcc-patches; +Cc: dodji, nd, kcc, jakub, dvyukov

On 09/09/19 11:01, Martin Liška wrote:
> Hi.
> 
> On 9/6/19 4:46 PM, Matthew Malcomson wrote:
>> Ensuring that the shadow stack is cleared on normal function exit will
>> be done by adding instrumentation to the function epilogue through the
>> compiler.
>> longjmp and setjmp are some abnormal methods of exiting the function
>> that can't be handled in the compiler since they can be called in
>> uninstrumented code to unwind past instrumented function frames.
> 
> I'm curious why you are adding a new code that is not part of libsanitizer runtime?
> Does it mean the current LLVM implementation does not properly handle setjmp and
> longjmp?

Honestly -- I'm not sure.

I did a basic test that seemed to show clang not supporting setjmp & 
longjmp and I made a bit of a foray into how one would approach the 
problem, but I then left it in a partially done state to focus on other 
things.

It also seems on first blush that C++ exceptions are not handled, but 
again I haven't yet gone and asked anyone in the know.

(it's on the list of things to do, but not yet at the top).

> 
> Note that rule of thumb is that we need to upstream all libsanitizer
> changes before we merge libsanitizer. We are doing that in order to not
> have a bug difference against upstream libsanitizer.

That sounds good to me -- I will remember to go upstream when I look 
into this.

> 
> Martin
> 

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC
  2019-09-06 14:46 [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Matthew Malcomson
                   ` (15 preceding siblings ...)
  2019-09-06 14:47 ` [RFC][PATCH 9/X][libsanitizer] Put tags into each stack variable pointer Matthew Malcomson
@ 2019-09-09 10:47 ` Martin Liška
  2019-09-09 15:55   ` Matthew Malcomson
  2019-09-23  8:02 ` Martin Liška
  17 siblings, 1 reply; 35+ messages in thread
From: Martin Liška @ 2019-09-09 10:47 UTC (permalink / raw)
  To: Matthew Malcomson, gcc-patches; +Cc: dodji, nd, kcc, jakub, dvyukov

On 9/6/19 4:46 PM, Matthew Malcomson wrote:
> Hello,
> 
> This patch series is a WORK-IN-PROGRESS towards porting the LLVM hardware
> address sanitizer (HWASAN) in GCC.  The document describing HWASAN can be found
> here http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html.

Hello.

I'm happy that you are working on the functionality for GCC and I can provide
my knowledge that I have with ASAN. I briefly read the patch series and I have
multiple questions (and observations):

1) Is the ambition of the patchset to be a software emulation of MTE that can
   work targets that do not support MTE? Is it something what clang
   names hwasan-abi=interceptor?

2) Do you have a real aarch64 hardware that has MTE support? Would it be possible
   for the future to give such a machine to GCC Compile Farm for testing purpose?

3) I like the idea of sharing of internal functions like ASAN_CHECK/HWASAN_CHECK.
   We should benefit from that in the future.

4) Am I correct that due to escape of "tagged" pointers, one needs to have an entire
DSO (dynamic shared object) built with hwasan enabled? Otherwise, a dereference of
a tagged pointer will lead to a segfault (except TBI feature on aarch64)?

5) Is there a documentation/definition of how shadow memory for memory tagging looks like?
Is it similar to ASAN, where one can get to tag with:
u8 memory_tag = *((PTR >> TG) + SHADOW_OFFSET) & 0xf?

6) Note that thing like memtag_tag_size, memtag_granule_size define an ABI of libsanitizer

> 
> The current patch series is far from complete, but I'm posting the current state
> to provide something to discuss at the Cauldron next week.
> 
> In its current state, this sanitizer only works on AArch64 with a custom kernel
> to allow tagged pointers in system calls.  This is discussed in the below link
> https://source.android.com/devices/tech/debug/hwasan -- the custom kernel allows
> tagged pointers in syscalls.

Can you be please more specific. Is the MTE in upstream linux kernel? If so,
starting from which version?

> I have also not yet put tests into the DejaGNU framework, but instead have a
> simple test file from which the tests will eventually come.  That test file is
> attached to this email despite not being in the patch series.
> 
> Something close to this patch series bootstraps and passes most regression
> tests when ~--with-build-config=bootstrap-hwasan~ is used.  The regressions it
> doesn't pass are all the other sanitizer tests and all linker plugin tests.
> The linker plugin tests fail due to a configuration problem where the library
> path is not correctly set.
> (I say "something close to this patch series" because I recently made a change
> that breaks bootstrap but I believe is the best approach once I've fixed it,
> hence for an RFC I'm leaving it in).
> 
> HWASAN works by storing a tag in the top bits of every pointer and a colour in
> a shadow memory region corresponding to every area of memory.  On every memory
> access through a pointer the tag in the pointer is checked against the colour in
> shadow memory corresponding to the memory the pointer is accessing.  If the tag
> and colour do not match then a fault is signalled.
> 
> The instrumentation required for this sanitizer has a large overlap with the
> instrumentation required for implementing MTE (which has similar functionality
> but checks are automatically done in the hardware and instructions for colouring
> shadow memory and for managing tags are provided by the architecture).
> https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/arm-a-profile-architecture-2018-developments-armv85a
> 
> We hope to use the HWASAN framework to implement MTE tagging on the stack, and
> hence I have a "dummy" patch demonstrating the approach envisaged for this.

What's the situation with heap allocated memory and global variables?

> 
> Though there is still much to implement here, the general approach should be
> clear.  Any feedback is welcomed, but I have three main points that I'm
> particularly hoping for external opinions.
> 
> 1) The current approach stores a tag on the RTL representing a given variable,
>    in order to implement HWASAN for x86_64 the tag needs to be removed before
>    every memory access but not on things like function calls.
>    Is there any obvious way to handle removing the tag in these places?
>    Maybe something with legitimize_address?

Not being a target expect, but I bet you'll need to store the tag with a RTL
representation of a stack variable.

Thanks,
Martin

> 2) The first draft presented here introduces a new RTL expression called
>    ADDTAG.  I now believe that a hook would be neater here but haven't yet
>    looked into it.  Do people agree?
>    (addtag is introduced in the patch titled "Put tags into each stack variable
>    pointer", but the reason it's introduced is so the backend can define how
>    this gets implemented with a ~define_expand~ and that's only needed for the
>    MTE handling as introduced in "Add in MTE stubs")
> 3) This patch series has not yet had much thought go towards it around command
>    line arguments.  I personally quite like the idea of having
>    ~-fsanitize=hwaddress~ turn on "checking memory tags against shadow memory
>    colour", and MTE being just a hardware acceleration of this ability.
>    I suspect this idea wouldn't be liked by all and would like to hear some
>    opinions.
> 
> Thanks,
> Matthew
> 

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC][PATCH 5/X][libsanitizer] Introduce longjmp/setjmp interceptors to libhwasan
  2019-09-09 10:29     ` Matthew Malcomson
@ 2019-09-09 10:49       ` Martin Liška
  0 siblings, 0 replies; 35+ messages in thread
From: Martin Liška @ 2019-09-09 10:49 UTC (permalink / raw)
  To: Matthew Malcomson, gcc-patches; +Cc: dodji, nd, kcc, jakub, dvyukov

On 9/9/19 12:29 PM, Matthew Malcomson wrote:
> On 09/09/19 11:01, Martin Liška wrote:
>> Hi.
>>
>> On 9/6/19 4:46 PM, Matthew Malcomson wrote:
>>> Ensuring that the shadow stack is cleared on normal function exit will
>>> be done by adding instrumentation to the function epilogue through the
>>> compiler.
>>> longjmp and setjmp are some abnormal methods of exiting the function
>>> that can't be handled in the compiler since they can be called in
>>> uninstrumented code to unwind past instrumented function frames.
>>
>> I'm curious why you are adding a new code that is not part of libsanitizer runtime?
>> Does it mean the current LLVM implementation does not properly handle setjmp and
>> longjmp?
> 
> Honestly -- I'm not sure.
> 
> I did a basic test that seemed to show clang not supporting setjmp & 
> longjmp and I made a bit of a foray into how one would approach the 
> problem, but I then left it in a partially done state to focus on other 
> things.

I see. Then I would probably file an issue and ask the community:
https://github.com/google/sanitizers/issues

> 
> It also seems on first blush that C++ exceptions are not handled, but 
> again I haven't yet gone and asked anyone in the know.

Likewise I would ask them for the C++ exceptions.

Martin

> 
> (it's on the list of things to do, but not yet at the top).
> 
>>
>> Note that rule of thumb is that we need to upstream all libsanitizer
>> changes before we merge libsanitizer. We are doing that in order to not
>> have a bug difference against upstream libsanitizer.
> 
> That sounds good to me -- I will remember to go upstream when I look 
> into this.
> 
>>
>> Martin
>>
> 

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC
  2019-09-09 10:47 ` [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Martin Liška
@ 2019-09-09 15:55   ` Matthew Malcomson
  2019-09-10  1:06     ` Kostya Serebryany via gcc-patches
  2019-09-11 11:53     ` Martin Liška
  0 siblings, 2 replies; 35+ messages in thread
From: Matthew Malcomson @ 2019-09-09 15:55 UTC (permalink / raw)
  To: Martin Liška, gcc-patches; +Cc: dodji, nd, kcc, jakub, dvyukov

On 09/09/19 11:47, Martin Liška wrote:
> On 9/6/19 4:46 PM, Matthew Malcomson wrote:
>> Hello,
>>
>> This patch series is a WORK-IN-PROGRESS towards porting the LLVM hardware
>> address sanitizer (HWASAN) in GCC.  The document describing HWASAN can be found
>> here http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html.
> 
> Hello.
> 
> I'm happy that you are working on the functionality for GCC and I can provide
> my knowledge that I have with ASAN. I briefly read the patch series and I have
> multiple questions (and observations):
> 
> 1) Is the ambition of the patchset to be a software emulation of MTE that can
>     work targets that do not support MTE? Is it something what clang
>     names hwasan-abi=interceptor?

The ambition is to provide a software emulation of MTE for AArch64 
targets that don't support MTE.
I also hope to have the framework set up so that enabling for other 
architectures is relatively easy and can be done by those interested.

As I understand it, `hwasan-abi=interceptor` vs `platform` is about 
adding such MTE emulation for "application code" or "platform code (e.g. 
kernel)" respectively.

> 
> 2) Do you have a real aarch64 hardware that has MTE support? Would it be possible
>     for the future to give such a machine to GCC Compile Farm for testing purpose?

No our team doesn't have real MTE hardware, I have been testing on an 
AArch64 machine that has TBI, other work in the team that requires MTE 
support is being tested on the Arm "Fast Models" emulator.

> 
> 3) I like the idea of sharing of internal functions like ASAN_CHECK/HWASAN_CHECK.
>     We should benefit from that in the future.
> 
> 4) Am I correct that due to escape of "tagged" pointers, one needs to have an entire
> DSO (dynamic shared object) built with hwasan enabled? Otherwise, a dereference of
> a tagged pointer will lead to a segfault (except TBI feature on aarch64)?


Yes, one needs to take pains to avoid the escape of tagged pointers on 
architectures other than AArch64.

I don't believe that compiling the entire DSO with HWASAN enabled is 
enough, since pointers can be passed across DSO boundaries.
I haven't yet looked into how to handle this.

There's an even more fundamental problem of accesses within the 
instrumented binary -- I haven't yet figured out how to remove the tag 
before accesses on architectures without the AArch64 TBI feature.


> 
> 5) Is there a documentation/definition of how shadow memory for memory tagging looks like?
> Is it similar to ASAN, where one can get to tag with:
> u8 memory_tag = *((PTR >> TG) + SHADOW_OFFSET) & 0xf?
> 

Yes, it's similar.

 From the libhwasan code, the function to fetch a pointer to the shadow 
memory byte corresponding to a memory address is MemToShadow.

constexpr uptr kShadowScale = 4;
inline uptr MemToShadow(uptr untagged_addr) {
   return (untagged_addr >> kShadowScale) +
          __hwasan_shadow_memory_dynamic_address;
}

https://github.com/llvm-mirror/compiler-rt/blob/99ce9876124e910475c627829bf14326b8073a9d/lib/hwasan/hwasan_mapping.h#L42


> 6) Note that thing like memtag_tag_size, memtag_granule_size define an ABI of libsanitizer
> 

Yes, the size of these values define an ABI.

Those particular hooks are added as a demonstration for how something 
like MTE would be implemented on top of this framework (where the 
backend would specify the tag and granule size to match their targets 
architecture).

HWASAN itself would use the hard-coded tag and granule size that matches 
what libsanitizer uses.
https://github.com/llvm-mirror/compiler-rt/blob/99ce9876124e910475c627829bf14326b8073a9d/lib/hwasan/hwasan_mapping.h#L36

I define these as `HWASAN_TAG_SIZE` and `HWASAN_TAG_GRANULE_SIZE` in 
asan.h, and when using the sanitizer library the macro 
`HARDWARE_MEMORY_TAGGING` would be false so their values would be constant.


>>
>> The current patch series is far from complete, but I'm posting the current state
>> to provide something to discuss at the Cauldron next week.
>>
>> In its current state, this sanitizer only works on AArch64 with a custom kernel
>> to allow tagged pointers in system calls.  This is discussed in the below link
>> https://source.android.com/devices/tech/debug/hwasan -- the custom kernel allows
>> tagged pointers in syscalls.
> 
> Can you be please more specific. Is the MTE in upstream linux kernel? If so,
> starting from which version?

I find I can only make complicated statements remotely clear in bullet 
points ;-)

What I was trying to say was:
- HWASAN from this patch series requires AArch64 TBI.
   (I have not handled architectures without TBI)
- The upstream kernel does not accept tagged pointers in syscalls.
   (programs that use TBI must currently clear tags before passing
    pointers to the kernel)
- This patch series doesn't include any way to avoid passing tagged
   pointers to syscalls.
- Hence on order to test the sanitizer I'm using a kernel that has been
   patched to accept tagged pointers in many syscalls.
- The link to the android.com site is just another source describing the
   same requirement.


The support for the relaxed ABI (of accepting tagged pointers in various 
syscalls in the kernel) is being discussed on the kernel mailing list, 
the latest patchset I know of is here:
https://lkml.org/lkml/2019/7/25/725

I wasn't trying to say anything about MTE in that paragraph, but kernel 
support for MTE is not in upstream linux kernel and is currently being 
worked on.

> 
>> I have also not yet put tests into the DejaGNU framework, but instead have a
>> simple test file from which the tests will eventually come.  That test file is
>> attached to this email despite not being in the patch series.
>>
>> Something close to this patch series bootstraps and passes most regression
>> tests when ~--with-build-config=bootstrap-hwasan~ is used.  The regressions it
>> doesn't pass are all the other sanitizer tests and all linker plugin tests.
>> The linker plugin tests fail due to a configuration problem where the library
>> path is not correctly set.
>> (I say "something close to this patch series" because I recently made a change
>> that breaks bootstrap but I believe is the best approach once I've fixed it,
>> hence for an RFC I'm leaving it in).
>>
>> HWASAN works by storing a tag in the top bits of every pointer and a colour in
>> a shadow memory region corresponding to every area of memory.  On every memory
>> access through a pointer the tag in the pointer is checked against the colour in
>> shadow memory corresponding to the memory the pointer is accessing.  If the tag
>> and colour do not match then a fault is signalled.
>>
>> The instrumentation required for this sanitizer has a large overlap with the
>> instrumentation required for implementing MTE (which has similar functionality
>> but checks are automatically done in the hardware and instructions for colouring
>> shadow memory and for managing tags are provided by the architecture).
>> https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/arm-a-profile-architecture-2018-developments-armv85a
>>
>> We hope to use the HWASAN framework to implement MTE tagging on the stack, and
>> hence I have a "dummy" patch demonstrating the approach envisaged for this.
> 
> What's the situation with heap allocated memory and global variables?

For the heap, whatever library function allocates memory should return a 
tagged pointer and colour the shadow memory accordingly.  This pointer 
can then be treated exactly the same as all other pointers in 
instrumented code.
On freeing of memory the shadow memory is uncoloured in order to detect 
use-after-free.

For HWASAN this means malloc and friends need to be intercepted, and 
this is done by the runtime library.

For MTE there will need to be some updates in the system libraries.
A discussion on the way this will be done in glibc has been started here:
https://www.sourceware.org/ml/libc-alpha/2019-09/msg00114.html



Global variables are untagged.

For MTE we are planning on having these untagged.
This is in order to allow uninstrumented object files to be statically 
linked into MTE aware object files.
Since global object accesses are directly generated into the code, there 
would be no way to tag global objects and still use the code from that 
static object.


Since global objects will not be coloured for MTE, I am not planning on 
colouring them for HWASAN.  There would be a reasonable amount of work, 
including a new mechanism for associating objects with tags.

Having all global variables untagged means that nothing need be done, 
all pointers to global variables will have a tag of zero and the shadow 
memory will correspondingly be left coloured as zero.

> 
>>
>> Though there is still much to implement here, the general approach should be
>> clear.  Any feedback is welcomed, but I have three main points that I'm
>> particularly hoping for external opinions.
>>
>> 1) The current approach stores a tag on the RTL representing a given variable,
>>     in order to implement HWASAN for x86_64 the tag needs to be removed before
>>     every memory access but not on things like function calls.
>>     Is there any obvious way to handle removing the tag in these places?
>>     Maybe something with legitimize_address?
> 
> Not being a target expect, but I bet you'll need to store the tag with a RTL
> representation of a stack variable.
> 
> Thanks,
> Martin
> 
>> 2) The first draft presented here introduces a new RTL expression called
>>     ADDTAG.  I now believe that a hook would be neater here but haven't yet
>>     looked into it.  Do people agree?
>>     (addtag is introduced in the patch titled "Put tags into each stack variable
>>     pointer", but the reason it's introduced is so the backend can define how
>>     this gets implemented with a ~define_expand~ and that's only needed for the
>>     MTE handling as introduced in "Add in MTE stubs")
>> 3) This patch series has not yet had much thought go towards it around command
>>     line arguments.  I personally quite like the idea of having
>>     ~-fsanitize=hwaddress~ turn on "checking memory tags against shadow memory
>>     colour", and MTE being just a hardware acceleration of this ability.
>>     I suspect this idea wouldn't be liked by all and would like to hear some
>>     opinions.
>>
>> Thanks,
>> Matthew
>>
> 

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC
  2019-09-09 15:55   ` Matthew Malcomson
@ 2019-09-10  1:06     ` Kostya Serebryany via gcc-patches
  2019-09-11 11:53     ` Martin Liška
  1 sibling, 0 replies; 35+ messages in thread
From: Kostya Serebryany via gcc-patches @ 2019-09-10  1:06 UTC (permalink / raw)
  To: Matthew Malcomson, Peter Collingbourne, Evgeniy Stepanov
  Cc: Martin Liška, gcc-patches, dodji, nd, jakub, dvyukov

+Peter Collingbourne +Evgeniy Stepanov (the main developers of HWASAN
in LLVM,  FYI)
Please note that Peter has recently implemented support for globals in
LLVM's HWASAN.

--kcc

On Mon, Sep 9, 2019 at 8:55 AM Matthew Malcomson
<Matthew.Malcomson@arm.com> wrote:
>
> On 09/09/19 11:47, Martin Liška wrote:
> > On 9/6/19 4:46 PM, Matthew Malcomson wrote:
> >> Hello,
> >>
> >> This patch series is a WORK-IN-PROGRESS towards porting the LLVM hardware
> >> address sanitizer (HWASAN) in GCC.  The document describing HWASAN can be found
> >> here http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html.
> >
> > Hello.
> >
> > I'm happy that you are working on the functionality for GCC and I can provide
> > my knowledge that I have with ASAN. I briefly read the patch series and I have
> > multiple questions (and observations):
> >
> > 1) Is the ambition of the patchset to be a software emulation of MTE that can
> >     work targets that do not support MTE? Is it something what clang
> >     names hwasan-abi=interceptor?
>
> The ambition is to provide a software emulation of MTE for AArch64
> targets that don't support MTE.
> I also hope to have the framework set up so that enabling for other
> architectures is relatively easy and can be done by those interested.
>
> As I understand it, `hwasan-abi=interceptor` vs `platform` is about
> adding such MTE emulation for "application code" or "platform code (e.g.
> kernel)" respectively.
>
> >
> > 2) Do you have a real aarch64 hardware that has MTE support? Would it be possible
> >     for the future to give such a machine to GCC Compile Farm for testing purpose?
>
> No our team doesn't have real MTE hardware, I have been testing on an
> AArch64 machine that has TBI, other work in the team that requires MTE
> support is being tested on the Arm "Fast Models" emulator.
>
> >
> > 3) I like the idea of sharing of internal functions like ASAN_CHECK/HWASAN_CHECK.
> >     We should benefit from that in the future.
> >
> > 4) Am I correct that due to escape of "tagged" pointers, one needs to have an entire
> > DSO (dynamic shared object) built with hwasan enabled? Otherwise, a dereference of
> > a tagged pointer will lead to a segfault (except TBI feature on aarch64)?
>
>
> Yes, one needs to take pains to avoid the escape of tagged pointers on
> architectures other than AArch64.
>
> I don't believe that compiling the entire DSO with HWASAN enabled is
> enough, since pointers can be passed across DSO boundaries.
> I haven't yet looked into how to handle this.
>
> There's an even more fundamental problem of accesses within the
> instrumented binary -- I haven't yet figured out how to remove the tag
> before accesses on architectures without the AArch64 TBI feature.
>
>
> >
> > 5) Is there a documentation/definition of how shadow memory for memory tagging looks like?
> > Is it similar to ASAN, where one can get to tag with:
> > u8 memory_tag = *((PTR >> TG) + SHADOW_OFFSET) & 0xf?
> >
>
> Yes, it's similar.
>
>  From the libhwasan code, the function to fetch a pointer to the shadow
> memory byte corresponding to a memory address is MemToShadow.
>
> constexpr uptr kShadowScale = 4;
> inline uptr MemToShadow(uptr untagged_addr) {
>    return (untagged_addr >> kShadowScale) +
>           __hwasan_shadow_memory_dynamic_address;
> }
>
> https://github.com/llvm-mirror/compiler-rt/blob/99ce9876124e910475c627829bf14326b8073a9d/lib/hwasan/hwasan_mapping.h#L42
>
>
> > 6) Note that thing like memtag_tag_size, memtag_granule_size define an ABI of libsanitizer
> >
>
> Yes, the size of these values define an ABI.
>
> Those particular hooks are added as a demonstration for how something
> like MTE would be implemented on top of this framework (where the
> backend would specify the tag and granule size to match their targets
> architecture).
>
> HWASAN itself would use the hard-coded tag and granule size that matches
> what libsanitizer uses.
> https://github.com/llvm-mirror/compiler-rt/blob/99ce9876124e910475c627829bf14326b8073a9d/lib/hwasan/hwasan_mapping.h#L36
>
> I define these as `HWASAN_TAG_SIZE` and `HWASAN_TAG_GRANULE_SIZE` in
> asan.h, and when using the sanitizer library the macro
> `HARDWARE_MEMORY_TAGGING` would be false so their values would be constant.
>
>
> >>
> >> The current patch series is far from complete, but I'm posting the current state
> >> to provide something to discuss at the Cauldron next week.
> >>
> >> In its current state, this sanitizer only works on AArch64 with a custom kernel
> >> to allow tagged pointers in system calls.  This is discussed in the below link
> >> https://source.android.com/devices/tech/debug/hwasan -- the custom kernel allows
> >> tagged pointers in syscalls.
> >
> > Can you be please more specific. Is the MTE in upstream linux kernel? If so,
> > starting from which version?
>
> I find I can only make complicated statements remotely clear in bullet
> points ;-)
>
> What I was trying to say was:
> - HWASAN from this patch series requires AArch64 TBI.
>    (I have not handled architectures without TBI)
> - The upstream kernel does not accept tagged pointers in syscalls.
>    (programs that use TBI must currently clear tags before passing
>     pointers to the kernel)
> - This patch series doesn't include any way to avoid passing tagged
>    pointers to syscalls.
> - Hence on order to test the sanitizer I'm using a kernel that has been
>    patched to accept tagged pointers in many syscalls.
> - The link to the android.com site is just another source describing the
>    same requirement.
>
>
> The support for the relaxed ABI (of accepting tagged pointers in various
> syscalls in the kernel) is being discussed on the kernel mailing list,
> the latest patchset I know of is here:
> https://lkml.org/lkml/2019/7/25/725
>
> I wasn't trying to say anything about MTE in that paragraph, but kernel
> support for MTE is not in upstream linux kernel and is currently being
> worked on.
>
> >
> >> I have also not yet put tests into the DejaGNU framework, but instead have a
> >> simple test file from which the tests will eventually come.  That test file is
> >> attached to this email despite not being in the patch series.
> >>
> >> Something close to this patch series bootstraps and passes most regression
> >> tests when ~--with-build-config=bootstrap-hwasan~ is used.  The regressions it
> >> doesn't pass are all the other sanitizer tests and all linker plugin tests.
> >> The linker plugin tests fail due to a configuration problem where the library
> >> path is not correctly set.
> >> (I say "something close to this patch series" because I recently made a change
> >> that breaks bootstrap but I believe is the best approach once I've fixed it,
> >> hence for an RFC I'm leaving it in).
> >>
> >> HWASAN works by storing a tag in the top bits of every pointer and a colour in
> >> a shadow memory region corresponding to every area of memory.  On every memory
> >> access through a pointer the tag in the pointer is checked against the colour in
> >> shadow memory corresponding to the memory the pointer is accessing.  If the tag
> >> and colour do not match then a fault is signalled.
> >>
> >> The instrumentation required for this sanitizer has a large overlap with the
> >> instrumentation required for implementing MTE (which has similar functionality
> >> but checks are automatically done in the hardware and instructions for colouring
> >> shadow memory and for managing tags are provided by the architecture).
> >> https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/arm-a-profile-architecture-2018-developments-armv85a
> >>
> >> We hope to use the HWASAN framework to implement MTE tagging on the stack, and
> >> hence I have a "dummy" patch demonstrating the approach envisaged for this.
> >
> > What's the situation with heap allocated memory and global variables?
>
> For the heap, whatever library function allocates memory should return a
> tagged pointer and colour the shadow memory accordingly.  This pointer
> can then be treated exactly the same as all other pointers in
> instrumented code.
> On freeing of memory the shadow memory is uncoloured in order to detect
> use-after-free.
>
> For HWASAN this means malloc and friends need to be intercepted, and
> this is done by the runtime library.
>
> For MTE there will need to be some updates in the system libraries.
> A discussion on the way this will be done in glibc has been started here:
> https://www.sourceware.org/ml/libc-alpha/2019-09/msg00114.html
>
>
>
> Global variables are untagged.
>
> For MTE we are planning on having these untagged.
> This is in order to allow uninstrumented object files to be statically
> linked into MTE aware object files.
> Since global object accesses are directly generated into the code, there
> would be no way to tag global objects and still use the code from that
> static object.
>
>
> Since global objects will not be coloured for MTE, I am not planning on
> colouring them for HWASAN.  There would be a reasonable amount of work,
> including a new mechanism for associating objects with tags.
>
> Having all global variables untagged means that nothing need be done,
> all pointers to global variables will have a tag of zero and the shadow
> memory will correspondingly be left coloured as zero.
>
> >
> >>
> >> Though there is still much to implement here, the general approach should be
> >> clear.  Any feedback is welcomed, but I have three main points that I'm
> >> particularly hoping for external opinions.
> >>
> >> 1) The current approach stores a tag on the RTL representing a given variable,
> >>     in order to implement HWASAN for x86_64 the tag needs to be removed before
> >>     every memory access but not on things like function calls.
> >>     Is there any obvious way to handle removing the tag in these places?
> >>     Maybe something with legitimize_address?
> >
> > Not being a target expect, but I bet you'll need to store the tag with a RTL
> > representation of a stack variable.
> >
> > Thanks,
> > Martin
> >
> >> 2) The first draft presented here introduces a new RTL expression called
> >>     ADDTAG.  I now believe that a hook would be neater here but haven't yet
> >>     looked into it.  Do people agree?
> >>     (addtag is introduced in the patch titled "Put tags into each stack variable
> >>     pointer", but the reason it's introduced is so the backend can define how
> >>     this gets implemented with a ~define_expand~ and that's only needed for the
> >>     MTE handling as introduced in "Add in MTE stubs")
> >> 3) This patch series has not yet had much thought go towards it around command
> >>     line arguments.  I personally quite like the idea of having
> >>     ~-fsanitize=hwaddress~ turn on "checking memory tags against shadow memory
> >>     colour", and MTE being just a hardware acceleration of this ability.
> >>     I suspect this idea wouldn't be liked by all and would like to hear some
> >>     opinions.
> >>
> >> Thanks,
> >> Matthew
> >>
> >
>

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC
  2019-09-09 15:55   ` Matthew Malcomson
  2019-09-10  1:06     ` Kostya Serebryany via gcc-patches
@ 2019-09-11 11:53     ` Martin Liška
  2019-09-11 16:37       ` Matthew Malcomson
  1 sibling, 1 reply; 35+ messages in thread
From: Martin Liška @ 2019-09-11 11:53 UTC (permalink / raw)
  To: Matthew Malcomson, gcc-patches; +Cc: dodji, nd, kcc, jakub, dvyukov

On 9/9/19 5:54 PM, Matthew Malcomson wrote:
> On 09/09/19 11:47, Martin Liška wrote:
>> On 9/6/19 4:46 PM, Matthew Malcomson wrote:
>>> Hello,
>>>
>>> This patch series is a WORK-IN-PROGRESS towards porting the LLVM hardware
>>> address sanitizer (HWASAN) in GCC.  The document describing HWASAN can be found
>>> here http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html.
>>
>> Hello.
>>
>> I'm happy that you are working on the functionality for GCC and I can provide
>> my knowledge that I have with ASAN. I briefly read the patch series and I have
>> multiple questions (and observations):
>>
>> 1) Is the ambition of the patchset to be a software emulation of MTE that can
>>     work targets that do not support MTE? Is it something what clang
>>     names hwasan-abi=interceptor?
> 
> The ambition is to provide a software emulation of MTE for AArch64 
> targets that don't support MTE.

Hello.

It would be also great to provide the emulation on targets that do not provide TBI
(like x86_64).

> I also hope to have the framework set up so that enabling for other 
> architectures is relatively easy and can be done by those interested.
> 
> As I understand it, `hwasan-abi=interceptor` vs `platform` is about 
> adding such MTE emulation for "application code" or "platform code (e.g. 
> kernel)" respectively.

Hm, are you sure? Clang also uses -fsanitize=kernel-hwaddress which should
be equivalent to kernel-address for -fsanitize=address.

> 
>>
>> 2) Do you have a real aarch64 hardware that has MTE support? Would it be possible
>>     for the future to give such a machine to GCC Compile Farm for testing purpose?
> 
> No our team doesn't have real MTE hardware, I have been testing on an 
> AArch64 machine that has TBI, other work in the team that requires MTE 
> support is being tested on the Arm "Fast Models" emulator.
> 
>>
>> 3) I like the idea of sharing of internal functions like ASAN_CHECK/HWASAN_CHECK.
>>     We should benefit from that in the future.
>>
>> 4) Am I correct that due to escape of "tagged" pointers, one needs to have an entire
>> DSO (dynamic shared object) built with hwasan enabled? Otherwise, a dereference of
>> a tagged pointer will lead to a segfault (except TBI feature on aarch64)?
> 
> 
> Yes, one needs to take pains to avoid the escape of tagged pointers on 
> architectures other than AArch64.

Which is the very same pain which MPX was suffering from, before it was dropped
in GCC :)

> 
> I don't believe that compiling the entire DSO with HWASAN enabled is 
> enough, since pointers can be passed across DSO boundaries.
> I haven't yet looked into how to handle this.
> 
> There's an even more fundamental problem of accesses within the 
> instrumented binary -- I haven't yet figured out how to remove the tag 
> before accesses on architectures without the AArch64 TBI feature.

Which should platforms like x86_64, right?

> 
> 
>>
>> 5) Is there a documentation/definition of how shadow memory for memory tagging looks like?
>> Is it similar to ASAN, where one can get to tag with:
>> u8 memory_tag = *((PTR >> TG) + SHADOW_OFFSET) & 0xf?
>>
> 
> Yes, it's similar.
> 
>  From the libhwasan code, the function to fetch a pointer to the shadow 
> memory byte corresponding to a memory address is MemToShadow.
> 
> constexpr uptr kShadowScale = 4;
> inline uptr MemToShadow(uptr untagged_addr) {
>    return (untagged_addr >> kShadowScale) +
>           __hwasan_shadow_memory_dynamic_address;
> }
> 
> https://github.com/llvm-mirror/compiler-rt/blob/99ce9876124e910475c627829bf14326b8073a9d/lib/hwasan/hwasan_mapping.h#L42
> 
> 
>> 6) Note that thing like memtag_tag_size, memtag_granule_size define an ABI of libsanitizer
>>
> 
> Yes, the size of these values define an ABI.
> 
> Those particular hooks are added as a demonstration for how something 
> like MTE would be implemented on top of this framework (where the 
> backend would specify the tag and granule size to match their targets 
> architecture).
> 
> HWASAN itself would use the hard-coded tag and granule size that matches 
> what libsanitizer uses.
> https://github.com/llvm-mirror/compiler-rt/blob/99ce9876124e910475c627829bf14326b8073a9d/lib/hwasan/hwasan_mapping.h#L36
> 
> I define these as `HWASAN_TAG_SIZE` and `HWASAN_TAG_GRANULE_SIZE` in 
> asan.h, and when using the sanitizer library the macro 
> `HARDWARE_MEMORY_TAGGING` would be false so their values would be constant.
> 
> 
>>>
>>> The current patch series is far from complete, but I'm posting the current state
>>> to provide something to discuss at the Cauldron next week.
>>>
>>> In its current state, this sanitizer only works on AArch64 with a custom kernel
>>> to allow tagged pointers in system calls.  This is discussed in the below link
>>> https://source.android.com/devices/tech/debug/hwasan -- the custom kernel allows
>>> tagged pointers in syscalls.
>>
>> Can you be please more specific. Is the MTE in upstream linux kernel? If so,
>> starting from which version?
> 
> I find I can only make complicated statements remotely clear in bullet 
> points ;-)
> 
> What I was trying to say was:
> - HWASAN from this patch series requires AArch64 TBI.
>    (I have not handled architectures without TBI)
> - The upstream kernel does not accept tagged pointers in syscalls.
>    (programs that use TBI must currently clear tags before passing
>     pointers to the kernel)

I know that in case of ASAN, the libasan provides wrappers (interceptors) for various glibc
functions that are often system calls. Similar wrappers are probably used in HWASAN
and so that one can create the memory pointer tags.

> - This patch series doesn't include any way to avoid passing tagged
>    pointers to syscalls.

I bet LLVM has the same problem so I would expect a handling in the interceptors.

> - Hence on order to test the sanitizer I'm using a kernel that has been
>    patched to accept tagged pointers in many syscalls.
> - The link to the android.com site is just another source describing the
>    same requirement.
> 
> 
> The support for the relaxed ABI (of accepting tagged pointers in various 
> syscalls in the kernel) is being discussed on the kernel mailing list, 
> the latest patchset I know of is here:
> https://lkml.org/lkml/2019/7/25/725

Thanks for pointer.

> 
> I wasn't trying to say anything about MTE in that paragraph, but kernel 
> support for MTE is not in upstream linux kernel and is currently being 
> worked on.
> 
>>
>>> I have also not yet put tests into the DejaGNU framework, but instead have a
>>> simple test file from which the tests will eventually come.  That test file is
>>> attached to this email despite not being in the patch series.
>>>
>>> Something close to this patch series bootstraps and passes most regression
>>> tests when ~--with-build-config=bootstrap-hwasan~ is used.  The regressions it
>>> doesn't pass are all the other sanitizer tests and all linker plugin tests.
>>> The linker plugin tests fail due to a configuration problem where the library
>>> path is not correctly set.
>>> (I say "something close to this patch series" because I recently made a change
>>> that breaks bootstrap but I believe is the best approach once I've fixed it,
>>> hence for an RFC I'm leaving it in).
>>>
>>> HWASAN works by storing a tag in the top bits of every pointer and a colour in
>>> a shadow memory region corresponding to every area of memory.  On every memory
>>> access through a pointer the tag in the pointer is checked against the colour in
>>> shadow memory corresponding to the memory the pointer is accessing.  If the tag
>>> and colour do not match then a fault is signalled.
>>>
>>> The instrumentation required for this sanitizer has a large overlap with the
>>> instrumentation required for implementing MTE (which has similar functionality
>>> but checks are automatically done in the hardware and instructions for colouring
>>> shadow memory and for managing tags are provided by the architecture).
>>> https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/arm-a-profile-architecture-2018-developments-armv85a
>>>
>>> We hope to use the HWASAN framework to implement MTE tagging on the stack, and
>>> hence I have a "dummy" patch demonstrating the approach envisaged for this.
>>
>> What's the situation with heap allocated memory and global variables?
> 
> For the heap, whatever library function allocates memory should return a 
> tagged pointer and colour the shadow memory accordingly.  This pointer 
> can then be treated exactly the same as all other pointers in 
> instrumented code.
> On freeing of memory the shadow memory is uncoloured in order to detect 
> use-after-free.
> 
> For HWASAN this means malloc and friends need to be intercepted, and 
> this is done by the runtime library.
> 
> For MTE there will need to be some updates in the system libraries.
> A discussion on the way this will be done in glibc has been started here:
> https://www.sourceware.org/ml/libc-alpha/2019-09/msg00114.html

I see.

Martin

> 
> 
> 
> Global variables are untagged.
> 
> For MTE we are planning on having these untagged.
> This is in order to allow uninstrumented object files to be statically 
> linked into MTE aware object files.
> Since global object accesses are directly generated into the code, there 
> would be no way to tag global objects and still use the code from that 
> static object.
> 
> 
> Since global objects will not be coloured for MTE, I am not planning on 
> colouring them for HWASAN.  There would be a reasonable amount of work, 
> including a new mechanism for associating objects with tags.
> 
> Having all global variables untagged means that nothing need be done, 
> all pointers to global variables will have a tag of zero and the shadow 
> memory will correspondingly be left coloured as zero.
> 
>>
>>>
>>> Though there is still much to implement here, the general approach should be
>>> clear.  Any feedback is welcomed, but I have three main points that I'm
>>> particularly hoping for external opinions.
>>>
>>> 1) The current approach stores a tag on the RTL representing a given variable,
>>>     in order to implement HWASAN for x86_64 the tag needs to be removed before
>>>     every memory access but not on things like function calls.
>>>     Is there any obvious way to handle removing the tag in these places?
>>>     Maybe something with legitimize_address?
>>
>> Not being a target expect, but I bet you'll need to store the tag with a RTL
>> representation of a stack variable.
>>
>> Thanks,
>> Martin
>>
>>> 2) The first draft presented here introduces a new RTL expression called
>>>     ADDTAG.  I now believe that a hook would be neater here but haven't yet
>>>     looked into it.  Do people agree?
>>>     (addtag is introduced in the patch titled "Put tags into each stack variable
>>>     pointer", but the reason it's introduced is so the backend can define how
>>>     this gets implemented with a ~define_expand~ and that's only needed for the
>>>     MTE handling as introduced in "Add in MTE stubs")
>>> 3) This patch series has not yet had much thought go towards it around command
>>>     line arguments.  I personally quite like the idea of having
>>>     ~-fsanitize=hwaddress~ turn on "checking memory tags against shadow memory
>>>     colour", and MTE being just a hardware acceleration of this ability.
>>>     I suspect this idea wouldn't be liked by all and would like to hear some
>>>     opinions.
>>>
>>> Thanks,
>>> Matthew
>>>
>>
> 

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC
  2019-09-11 11:53     ` Martin Liška
@ 2019-09-11 16:37       ` Matthew Malcomson
  2019-09-11 18:34         ` Evgenii Stepanov via gcc-patches
  0 siblings, 1 reply; 35+ messages in thread
From: Matthew Malcomson @ 2019-09-11 16:37 UTC (permalink / raw)
  To: Martin Liška, gcc-patches; +Cc: dodji, nd, kcc, jakub, dvyukov

On 11/09/19 12:53, Martin Liška wrote:
> On 9/9/19 5:54 PM, Matthew Malcomson wrote:
>> On 09/09/19 11:47, Martin Liška wrote:
>>> On 9/6/19 4:46 PM, Matthew Malcomson wrote:
>>>> Hello,
>>>>
>> As I understand it, `hwasan-abi=interceptor` vs `platform` is about
>> adding such MTE emulation for "application code" or "platform code (e.g.
>> kernel)" respectively.
> 
> Hm, are you sure? Clang also uses -fsanitize=kernel-hwaddress which should
> be equivalent to kernel-address for -fsanitize=address.
> 

I'm not at all sure it's to do with the kernel ;-}

Here's the commit that adds the flag.
https://reviews.llvm.org/D56038

 From the commit message it seems the point is to distinguish between 
running on runtimes that natively support HWASAN (named the "platform" 
abi) and those where functions like malloc and pthread_create have to be 
intercepted (named the "interceptor" abi).

I had assumed that targeting the kernel would be in the "platform" 
group, but it could easily not be the case.

Considering the message form the below commit it seems that this is more 
targeted at instrumenting things like libc https://reviews.llvm.org/D50922.

I'm currently working on writing down the questions I plan to ask the 
developers of HWASAN in LLVM, I'll put this on the list :-)

>>
>>>
>> There's an even more fundamental problem of accesses within the
>> instrumented binary -- I haven't yet figured out how to remove the tag
>> before accesses on architectures without the AArch64 TBI feature.
> 
> Which should platforms like x86_64, right?

Yes.
As yet I haven't gotten anything working for architectures without TBI 
(everything except AArch64).
This particular problem was one I was hoping for suggestions around (my 
first of the questions in my cover letter).

>>>>
>>>> The current patch series is far from complete, but I'm posting the current state
>>>> to provide something to discuss at the Cauldron next week.
>>>>
>>>> In its current state, this sanitizer only works on AArch64 with a custom kernel
>>>> to allow tagged pointers in system calls.  This is discussed in the below link
>>>> https://source.android.com/devices/tech/debug/hwasan -- the custom kernel allows
>>>> tagged pointers in syscalls.
>>>
>>> Can you be please more specific. Is the MTE in upstream linux kernel? If so,
>>> starting from which version?
>>
>> I find I can only make complicated statements remotely clear in bullet
>> points ;-)
>>
>> What I was trying to say was:
>> - HWASAN from this patch series requires AArch64 TBI.
>>     (I have not handled architectures without TBI)
>> - The upstream kernel does not accept tagged pointers in syscalls.
>>     (programs that use TBI must currently clear tags before passing
>>      pointers to the kernel)
> 
> I know that in case of ASAN, the libasan provides wrappers (interceptors) for various glibc
> functions that are often system calls. Similar wrappers are probably used in HWASAN
> and so that one can create the memory pointer tags.
> 
>> - This patch series doesn't include any way to avoid passing tagged
>>     pointers to syscalls.
> 
> I bet LLVM has the same problem so I would expect a handling in the interceptors.
> 

I'm pretty sure this problem hasn't been solved with interceptors.

The android page describing hwasan specifically mentions the requirement 
of a Linux kernel accepting tagged pointers, and I believe this is the 
most supported environment.

https://source.android.com/devices/tech/debug/hwasan
"HWASan requires the Linux kernel to accept tagged pointers in system 
call arguments."

Also, there are surprisingly few interceptors defined in libhwasan.

Thanks,
Matthew

>> - Hence on order to test the sanitizer I'm using a kernel that has been
>>     patched to accept tagged pointers in many syscalls.
>> - The link to the android.com site is just another source describing the
>>     same requirement.
>>
>>
>> The support for the relaxed ABI (of accepting tagged pointers in various
>> syscalls in the kernel) is being discussed on the kernel mailing list,
>> the latest patchset I know of is here:
>> https://lkml.org/lkml/2019/7/25/725
> 
> Thanks for pointer.
> 

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC
  2019-09-11 16:37       ` Matthew Malcomson
@ 2019-09-11 18:34         ` Evgenii Stepanov via gcc-patches
  0 siblings, 0 replies; 35+ messages in thread
From: Evgenii Stepanov via gcc-patches @ 2019-09-11 18:34 UTC (permalink / raw)
  To: Matthew Malcomson
  Cc: Martin Liška, gcc-patches, dodji, nd, kcc, jakub, dvyukov

On Wed, Sep 11, 2019 at 9:37 AM Matthew Malcomson
<Matthew.Malcomson@arm.com> wrote:
>
> On 11/09/19 12:53, Martin Liška wrote:
> > On 9/9/19 5:54 PM, Matthew Malcomson wrote:
> >> On 09/09/19 11:47, Martin Liška wrote:
> >>> On 9/6/19 4:46 PM, Matthew Malcomson wrote:
> >>>> Hello,
> >>>>
> >> As I understand it, `hwasan-abi=interceptor` vs `platform` is about
> >> adding such MTE emulation for "application code" or "platform code (e.g.
> >> kernel)" respectively.
> >
> > Hm, are you sure? Clang also uses -fsanitize=kernel-hwaddress which should
> > be equivalent to kernel-address for -fsanitize=address.
> >
>
> I'm not at all sure it's to do with the kernel ;-}
>
> Here's the commit that adds the flag.
> https://reviews.llvm.org/D56038
>
>  From the commit message it seems the point is to distinguish between
> running on runtimes that natively support HWASAN (named the "platform"
> abi) and those where functions like malloc and pthread_create have to be
> intercepted (named the "interceptor" abi).
>
> I had assumed that targeting the kernel would be in the "platform"
> group, but it could easily not be the case.
>
> Considering the message form the below commit it seems that this is more
> targeted at instrumenting things like libc https://reviews.llvm.org/D50922.

With hwasan we tried a different approach from asan: instead of
intercepting libc we build it with sanitizer instrumentation, and rely
on a few hooks to update internal state of the tool on interesting
events, such as process startup, thread creation and destruction,
stack unwind (longjmp, vfork). This effectively puts hwasan _below_
libc (as in libc depends on libhwasan).

It has worked amazingly well for Android, where we aim to sanitize
most of platform code at once. Ex. ASan has this requirement that the
main executable needs to be built with ASan before any of the
libraries could - otherwise the tool will not be able to interpose
malloc/free symbols. As a consequence, when there are binaries that
can not be sanitized for any reason, we need to keep unsanitized
copies of all their transitive dependencies, and that turns into a
huge build/deployment mess. Hwasan approach avoids this problem by
making sure that the allocator is always there (because everything
depends on libc).

The downside, of course, is that this can not be used to sanitize a
single binary without a specially built libc. Hence the "interceptor"
ABI, which was an attempt to support running hwasan-instrumented
applications on regular, non-hwasan devices. We are not developing
this mode any longer, but it is used to run compiler-rt tests on
aarch64-android.

> I'm currently working on writing down the questions I plan to ask the
> developers of HWASAN in LLVM, I'll put this on the list :-)
>
> >>
> >>>
> >> There's an even more fundamental problem of accesses within the
> >> instrumented binary -- I haven't yet figured out how to remove the tag
> >> before accesses on architectures without the AArch64 TBI feature.
> >
> > Which should platforms like x86_64, right?
>
> Yes.
> As yet I haven't gotten anything working for architectures without TBI
> (everything except AArch64).
> This particular problem was one I was hoping for suggestions around (my
> first of the questions in my cover letter).

We have support for hwasan on x86_64 in LLVM (by removing tags before
accesses), but it is not really practical because any library built
without instrumentation is a big source of false positives. Even, say,
libc++/libstdc++. We use it exclusively for tests.

> >>>>
> >>>> The current patch series is far from complete, but I'm posting the current state
> >>>> to provide something to discuss at the Cauldron next week.
> >>>>
> >>>> In its current state, this sanitizer only works on AArch64 with a custom kernel
> >>>> to allow tagged pointers in system calls.  This is discussed in the below link
> >>>> https://source.android.com/devices/tech/debug/hwasan -- the custom kernel allows
> >>>> tagged pointers in syscalls.
> >>>
> >>> Can you be please more specific. Is the MTE in upstream linux kernel? If so,
> >>> starting from which version?
> >>
> >> I find I can only make complicated statements remotely clear in bullet
> >> points ;-)
> >>
> >> What I was trying to say was:
> >> - HWASAN from this patch series requires AArch64 TBI.
> >>     (I have not handled architectures without TBI)
> >> - The upstream kernel does not accept tagged pointers in syscalls.
> >>     (programs that use TBI must currently clear tags before passing
> >>      pointers to the kernel)
> >
> > I know that in case of ASAN, the libasan provides wrappers (interceptors) for various glibc
> > functions that are often system calls. Similar wrappers are probably used in HWASAN
> > and so that one can create the memory pointer tags.
> >
> >> - This patch series doesn't include any way to avoid passing tagged
> >>     pointers to syscalls.
> >
> > I bet LLVM has the same problem so I would expect a handling in the interceptors.
> >
>
> I'm pretty sure this problem hasn't been solved with interceptors.
>
> The android page describing hwasan specifically mentions the requirement
> of a Linux kernel accepting tagged pointers, and I believe this is the
> most supported environment.
>
> https://source.android.com/devices/tech/debug/hwasan
> "HWASan requires the Linux kernel to accept tagged pointers in system
> call arguments."
>
> Also, there are surprisingly few interceptors defined in libhwasan.
>
> Thanks,
> Matthew
>
> >> - Hence on order to test the sanitizer I'm using a kernel that has been
> >>     patched to accept tagged pointers in many syscalls.
> >> - The link to the android.com site is just another source describing the
> >>     same requirement.
> >>
> >>
> >> The support for the relaxed ABI (of accepting tagged pointers in various
> >> syscalls in the kernel) is being discussed on the kernel mailing list,
> >> the latest patchset I know of is here:
> >> https://lkml.org/lkml/2019/7/25/725

The main patchset is this one:
https://patchwork.kernel.org/cover/11055001/

AFAIK, it's expected to go in the next merge window.

> >
> > Thanks for pointer.
> >

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC
  2019-09-06 14:46 [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Matthew Malcomson
                   ` (16 preceding siblings ...)
  2019-09-09 10:47 ` [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Martin Liška
@ 2019-09-23  8:02 ` Martin Liška
  2019-10-23 11:02   ` Matthew Malcomson
  17 siblings, 1 reply; 35+ messages in thread
From: Martin Liška @ 2019-09-23  8:02 UTC (permalink / raw)
  To: Matthew Malcomson, gcc-patches; +Cc: dodji, nd, kcc, jakub, dvyukov

Hi.

As mentioned in the next email thread, there are main objectives
that will help me to make a proper patch review:

1) Make first libsanitizer merge from trunk, it will remove the need
   of the backports that you made. Plus I will be able to apply the
   patchset on the current master.
2) I would exclude the setjmp/longjmp - these should be upstreamed first
   in libsanitizer.
3) I would like to see a two HWASAN options that will clearly separate the
   2 supported modes: TBI without MTE and MTE. Here I would appreciate to have
   a compiler farm machine with TBI which we can use for testing.
4) About the BUILTIN expansion: you provided a patch for couple of them. My question
   is whether the list is complete?
5) I would appreciate the patch set to be split into less logical parts, e.g.
   libsanitizer changes; option introduction; stack variable handling (colour/uncolour/alignment);
   hwasan pass and other GIMPLE-related changes; RTL hooks, new RTL instructions and expansion changes.

Thank you,
Martin
   

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC
  2019-09-23  8:02 ` Martin Liška
@ 2019-10-23 11:02   ` Matthew Malcomson
  2019-10-24 10:11     ` Martin Liška
  0 siblings, 1 reply; 35+ messages in thread
From: Matthew Malcomson @ 2019-10-23 11:02 UTC (permalink / raw)
  To: Martin Liška, gcc-patches; +Cc: dodji, nd, kcc, jakub, dvyukov

Hi Martin,

I'm getting close to putting up a patch series that I believe could go 
in before stage1 close.

I currently have to do testing on sanitizing the kernel, and track down 
a bootstrap comparison diff in the code handling shadow-stack cleanup 
during exception unwinding.

I just thought I'd answer these questions below to see if there's 
anything I extra could to do to make reviewing easier.

On 23/09/19 09:02, Martin Liška wrote:
> Hi.
> 
> As mentioned in the next email thread, there are main objectives
> that will help me to make a proper patch review:
> 
> 1) Make first libsanitizer merge from trunk, it will remove the need
>     of the backports that you made. Plus I will be able to apply the
>     patchset on the current master.
Done
> 2) I would exclude the setjmp/longjmp - these should be upstreamed first
>     in libsanitizer.

Will exclude in the patch series, upstreaming under progress 
(https://reviews.llvm.org/D69045)

> 3) I would like to see a two HWASAN options that will clearly separate the
>     2 supported modes: TBI without MTE and MTE. Here I would appreciate to have
>     a compiler farm machine with TBI which we can use for testing.

I went back and looked at clang to see that it uses 
`-fsanitize=hwaddress` and `-fsanitize=memtag`, which are completely 
different options.

I'm now doing the same, with the two sanitizers just using similar code 
paths.

In fact, I'm not going to have the MTE instrumentation ready by the end 
of stage1, so my aim is to just put the `-fsanitize=hwaddress` sanitizer 
in, but send some outline code to the mailing list to demonstrate how 
`-fsanitize=memtag` would fit in.


## w.r.t. a compiler farm machine with TBI

Any AArch64 machine has this feature.  However in order to use the 
sanitizer the kernel needs to allow "tagged pointers" in syscalls.

The kernel has allowed these tagged pointers in syscalls (once it's been 
turned on with a relevant prctl) in mainline since 5.4-rc1 (i.e. the 
start of this month).

My testing has been on a virtual machine with a mainline kernel built 
from source.

Given that I'm not sure how you want to proceed.
Could we set up a virtual machine on the compiler farm?


> 4) About the BUILTIN expansion: you provided a patch for couple of them. My question
>     is whether the list is complete?

The list of BUILTINs was nowhere near complete at the time I posted the 
RFC patches.

Since then I've added features and correspondingly added BUILTINs.

Now I believe I've added all the BUILTIN's into sanitizer.def this 
sanitizer will need.

> 5) I would appreciate the patch set to be split into less logical parts, e.g.
>     libsanitizer changes; option introduction; stack variable handling (colour/uncolour/alignment);
>     hwasan pass and other GIMPLE-related changes; RTL hooks, new RTL instructions and expansion changes.
> 

Will do!

> Thank you,
> Martin
>     
> 

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC
  2019-10-23 11:02   ` Matthew Malcomson
@ 2019-10-24 10:11     ` Martin Liška
  0 siblings, 0 replies; 35+ messages in thread
From: Martin Liška @ 2019-10-24 10:11 UTC (permalink / raw)
  To: Matthew Malcomson, gcc-patches; +Cc: dodji, nd, kcc, jakub, dvyukov

On 10/23/19 1:01 PM, Matthew Malcomson wrote:
> Hi Martin,

Hello.

> 
> I'm getting close to putting up a patch series that I believe could go 
> in before stage1 close.
> 
> I currently have to do testing on sanitizing the kernel, and track down 
> a bootstrap comparison diff in the code handling shadow-stack cleanup 
> during exception unwinding.
> 
> I just thought I'd answer these questions below to see if there's 
> anything I extra could to do to make reviewing easier.

I welcome that approach.

> 
> On 23/09/19 09:02, Martin Liška wrote:
>> Hi.
>>
>> As mentioned in the next email thread, there are main objectives
>> that will help me to make a proper patch review:
>>
>> 1) Make first libsanitizer merge from trunk, it will remove the need
>>     of the backports that you made. Plus I will be able to apply the
>>     patchset on the current master.
> Done
>> 2) I would exclude the setjmp/longjmp - these should be upstreamed first
>>     in libsanitizer.
> 
> Will exclude in the patch series, upstreaming under progress 
> (https://reviews.llvm.org/D69045)
> 
>> 3) I would like to see a two HWASAN options that will clearly separate the
>>     2 supported modes: TBI without MTE and MTE. Here I would appreciate to have
>>     a compiler farm machine with TBI which we can use for testing.
> 
> I went back and looked at clang to see that it uses 
> `-fsanitize=hwaddress` and `-fsanitize=memtag`, which are completely 
> different options.
> 
> I'm now doing the same, with the two sanitizers just using similar code 
> paths.
> 
> In fact, I'm not going to have the MTE instrumentation ready by the end 
> of stage1, so my aim is to just put the `-fsanitize=hwaddress` sanitizer 
> in, but send some outline code to the mailing list to demonstrate how 
> `-fsanitize=memtag` would fit in.

As well here. That will make it easier to merge -fsanitize=hwaddress first.

> 
> 
> ## w.r.t. a compiler farm machine with TBI
> 
> Any AArch64 machine has this feature.  However in order to use the 
> sanitizer the kernel needs to allow "tagged pointers" in syscalls.

If so, then it will be very easy to grab a machine and run 5.4 kernel in it.
So I'll will be able to test the patches.

> 
> The kernel has allowed these tagged pointers in syscalls (once it's been 
> turned on with a relevant prctl) in mainline since 5.4-rc1 (i.e. the 
> start of this month).
> 
> My testing has been on a virtual machine with a mainline kernel built 
> from source.
> 
> Given that I'm not sure how you want to proceed.
> Could we set up a virtual machine on the compiler farm?
> 
> 
>> 4) About the BUILTIN expansion: you provided a patch for couple of them. My question
>>     is whether the list is complete?
> 
> The list of BUILTINs was nowhere near complete at the time I posted the 
> RFC patches.
> 
> Since then I've added features and correspondingly added BUILTINs.
> 
> Now I believe I've added all the BUILTIN's into sanitizer.def this 
> sanitizer will need.
> 
>> 5) I would appreciate the patch set to be split into less logical parts, e.g.
>>     libsanitizer changes; option introduction; stack variable handling (colour/uncolour/alignment);
>>     hwasan pass and other GIMPLE-related changes; RTL hooks, new RTL instructions and expansion changes.
>>
> 
> Will do!

Great.

Thanks,
Martin

> 
>> Thank you,
>> Martin
>>     
>>
> 

^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2019-10-24 10:08 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-09-06 14:46 [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Matthew Malcomson
2019-09-06 14:46 ` [RFC][PATCH 3/X][libsanitizer] Allow compilation for HWASAN_WITH_INTERCEPTORS=OFF Matthew Malcomson
2019-09-09  9:27   ` Martin Liška
2019-09-06 14:46 ` [RFC][PATCH 2/X][libsanitizer] Tie the hwasan library into our build system Matthew Malcomson
2019-09-06 14:46 ` [RFC][PATCH 4/X][libsanitizer] Pass size and pointer info to error reporting functions Matthew Malcomson
2019-09-09  9:27   ` Martin Liška
2019-09-06 14:46 ` [RFC][PATCH 7/X][libsanitizer] Add option to bootstrap using HWASAN Matthew Malcomson
2019-09-06 14:46 ` [RFC][PATCH 8/X][libsanitizer] Ensure HWASAN required alignment for stack variables Matthew Malcomson
2019-09-06 14:46 ` [RFC][PATCH 5/X][libsanitizer] Introduce longjmp/setjmp interceptors to libhwasan Matthew Malcomson
2019-09-09 10:02   ` Martin Liška
2019-09-09 10:29     ` Matthew Malcomson
2019-09-09 10:49       ` Martin Liška
2019-09-06 14:46 ` [RFC][PATCH 14/X][libsanitizer] Introduce HWASAN block-scope poisoning Matthew Malcomson
2019-09-06 14:46 ` [RFC][PATCH 1/X][libsanitizer] Introduce libsanitizer to GCC tree Matthew Malcomson
2019-09-09  9:26   ` Martin Liška
2019-09-06 14:47 ` [RFC][PATCH 13/X][libsanitizer] Instrument known builtin function calls Matthew Malcomson
2019-09-06 14:47 ` [RFC][PATCH 10/X][libsanitizer] Colour the shadow stack for each stack variable Matthew Malcomson
2019-09-06 14:47 ` [RFC][PATCH 15/X][libsanitizer] Add in MTE stubs Matthew Malcomson
2019-09-06 14:47 ` [RFC][PATCH 11/X][libsanitizer] Uncolour stack frame on function exit Matthew Malcomson
2019-09-06 14:47 ` [RFC][PATCH 16/X][libsanitizer] Build libhwasan with interceptors Matthew Malcomson
2019-09-06 14:47 ` [RFC][PATCH 12/X][libsanitizer] Check pointer tags match address tags Matthew Malcomson
2019-09-06 14:47 ` [RFC][PATCH 6/X][libsanitizer] Add -fsanitize=hwaddress flags Matthew Malcomson
2019-09-09 10:06   ` Martin Liška
2019-09-09 10:18     ` Matthew Malcomson
2019-09-09 10:20       ` Martin Liška
2019-09-06 14:47 ` [RFC][PATCH 9/X][libsanitizer] Put tags into each stack variable pointer Matthew Malcomson
2019-09-09 10:47 ` [Patch 0/X] [WIP][RFC][libsanitizer] Introduce HWASAN to GCC Martin Liška
2019-09-09 15:55   ` Matthew Malcomson
2019-09-10  1:06     ` Kostya Serebryany via gcc-patches
2019-09-11 11:53     ` Martin Liška
2019-09-11 16:37       ` Matthew Malcomson
2019-09-11 18:34         ` Evgenii Stepanov via gcc-patches
2019-09-23  8:02 ` Martin Liška
2019-10-23 11:02   ` Matthew Malcomson
2019-10-24 10:11     ` Martin Liška

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).