RFD - Support for memory tagging in GLIBC

Richard Earnshaw (lists) Richard.Earnshaw@arm.com
Fri Sep 6 09:14:00 GMT 2019


NOTE: This code is not yet in a state to be committed, but I wanted to 
publish something at this point in order to start public discussions on 
the approach before I develop it further.  The code, as published has 
been tested on a model running a kernel that enables memory tagging, but 
there are a number of issues that still need to be resolved before I 
would even consider asking for a merge.  I'm not asking for a review of 
the code as much as a review of the approach at this point in time.

I'm posting this now before the Cauldron so hopefully we can have some 
useful discussions on the matter during that.

ARMv8.5 adds an extension known as MTE (memory tagging extension); the 
extension allows granules of memory (16 bytes per granule) to be 
individually 'coloured' with a 4-bit tag value.  Unused bits in the top 
byte of a 64-bit address pointer can then be set to describe the colour 
expected at that address and a protection fault can be raised if there 
is then a mismatch.  This can then be used for a number of purposes, but 
primarily is intended to assist with debugging a number of run-time 
faults that are common in code, including buffer overrun faults and 
use-after-free type errors.

Nomenclature: The AArch64 extension is called MTE.  I've tried to use 
the term 'memory tagging' (mtag) in the generic code to keep the layers 
separate.  Ideally mtag can be used on multiple architectures.

This patch proposes a way to utilize the extension to provide such 
protection in Glibc's malloc() API.  Essentially the code here is 
divided into four logical set of changes, though for the purposes of 
this discussion I've rolled this up into a single patch set.

Part 1 is a simple change to the configuration code to allow memory 
tagging support to built into glibc
Part 2 introduces a new (currently internal) API within glibc that 
provides access to the architecture-specific memory tagging operations. 
The API essentially compiles down either no-ops or existing standard 
library functions when the extension is disabled
Part 3 is the bulk of the changes to malloc/malloc.c to use the API to 
colour memory; I've tried to ensure that when the extension is disabled 
there is no overhead on existing users.  If the extension is enabled 
during the build, but disabled at run time (eg to support systems that 
do not have the extension), then there are some minor overheads, but 
they are hopefully not significant.
Part 4 is finally some target specific changes for AArch64; when MTE is 
enabled we have to be very careful about buffer overruns on read 
operations.  Consequently we have to constrain some of the string 
operations to ensure that they do not unsafely read across a tag granule 
boundary.  This code is very preliminary at present - eventually we 
would want to be able to select the code at run time and revert back to 
the standard code if tagging is disabled.

Parts 2 and 3 are obviously the focus of the discussion I'd like to have 
at present.

For part 2, the API is currently entirely private within glibc, but 
potentially in future (once we're happy that the concept is stable) it 
might be useful to open this up to users as well.

Part 3, which is the bulk of the changes colours all memory requests 
obtained through the malloc API.  Each call to malloc (or any of the 
more aligned variants) or realloc will return a coloured pointer if the 
extension is enabled

- for realloc I've chosen to recolour all affected memory even if the 
same logical address is returned (the pointer will contain a different 
colour, ensuring that before-and-after pointers will not compare equal). 
  This is perhaps the most extreme position, but in some cases that 
might catch assumptions or code that continues to use the pre-realloc 
address incorrectly.

- colouring is mostly done at the outermost level of the library.  This 
is not necessarily the most efficient point to do this, but it certainly 
creates the least disruption in the code base.  The main exception to 
this is realloc where the separation of the layers is not quite as clean 
as for the other entry points.  The advantage of colouring at the 
outermost level is that calloc() can combine the clearing of the memory 
with the colouring process if the architecture supports that (MTE does).

- one colour is retained for use by libc itself.  This can be used to 
detect when user code goes outside the allocated buffer region.

- free() recolours the memory; this is a run-time overhead but is useful 
for catching use-after-free accesses.

Limitations in the prototype:

MTE has a granule size (minimum colourable memory block) of 16 bytes. 
This happens to fit well with malloc's block header, which on aarch64 is 
also 16 bytes of size and thus leads to little overhead in the data 
structures.  I haven't attempted yet to look at support for other sizes, 
but I suspect that things will become a bit messy if the granule is 
larger than the block header (it will certainly be less efficient).

At present, the code simply assumes that all memory could be tagged 
(though it works correctly if it is not).  We are in discussions with 
the kernel folk about the possible syscall API extensions that might be 
needed to make requests for memory from the kernel tagable.

I've written enough for now.  Let the discussions begin...

-----

[mtag] Allow memory tagging to be enabled from the command line

This patch adds the configuration machinery to allow memory tagging to be
enabled from the command line via the configure option 
--enable-memory-tagging.

The current default is off, though in time we may change that once the API
is more stable.

[AArch64][mtag] Basic support for memory tagging

This patch adds the basic support for memory tagging.  This is very much
preliminary code and is unlikely to be in its final form.

- generic/libc-mtag.h - default implementation of the memory tagging
   interface.  Maps most functions onto no-ops, a few are mapped back onto
   existing APIs (eg memset).
- aarch64/libc-mtag.h - implementation for AArch64.
- aarch64/__mtag_* - helper functions for memory tagging (unoptimized).
- malloc/malloc.c - updates to support tagging of memory allocations.

[AArch64][mtag] Mitigations for string functions when MTE is enabled.

This is an initial set of patches for mitigating against MTE issues when
that is enabled.  Most of the changes are sub-optimal, but should avoid 
the boundary conditions that can cause spurious MTE faults.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: mte.patch
Type: text/x-patch
Size: 30579 bytes
Desc: not available
URL: <http://sourceware.org/pipermail/libc-alpha/attachments/20190906/60a4a79e/attachment.bin>


More information about the Libc-alpha mailing list