]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
asan: add new memtag sanitizer
authorIndu Bhagat <indu.bhagat@oracle.com>
Wed, 9 Jul 2025 12:33:14 +0000 (15:33 +0300)
committerClaudiu Zissulescu <claudiu.zissulescu-ianculescu@oracle.com>
Tue, 16 Dec 2025 09:18:49 +0000 (11:18 +0200)
Add new command line option -fsanitize=memtag-stack with the following
new params:
--param memtag-instrument-alloca [0,1] (default 1) to use MTE insns
for enabling dynamic checking of stack allocas.

Along with the new SANITIZE_MEMTAG_STACK, define a SANITIZE_MEMTAG
which will be set if any kind of memtag sanitizer is in effect (e.g.,
later we may add -fsanitize=memtag-globals).  Add errors to convey
that memtag sanitizer does not work with hwaddress and address
sanitizers.  Also error out if memtag ISA extension is not enabled.

MEMTAG sanitizer will use the HWASAN machinery, but with a few
differences:
  - The tags are always generated at runtime by the hardware, so
    -fsanitize=memtag-stack enforces a --param hwasan-random-frame-tag=1

Add documentation in gcc/doc/invoke.texi.

gcc/
* builtins.def: Adjust the macro to include the new
SANTIZIE_MEMTAG_STACK.
* flag-types.h (enum sanitize_code): Add new enumerator for
SANITIZE_MEMTAG and SANITIZE_MEMTAG_STACK.
* opts.cc (finish_options): memtag-stack sanitizer conflicts with
hwaddress and address sanitizers.
(sanitizer_opts): Add new memtag-stack sanitizer.
(parse_sanitizer_options): memtag-stack sanitizer cannot recover.
* params.opt: Add new params for memtag-stack sanitizer.
* doc/invoke.texi: Update documentation.

Signed-off-by: Claudiu Zissulescu <claudiu.zissulescu-ianculescu@oracle.com>
Co-authored-by: Claudiu Zissulescu <claudiu.zissulescu-ianculescu@oracle.com>
gcc/builtins.def
gcc/doc/invoke.texi
gcc/flag-types.h
gcc/opts.cc
gcc/params.opt

index 7cd5353bcb16b931c135f25283ad10135037fcfd..714abb9cbc71729b8be22f503f0b3c1f77b5b058 100644 (file)
@@ -257,6 +257,7 @@ along with GCC; see the file COPYING3.  If not see
               true, true, true, ATTRS, true, \
              (flag_sanitize & (SANITIZE_ADDRESS | SANITIZE_THREAD \
                                | SANITIZE_HWADDRESS \
+                               | SANITIZE_MEMTAG_STACK \
                                | SANITIZE_UNDEFINED \
                                | SANITIZE_UNDEFINED_NONDEFAULT) \
               || flag_sanitize_coverage))
index 4635d860a621a102c99b327942400bb0881829b3..3ee16f01651cec9df690bee1d45e108b33bc5a75 100644 (file)
@@ -17698,7 +17698,7 @@ When using stack instrumentation, decide tags for stack variables using a
 deterministic sequence beginning at a random tag for each frame.  With this
 parameter unset tags are chosen using the same sequence but beginning from 1.
 This is enabled by default for @option{-fsanitize=hwaddress} and unavailable
-for @option{-fsanitize=kernel-hwaddress}.
+for @option{-fsanitize=kernel-hwaddress} and @option{-fsanitize=memtag-stack}.
 To disable it use @option{--param hwasan-random-frame-tag=0}.
 
 @item hwasan-instrument-allocas
@@ -17731,6 +17731,11 @@ and @option{-fsanitize=kernel-hwaddress}.
 To disable instrumentation of builtin functions use
 @option{--param hwasan-instrument-mem-intrinsics=0}.
 
+@item memtag-instrument-allocas
+Enable hardware-assisted memory tagging of dynamically sized stack-allocated
+variables.  This kind of code generation is enabled by default when using
+@option{-fsanitize=memtag-stack}.
+
 @item use-after-scope-direct-emission-threshold
 If the size of a local variable in bytes is smaller or equal to this
 number, directly poison (or unpoison) shadow memory instead of using
@@ -18684,6 +18689,13 @@ possible by specifying the command-line options
 @option{--param hwasan-instrument-allocas=1} respectively. Using a random frame
 tag is not implemented for kernel instrumentation.
 
+@opindex fsanitize=memtag-stack
+@item -fsanitize=memtag-stack
+Use Memory Tagging Extension instructions instead of instrumentation
+to allow the detection of memory errors.  Similar to HWASAN, it is
+also a probabilistic method.  This option is available only on those
+AArch64 architectures that support Memory Tagging Extensions.
+
 @opindex fsanitize=pointer-compare
 @item -fsanitize=pointer-compare
 Instrument comparison operation (<, <=, >, >=) with pointer operands.
