0% found this document useful (0 votes)
32 views5 pages

ARM Memory Tagging Extension and How It Improves C:C++ Memory Safety

Uploaded by

xwmxkun
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
32 views5 pages

ARM Memory Tagging Extension and How It Improves C:C++ Memory Safety

Uploaded by

xwmxkun
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 5

SECURITY

ARM Memory Tagging Extension and


How It Improves C/C++ Memory Safety
K O S T YA S E R E B R YA N Y

I
Konstantin (Kostya) Serebryany discuss memory safety bugs typical to C and C++, current tools and
is a Software Engineer at
approaches to finding such bugs or mitigating their risk, and a new
Google. His team develops
and deploys dynamic testing
hardware feature, ARM MTE, that promises to be the biggest improve-
tools, such as AddressSanitizer, ment since the introduction of page protection.
MemorySanitizer, ThreadSanitizer, and
libFuzzer. Prior to joining Google in 2007, Memory (Un)safety
Konstantin spent four years at Elbrus/MCST More than 30 years after the Internet Worm, we are still talking about memory safety bugs
working for Sun compiler lab and then three in C and C++ programs. Numerous improvements in the software development process are
years at Intel Compiler Lab. Konstantin holds dwarfed by the exponential increase in the amount of software, its exposed attack surface,
a PhD from Moscow State University of and the discovery of new attack techniques.
Economics, Statistics, and Informatics and an Memory safety bug is an umbrella term to represent program defects inherent in C and C++
MS from Moscow State University. but also present in other languages. The most common classes of bugs are buffer overflows,
[email protected] heap-use-after-free, and stack-use-after-return.
These bugs often make the code vulnerable to exploitation. Malicious actors can leverage
memory-unsafe behavior to remotely execute code, leak sensitive information, escalate
privileges, or escape VMs. A buffer overflow in OpenSSL, nicknamed Heartbleed, achieved
notoriety for its ease of exploitation and high impact. It allowed attackers to steal a server’s
private memory, including cryptographic information such as keys and passwords, without
being detected. But named bugs like Heartbleed and Stagefright, a family of remotely exploit-
able bugs in Android, are just the tip of the iceberg.
Thousands of memory safety bugs are filed as CVEs every year. Roughly two-thirds of all
CVEs in the Android platform are memory safety bugs. A similar picture is seen across the
industry, affecting browsers, operating systems, and server-side and IoT software [1, 2]. And
even these bugs are still the tip of the iceberg. Many more bugs do not get CVEs assigned, and
many others remain unknown to software vendors. Some are being silently exploited, others
cause hard to detect data corruption, and some lie dormant waiting to strike.

Typical Bugs
Before we dive deeper, let’s take a closer look at two of our most beloved insects.
A heap-buffer-overflow happens when an object of a certain size is allocated on the heap,
and then a pointer to this object is used to access memory outside of the object bounds.
­T ypically, the object is an array of n elements, and the code accesses the i-th element where
i < 0 or i >= n.
int *array = new int[n]; // heap allocation
array[n] = 42; // buffer overflow
array[-1] = 42; // buffer overflow (underflow)
array[100500] = 42; // buffer overflow, assuming n <= 100500

12 SUMMER 2019 VO L . 4 4 , N O . 2 www.usenix.org


SECURITY
ARM Memory Tagging Extension and How It Improves C/C++ Memory Safety

A heap-use-after-free happens when an object is allocated on


the heap, and later deallocated, but a pointer to the object is pre-
served somewhere and is used to access the deallocated memory.
Object *obj = new Object; // heap allocation, or “malloc”
delete obj; // heap deallocation, or “free”
obj->member = 0; // heap-use-after-free, or Figure 1: Heap-buffer-overflow is detected by MTE because the pointer’s
// access via a dangling pointer address tag 0xA does not match the memory tag 0xE.

In both cases the buggy memory access touches someone


else’s memory. In the C and C++ standards this is considered
ARM MTE
On September 2018 ARM announced the Memory Tagging
un­defined behavior. In real life it may cause a loud crash, a
Extension, or MTE [6], a part of the ARM v8.5 architecture. It
silent data corruption, or a convenient back door.
does not yet exist in real hardware, but everything else about this
extension is very promising.
Existing Tools and Practices
We haven’t been exactly ignoring the problem for 30 years. The extension introduces a notion of two types of tags: address
tags and memory tags.
Coding practices and testing tools reduced the likelihood of
introducing a memory bug. A test-driven development process An address tag is a 4-bit value stored at the top of every pointer in
together with dynamic testing tools like AddressSanitizer [3] or the process. MTE utilizes top-byte-ignore, an existing AArch64
Valgrind will help avoid many bugs. Fuzzing (and, ideally, fuzz- feature that instructs the hardware to ignore the topmost byte of
driven development [4]) will pick up the next layer of bugs. Some addresses, allowing this byte to be used as user-controlled meta-
memory bugs can be spotted by static analysis. data. Therefore MTE is applicable only to 64-bit software.
Software-based code-hardening techniques make it harder for A memory tag is a 4-bit value associated with every aligned
attackers to exploit memory safety bugs that reach production. 16-byte region of application memory (memory granule). The
Stack cookies, non-executable memory, ASLR, control flow way memory tags are stored is a hardware implementation
integrity (LLVM CFI, Microsoft CFG, Shadow Call Stack), and detail. Logically, every 16 bytes of memory now contain an
other techniques help prevent memory safety bugs from divert- extra 4 bits of metadata in addition to 128 bits of data.
ing program control flow, the end goal of many exploits. Hard-
Every time a heap region is allocated, the software chooses a
ened memory allocators, such as Scudo Hardened Allocator or
random 4-bit tag and marks both the address and all the newly
Chrome’s Partition Alloc, frustrate exploitation and may make it
allocated memory granules with this tag. The load and store
impossible in some cases.
instructions verify that the address tag matches the memory tag,
Hardware-based solutions have begun to appear as well. causing a hardware exception on tag mismatch. MTE introduces
ARM Pointer Authentication, already available in the most new instructions to manipulate the tags.
recent Apple hardware, cryptographically authenticates return
Let’s look at the example in Figure 1. When the user code requests
addresses and discourages attackers from using return-oriented
20 bytes of heap to be allocated, operator new() rounds up the
programming (ROP). Intel Control-flow Enforcement Technol-
size to the 16-byte boundary (i.e., to 32), allocates a 32-byte
ogy is expected to appear soon to solve ROP in a different way,
chunk of memory (i.e., two 16-byte memory granules), chooses
by keeping the return address on a separate stack with special
a random 4-bit tag (in this case, 0xA), puts this tag into the
permissions.
top-byte of the address, and updates the tags for the two newly
All these tools are making our software more stable and secure, allocated memory granules (the white-colored regions in the
but they are not enough. No amount of testing guarantees the diagram). The adjacent memory regions have different memory
absence of bugs, and existing exploit mitigations only prevent tags (light gray granules have the tag 0x7, dark gray granules
some attacks, while almost entirely ignoring others, e.g., data- have the tag 0xE), so when the code tries to access memory at
oriented attacks. offset 32 from the pointer, MTE raises an exception because the
tag of the pointer does not match the tag of the memory granule
Among the hardware-based solutions two stand out, SPARC
being accessed.
ADI and ARM MTE, both implementations of a concept known
as memory tagging or memory coloring. SPARC ADI has been Figure 2 demonstrates an example of how heap-use-after-free
available in mass-produced hardware since 2016; we covered this is detected. On deallocation, operator delete() changes the tag
feature in an earlier paper [5]. This article focuses on ARM MTE. of all three deallocated granules of memory from 0xD to 0x4,

www.usenix.org SUMMER 2019 VO L . 4 4 , N O . 2 13


SECURITY
ARM Memory Tagging Extension and How It Improves C/C++ Memory Safety

Compared to AddressSanitizer, MTE brings the following


benefits:
◆◆ MTE checking can be turned on and off at runtime.
◆◆ CPU overhead is expected to be very small, hopefully a small
single-digit percentage, while AddressSanitizer typically has
2x–3x slowdown.
◆◆ MTE can find heap-related bugs without recompilation.
◆◆ Due to the small overhead, the same binary can be used for
­testing and for production.
Figure 2: Heap-use-after-free is detected by MTE because the pointer’s ◆◆ MTE’s memory overhead is 3%–5%, compared to 2x–3x for
address tag 0xD does not match the memory tag 0x4. AddressSanitizer.
so that any access to this memory via an old (dangling) pointer ◆◆ Memory accesses that happen far from the object bounds
causes an exception because the pointer still has the old tag 0xD. or long after the object lifetime are more likely to be spotted
by MTE than AddressSanitizer, which makes MTE a better
The adjacent memory regions (tagged with 0x9 and 0xB) are not
exploit mitigation.
affected by retagging of this region.
The only downside of MTE is that it may fail to detect buffer
You may have noticed that bug detection with MTE is proba- overflows that happen within the 16-byte granule:
bilistic. Indeed, there are only 16 possible values of a 4-bit tag.
One random tag will be different from another random tag with char *array = new char [13]; // allocates one 16-byte granule

a probability of 15/16 or ~93%. It is up to the software to decide array[14] = 0; // access within the same 16-byte granule

whether to increase this probability with other tricks. For Various software strategies are possible to improve bug detec-
example, in order to detect contiguous buffer overflows with tion for such cases with additional cost or complexity.
perfect accuracy, the allocator may enforce that tags for adjacent
chunks are never equal. Uses of MTE
With MTE, the heap memory is tagged inside malloc() and We envision several different usage modes for MTE.
free(), and the tag checking is performed by the hardware. It First, MTE is going to be a much nicer version of AddressSani-
means that recompilation will not be required for detecting tizer for testing and fuzzing. It will find more bugs at a fraction
heap-related bugs. MTE can also identify stack-use-after-return of the cost. In many cases it will allow testing using the same
and buffer overflows on the stack or in global variables, but it binary as shipped to production.
will require recompilation with extra compiler options.
Second, MTE could be used as a mechanism for testing in pro-
Comparison with AddressSanitizer duction (e.g., crowdsourced bug detection), always-on or enabled
AddressSanitizer is a widely used tool for detecting memory randomly. For client software, such as web browsers, it means
safety issues. It uses compiler instrumentation to observe all that when a bug happens on a user device it will be detected, and,
loads and stores. Its specialized malloc “poisons” red zones with user consent, an actionable bug report will be sent to the
around heap objects to detect buffer overflows and keeps freed vendor. For server-side software it means that even the rarest
memory in quarantine to detect use-after-free. The red zones bugs will be detected immediately once they get triggered.
and the quarantine are the major causes of AddressSanitizer’s Finally, MTE can be seen as a strong security mitigation. It
high memory overhead. is true that it prevents exploitation with less than 100% prob-
MTE is conceptually similar to AddressSanitizer: both detect ability, but the probability is still very high, and the first failed
bugs at runtime, both require special functionality in malloc and exploitation attempt will warn the user and the software vendor.
free, and both require some amount of compiler support. We believe that memory tagging will detect the most common
classes of memory safety bugs in the wild, helping vendors
However, the use of address tags makes MTE sufficiently dif- identify and fix them and discouraging malicious actors from
ferent: it does not require red zones or quarantine to detect bugs. exploiting them.
This allows MTE to consume less memory. Moreover, MTE
performs checking in hardware, thus eliminating the overhead Other clever ways to use MTE will likely be discovered. MTE
of compiler instrumentation for every load and store. may allow building debuggers with infinite hardware watch-
points, efficient race detectors, or faster garbage collectors.

14 SUMMER 2019 VO L . 4 4 , N O . 2 www.usenix.org


SECURITY
ARM Memory Tagging Extension and How It Improves C/C++ Memory Safety

HWASAN Here, by accessing an array out of bounds we end up reading


