The vulnerability is a use-after-free caused by a race condition in the oneshot crate's channel implementation. The issue occurs when an asynchronous oneshot::Receiver is polled but then dropped before the operation completes.
- When
Future::poll is called on a Receiver, it places the channel into a RECEIVING state and stores a Waker in the channel's shared memory.
- If the
Receiver future is then dropped (e.g., due to a timeout), its drop implementation is executed.
- The vulnerable version of
Receiver::drop would first unconditionally change the channel's state to DISCONNECTED.
- This
DISCONNECTED state signals to the Sender that it can safely deallocate the shared channel memory.
- After setting the state, the
Receiver::drop implementation would then check the previous state. If it was RECEIVING, it would proceed to access the shared channel memory to retrieve and drop the Waker.
- A race condition exists here: if the
Sender thread processes the DISCONNECTED state and deallocates the channel memory before the Receiver's drop logic finishes with it, the Receiver will attempt to read from freed memory, causing a use-after-free.
The fix, seen in commit d1a1506010bc48962634807d0dcca682af4f50ba, resolves this by changing the logic in Receiver::drop. Before marking the channel as DISCONNECTED, it now checks if the state is RECEIVING. If so, it atomically swaps it to EMPTY, ensuring it has exclusive access to the Waker before the Sender is signaled to deallocate the memory.
The primary vulnerable function is oneshot::Receiver::drop, as it contains the flawed logic that leads to the use-after-free.