Closed
Description
I tried this code:
#![forbid(unsafe_code)]
#![feature(coroutine_trait, coroutines)]
use ::core::ops::Coroutine;
use ::std::{thread, time};
fn demo<'not_static>(s: &'not_static str) -> thread::JoinHandle<()> {
let mut generator = Box::pin({
#[coroutine]
move |_ctx| {
let ctx: &'not_static str = yield;
yield;
dbg!(ctx);
}
});
// PROBLEM: `typeof(generator) : 'static`!
let _assert_usable_for_static: &dyn ::core::any::Any = &generator;
// exploit:
generator.as_mut().resume("");
generator.as_mut().resume(s); // <- generator hoards it as `let ctx`.
thread::spawn(move || {
thread::sleep(time::Duration::from_millis(200));
generator.as_mut().resume(""); // <- resumes from the last `yield`, running `dbg!(ctx)`.
})
}
fn main() {
let local = String::from("...");
let thread = demo(&local);
drop(local);
let _unrelated = String::from("UAF");
thread.join().unwrap();
}
- Demo: godbolt permalink
- Demo: on current playground
I expected to see this happen:
Compilation error because 'not_static : 'static
would be needed for that spawn()
(or Any
) to pass.
Instead, this happened:
No compilation error, thus unsoundness ensues (coroutine prints UAF
in the current playground, thereby proving it is reading unrelated/UAF memory. Miri reports UB).
Meta
-
rustc --version --verbose
:2024-10-23 4f2f477fded0a47b21ed
@rustbot label +I-unsound +A-coroutines +F-coroutines +F-coroutine_trait +requires-nightly