You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
BiLockGuard implements Send for T: Send and Sync for T: Send that are propagated from manual unsafe Send/Sync impl for Inner. However, BiLockGuard implements Deref for T which requires T: Sync bound for Sync. This definition allows parallel access to T: !Sync type, which is unsound.
Observation on impact
BiLock API is unstable, so hopefully the bug wouldn't affect a lot of people. I also lightly audited io split and stream split, two places where BiLock is internally used. All of them seem to call as_pin_mut() right after locking which I believe to be sound with the current definition (but it's not a guarantee!)
Proof of Concept
Tested with futures 0.3.21.
Code:
#![forbid(unsafe_code)]use std::cell::Cell;use std::sync::Arc;use std::thread;use futures::lock::BiLock;#[derive(Clone,Copy)]enumRefOrInt{Ref(&'static u64),Int(u64),}staticSTATIC_INT:u64 = 123;implDefaultforRefOrInt{fndefault() -> Self{RefOrInt::Ref(&STATIC_INT)}}#[tokio::main]asyncfnmain(){let(lock1, _lock2) = BiLock::new(Cell::new(RefOrInt::default()));// Contrived use case for easier demonstrationlet lock1 = Box::leak(Box::new(lock1));let guard1 = Arc::new(lock1.lock().await);let guard2 = guard1.clone();
thread::spawn(move || {loop{// Repeatedly write Ref(&addr) and Int(0xdeadbeef) into the cell.
guard1.set(RefOrInt::Ref(&STATIC_INT));
guard1.set(RefOrInt::Int(0xdeadbeef));}});loop{ifletRefOrInt::Ref(addr) = guard2.get(){if addr as*constu64 == &STATIC_INTas*constu64{continue;}// We got Ref(0xdeadbeef) due to data raceprintln!("Pointer is now: {:p}", addr);println!("Dereferencing addr will now segfault");println!("{}", addr);}}}
Output:
Pointer is now: 0xdeadbeef
Dereferencing addr will now segfault
segmentation fault (core dumped)
The text was updated successfully, but these errors were encountered:
Bug Description
futures-rs/futures-util/src/lock/bilock.rs
Lines 48 to 49 in d74763c
BiLockGuard
implementsSend
forT: Send
andSync
forT: Send
that are propagated from manual unsafe Send/Sync impl forInner
. However,BiLockGuard
implementsDeref
forT
which requiresT: Sync
bound forSync
. This definition allows parallel access toT: !Sync
type, which is unsound.Observation on impact
BiLock
API is unstable, so hopefully the bug wouldn't affect a lot of people. I also lightly audited io split and stream split, two places whereBiLock
is internally used. All of them seem to callas_pin_mut()
right after locking which I believe to be sound with the current definition (but it's not a guarantee!)Proof of Concept
Tested with futures 0.3.21.
Code:
Output:
The text was updated successfully, but these errors were encountered: