Everything about Memory - Part 1 (Memory Tagging)

 


In this series I will talk about how to memory management, memory improvements, infrastructure of a system that you are using, understanding all memory concepts, etc. At the end of this series, you will find out how Virtual Machines work and how your Operation System is doing with your data! 

If you are C/C++ developer, you probably heard of that this language is known for it's speed and optimization, but not at level that you don't control and optimize it for your self, everything is depend on developer.

Let's get started!

Special Thanks to: Kostya Serebryany, Evgenii Stepanov, Aleksey Shlyapnikov, Vlad Tsyrklevich, Dmitry Vyukov, Google

Introduction

Memory safety in C and C++ remains largely unresolved. A technique usually called “memory tagging” may dramatically improve the situation if implemented in hardware with reasonable overhead. This paper describes two existing implementations of memory tagging: one is the full hardware implementation in SPARC; the other is a partially hardware-assisted compiler-based tool for AArch64. We describe the basic idea, evaluate the two implementations, and explain how they improve memory safety.

Memory Safety in C/C++

C and C++ are well known for their performance and flexibility, but perhaps even more for their extreme memory unsafety. Next year we are celebrating the 33th anniversary of the Morris Worm , one of the first known exploitations of a memory safety bug, and the problem is still not solved. If anything, it’s more severe due to the exponential increase in the amount and complexity of modern software and a new focus on client-side applications with rich attack surfaces.

There are numerous tools (e.g. AddressSanitizer or Valgrind ) and techniques (e.g. fuzzing or concolic execution ) that find memory safety bugs during testing. There are also many techniques and tools that mitigate some aspects of memory safety bugs in production (e.g. ASLR , CFI ). Yet there is no end to memory safety bugs found in shipped software, and to exploits based on those bugs. The more constrained environments motivated the invention of new exploitation techniques (e.g. ROP , DOP , JOP ).

AddressSanitizer

AddressSanitizer (ASAN) is a software-only tool based on compiler instrumentation introduced to the LLVM and GCC compilers in 2011. ASAN finds the following classes of bugs:

● Temporal: heap-use-after-free , stack-use-after-return , stack-use-after-scope .

● Spatial: heap-buffer-overflow , stack-buffer-overflow , global-buffer-overflow , container-overflow .

● Other (not relevant for this discussion) Among the bug classes not detected by ASAN are use-of-uninitialized-memory (see MemorySanitizer ) and intra-object-buffer-overflow . Redzones around heap, stack, and global objects are used to detect spatial bugs, and thus an access that jumps over a redzone (aka non-linear buffer-overflow) may be undetected by ASAN.

Quarantine for heap and stack objects delays the reuse of deallocated objects and thus helps to detect temporal bugs. Exhausting the quarantine may lead to undetected temporal bugs. A shadow memory maps every 8 bytes of the application memory into 1 byte of metadata to mark memory as either valid or invalid. The shadow is checked by instrumentation code injected by the compiler.

Memory Tagging

The general idea of memory tagging (MT, also known as memory coloring, memory tainting, lock and key) on 64-bit platforms is as follows:

● Every TG (tagging granularity) bytes of memory aligned by TG are associated with a tag of TS (tag size) bits. These TG bytes are called the granule .

● TS bits in the upper part of every pointer contain a tag.

● Memory allocation (e.g. malloc) chooses a tag, associates the memory chunk being allocated with this tag, and sets this tag in the returned pointer.

● Every load and store instruction raises an exception on mismatch between the pointer and memory tags.

● The memory access and tag check do not necessarily occur atomically with respect to each other. The value of TS should be large enough to allow a sufficient number of different tag values (i.e. at least 4 to provide ~ 16 tag values) and small enough to fit into the unused upper bits of a pointer (usually up to 8 or 16, depending on the architecture). TS also affects the complexity and the size of the tag storage.

The value of TG is a balance between the size of the tag storage, the alignment requirement, and hardware possibilities.


End of Part 1 - Part 2 is here


Good Luck πŸ‘



Comments