Indu Bhagat <indu.bha...@oracle.com> writes: > Memory tagging is used for detecting memory safety bugs. On AArch64, the > memory tagging extension (MTE) helps in reducing the overheads of memory > tagging: > - CPU: MTE instructions for efficiently tagging and untagging memory. > - Memory: New memory type, Normal Tagged Memory, added to the Arm > Architecture. > > The MEMory TAGging (MEMTAG) sanitizer uses the same infrastructure as > HWASAN. MEMTAG and HWASAN are both hardware-assisted solutions, and > rely on the same sanitizer machinery in parts. So, define new > constructs that allow MEMTAG and HWASAN to share the infrastructure: > > - hwassist_sanitize_p () is true when either SANITIZE_MEMTAG or > SANITIZE_HWASAN is true. > - hwassist_sanitize_stack_p () is when hwassist_sanitize_p () and > stack variables are to be sanitized. > > MEMTAG and HWASAN do have differences, however, and hence, the need to > conditionalize using memtag_sanitize_p () in the relevant places. E.g., > > - Instead of generating the libcall __hwasan_tag_memory, MEMTAG needs > to invoke the target-specific hook TARGET_MEMTAG_TAG_MEMORY to tag > memory. Similar approach can be seen for handling > handle_builtin_alloca, where instead of doing the gimple > transformations, target hooks are used. > > - Add a new internal function HWASAN_ALLOCA_POISON to handle > dynamically allocated stack when MEMTAG sanitizer is enabled. At > expansion, this allows to, in turn, invoke target-hooks to increment > tag, and use the generated tag to finally tag the dynamically allocated > memory. > > - HWASAN uses HWASAN_STACK_BACKGROUND as the background color. In > case of MEMTAG, we simply pick stack_pointer_rtx. See > hwasan_emit_untag_frame (). > > - HWASAN relies on CFN_HWASAN_CHOOSE_TAG to extract the tag if > necessary. For MEMTAG, however, since there is no hardware > instruction to extract tag from register, we make the implementation > diverge a bit. > > The usual pattern: > irg x0, x0, x0 > subg x0, x0, #16, #0 > creates a tag in x0 and so on. For alloca, we need to apply the > generated tag to the new sp. In absense of an extract tag insn, the > implemenation in expand_HWASAN_ALLOCA_POISON resorts to invoking irg > again.
This is probably one of those where the reason will click as soon as I hit send, but I'm sure why this is necessary. Can't the tag be extracted using normal base Armv8-A instructions? AIUI, the point of hwasan_frame_tag_offset is to "guarantee" that ajoining data in the same frame has a different tag. Wouldn't reusing IRG be weaker, given the randomness? > TBD: > - Not sure if we really need param_memtag_instrument_mem_intrinsics > explicitly. > - Conditionalizing using hwassist_sanitize_p (), memtag_sanitize_p () > etc looks unappetizing in some cases. Not sure if there is a better > way. Is this generally the right thing to do, or is there some > desirable refactorings. > - adding decl to hwasan_stack_var. double check if this is necessary. > See how we update the RTL for decl at expand_one_stack_var_at. And > then use the RTL for decl in hwasan_emit_prologue. Add testcases > around this. > - In hwasan_frame_base (), see if checking for memtag_sanitize_p () for > force_reg etc is really necessary. Revisit to see what gives, fix or > add documentation. > - Error out if user specifies stack alloc alignment not a factor of 16 ? I think it's up to gcc to round up the alignment to STACK_BOUNDARY. Specifying a smaller alignment doesn't seem like an error; it's a minimum rather than a maximum. Thanks, Richard > > > gcc/ChangeLog: > > * asan.cc (struct hwasan_stack_var): > (handle_builtin_stack_restore): Accommodate MEMTAG sanitizer. > (handle_builtin_alloca): Expand differently if MEMTAG sanitizer. > (get_mem_refs_of_builtin_call): Include MEMTAG along with > HWASAN. > (memtag_sanitize_stack_p): New definition. > (memtag_sanitize_allocas_p): Likewise. > (memtag_memintrin): Likewise. > (hwassist_sanitize_p): Likewise. > (hwassist_sanitize_stack_p): Likewise. > (report_error_func): Include MEMTAG along with HWASAN. > (build_check_stmt): Likewise. > (instrument_derefs): MEMTAG too does not deal with globals yet. > (instrument_builtin_call): > (maybe_instrument_call): Include MEMTAG along with HWASAN. > (asan_expand_mark_ifn): Likewise. > (asan_expand_check_ifn): Likewise. > (asan_expand_poison_ifn): Expand differently if MEMTAG sanitizer. > (asan_instrument): > (hwasan_frame_base): > (hwasan_record_stack_var): > (hwasan_emit_prologue): Expand differently if MEMTAG sanitizer. > (hwasan_emit_untag_frame): Likewise. > * asan.h (hwasan_record_stack_var): > (memtag_sanitize_stack_p): New declaration. > (memtag_sanitize_allocas_p): Likewise. > (hwassist_sanitize_p): Likewise. > (hwassist_sanitize_stack_p): Likewise. > (asan_sanitize_use_after_scope): Include MEMTAG along with > HWASAN. > * cfgexpand.cc (align_local_variable): Likewise. > (expand_one_stack_var_at): Likewise. > (expand_stack_vars): Likewise. > (expand_one_stack_var_1): Likewise. > (init_vars_expansion): Likewise. > (expand_used_vars): Likewise. > (pass_expand::execute): Likewise. > * gimplify.cc (asan_poison_variable): Likewise. > * internal-fn.cc (expand_HWASAN_ALLOCA_POISON): New definition. > (expand_HWASAN_ALLOCA_UNPOISON): Expand differently if MEMTAG > sanitizer. > (expand_HWASAN_MARK): Likewise. > * internal-fn.def (HWASAN_ALLOCA_POISON): Define new. > * params.opt: Document new param. FIXME. > * sanopt.cc (pass_sanopt::execute): Include MEMTAG along with > HWASAN. > > --- > [Changes from RFC V1] > - Bugfixes > [End of changes from RFC V1] > --- > gcc/asan.cc | 245 +++++++++++++++++++++++++++++++++----------- > gcc/asan.h | 9 +- > gcc/cfgexpand.cc | 37 ++++--- > gcc/gimplify.cc | 5 +- > gcc/internal-fn.cc | 73 +++++++++++-- > gcc/internal-fn.def | 1 + > gcc/params.opt | 4 + > gcc/sanopt.cc | 2 +- > 8 files changed, 286 insertions(+), 90 deletions(-) > > diff --git a/gcc/asan.cc b/gcc/asan.cc > index 0123ed415a0a..d71a540edc52 100644 > --- a/gcc/asan.cc > +++ b/gcc/asan.cc > @@ -298,6 +298,7 @@ static GTY(()) rtx_insn *hwasan_frame_base_init_seq = > NULL; > tagged_base). */ > struct hwasan_stack_var > { > + tree decl; > rtx untagged_base; > rtx tagged_base; > poly_int64 nearest_offset; > @@ -762,14 +763,15 @@ static void > handle_builtin_stack_restore (gcall *call, gimple_stmt_iterator *iter) > { > if (!iter > - || !(asan_sanitize_allocas_p () || hwasan_sanitize_allocas_p ())) > + || !(asan_sanitize_allocas_p () || hwasan_sanitize_allocas_p () > + || memtag_sanitize_allocas_p ())) > return; > > tree restored_stack = gimple_call_arg (call, 0); > > gimple *g; > > - if (hwasan_sanitize_allocas_p ()) > + if (hwasan_sanitize_allocas_p () || memtag_sanitize_allocas_p ()) > { > enum internal_fn fn = IFN_HWASAN_ALLOCA_UNPOISON; > /* There is only one piece of information > `expand_HWASAN_ALLOCA_UNPOISON` > @@ -818,7 +820,8 @@ static void > handle_builtin_alloca (gcall *call, gimple_stmt_iterator *iter) > { > if (!iter > - || !(asan_sanitize_allocas_p () || hwasan_sanitize_allocas_p ())) > + || !(asan_sanitize_allocas_p () || hwasan_sanitize_allocas_p () > + || memtag_sanitize_allocas_p ())) > return; > > gassign *g; > @@ -842,23 +845,31 @@ handle_builtin_alloca (gcall *call, > gimple_stmt_iterator *iter) > e = find_fallthru_edge (gsi_bb (*iter)->succs); > } > > - if (hwasan_sanitize_allocas_p ()) > + if (hwasan_sanitize_allocas_p () || memtag_sanitize_allocas_p ()) > { > gimple_seq stmts = NULL; > location_t loc = gimple_location (gsi_stmt (*iter)); > - /* > - HWASAN needs a different expansion. > + /* HWASAN and MEMTAG need a different expansion. > > addr = __builtin_alloca (size, align); > > - should be replaced by > + in case of HWASAN, should be replaced by > > new_size = size rounded up to HWASAN_TAG_GRANULE_SIZE byte alignment; > untagged_addr = __builtin_alloca (new_size, align); > tag = __hwasan_choose_alloca_tag (); > addr = ifn_HWASAN_SET_TAG (untagged_addr, tag); > __hwasan_tag_memory (untagged_addr, tag, new_size); > - */ > + > + in case of MEMTAG, should be replaced by > + > + new_size = size rounded up to HWASAN_TAG_GRANULE_SIZE byte alignment; > + untagged_addr = __builtin_alloca (new_size, align); > + addr = ifn_HWASAN_ALLOCA_POISON (untagged_addr, new_size); > + > + where a new tag is chosen and set on untagged_addr when > + HWASAN_ALLOCA_POISON is expanded. */ > + > /* Ensure alignment at least HWASAN_TAG_GRANULE_SIZE bytes so we start > on > a tag granule. */ > align = align > HWASAN_TAG_GRANULE_SIZE ? align : > HWASAN_TAG_GRANULE_SIZE; > @@ -874,23 +885,30 @@ handle_builtin_alloca (gcall *call, > gimple_stmt_iterator *iter) > as_combined_fn (BUILT_IN_ALLOCA_WITH_ALIGN), ptr_type, > new_size, build_int_cst (size_type_node, align)); > > - /* Choose the tag. > - Here we use an internal function so we can choose the tag at expand > - time. We need the decision to be made after stack variables have been > - assigned their tag (i.e. once the hwasan_frame_tag_offset variable has > - been set to one after the last stack variables tag). */ > - tree tag = gimple_build (&stmts, loc, CFN_HWASAN_CHOOSE_TAG, > - unsigned_char_type_node); > - > - /* Add tag to pointer. */ > - tree addr > - = gimple_build (&stmts, loc, CFN_HWASAN_SET_TAG, ptr_type, > - untagged_addr, tag); > + tree addr; > > - /* Tag shadow memory. > - NOTE: require using `untagged_addr` here for libhwasan API. */ > - gimple_build (&stmts, loc, as_combined_fn (BUILT_IN_HWASAN_TAG_MEM), > - void_type_node, untagged_addr, tag, new_size); > + if (memtag_sanitize_p ()) > + addr = gimple_build (&stmts, loc, CFN_HWASAN_ALLOCA_POISON, ptr_type, > + untagged_addr, new_size); > + else > + { > + /* Choose the tag. > + Here we use an internal function so we can choose the tag at expand > + time. We need the decision to be made after stack variables have > been > + assigned their tag (i.e. once the hwasan_frame_tag_offset variable > has > + been set to one after the last stack variables tag). */ > + tree tag = gimple_build (&stmts, loc, CFN_HWASAN_CHOOSE_TAG, > + unsigned_char_type_node); > + > + /* Add tag to pointer. */ > + addr = gimple_build (&stmts, loc, CFN_HWASAN_SET_TAG, ptr_type, > + untagged_addr, tag); > + > + /* Tag shadow memory. > + NOTE: require using `untagged_addr` here for libhwasan API. */ > + gimple_build (&stmts, loc, as_combined_fn (BUILT_IN_HWASAN_TAG_MEM), > + void_type_node, untagged_addr, tag, new_size); > + } > > /* Insert the built up code sequence into the original instruction > stream > the iterator points to. */ > @@ -1104,7 +1122,7 @@ get_mem_refs_of_builtin_call (gcall *call, > for now we choose 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 (hwasan_sanitize_p ()) > + if (hwassist_sanitize_p ()) > return false; > source0 = gimple_call_arg (call, 0); > len = gimple_call_lhs (call); > @@ -1887,9 +1905,39 @@ hwasan_memintrin (void) > return (hwasan_sanitize_p () && param_hwasan_instrument_mem_intrinsics); > } > > -/* MEMoryTAGging sanitizer (memtag) uses a hardware based capability known as > - memory tagging to detect memory safety vulnerabilities. Similar to > hwasan, > - it is also a probabilistic method. */ > +/* MEMoryTAGging sanitizer (MEMTAG) uses a hardware based capability known as > + memory tagging to detect memory safety vulnerabilities. Similar to > HWASAN, > + it is also a probabilistic method. > + > + MEMTAG relies on the optional extension in armv8.5a, known as MTE (Memory > + Tagging Extension). The extension is available in AARCH64 only and > + introduces two types of tags: > + - Logical Address Tag - bits 56-59 (TARGET_MEMTAG_TAG_SIZE) of the > virtual > + address. > + - Allocation Tag - 4 bits for each tag granule > (TARGET_MEMTAG_GRANULE_SIZE > + set to 16 bytes), stored separately. > + Load / store instructions raise an exception if tags differ, thereby > + providing a faster way (than HWASAN) to detect memory safety issues. > + Further, new instructions are available in MTE to manipulate (generate, > + update address with) tags. Load / store instructions with SP base > register > + and immediate offset do not check tags. > + > + PS: Currently, MEMTAG sanitizer is capable of stack (variable / memory) > + tagging only. > + > + In general, detecting stack-related memory bugs requires the compiler to: > + - ensure that each tag granule is only used by one variable at a time. > + This includes alloca. > + - Tag/Color: put tags into each stack variable pointer. > + - Untag: the function epilogue will retag the memory. > + > + MEMTAG sanitizer is based off the HWASAN sanitizer implementation > + internally. Similar to HWASAN: > + - Assigning an independently random tag to each variable is carried out > by > + keeping a tagged base pointer. A tagged base pointer allows > addressing > + variables with (addr offset, tag offset). > + - TBD > + */ > > /* Returns whether we are tagging pointers and checking those tags on memory > access. */ > @@ -1899,6 +1947,42 @@ memtag_sanitize_p () > return false; > } > > +/* Are we tagging the stack? */ > +bool > +memtag_sanitize_stack_p () > +{ > + return (memtag_sanitize_p () && param_memtag_instrument_stack); > +} > + > +/* Are we tagging alloca objects? */ > +bool > +memtag_sanitize_allocas_p (void) > +{ > + return (memtag_sanitize_stack_p () && param_memtag_instrument_allocas); > +} > + > +/* Are we taggin mem intrinsics? */ > +bool > +memtag_memintrin (void) > +{ > + return (memtag_sanitize_p () && param_memtag_instrument_mem_intrinsics); > +} > + > +/* Returns whether we are tagging pointers and checking those tags on memory > + access. */ > +bool > +hwassist_sanitize_p () > +{ > + return (hwasan_sanitize_p () || memtag_sanitize_p ()); > +} > + > +/* Are we tagging stack objects for hwasan or memtag? */ > +bool > +hwassist_sanitize_stack_p () > +{ > + return (hwasan_sanitize_stack_p () || memtag_sanitize_stack_p ()); > +} > + > /* 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 > @@ -2432,7 +2516,7 @@ static tree > report_error_func (bool is_store, bool recover_p, HOST_WIDE_INT > size_in_bytes, > int *nargs) > { > - gcc_assert (!hwasan_sanitize_p ()); > + gcc_assert (!hwassist_sanitize_p ()); > > static enum built_in_function report[2][2][6] > = { { { BUILT_IN_ASAN_REPORT_LOAD1, BUILT_IN_ASAN_REPORT_LOAD2, > @@ -2771,7 +2855,7 @@ build_check_stmt (location_t loc, tree base, tree len, > if (is_scalar_access) > flags |= ASAN_CHECK_SCALAR_ACCESS; > > - enum internal_fn fn = hwasan_sanitize_p () > + enum internal_fn fn = hwassist_sanitize_p () > ? IFN_HWASAN_CHECK > : IFN_ASAN_CHECK; > > @@ -2871,7 +2955,7 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t, > access is inside a global variable, then there's no point adding > instrumentation to check the access. N.b. hwasan currently never > sanitizes globals. */ > - if ((hwasan_sanitize_p () || !param_asan_globals) > + if ((hwassist_sanitize_p () || !param_asan_globals) > && is_global_var (inner)) > return; > if (!TREE_STATIC (inner)) > @@ -2970,7 +3054,8 @@ instrument_mem_region_access (tree base, tree len, > static bool > instrument_builtin_call (gimple_stmt_iterator *iter) > { > - if (!(asan_memintrin () || hwasan_memintrin ())) > + if (!(asan_memintrin () || hwasan_memintrin () > + || memtag_memintrin ())) > return false; > > bool iter_advanced_p = false; > @@ -3124,7 +3209,7 @@ maybe_instrument_call (gimple_stmt_iterator *iter) > `longjmp`, thread exit, and exceptions in a different way. These > problems must be handled externally to the compiler, e.g. in the > language runtime. */ > - if (! hwasan_sanitize_p ()) > + if (! hwassist_sanitize_p ()) > { > tree decl = builtin_decl_implicit (BUILT_IN_ASAN_HANDLE_NO_RETURN); > gimple *g = gimple_build_call (decl, 0); > @@ -3877,7 +3962,7 @@ asan_expand_mark_ifn (gimple_stmt_iterator *iter) > > gcc_checking_assert (TREE_CODE (decl) == VAR_DECL); > > - if (hwasan_sanitize_p ()) > + if (hwassist_sanitize_p ()) > { > gcc_assert (param_hwasan_instrument_stack); > gimple_seq stmts = NULL; > @@ -3975,7 +4060,7 @@ asan_expand_mark_ifn (gimple_stmt_iterator *iter) > bool > asan_expand_check_ifn (gimple_stmt_iterator *iter, bool use_calls) > { > - gcc_assert (!hwasan_sanitize_p ()); > + gcc_assert (!hwassist_sanitize_p ()); > gimple *g = gsi_stmt (*iter); > location_t loc = gimple_location (g); > bool recover_p; > @@ -4250,7 +4335,7 @@ asan_expand_poison_ifn (gimple_stmt_iterator *iter, > int nargs; > bool store_p = gimple_call_internal_p (use, IFN_ASAN_POISON_USE); > gcall *call; > - if (hwasan_sanitize_p ()) > + if (hwassist_sanitize_p ()) > { > tree fun = builtin_decl_implicit (BUILT_IN_HWASAN_TAG_MISMATCH4); > /* NOTE: hwasan has no __hwasan_report_* functions like asan does. > @@ -4351,7 +4436,7 @@ asan_expand_poison_ifn (gimple_stmt_iterator *iter, > static unsigned int > asan_instrument (void) > { > - if (hwasan_sanitize_p ()) > + if (hwassist_sanitize_p ()) > { > initialize_sanitizer_builtins (); > transform_statements (); > @@ -4480,10 +4565,15 @@ hwasan_frame_base () > if (! hwasan_frame_base_ptr) > { > start_sequence (); > - hwasan_frame_base_ptr > - = force_reg (Pmode, > - targetm.memtag.insert_random_tag (virtual_stack_vars_rtx, > - NULL_RTX)); > + if (memtag_sanitize_p ()) > + hwasan_frame_base_ptr > + = targetm.memtag.insert_random_tag (virtual_stack_vars_rtx, > + NULL_RTX); > + else > + hwasan_frame_base_ptr > + = force_reg (Pmode, > + targetm.memtag.insert_random_tag (virtual_stack_vars_rtx, > + NULL_RTX)); > hwasan_frame_base_init_seq = get_insns (); > end_sequence (); > } > @@ -4538,10 +4628,11 @@ hwasan_maybe_emit_frame_base_init () > We record the `untagged_base` since the functions in the hwasan library we > use to tag memory take pointers without a tag. */ > void > -hwasan_record_stack_var (rtx untagged_base, rtx tagged_base, > +hwasan_record_stack_var (tree decl, rtx untagged_base, rtx tagged_base, > poly_int64 nearest_offset, poly_int64 farthest_offset) > { > hwasan_stack_var cur_var; > + cur_var.decl = decl; > cur_var.untagged_base = untagged_base; > cur_var.tagged_base = tagged_base; > cur_var.nearest_offset = nearest_offset; > @@ -4693,19 +4784,39 @@ hwasan_emit_prologue () > gcc_assert (multiple_p (bot, HWASAN_TAG_GRANULE_SIZE)); > gcc_assert (multiple_p (size, HWASAN_TAG_GRANULE_SIZE)); > > - rtx fn = init_one_libfunc ("__hwasan_tag_memory"); > - rtx base_tag = targetm.memtag.extract_tag (cur.tagged_base, NULL_RTX); > - rtx tag = plus_constant (QImode, base_tag, cur.tag_offset); > - tag = hwasan_truncate_to_tag_size (tag, NULL_RTX); > - > - rtx bottom = convert_memory_address (ptr_mode, > - plus_constant (Pmode, > - cur.untagged_base, > - bot)); > - emit_library_call (fn, LCT_NORMAL, VOIDmode, > - bottom, ptr_mode, > - tag, QImode, > - gen_int_mode (size, ptr_mode), ptr_mode); > + if (memtag_sanitize_p ()) > + { > + rtx x = NULL_RTX; > + if (HAS_RTL_P (cur.decl)) > + x = XEXP (DECL_RTL (cur.decl), 0); > + else if (SSA_NAME_VAR (cur.decl) > + && (VAR_P (SSA_NAME_VAR (cur.decl)) > + || SSA_NAME_IS_DEFAULT_DEF (cur.decl))) > + { > + tree var = SSA_NAME_VAR (cur.decl); > + x = XEXP (DECL_RTL (var), 0); > + } > + if (x != NULL_RTX) > + targetm.memtag.tag_memory (x, gen_int_mode (size, ptr_mode), x); > + } > + else > + { > + rtx fn = init_one_libfunc ("__hwasan_tag_memory"); > + > + rtx bottom = convert_memory_address (ptr_mode, > + plus_constant (Pmode, > + cur.untagged_base, > + bot)); > + > + rtx base_tag = targetm.memtag.extract_tag (cur.tagged_base, NULL_RTX); > + rtx tag = plus_constant (QImode, base_tag, cur.tag_offset); > + tag = hwasan_truncate_to_tag_size (tag, NULL_RTX); > + > + emit_library_call (fn, LCT_NORMAL, VOIDmode, > + bottom, ptr_mode, > + tag, QImode, > + gen_int_mode (size, ptr_mode), ptr_mode); > + } > } > /* Clear the stack vars, we've emitted the prologue for them all now. */ > hwasan_tagged_stack_vars.truncate (0); > @@ -4746,11 +4857,25 @@ hwasan_emit_untag_frame (rtx dynamic, rtx vars) > NULL_RTX, /* unsignedp = */0, > OPTAB_DIRECT); > > - rtx fn = init_one_libfunc ("__hwasan_tag_memory"); > - emit_library_call (fn, LCT_NORMAL, VOIDmode, > - bot_rtx, ptr_mode, > - HWASAN_STACK_BACKGROUND, QImode, > - size_rtx, ptr_mode); > + if (memtag_sanitize_p ()) > + { > + /* FIXME - not sure if this is OK to do. */ > + if (!cfun->calls_alloca) > + { > + HOST_WIDE_INT size = frame_offset.to_constant (); > + size_rtx = gen_int_mode (size, ptr_mode); > + } > + > + targetm.memtag.tag_memory (bot_rtx, size_rtx, stack_pointer_rtx); > + } > + else > + { > + rtx fn = init_one_libfunc ("__hwasan_tag_memory"); > + emit_library_call (fn, LCT_NORMAL, VOIDmode, > + bot_rtx, ptr_mode, > + HWASAN_STACK_BACKGROUND, QImode, > + size_rtx, ptr_mode); > + } > > do_pending_stack_adjust (); > rtx_insn *insns = get_insns (); > diff --git a/gcc/asan.h b/gcc/asan.h > index c3d5b311d300..832e743401db 100644 > --- a/gcc/asan.h > +++ b/gcc/asan.h > @@ -39,7 +39,7 @@ extern void > asan_maybe_insert_dynamic_shadow_at_function_entry (function *); > > extern void hwasan_record_frame_init (); > -extern void hwasan_record_stack_var (rtx, rtx, poly_int64, poly_int64); > +extern void hwasan_record_stack_var (tree, rtx, rtx, poly_int64, poly_int64); > extern void hwasan_emit_prologue (); > extern rtx_insn *hwasan_emit_untag_frame (rtx, rtx); > extern rtx hwasan_get_frame_extent (); > @@ -58,6 +58,11 @@ extern bool hwasan_expand_mark_ifn (gimple_stmt_iterator > *); > extern bool gate_hwasan (void); > > extern bool memtag_sanitize_p (void); > +extern bool memtag_sanitize_stack_p (void); > +extern bool memtag_sanitize_allocas_p (void); > + > +bool hwassist_sanitize_p (void); > +bool hwassist_sanitize_stack_p (void); > > extern gimple_stmt_iterator create_cond_insert_point > (gimple_stmt_iterator *, bool, bool, bool, basic_block *, basic_block > *); > @@ -227,7 +232,7 @@ inline bool > asan_sanitize_use_after_scope (void) > { > return (flag_sanitize_address_use_after_scope > - && (asan_sanitize_stack_p () || hwasan_sanitize_stack_p ())); > + && (asan_sanitize_stack_p () || hwassist_sanitize_stack_p ())); > } > > /* Return true if DECL should be guarded on the stack. */ > diff --git a/gcc/cfgexpand.cc b/gcc/cfgexpand.cc > index 2b27076658fd..8b27c2c71b86 100644 > --- a/gcc/cfgexpand.cc > +++ b/gcc/cfgexpand.cc > @@ -381,7 +381,7 @@ align_local_variable (tree decl, bool really_expand) > else > align = LOCAL_DECL_ALIGNMENT (decl); > > - if (hwasan_sanitize_stack_p ()) > + if (hwassist_sanitize_stack_p ()) > align = MAX (align, (unsigned) HWASAN_TAG_GRANULE_SIZE * BITS_PER_UNIT); > > if (TREE_CODE (decl) != SSA_NAME && really_expand) > @@ -1328,7 +1328,7 @@ 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))); > > - if (hwasan_sanitize_stack_p ()) > + if (hwassist_sanitize_stack_p ()) > x = targetm.memtag.add_tag (base, offset, > hwasan_current_frame_tag ()); > else > @@ -1463,14 +1463,14 @@ expand_stack_vars (bool (*pred) (unsigned), class > stack_vars_data *data) > if (pred && !pred (i)) > continue; > > - base = (hwasan_sanitize_stack_p () > + base = (hwassist_sanitize_stack_p () > ? hwasan_frame_base () > : virtual_stack_vars_rtx); > alignb = stack_vars[i].alignb; > if (alignb * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT) > { > poly_int64 hwasan_orig_offset; > - if (hwasan_sanitize_stack_p ()) > + if (hwassist_sanitize_stack_p ()) > { > /* There must be no tag granule "shared" between different > objects. This means that no HWASAN_TAG_GRANULE_SIZE byte > @@ -1569,7 +1569,7 @@ expand_stack_vars (bool (*pred) (unsigned), class > stack_vars_data *data) > offset = alloc_stack_frame_space (stack_vars[i].size, alignb); > base_align = crtl->max_used_stack_slot_alignment; > > - if (hwasan_sanitize_stack_p ()) > + if (hwassist_sanitize_stack_p ()) > { > /* Align again since the point of this alignment is to handle > the "end" of the object (i.e. smallest address after the > @@ -1583,7 +1583,8 @@ expand_stack_vars (bool (*pred) (unsigned), class > stack_vars_data *data) > allocated for this particular variable while `offset` > describes the address that this variable starts at. */ > align_frame_offset (HWASAN_TAG_GRANULE_SIZE); > - hwasan_record_stack_var (virtual_stack_vars_rtx, base, > + hwasan_record_stack_var (stack_vars[i].decl, > + virtual_stack_vars_rtx, base, > hwasan_orig_offset, frame_offset); > } > } > @@ -1614,7 +1615,7 @@ expand_stack_vars (bool (*pred) (unsigned), class > stack_vars_data *data) > large_alloc = aligned_upper_bound (large_alloc, alignb); > offset = large_alloc; > large_alloc += stack_vars[i].size; > - if (hwasan_sanitize_stack_p ()) > + if (hwassist_sanitize_stack_p ()) > { > /* An object with a large alignment requirement means that the > alignment requirement is greater than the required alignment > @@ -1630,7 +1631,8 @@ expand_stack_vars (bool (*pred) (unsigned), class > stack_vars_data *data) > then use positive offsets from that. Hence the farthest > offset is `align_again` and the nearest offset from the base > is `offset`. */ > - hwasan_record_stack_var (large_untagged_base, large_base, > + hwasan_record_stack_var (stack_vars[i].decl, > + large_untagged_base, large_base, > offset, align_again); > } > > @@ -1645,7 +1647,7 @@ expand_stack_vars (bool (*pred) (unsigned), class > stack_vars_data *data) > expand_one_stack_var_at (stack_vars[j].decl, > base, base_align, offset); > } > - if (hwasan_sanitize_stack_p ()) > + if (hwassist_sanitize_stack_p ()) > hwasan_increment_frame_tag (); > } > > @@ -1738,7 +1740,7 @@ expand_one_stack_var_1 (tree var) > gcc_assert (byte_align * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT); > > rtx base; > - if (hwasan_sanitize_stack_p ()) > + if (hwassist_sanitize_stack_p ()) > { > /* Allocate zero bytes to align the stack. */ > poly_int64 hwasan_orig_offset > @@ -1754,7 +1756,7 @@ expand_one_stack_var_1 (tree var) > the "furthest" offset from the base delimiting the current stack > object. `frame_offset` will always delimit the extent that the frame. > */ > - hwasan_record_stack_var (virtual_stack_vars_rtx, base, > + hwasan_record_stack_var (var, virtual_stack_vars_rtx, base, > hwasan_orig_offset, frame_offset); > } > else > @@ -1766,7 +1768,7 @@ expand_one_stack_var_1 (tree var) > expand_one_stack_var_at (var, base, > crtl->max_used_stack_slot_alignment, offset); > > - if (hwasan_sanitize_stack_p ()) > + if (hwassist_sanitize_stack_p ()) > hwasan_increment_frame_tag (); > } > > @@ -2370,7 +2372,7 @@ init_vars_expansion (void) > /* Initialize local stack smashing state. */ > has_protected_decls = false; > has_short_buffer = false; > - if (hwasan_sanitize_stack_p ()) > + if (hwassist_sanitize_stack_p ()) > hwasan_record_frame_init (); > } > > @@ -2696,13 +2698,14 @@ expand_used_vars (bitmap forced_stack_vars) > expand_stack_vars (NULL, &data); > } > > - if (hwasan_sanitize_stack_p ()) > + if (hwassist_sanitize_stack_p ()) > hwasan_emit_prologue (); > if (asan_sanitize_allocas_p () && cfun->calls_alloca) > var_end_seq = asan_emit_allocas_unpoison (virtual_stack_dynamic_rtx, > virtual_stack_vars_rtx, > var_end_seq); > - else if (hwasan_sanitize_allocas_p () && cfun->calls_alloca) > + else if ((hwasan_sanitize_allocas_p () || memtag_sanitize_p ()) > + && cfun->calls_alloca) > /* When using out-of-line instrumentation we only want to emit one > function > call for clearing the tags in a region of shadow stack. When there > are > alloca calls in this frame we want to emit a call using the > @@ -2710,7 +2713,7 @@ expand_used_vars (bitmap forced_stack_vars) > rtx we created in expand_stack_vars. */ > var_end_seq = hwasan_emit_untag_frame (virtual_stack_dynamic_rtx, > virtual_stack_vars_rtx); > - else if (hwasan_sanitize_stack_p ()) > + else if (hwassist_sanitize_stack_p ()) > /* If no variables were stored on the stack, `hwasan_get_frame_extent` > will return NULL_RTX and hence `hwasan_emit_untag_frame` will return > NULL (i.e. an empty sequence). */ > @@ -7215,7 +7218,7 @@ pass_expand::execute (function *fun) > emit_insn_after (var_ret_seq, after); > } > > - if (hwasan_sanitize_stack_p ()) > + if (hwassist_sanitize_stack_p ()) > hwasan_maybe_emit_frame_base_init (); > > /* Zap the tree EH table. */ > diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc > index 4f385b1b779b..1e6e3db5a570 100644 > --- a/gcc/gimplify.cc > +++ b/gcc/gimplify.cc > @@ -1310,9 +1310,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. */ > - gcc_assert (!hwasan_sanitize_p () || hwasan_sanitize_stack_p ()); > + gcc_assert (!hwassist_sanitize_p () || hwassist_sanitize_stack_p ()); > unsigned shadow_granularity > - = hwasan_sanitize_p () ? HWASAN_TAG_GRANULE_SIZE : > ASAN_SHADOW_GRANULARITY; > + = (hwassist_sanitize_p () > + ? HWASAN_TAG_GRANULE_SIZE : ASAN_SHADOW_GRANULARITY); > if (DECL_ALIGN_UNIT (decl) <= shadow_granularity) > SET_DECL_ALIGN (decl, BITS_PER_UNIT * shadow_granularity); > > diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc > index 21eac80819a5..c5cbd53372cc 100644 > --- a/gcc/internal-fn.cc > +++ b/gcc/internal-fn.cc > @@ -748,6 +748,43 @@ expand_HWASAN_CHECK (internal_fn, gcall *) > gcc_unreachable (); > } > > +/* For hwasan stack tagging: > + Tag memory which is dynamically allocated. */ > +static void > +expand_HWASAN_ALLOCA_POISON (internal_fn, gcall *gc) > +{ > + gcc_assert (ptr_mode == Pmode); > + tree g_target = gimple_call_lhs (gc); > + tree g_ptr = gimple_call_arg (gc, 0); > + tree g_size = gimple_call_arg (gc, 1); > + > + rtx ptr = expand_normal (g_ptr); > + /* Get new tag for the alloca'd memory. > + Doing a regular add_tag () like so: > + rtx tag = targetm.memtag.add_tag (hwasan_frame_base (), 0, > + hwasan_current_frame_tag ()); > + gets a new tag, which can be used for tagging memory. But for alloca, > we > + need both tagged memory and a tagged pointer to pass to consumers. > Invoke > + insert_random_tag () instead to add a random tag to ptr to get a tagged > + pointer that will work for both purposes. */ > + rtx tagged_ptr = targetm.memtag.insert_random_tag (ptr, NULL_RTX); > + rtx size = expand_normal (g_size); > + rtx target = expand_normal (g_target); > + > + if (memtag_sanitize_p ()) > + { > + /* Need to put the tagged ptr into the `target` RTX for consumers > + of alloca'd memory. */ > + if (tagged_ptr != target) > + emit_move_insn (target, tagged_ptr); > + /* Tag the memory. */ > + targetm.memtag.tag_memory (ptr, size, tagged_ptr); > + hwasan_increment_frame_tag (); > + } > + else > + gcc_unreachable (); > +} > + > /* For hwasan stack tagging: > Clear tags on the dynamically allocated space. > For use after an object dynamically allocated on the stack goes out of > @@ -759,14 +796,27 @@ expand_HWASAN_ALLOCA_UNPOISON (internal_fn, gcall *gc) > tree restored_position = gimple_call_arg (gc, 0); > rtx restored_rtx = expand_expr (restored_position, NULL_RTX, VOIDmode, > EXPAND_NORMAL); > - rtx func = init_one_libfunc ("__hwasan_tag_memory"); > rtx off = expand_simple_binop (Pmode, MINUS, restored_rtx, > stack_pointer_rtx, NULL_RTX, 0, > OPTAB_WIDEN); > - emit_library_call_value (func, NULL_RTX, LCT_NORMAL, VOIDmode, > - virtual_stack_dynamic_rtx, Pmode, > - HWASAN_STACK_BACKGROUND, QImode, > - off, Pmode); > + > + if (memtag_sanitize_p ()) > + { > + emit_insn (targetm.memtag.tag_memory (virtual_stack_dynamic_rtx, > + off, > + virtual_stack_dynamic_rtx)); > + } > + else > + { > + rtx func = init_one_libfunc ("__hwasan_tag_memory"); > + rtx off = expand_simple_binop (Pmode, MINUS, restored_rtx, > + stack_pointer_rtx, NULL_RTX, 0, > + OPTAB_WIDEN); > + emit_library_call_value (func, NULL_RTX, LCT_NORMAL, VOIDmode, > + virtual_stack_dynamic_rtx, Pmode, > + HWASAN_STACK_BACKGROUND, QImode, > + off, Pmode); > + } > } > > /* For hwasan stack tagging: > @@ -820,9 +870,16 @@ expand_HWASAN_MARK (internal_fn, gcall *gc) > tree len = gimple_call_arg (gc, 2); > rtx r_len = expand_normal (len); > > - rtx func = init_one_libfunc ("__hwasan_tag_memory"); > - emit_library_call (func, LCT_NORMAL, VOIDmode, address, Pmode, > - tag, QImode, r_len, Pmode); > + if (memtag_sanitize_p ()) > + { > + emit_insn (targetm.memtag.tag_memory (address, r_len, tag)); > + } > + else > + { > + rtx func = init_one_libfunc ("__hwasan_tag_memory"); > + emit_library_call (func, LCT_NORMAL, VOIDmode, address, Pmode, > + tag, QImode, r_len, Pmode); > + } > } > > /* For hwasan stack tagging: > diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def > index 8edfa3540f8c..d096856d2e98 100644 > --- a/gcc/internal-fn.def > +++ b/gcc/internal-fn.def > @@ -489,6 +489,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_ALLOCA_POISON, ECF_LEAF | ECF_NOTHROW, NULL) > DEF_INTERNAL_FN (HWASAN_ALLOCA_UNPOISON, ECF_LEAF | ECF_NOTHROW, ". R ") > DEF_INTERNAL_FN (HWASAN_CHOOSE_TAG, ECF_LEAF | ECF_NOTHROW, ". ") > DEF_INTERNAL_FN (HWASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, > diff --git a/gcc/params.opt b/gcc/params.opt > index 77ece0c50512..3d624e38bf0d 100644 > --- a/gcc/params.opt > +++ b/gcc/params.opt > @@ -102,6 +102,10 @@ When sanitizing using MTE instructions, add checks for > all stack automatics. > 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=memtag-instrument-mem-intrinsics= > +Common Joined UInteger Var(param_memtag_instrument_mem_intrinsics) Init(1) > IntegerRange(0, 1) Param Optimization > +When sanitizing using MTE instructions, include builtin functions. > + > -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. > diff --git a/gcc/sanopt.cc b/gcc/sanopt.cc > index ff5a5ff2231d..33f62540747d 100644 > --- a/gcc/sanopt.cc > +++ b/gcc/sanopt.cc > @@ -1330,7 +1330,7 @@ pass_sanopt::execute (function *fun) > sanitize_asan_mark_poison (); > } > > - if (asan_sanitize_stack_p () || hwasan_sanitize_stack_p ()) > + if (asan_sanitize_stack_p () || hwassist_sanitize_stack_p ()) > sanitize_rewrite_addressable_params (fun); > > bool use_calls = param_asan_instrumentation_with_call_threshold < INT_MAX