The vulnerability arises from the broadcast channel calling T::clone() on received values which are Send but not necessarily Sync, without ensuring that the clone operation itself is synchronized if T::clone() is not thread-safe for concurrent calls. This could lead to data races.
The primary commit fixing this is 4b174ce2c95fe1d1a217917db93fcc935e17e0da. The analysis of this commit reveals:
- The
clone() operation on the received value T happens within the tokio::sync::broadcast::RecvGuard::clone_value method. The way this method accessed the value (previously through UnsafeCell::with on a field of a struct guarded by RwLockReadGuard) was changed.
- The synchronization primitive for accessing shared channel
Slots was changed from RwLock to Mutex. This change is evident in tokio::sync::broadcast::Receiver::recv_priv where the lock is acquired (self.shared.buffer[idx].read().unwrap() became self.shared.buffer[idx].lock()), and also in Sender::send and Sender::new.
The function tokio::sync::broadcast::RecvGuard::clone_value is where the potentially unsynchronized clone occurred. The function tokio::sync::broadcast::Receiver::recv_priv is where the insufficient locking (RwLock) was performed, setting up the conditions for the unsafe clone. The patch addresses this by changing to a Mutex, ensuring exclusive access to the Slot during the clone operation.
Therefore, these two functions are identified as critical. RecvGuard::clone_value is where the vulnerable operation (the clone itself) is performed, and Receiver::recv_priv is where the flawed synchronization strategy (that permitted the vulnerability) was implemented and subsequently fixed. Public API functions like Receiver::recv and Receiver::try_recv would call recv_priv and thus be part of an exploit's call stack.