Skip to content

LLVM AllocToken and Heap Partitioning Support for Rust #1032

Description

@rcvalle

Proposal

Add LLVM AllocToken and heap partitioning support to the Rust compiler (i.e., rustc).

Heap partitioning is an exploit mitigation that protects programs from having their heap layout controlled for exploitation by separating allocations into isolated heap partitions. It is implemented by modern memory allocators and operating systems, such as the Apple XNU kernel kalloc_type allocator, the Chromium PartitionAlloc allocator, the GrapheneOS hardened_malloc allocator, and the Linux kernel randomized kmalloc caches. LLVM AllocToken (available in LLVM 22 or higher, with Clang support) assigns a token identifier (i.e., an integer) to each allocation, and passes it to the allocator by rewriting allocation calls to token-enabled versions of the allocation functions.

The Rust compiler currently does not support heap partitioning when

  • building Rust-compiled code only programs.
  • linking foreign C- or C++-compiled code into a program written in Rust.
  • linking foreign Rust-compiled code into a program written in C or C++.

Therefore, the absence of support for heap partitioning in the Rust compiler is a security concern when gradually migrating from C and C++ to Rust, and when C or C++ and Rust-compiled code share the same virtual address space and memory allocator.

LLVM AllocToken and heap partitioning support for the Rust compiler work is broken in these steps:

  • Add compiler options (i.e., -Zsanitizer=alloc-token, -Zsanitizer-alloc-token-scheme, -Zsanitizer-alloc-token-max, -Zsanitizer-alloc-token-extended, and -Zsanitizer-alloc-token-fast-abi), including target support specification (i.e., supported_sanitizers in target specifications).
  • Add the alloc_token_hint attribute (i.e., the attribute that allows the user to define the allocation token hint for user-defined types) and the internal rustc_alloc_token_hint attribute.
  • Implement the pointer-split and type-hash-pointer-split heap partitioning schemes (i.e., the Rust compiler-side code that compute allocation token hints for allocated types) in the rustc_sanitizers crate. The pointer-split heap partitioning scheme is the default heap partitioning scheme for the Rust compiler. It separates allocations into two partitions: one containing pointers and another not containing pointers, with default or unknown being the partition containing pointers.
  • Add the allocation token abstraction to backend-agnostic code and implement it for the LLVM backend (i.e., attach !alloc_token metadata to allocation calls, and add the alloc-token-mode, alloc-token-max, alloc-token-extended, and alloc-token-fast-abi module flags for the AllocTokenPass).
  • Add typed allocation paths (i.e., internal, unstable, generic allocation functions annotated with the rustc_alloc_token_hint attribute, whose type parameter identifies the allocated type) to the Rust standard library.
  • Add token-enabled allocator interface support to the Rust standard library (i.e., new unstable, token-enabled methods of the GlobalAlloc trait, token-enabled versions of the allocation functions in the allocator shim generation, and weak default definitions of the token-enabled C allocator interface, so that programs without a token-enabled memory allocator degrade gracefully (i.e., programs remain correct, without heap partitioning)).
  • Add the alloc_token_infer intrinsic (i.e., the Rust equivalent of the Clang __builtin_infer_alloc_token builtin).
  • Add documentation.

For cross-language LLVM AllocToken and heap partitioning support, both Clang and the Rust compiler rewrite allocation calls to the same token-enabled allocator interface, so that a single token-enabled memory allocator serves all compiled code in a mixed binary (i.e., for when C or C++ and Rust-compiled code share the same virtual address space and memory allocator). For example, a TCMalloc built with allocation token instrumentation enabled serves both the C- and Rust-compiled code, with allocations of types not containing pointers and allocations of types containing pointers placed in separate heap partitions.

Working examples are available in the rust-heap-partitioning-examples repository, the complete implementation is available in the rust-lang/rust#160298 draft PR, and the design is described detail in the design document in the tracking issue rust-lang/rust#159111.

Mentors or Reviewers

I (@rcvalle) am implementing this work, and @bjorn3 is the reviewer.

Process

The main points of the Major Change Process are as follows:

  • File an issue describing the proposal.
  • A compiler team member who is knowledgeable in the area can second by writing @rustbot second or kickoff a team FCP with @rfcbot fcp $RESOLUTION.
  • Once an MCP is seconded, the Final Comment Period begins.
    • Final Comment Period lasts for 10 days after all outstanding concerns are solved.
    • Outstanding concerns will block the Final Comment Period from finishing. Once all concerns are resolved, the 10 day countdown is restarted.
    • If no concerns are raised after 10 days since the resolution of the last outstanding concern, the MCP is considered approved.

You can read more about Major Change Proposals on forge.

Metadata

Metadata

Assignees

No one assigned

    Labels

    T-compilerAdd this label so rfcbot knows to poll the compiler teammajor-changeA proposal to make a major change to rustcto-announceAnnounce this issue on triage meeting

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions