Repository navigation
Tracking Issue for LLVM AllocToken and Heap Partitioning Support for Rust #159111
Copy link
Copy link
Open
Labels
A-sanitizersArea: Sanitizers for correctness and code qualityArea: Sanitizers for correctness and code qualityC-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCCategory: An issue tracking the progress of sth. like the implementation of an RFCPG-exploit-mitigationsProject group: Exploit mitigationsProject group: Exploit mitigationsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language teamRelevant to the language teamT-libsRelevant to the library team, which will review and decide on the PR/issue.Relevant to the library team, which will review and decide on the PR/issue.
Description
This is a tracking issue for the LLVM AllocToken and Heap Partitioning Support for Rust project (see the design document draft).
Steps
- Add option to the Rust compiler driver and frontend (i.e.,
-Zsanitizer=alloc-tokenand related options). - Add support for emitting allocation token function attributes, module flags, and allocation token hint metadata to the Rust compiler code generation.
- Implement the default
pointer-splitheap partitioning scheme in therustc_sanitizerscrate. - Define allocation token classifications and type name encodings for cross-language LLVM AllocToken and heap partitioning support.
- Change the initial implementation to use the defined classifications and type name encodings for cross-language LLVM AllocToken and heap partitioning support.
- Add typed allocation paths and allocation token hints to the Rust standard library.
- Add token-enabled allocator interface support to the Rust standard library and to the Rust compiler allocator shim generation.
- Add the alloc_token_infer intrinsic.
- Create documentation and tests.
Unresolved Questions
None.
Implementation history
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
A-sanitizersArea: Sanitizers for correctness and code qualityArea: Sanitizers for correctness and code qualityC-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCCategory: An issue tracking the progress of sth. like the implementation of an RFCPG-exploit-mitigationsProject group: Exploit mitigationsProject group: Exploit mitigationsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language teamRelevant to the language teamT-libsRelevant to the library team, which will review and decide on the PR/issue.Relevant to the library team, which will review and decide on the PR/issue.
Activity
bjorn3 commentedon Jul 12, 2026
Left a couple of review comments on rcvalle@41bf600
bjorn3 commentedon Jul 21, 2026
I see you reacted to my comments, but github just doesn't show any commit comments at all anymore. The file sidebar shows comment counts, but nothing is shown inside the actual diff: rcvalle@41bf600
rcvalle commentedon Jul 22, 2026
Yes, it's happening to me as well. I had to expand all the files to be able to see your comments, but even doing so the third comment didn't show up--I wanted to reply I fixed it as well and I couldn't. Let me open a draft PR sometime later this week and we can continue the discussions and review there.
nikic commentedon Jul 23, 2026
usize/isize should not be classified as pointer-containing types.
rcvalle commentedon Jul 31, 2026
It's a bit complicated (see the Classification compatibility for the pointer-split heap partitioning scheme section in the design doc). The tl;dr is that the classification is conservative1 and consistent with how Clang classifies
uintptr_tandintptr_t, which end up asusizeandisizeacross the FFI boundary in "mixed binaries"--for cross-language LLVM AllocToken and heap partitioning support--and because pointers may be stored as usize (e.g., viaptr::expose_provenanceandptr::with_exposed_provenance, andAtomicUsize).Footnotes
Misclassifying a type not containing pointers into the partition containing pointers only loses part of the separation benefit for that type, while misclassifying a type containing pointers into the partition not containing pointers breaks the guarantee of the partition not containing pointers. ↩
RalfJung commentedon Aug 8, 2026
No, pointers can't be stored in usize. usize cannot hold provenance. The address part of a pointer can be stored in usize, but that's not a whole pointer. And almost all uses of
usizeare not for pointers.usizeshould be treated likesize_t, not likeuintptr_t.RalfJung commentedon Aug 8, 2026
Tracking issues are typically for already accepted proposals. Where was the prior discussion and which team has accepted this proposal using which process?
rcvalle commentedon Aug 8, 2026
Yes, an address is what an attacker would target in e.g., a heap-based out-of-bounds write, and that's what we want to hint the
AllocTokenPassabout the possibility of, and it doesn't change the language semantics or the program correctness in any way. Think of it as similar to a low-level optimization hint, and what a token-enabled memory allocator does with the token identifier derived from that (by theAllocTokenPass) is implementation specific.rcvalle commentedon Aug 8, 2026
Sorry, almost all sanitizers support were done without an MCP or tracking issue (or a design document). I mostly use these tracking issues to track our Compiler team and PG exploit mitigations work (and for possibly future stabilization) and didn't know they were strictly for that so apologies. Happy to open an MCP or do as you suggested in the PR in this case if you think that would be helpful. Let me know.
RalfJung commentedon Aug 9, 2026
Thanks for explaining. I haven't seen such tracking issues before so I was just a little surprised.
The public lib API change will definitely need an ACP. As for the MCP, the change seemed big enough (with new flags and new attributes) for me to warrant one; I assume @bjorn3 would second it fairly quickly but it'd be a chance for the rest of the team to chime in with feedback.
I see. Still seems odd to me given that most
usizeare not pointers so mixing them with pointers could be bad, but you are the mitigation expert here. :)rcvalle commentedon Aug 10, 2026
@RalfJung will do that as soon as I've some time. Thank you!
nikic commentedon Aug 21, 2026
I don't think this makes sense. This goes beyond being conservative, into trying to handle some rare, very non-idiomatic code patterns like first-class citizens. For various reasons (including a focus on strict provenance) Rust generally has a lot less of these "storing pointers in integers" pattern than C does, and I don't think it's a good idea to assume that it's happening by default.
rcvalle commentedon Aug 25, 2026
Storing pointers in
usizeandisizeis very common in mixed binaries, which is also a very common use of Rust. What is the harm that you see in conservatively classifying them as may contain pointers? Does it outweigh the risk of classifying a type that may contain pointers into the partition not containing pointers and breaking the guarantee of the partition not containing pointers.RalfJung commentedon Aug 25, 2026
Do we have actual data on that? Rust is quite clear that one shouldn't do this so I would hope people usually use proper types instead of letting bad C practices leak onto the Rust side.
rcvalle commentedon Aug 28, 2026
For example, pretty much all occurrences of
uintptr_tin#[repr(C)]types and in FFI bindings/at the FFI boundary? I still want to know what is the harm that you see in conservatively classifying them as may contain pointers? Does it outweigh the risk of classifying a type that may contain pointers into the partition not containing pointers and breaking the guarantee of the partition not containing pointers?hanna-kruppe commentedon Aug 28, 2026
The main risk I see is that it'll lead to classifying far more allocations as containing pointers than you would in C. In the limit, if you conservatively classify too many allocation as containing pointers when they don't, the mitigation becomes less effective, right?
It's true that there are some C bindings that use
usizefor things that can contain pointers. The main offender I'm aware of are the signal handler/sigaction values, which are either SIG_DFL / SIG_IGN or function pointers (although these are very rarely, if ever, heap allocated). However, there are far less than you may expect from looking at uses ofuintptr_tin C, since (as Ralf mentioned) it's generally incorrect to use integers for anything that needs pointer provenance. So I think it would be good to measure the actual difference between classifying usize/isize as pointers or as integers in Rust.rcvalle commentedon Aug 28, 2026
Do you have any suggestions on how we could best measure the actual difference? My main concern is breaking the guarantee of the partition not containing pointers--this is what would meaningfully affect the mitigations effectiveness.
hanna-kruppe commentedon Aug 28, 2026
Once the sanitizer is implemented, one could compile a bunch of real world projects twice, once with usize/isize counting as pointers and once without, and look at:
rcvalle commentedon Aug 28, 2026
I can try to do that. I've a working implementation in the #160298 draft PR, and working examples in the rust-heap-partitioning-examples repository. Do you have any suggestions of real-world projects that would be close to being representative for doing that?
RalfJung commentedon Aug 28, 2026
Can you talk a bit about the risks in the other direction here? What are potential problems associated with marking too many allocations as containing pointers? Why does the sanitizer not simply treat all allocations as potentially containing pointers?
rcvalle commentedon Aug 28, 2026
The main goal of the first-level pointer-split partitioning is isolating types that are susceptible to out-of-bounds reads and writes (e.g., char[] buffers, std::string, etc., or Box<[u8; N]>, Vec, etc., when unsafe operations are done on them) from types that contain pointers, so even if the attacker has such a primitive they can't read or write any pointers.
That is why misclassifying a type not containing pointers into the partition containing pointers only loses part of the separation benefit for that type (i.e., only if that type is susceptible to out-of-bounds reads and writes and its use is actually vulnerable), while misclassifying a type containing pointers into the partition not containing pointers breaks the guarantee of the partition not containing pointers (i.e., any type that is susceptible to out-of-bounds reads and writes and their use are vulnerable becomes a way to read or write to the pointers that made in).