Hi,

For MTE stack tagging support in the GNU toolchain, one of the key pieces is
the memtag sanitizer in GCC.  The current series is V2 of the previously sent
RFC series https://gcc.gnu.org/pipermail/gcc-patches/2024-November/668017.html.

The other two pieces, which (work in progress) are needed to run binaries
generated with the current patch series adding -fsanitize=memtag support in
GCC, on an MTE-enabled hardware are:
  - Bintuils patch series for gas/ld support:
    V1: 
https://inbox.sourceware.org/binutils/20241205225837.2912674-1-indu.bha...@oracle.com/
    V2: 
https://inbox.sourceware.org/binutils/20250411041635.1984719-1-indu.bha...@oracle.com/
        V2 Available in upstream branch : users/ibhagat/try-mte-rfc-v2
    
  - glibc patch series:
    
https://inbox.sourceware.org/libc-alpha/20250314132142.49243-1-cupertino.mira...@oracle.com/

Another piece necessary to complete the offering in the GNU Toolchain is "MTE
aware execption handling and unwinding routines".  Further notes below in the
"Additional necessary pieces" section.

As for this series, I would like to get feedback on whether this is generally
the right direction for adding the MEMTAG (stack) sanitizer in GCC; Also, I have
added some TBD/FIXME notes to each commit log where I need inputs for improving
this series.  The machine description of the new instructions and their
generation in the AArch64 backend also likely need improvements.

Thanks!

======================================
MTE on AArch64 and Memory Tagging
---------------------------------
Memory Tagging Extension (MTE) is an AArch64 extension.  This extension allows
coloring of 16-byte memory granules with 4-bit tag values.  The extension
provides additional instructions in ISA and a new memory type, Normal Tagged
Memory, added to the Arm Architecture.  This hardware-assisted mechanism can be
used to detect memory bugs like buffer overrun or use-after-free.  The
detection is probabilistic.

Under the hoods, the MTE extension introduces two types of tags:
  - Address Tags, and,
  - Allocation Tags (a.k.a., Memory Tags)

Address Tag: which acts as the key.  This adds four bits to the top of a
virtual address.  It is built on AArch64 'top-byte-ignore'(TBI) feature.

Allocation Tag: which acts as the lock.  Allocation tags also consist of four
bits, linked with every aligned 16-byte region in the physical memory space.
Arm refers to these 16-byte regions as tag granules.  The way Allocation tags
are stored is a hardware implementation detail.

A subset of the MTE instructions which are relevant in the current
context are:

[Xn, Xd are registers containing addresses].

- irg Xd, Xn
  Copy Xn into Xd, insert a random 4-bit Address Tag into Xd.
- addg Xd, Xn, #<immA>, #<immB>
  Xd = Xn + immA, with Address Tag modified by #immB. Similarly, there
  exists a subg.
- stg Xd, [Xn]
  (Store Allocation Tag) updates Allocation Tag for [Xn, Xn + 16) to the
  Address Tag of Xd.
- stzg Xd, [Xn]
  writes zero to [Xn, Xn + 16) and updates the Allocation Tag for
  [Xn, Xn + 16] to the Address Tag of Xd.
- stgp Xt, Xt2, [Xn]
  Similar to STP, writes a pair of registers to memory at [Xn, Xn + 16) and
  updates Allocation Tag to match the Address Tag of Xn.

Additionally, note that load and store instructions with SP base
register do not check tags.

MEMTAG sanitizer for stack
--------------------------
Use MTE instructions to instrument stack accesses to detect memory safety
issues.

Detecting stack-related memory bugs requires the compiler to:
  - ensure that each object on the stack is allocated in its own 16-byte
    granule. 
  - Tag/Color: put tags into each stack variable pointer.
  - Untag: the function epilogue will untag the (stack) memory.
Above should work with dynamic stack allocation as well.

GCC has HWASAN machinery for coloring stack variables.  Extend the machinery to
emit MTE instructions when MEMTAG sanitizer is in effect.

Deploying and running user space programs built with -fsanitizer=memtag will
need following additional pieces in place.  If there is any existing work /
ideas on any of the following, please send comments to help define the work.

Additional necessary pieces
----------------------------

* MTE aware exception handling and unwinding routines
The additional stack coloring must work with C++ exceptions and C 
setjmp/longjmp.

When unwinding the stack for handling C++ exceptions, the unwinder additionally
also needs to untag the stack frame.  As per the AADWARF64 document ([4]): "The
character 'G' indicates that associated frames may modify MTE tags on the stack
space they use."

Some discussion on issues with MTE aware Exception handling was previously done
here ([5]).  If you have insight/comments on this, please let me know.

When restoring the context in longjmp, we need to additionally untag the stack.

References:
[1] "Memory Tagging Extension (MTE) in AArch64 Linux" 
https://docs.kernel.org/arch/arm64/memory-tagging-extension.html
[2] "Stack instrumentation with ARM Memory Tagging Extension (MTE)" 
https://github.com/google/sanitizers/wiki/Stack-instrumentation-with-ARM-Memory-Tagging-Extension-(MTE)
[3] "glibc.mem.tagging" 
https://www.gnu.org/software/libc/manual/html_node/Memory-Related-Tunables.html
[4] "DWARF for the Arm® 64-bit Architecture (AArch64)" 
https://github.com/ARM-software/abi-aa/blob/main/aadwarf64/aadwarf64.rst
[5] "MTE – discussion on Exception unwinding ABI" 
https://discourse.llvm.org/t/mte-discussion-on-exception-unwinding-abi/55226RFC

Thanks,

Indu Bhagat (14):
  opts: use unsigned HOST_WIDE_INT for sanitizer flags
  aarch64: add new define_insn for subg
  aarch64: add new insn definition for st2g
  aarch64: add new definition for post-index st2g
  aarch64: add new definition for post-index stg
  opts: doc: aarch64: add new memtag sanitizer
  targhooks: add new target hook TARGET_MEMTAG_TAG_MEMORY
  aarch64: memtag: implement target hooks
  hwasan: add support for generating MTE instructions for memory tagging
  asan: memtag: enable pass_asan for memtag sanitizer
  memtag: testsuite: add new tests
  memtag: doc: add new option -fsanitize-memtag-mode=<sync,async,asymm>
  gcc: aarch64: memtag: update link spec to pass arguments to linker
  aarch64: testsuite: emit CFI directive when stack frames use MTE
    tagging

 gcc/asan.cc                                   | 261 ++++++++++----
 gcc/asan.h                                    |  17 +-
 gcc/builtins.def                              |   1 +
 gcc/c-family/c-attribs.cc                     |  17 +-
 gcc/c-family/c-common.h                       |   2 +-
 gcc/c/c-parser.cc                             |   4 +-
 gcc/cfgexpand.cc                              |  37 +-
 gcc/common.opt                                |   6 +-
 gcc/config/aarch64/aarch64-linux.h            |   4 +-
 gcc/config/aarch64/aarch64.cc                 | 321 +++++++++++++++++-
 gcc/config/aarch64/aarch64.md                 |  72 ++++
 gcc/cp/typeck.cc                              |   2 +-
 gcc/d/d-attribs.cc                            |   9 +-
 gcc/doc/invoke.texi                           |  31 +-
 gcc/doc/tm.texi                               |   5 +
 gcc/doc/tm.texi.in                            |   2 +
 gcc/dwarf2asm.cc                              |   2 +-
 gcc/flag-types.h                              |   2 +
 gcc/gcc.cc                                    |   2 +
 gcc/gimplify.cc                               |   5 +-
 gcc/internal-fn.cc                            |  73 +++-
 gcc/internal-fn.def                           |   1 +
 gcc/opts.cc                                   |  36 +-
 gcc/opts.h                                    |   9 +-
 gcc/params.opt                                |  12 +
 gcc/sanopt.cc                                 |   2 +-
 gcc/target.def                                |   6 +
 gcc/targhooks.cc                              |   7 +
 gcc/targhooks.h                               |   1 +
 .../gcc.target/aarch64/memtag/alloca-1.c      |  14 +
 .../gcc.target/aarch64/memtag/alloca-3.c      |  27 ++
 .../gcc.target/aarch64/memtag/arguments-1.c   |   3 +
 .../gcc.target/aarch64/memtag/arguments-2.c   |   3 +
 .../gcc.target/aarch64/memtag/arguments-4.c   |  16 +
 .../gcc.target/aarch64/memtag/arguments.c     |   3 +
 .../gcc.target/aarch64/memtag/basic-1.c       |  15 +
 .../gcc.target/aarch64/memtag/basic-3.c       |  18 +
 .../gcc.target/aarch64/memtag/basic-struct.c  |  23 ++
 .../aarch64/memtag/cfi-mte-memtag-frame-1.c   |  12 +
 .../gcc.target/aarch64/memtag/large-array.c   |  24 ++
 .../aarch64/memtag/local-no-escape.c          |  20 ++
 .../gcc.target/aarch64/memtag/memtag.exp      |  32 ++
 .../aarch64/memtag/no-sanitize-attribute.c    |  17 +
 .../aarch64/memtag/vararray-gimple.c          |  17 +
 .../aarch64/memtag/vararray-nested-gimple.c   |  21 ++
 .../gcc.target/aarch64/memtag/vararray.c      |  14 +
 gcc/testsuite/lib/target-supports.exp         |  12 +
 gcc/tree-cfg.cc                               |   2 +-
 48 files changed, 1113 insertions(+), 129 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/alloca-1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/alloca-3.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/arguments-1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/arguments-2.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/arguments-4.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/arguments.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/basic-1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/basic-3.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/basic-struct.c
 create mode 100644 
gcc/testsuite/gcc.target/aarch64/memtag/cfi-mte-memtag-frame-1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/large-array.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/local-no-escape.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/memtag.exp
 create mode 100644 
gcc/testsuite/gcc.target/aarch64/memtag/no-sanitize-attribute.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/vararray-gimple.c
 create mode 100644 
gcc/testsuite/gcc.target/aarch64/memtag/vararray-nested-gimple.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/memtag/vararray.c

-- 
2.43.0

Reply via email to