The full potential of memory tagging will only be available with another field in the same struct. In this case, AddressSanitizer,
future hardware, several years from now. But you can reap some of HWASAN, or MTE will not find the bug because the access
the benefits now, like significantly reduced memory consumption, happens within the same heap- (or stack-) allocated object. The
by using a software implementation of memory tagging: HWASAN Undefined Behavior Sanitizer (UBSan) can detect some simper
(hardware-assisted AddressSanitizer) [7]. HWASAN is similar in cases, but not the more complex ones like this one because the
spirit to AddressSanitizer, but its smaller memory footprint makes function GetInt() that accesses the memory has lost the static
it a better choice on memory-restricted devices, such as mobile bound information available in Foo(). There were multiple
phones. Today, the tool only supports 64-bit ARM CPUs, since it attempts to solve this problem (including at least one hardware
requires the top-byte-ignore feature and a small modification in extension, Intel MPX), but none were practical enough to be
the kernel to allow passing tagged addresses to system calls. widely used.
A potential solution would combine dynamic bounds ­checking,
Compatibility
static analysis (proving that either the code is correct or that
MTE and HWASAN offer a high level of compatibility with exist-
dynamic checks are effective), and the banning of certain language
ing code bases. We build the Android platform and the Chromium
constructs (like passing sub-objects without their bound infor-
browser with HWASAN with few source code changes.
mation to unknown functions). For modern C++ code, perhaps
However, we have observed several cases of incompatibility. the best solution is to replace arrays inside structs or classes
In one such case, pointers to a particular type had application- with std::array and rely on the runtime for bounds checking.
specific metadata stored in the top 16 address bits. In another
case, a pointer was cast to double and then back, losing the Type-Confusion
lower address bits. In one more case, the code computed dif- Another bug class not directly addressed by MTE is
ference between the addresses of local variables from different type-confusion.
stack frames as a way to measure recursion depth. All these
struct Image {
cases were easy to fix.
int pixels[100];
};
Related Work
With this article I hope to increase the awareness of the concept struct Secret {
of memory tagging, as well as ARM’s fantastic Memory Tagging int sensitive_data[200];
Extension, so that other CPU vendors adopt it sooner rather than };
later. Unlike most other existing hardware security extensions,
Secret *secret = new Secret;
ARM MTE directly addresses the memory safety bugs, that is,
...
the root cause of many vulnerabilities, not just how attackers
DrawOnScreen((Image*) secret);
happen to exploit their consequences today. Beyond its effective-
ness as a mitigation, MTE also serves as an effective bug detec- This code performs a cast between incompatible types; the
tion tool that can be deployed in the wild. But even MTE is not a following memory accesses in DrawOnScreen() will mistak-
panacea for all classes of memory safety bugs. enly access sensitive data without violating object bounds or
lifetimes.
Intra-Object-Buffer-Overflow
A potential solution is to use a stricter subset of C++ that dis­
There are other classes of C/C++ bugs waiting to be dealt with.
allows some invalid casts statically (via compile-time errors)
One such bug class is called intra-object-buffer-overflow.
and some other invalid casts dynamically (using a mechanism
struct S { such as implemented in LLVM CFI).
int array[5];
int another_field; Uninitialized Memory
}; A side effect of MTE is that whenever a memory allocation is
tagged, it can also be initialized at no extra cost. The new ARM
int GetInt(int *p, size_t idx) {
instructions can store memory tags and initialize the memory
return p[idx];
itself at the same time. Therefore, enabling MTE for an applica-
}
tion’s heap and stack will mitigate most vulnerabilities from
int Foo(S *s) {
another class, uses of uninitialized memory.
return GetInt(s->array, 5);
}

www.usenix.org SUMMER 2019 VO L . 4 4 , N O . 2 15


SECURITY
ARM Memory Tagging Extension and How It Improves C/C++ Memory Safety

However, we do not have to wait for MTE to eradicate this class sampled. This means that the overhead, and the bug detection
of bugs. For example, Clang/LLVM 9.0 will have an option [8] to probability, can be scaled to be arbitrarily small. The small prob-
automatically initialize all stack variables. ability of bug detection can be improved by deploying the tool at
large scale in production. We are beginning to detect bugs this
Safer Languages way in the Google Chrome browser and other software.
No discussion of memory safety in C and C++ can ignore the
GWP-ASan is not a replacement for AddressSanitizer or
existence of “safe languages.” Java, Go, Swift, and Rust, among
HWASAN since it handles a smaller subset of bugs and has very
others, are indeed much safer, and in many cases they are a bet-
low detection probability, but it finds bugs that evade testing and
ter choice for developing new software.
only manifest in production. In the most performance-critical
But none of them are really safe. Go and Swift have data races, applications, where even 1% overhead is prohibitively expensive,
Java’s huge runtime is itself written in C++, and only Rust we will be able to use MTE to implement sampled bug detection
comes close to being safe, at a cost of a (subjectively) steeper similar to GWP-ASan, but with a much lower cost and hence
learning curve. higher sampling and detection rate.
All of these languages, of course, have the “unsafe” escape hatch.
Whenever the unsafe section is used, it turns the language into
Conclusion
Once available in hardware, the ARM Memory Tagging Exten-
C, but just slightly worse, because fewer tools, practices, and
sion will reduce C and C++ memory unsafety from disastrous
habits are available for that language to avoid memory safety
to tolerable. Hopefully, other hardware vendors will implement
bugs. Here, again, Rust is probably the best with its support for
their variants of memory tagging. Before that happens, don’t
AddressSanitizer and fuzzing. MTE will be useful for Rust and
forget to test your software with all available testing tools (e.g.,
any other memory-safe language with “unsafe” code.
AddressSanitizer or HWASAN) and fuzzers (e.g., libFuzzer),
Besides, the billions of lines of C and C++ code are not going and harden your binaries in production.
away any time soon.
Acknowledgments
GWP-ASan I want to thank my colleagues Vlad Tsyrklevich, Dmitry Vyukov,
GWP-ASan [9] is another bug detection tool that finds heap- Alexander Potapenko, and Evgeniy Stepanov for helping me
use-after-free and heap-buffer-overflows. It relies on protected prepare this article.
guard pages, the old trick used in the Electric Fence Malloc
and similar tools. But there is a twist: guarded allocations are

References [5] K. Serebryany, E. Stepanov, A. Shlyapnikov, V. Tsyrklevich,


[1] K. Serebryany, “Hardware Memory Tagging to Make C/ D. Vyukov, “Memory Tagging and How It Improves C/C++
C++ Memory Safe(r),” iSecCon’18: https://github.com/google​ Memory Safety”: https://arxiv.org/pdf/1802.09517.pdf.
/sanitizers/blob/master/hwaddress-sanitizer/MTE-iSecCon​
[6] Arm A-Profile Architecture Developments 2018: Armv8.5-
-2018.pdf.
A: https://community.arm.com/processors/b/blog/posts/arm​
[2] M. Miller, “Trends, Challenges, and Strategic Shifts in the -a-profile-architecture-2018-developments-armv85a.
Software Vulnerability Mitigation Landscape,” BlueHat 2019:
[7] HWASAN documentation: https://clang.llvm.org/docs/Har
https://www.youtube.com/watch?v=PjbGojjnBZQ.
dwareAssistedAddressSanitizerDesign.html.
[3] K. Serebryany, D. Bruening, A. Potapenko, D. Vyukov,
[8] J. F. Bastien, “Automatic Variable Initialization”: https://​
“AddressSanitizer: A Fast Address Sanity Checker,” 2012
reviews.llvm.org/D54604.
­USENIX Advanced Technical Conference (USENIX ATC ’12):
https://www.usenix.org/system/files/conference/atc12/atc12​ [9] GWP-ASan for Chromium documentation: https://chromium​
-final39.pdf. .googlesource.com/chromium/src/+/lkgr/docs/gwp_asan.md.

[4] K. Serebryany, “OSS-Fuzz—Google’s Continuous Fuzzing


Service for Open Source Software,” 26th USENIX Security
Symposium (USENIX Security ’17): https://www.usenix.org​
/conference/usenixsecurity17/technical-sessions/presentation​
/serebryany.

16 SUMMER 2019 VO L . 4 4 , N O . 2 www.usenix.org

You might also like