index 44a90becb27ad9dcf44c3100b8fb915e56aa6e5b..f7cb3a2be41a2ae671e351b13449a4212b5d3c3d 100644 (file)
@@ -338,6 +338,10 @@ enum sanitize_code {
   SANITIZE_KERNEL_HWADDRESS = 1UL << 30,
   /* Shadow Call Stack.  */
   SANITIZE_SHADOW_CALL_STACK = 1UL << 31,
+  /* Memory Tagging for Stack.  */
+  SANITIZE_MEMTAG_STACK = 1ULL << 32,
+  /* Memory Tagging.  */
+  SANITIZE_MEMTAG = SANITIZE_MEMTAG_STACK,
   SANITIZE_SHIFT = SANITIZE_SHIFT_BASE | SANITIZE_SHIFT_EXPONENT,
   SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
                       | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN
index abbf7cedff3a9afcdb7c07d3094d348dd3ecbd13..b9378a96dd2e5e8a53943fff43a6306699e32654 100644 (file)
@@ -1319,6 +1319,24 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set,
   report_conflicting_sanitizer_options (opts, loc, SANITIZE_USER_ADDRESS,
                                        SANITIZE_KERNEL_ADDRESS);
 
+  /* Sanitizers using Memory-Tagging Extension conflict with HWASAN and
+     ASAN.  */
+  report_conflicting_sanitizer_options (opts, loc, SANITIZE_MEMTAG,
+                                       SANITIZE_HWADDRESS);
+  report_conflicting_sanitizer_options (opts, loc, SANITIZE_MEMTAG,
+                                       SANITIZE_ADDRESS);
+
+  /* Memtag sanitizer implies HWASAN but with tags always generated by
+     the hardware randomly.  */
+  if ((opts->x_flag_sanitize & SANITIZE_MEMTAG_STACK)
+      && opts->x_param_hwasan_random_frame_tag == 0)
+    {
+       warning_at (loc, OPT_fsanitize_,
+                  "%<--param hwasan-random-frame-tag=0%> is ignored when "
+                  "%<-fsanitize=memtag-stack%> is present");
+       opts->x_param_hwasan_random_frame_tag = 1;
+    }
+
   /* 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)
@@ -2183,6 +2201,7 @@ const struct sanitizer_opts_s sanitizer_opts[] =
   SANITIZER_OPT (pointer-overflow, SANITIZE_POINTER_OVERFLOW, true, true),
   SANITIZER_OPT (builtin, SANITIZE_BUILTIN, true, true),
   SANITIZER_OPT (shadow-call-stack, SANITIZE_SHADOW_CALL_STACK, false, false),
+  SANITIZER_OPT (memtag-stack, SANITIZE_MEMTAG_STACK, false, false),
   SANITIZER_OPT (all, ~sanitize_code_type (0), true, true),
 #undef SANITIZER_OPT
   { NULL, sanitize_code_type (0), 0UL, false, false }
@@ -2321,7 +2340,8 @@ parse_sanitizer_options (const char *p, location_t loc, int scode,
                else if (code == OPT_fsanitize_recover_)
                  flags |= ~(SANITIZE_THREAD | SANITIZE_LEAK
                             | SANITIZE_UNREACHABLE | SANITIZE_RETURN
-                            | SANITIZE_SHADOW_CALL_STACK);
+                            | SANITIZE_SHADOW_CALL_STACK
+                            | SANITIZE_MEMTAG_STACK);
                else /* if (code == OPT_fsanitize_trap_) */
                  flags |= (SANITIZE_UNDEFINED
                            | SANITIZE_UNDEFINED_NONDEFAULT);
index ad5ee88736762a27b800256c658d4b61d583320f..cf3b387ad7b72acfc26af14591cb54a7c4dce9be 100644 (file)
@@ -98,6 +98,10 @@ Enable hwasan instrumentation of store operations.
 Common Joined UInteger Var(param_hwasan_instrument_mem_intrinsics) Init(1) IntegerRange(0, 1) Param Optimization
 Enable hwasan instrumentation of builtin functions.
 
+-param=memtag-instrument-allocas=
+Target Joined UInteger Var(param_memtag_instrument_allocas) Init(1) IntegerRange(0, 1) Param
+When sanitizing using MTE instructions, add checks for all stack allocas.
+
 -param=avg-loop-niter=
 Common Joined UInteger Var(param_avg_loop_niter) Init(10) IntegerRange(1, 65536) Param Optimization
 Average number of iterations of a loop.