Hi, Sending the current state of the work.
I would like to get feedback on whether this is generally the right direction of adding the MEMTAG sanitizer in GCC. I have added some TBD/FIXME notes to each commit log. These are some of the things I am aware of and need to be resolved. Please let me know any comments on those or other issues that you may see. Another incentive to send the series in the current state is to get started on the discussion on what else needs to be done on the toolchain side to support userspace programs which use MTE extension. See the section on "Additional necessary pieces" with notes on "Kernel and User space ABI" and "MTE aware exeption handling and unwinding routines" towards the end of the cover letter. 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 these topics. Additional necessary pieces ---------------------------- * Kernel and User space ABI A user program may exercise MTE on stack, heap and/or globals data accesses. The applicable memory range must be mapped with the Normal-Tagged memory attribute ([1]). When available and enabled, the kernel advertises the feature to userspace via HWCAP2_MTE. The new flag PROT_MTE (for mmap () and mprotect ()) specified that the associated pages allow access to the MTE allocation tags. glibc currently provides a tunable glibc.mem.tagging ([3]) and MTE aware malloc. The tunable can be used to enable the malloc subsystem to allocate tagged memory with either precise or deferred faulting mode. For userspace programs using MTE on AArch64, we need to define the necessary ABI, so that the OS can set up the initial memory maps with PROT_MTE. Along with enabling PROT_MTE on address ranges, the OS also will setup the faulting mode: default, sync, async and asymm. The latter is done by privileged insns operating on privileged registers and hence, must be carried out by the OS. This will mean additional Binutils support to tag the ELF components (object files, executables and shared libraries) and additional assembler and linker command line options. The linker may want to warn when mixing code with mixed MTE usage. I will create a separate thread to discuss these ABI specification aspects soon. * 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 send notes here. 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 (9): opts: use unsigned HOST_WIDE_INT for sanitizer flags aarch64: add new define_insn for subg aarch64: add new insn definition for st2g 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 gcc/asan.cc | 252 ++++++++++++---- 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.cc | 270 +++++++++++++++++- gcc/config/aarch64/aarch64.md | 37 +++ gcc/cp/typeck.cc | 2 +- gcc/d/d-attribs.cc | 9 +- gcc/doc/invoke.texi | 11 +- gcc/doc/tm.texi | 5 + gcc/doc/tm.texi.in | 2 + gcc/dwarf2asm.cc | 2 +- gcc/flag-types.h | 2 + gcc/gimplify.cc | 5 +- gcc/internal-fn.cc | 69 ++++- 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 | 24 ++ .../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 | 16 ++ .../gcc.target/aarch64/memtag/basic-struct.c | 23 ++ .../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 ++ .../gcc.target/aarch64/memtag/vararray.c | 14 + gcc/testsuite/lib/target-supports.exp | 12 + gcc/tree-cfg.cc | 2 +- 44 files changed, 953 insertions(+), 126 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/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.c -- 2.43.0