Microsoft FORGE Details Rust Standard Library Bugs Found With AI-Assisted Research

· Original article ↗

Summary

Microsoft FORGE Lab details Rust standard-library soundness bugs investigated with AI-assisted tools, including panic-safety, custom-trait, signal-stack, and environment-lock issues. Some issues remained open; practical exploitation of one was assessed as unlikely.

Key points

  • FORGE researchers report memory-safety soundness bugs in Rust's standard library, including cases where safe Rust can trigger undefined behavior.
  • The investigation describes three recurring trust failures: code that may panic, caller-provided implementations that may behave unexpectedly, and assumptions about process-wide or operating-system state.
  • A custom Pattern implementation could cause str::replace to return invalid UTF-8; the fix changed StringPattern to hold &str.
  • A child thread calling process::exit could unmap the main thread's alternate signal stack. The reported fix stops cleaning up that stack; researchers found no reliable exploitation path under the conditions they tested.
  • CommandExt::exec writes the process environment while holding only a read lock, allowing races; a fix using execve directly was under review.
  • Some issues reported by FORGE remained open at publication, while other fixes were implemented or under review. The article cautions that a soundness bug is not automatically exploitable in real programs.
  • Some findings were made with Hyenas, FORGE's research version of codename MDASH; researchers reproduced bugs, assessed potential impact, and worked with Rust maintainers.

Article Details

Attack Vectors
  • A panic from user-provided `T::clone` during `MapWindows::clone` can unwind while a buffer contains uninitialized slots, causing its destructor to access uninitialized memory.
  • A custom safe `Pattern` implementation can report a non-ASCII byte as a one-byte string pattern; `str::replace` may then return invalid UTF-8, leading to undefined behavior in later string operations.
  • Caller-provided implementations that return inconsistent results can violate assumptions in unsafe library code, including implementations of `AsRef`, `Borrow`, or `Pattern`.
  • `process::exit` called from a child thread can unmap the main thread’s alternate signal stack while that thread is still running. The researchers found no reliable exploitation path under the conditions they tested and assessed practical exploitation as unlikely.
  • `CommandExt::exec` writes the process-global environment while holding only a read lock, allowing other threads to observe transient environment values; racing failed `exec` calls can leave the environment pointing to freed memory.
  • A thread-local destructor that calls `process::exit` while a thread local is being replaced can cause that thread local to be dropped twice; this issue was reported by someone else.
Defensive Notes
  • Keep partially initialized state safe to unwind through: the article describes holding the buffer in `ManuallyDrop` until it is fully written or using a guard that restores the invariant.
  • Treat calls to user-controlled code as possible panic or early-exit points. Call implementations once and retain the result, validate returned values, or encode required properties in types that safe code cannot forge.
  • The article says Rust’s allocator API stabilization requires allocator trait methods and `drop` not to unwind; the reported allocation-related issues arose when an allocator unwound.
  • The fix for the main-thread signal-stack issue stops cleaning up that stack. For the environment issue, a fix that avoids modifying `environ` by calling `execve` directly was in review at publication.
  • A soundness bug does not automatically make programs using the affected API vulnerable; the article says exploitation generally requires unusual triggering conditions and a real program to reach them.

CVE

Vendors

Products

Tools

Related Articles