Google Sanitizers

repository·master·Indexed 11 days ago

https://github.com/google/sanitizers

A collection of tools for detecting memory errors, data races, and undefined behavior, including AddressSanitizer (ASan), MemorySanitizer (MSan), ThreadSanitizer (TSan), HWASAN, and UBSan. This repository includes Android example apps, the check_registers test suite for x86 CPU hardware pointer tagging, MTE dynamic carveout configurations for QEMU and Device Tree, and a build status dashboard.

Tokens
5.9K
Snippets
16
Records
32
Agent score
95%

What's inside Sanitizers

  1. Overview of available sanitizers

    master

    The Sanitizers project includes several tools for detecting different types of software errors. Note that the core code for these sanitizers is now maintained within the LLVM repository.

    User-space Sanitizers

    • AddressSanitizer (ASan): Detects addressability issues.
    • LeakSanitizer (LSan): Detects memory leaks.
    • ThreadSanitizer (TSan): Detects data races and deadlocks (available for C++ and Go).
    • MemorySanitizer (MSan): Detects use of uninitialized memory.
    • HWASAN (Hardware-assisted AddressSanitizer): A variant of AddressSanitizer designed to consume significantly less memory.
    • UBSan (UndefinedBehaviorSanitizer): Detects undefined behavior.
  2. How MarkUs integrates with Memory Tagging (HWASAN / MTE)

    master

    MarkUs can be combined with Memory Tagging (such as Arm MTE, HWASAN, or SPARC ADI) to significantly reduce performance overhead. This combination provides both the security that tagging lacks and the debugging capabilities that MarkUs does not aim to provide.

    The Integrated Scheme:

    1. Tagging: Every heap region is assigned a tag (starting at 0).
    2. Deallocation: On free(), the memory tag is incremented.
      • If the tag has not overflowed, the memory is returned to malloc free-lists for immediate reuse.
      • If the tag has overflowed (reaching MaxTag), the memory chunk is placed into the MarkUs quarantine.
    3. Safety: Because the new allocation uses a different tag, any dangling pointers from previous generations will trigger a memory tagging trap.
    4. GC Scan: Once the quarantine reaches its threshold, a GC scan is run to evict only those allocations whose versions are not found in live memory.

    Performance Benefit: Using Arm MTE, this approach can result in up to 16x fewer GC scans compared to using MarkUs alone.

  3. Understand check_registers test case groups

    master

    Test cases are categorized into data flow and control flow groups. On a tagging-enabled host, their expected behavior differs:

    Data Flow Tests (Expected to PASS)

    These tests perform operations using tagged pointers (non-canonical form).

    • mov_$seg_$reg: Performs movq $seg:(%$reg), %rbx.
    • movaps_$seg_$reg: Performs movaps $seg:(%$reg), %xmm0.
    • tls_fs_$reg: Performs movq fs:(%$reg).

    Control Flow Tests (Expected to FAIL)

    These tests involve instructions that do not support segment prefixes and are expected to fail when using tagged pointers.

    • call_cs_$reg: Performs callq *%$reg (where $reg is not %rsp).
    • jump_cs_$reg: Performs jmpq *%$reg.
    • ret_cs: Performs ret (uses implicit CS: segment prefix).
  4. Understand the overhead and performance of MarkUs

    master

    MarkUs introduces CPU and RAM overhead, as well as GC pauses. The performance characteristics are roughly defined by the following factors:

    • CPU Overhead: Approximately O(MemoryFootprint * HeapAllocationSpeed / NumberOfThreads).
      • GC Scan Time: Proportional to the memory being scanned. For a 1GB footprint, a single-threaded scan might cause pauses of ~0.1s.
      • Scan Frequency: Proportional to the heap allocation speed (bytes allocated per second).
    • RAM Overhead: Depends on the size of the quarantine.

    Optimization Trade-off: You can trade CPU for RAM by adjusting the quarantine size. A smaller quarantine requires more frequent GC scans (higher CPU), while a larger quarantine consumes more RAM.

  5. How MarkUs-GC prevents Use-After-Free (UAF) bugs

    master

    MarkUs is a mechanism designed to make heap-use-after-free (UAF) bugs unexploitable without changing the semantics of C or C++. It does not detect UAFs; instead, it ensures that if a UAF occurs, the access is guaranteed to hit quarantined memory rather than reallocated data.

    Core Workflow:

    1. Quarantine on free(): When memory is freed, it is placed into a quarantine instead of being immediately available for reallocation.
    2. GC-like Scan: When the quarantine reaches a specific size threshold, a scan is performed to identify all pointers accessible from live memory.
    3. Eviction: Pointers marked as 'live' remain in quarantine. All non-marked (unreachable) pointers are evicted from the quarantine, allowing that memory to be re-allocated.

    This approach allows existing codebases to be deployed with relative ease as malloc and free continue to work as expected from the user's perspective.

  6. Hardware Requirements for MTE Dynamic Tag Storage

    master

    To support dynamic tag storage, hardware must meet specific requirements. These are divided into Base and Optional (for relocatable Tag Blocks).

    Base Hardware Requirements

    1. Tag Storage Clean Operation: The hardware must support a sequence (e.g., DC CIGVAC, Xt over Data Pages followed by DC CIVAC, Xt over the Tag Page) that ensures neither cached tags nor cached data will be written back to the Tag Page. This prevents stale tag/data writebacks when switching modes.
    2. Writeback Isolation: Stores to pages mapped as Normal or Tagged Normal must not trigger a writeback of tags to the Tag Page after a Tag Storage Clean operation.
    3. Coherent Tag Storage: Allocation tags must be stored in regular RAM (not ECC) that can be mapped as Normal memory. This memory must be coherent between CPUs for regular memory access.

    Optional Requirements for Relocatable Tag Blocks

    If the hardware supports relocating Tag Blocks (e.g., moving them to a different Physical Address), it must satisfy:

    1. Known Layout: If the Tag Storage Clean operation does not invalidate caches, the tag storage layout must be known.
    2. Relocation Integrity: After a Tag Storage Clean, a Tag Block can be copied to a different PA using regular load/store instructions. If the new block is Tagged Normal, tags must remain identical. If caches are not invalidated, the Tag Page data must be restored by writing it twice (once via tag stores to the Data Page, and once via data stores to the Tag Page) to ensure coherency.
  7. Understand MTE Dynamic Tag Storage and Tag Blocks

    master

    MTE (Memory Tagging Extension) Dynamic Tag Storage allows an operating system to decide at runtime whether to use a specific memory region for tagged data or as untagged data.

    This is managed through Tag Blocks. A Tag Block consists of:

    • 32 Data Pages
    • 1 Tag Page (the corresponding tag storage for those 32 pages)

    Calculating available Tag Blocks: If you know the total DRAM size and the page size, the number of available Tag Blocks can be estimated as: Number of Tag Blocks = (DRAM size / Page size / 33)

  8. Configure MTE dynamic carveout in QEMU

    master

    To use the MTE dynamic carveout feature in the patched QEMU prototype, you must instruct QEMU to expose tag storage to the guest and provide the expected device tree nodes. This is achieved by passing the mte-shared-alloc=on flag within the -machine command line argument.

    Note that this requires the prototype QEMU patch.

    -machine virt,virtualization=on,mte=on,mte-shared-alloc=on
  9. Debug check_registers with gdb

    master

    To debug a specific test case using gdb, you must set the follow-fork-mode to child (as tests may spawn processes) and set a breakpoint on the mangled function name.

    To find the exact mangled function name for a test case, use nm check_registers or check the source code.

    Example debugging movaps_cs_rcx:

    $ gdb ./check_registers
    (gdb) set follow-fork-mode child
    (gdb) br _Z13movaps_cs_rcxPv
    (gdb) r movaps_cs_rcx
  10. Hypervisor Design for MTE Dynamic Tag Storage

    master

    A hypervisor (running at EL2) can manage MTE dynamic tag storage for guests using two primary strategies:

    Strategy 1: Page-level Virtualization

    In this model, the hypervisor manages individual pages. This is simpler but incurs memory overhead because Tag Pages are allocated for every tagged page handed to the guest, even if they aren't used.

    • Allocation: On a data/instruction abort, allocate a page from the tagged page freelist to the guest.
    • Isolation: Hide the corresponding Tag Page from the guest using Stage 2 page tables. Note that the guest can still access tags via tag load/store instructions because these only require permission for the Data Page, not the Tag Page.
    • Untagged Guests: If MTE is disabled in the guest, pages (including Tag Pages) can be allocated from the untagged page freelist.

    Strategy 2: Tag Block-level Virtualization

    This model allows the guest to use unused tag storage by virtualizing entire Tag Blocks. This is more memory-efficient but requires memory to be handed to the guest in Tag Block-sized chunks.

    • Discovery: The hypervisor provides a virtualized device tree or ACPI entry describing the virtualized Tag Blocks.
    • Allocation: On a data/instruction abort within a virtualized Tag Block, allocate a physical Tag Block to the guest. Both Data Pages and the Tag Page are exposed via Stage 2 page tables.
    • Swapping/Removal: If a Tag Block is removed (e.g., swapped out), the hypervisor must perform a Tag Storage Clean operation before accessing the block directly.
    • Restoration: If a guest accesses a removed virtualized Tag Block, the data must be restored to a physical Tag Block. If the hardware supports relocatable Tag Blocks, the specific physical block used for restoration does not matter as tags will be preserved.
  11. Install prebuilt Sanitizer Example Android Apps

    master

    Prebuilt APKs for the Sanitizer Test App are located in the prebuilt-apks folder. Each APK corresponds to a different memory safety tool variant (HWASan, GWP-ASan, MTE, or None). Use adb to install the desired variant onto your device.

    If you encounter the error Failure [INSTALL_FAILED_VERIFICATION_FAILURE: Package Verification Result], run adb unroot before attempting the installation again.

    adb install prebuilt-apks/app-<variant>-release.apk