On Sun, 12 Jan 2020 00:14:55 +0800 Jia-Ju Bai <baijiaju1990@xxxxxxxxx> wrote: > The functions b43_op_tx() and b43_tx_work() may be concurrently executed. > > In b43_tx_work(), the variable wl->tx_queue_stopped[queue_num] is > accessed with holding a mutex lock wl->mutex. But in b43_op_tx(), the > identical variable wl->tx_queue_stopped[skb->queue_mapping] is accessed > without holding this mutex lock. Thus, a possible data race may occur. > > To fix this data race, in b43_op_tx(), the variable > wl->tx_queue_stopped[skb->queue_mapping] is accessed with holding the > mutex lock wl->mutex. > > This data race is found by the runtime testing of our tool DILP-2. > > Signed-off-by: Jia-Ju Bai <baijiaju1990@xxxxxxxxx> > --- > drivers/net/wireless/broadcom/b43/main.c | 7 ++++++- > 1 file changed, 6 insertions(+), 1 deletion(-) > > diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c > index 39da1a4c30ac..adedb38f50f2 100644 > --- a/drivers/net/wireless/broadcom/b43/main.c > +++ b/drivers/net/wireless/broadcom/b43/main.c > @@ -3625,6 +3625,11 @@ static void b43_op_tx(struct ieee80211_hw *hw, > struct sk_buff *skb) > { > struct b43_wl *wl = hw_to_b43_wl(hw); > + bool stopped; > + > + mutex_lock(&wl->mutex); > + stopped = wl->tx_queue_stopped[skb->queue_mapping]; > + mutex_unlock(&wl->mutex); > > if (unlikely(skb->len < 2 + 2 + 6)) { > /* Too short, this can't be a valid frame. */ > @@ -3634,7 +3639,7 @@ static void b43_op_tx(struct ieee80211_hw *hw, > B43_WARN_ON(skb_shinfo(skb)->nr_frags); > > skb_queue_tail(&wl->tx_queue[skb->queue_mapping], skb); > - if (!wl->tx_queue_stopped[skb->queue_mapping]) { > + if (!stopped) { > ieee80211_queue_work(wl->hw, &wl->tx_work); > } else { > ieee80211_stop_queue(wl->hw, skb->queue_mapping); Hi, thanks for your patch. Unfortunately it is not possible to acquire a sleeping mutex in the tx op: /** * struct ieee80211_ops - callbacks from mac80211 to the driver * * @tx: Handler that 802.11 module calls for each transmitted frame. * skb contains the buffer starting from the IEEE 802.11 header. * The low-level driver should send the frame out based on * configuration in the TX control data. This handler should, * preferably, never fail and stop queues appropriately. * Must be atomic. ^^^^^^^^^^^^^^ I also don't think that the change really fixes any race. The variable tx_queue_stopped is a boolean. Reading that under mutex and then doing the actual action based on a copy does not really change anything. The other end may just set it to false after mutex_unlock, but before the queue_work. Thus this change does probably even increase the race window size. The other thing to consider is: What can actually go wrong, if the race happens? I currently don't see any fatal behavior. A packet might still make it into the queue, although it has already been stopped. But that's not fatal. -- Michael
Attachment:
pgpNqAnT5hp1y.pgp
Description: OpenPGP digital signature