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

Reply via email to