wifi: zd1211rw: Fix potential NULL pointer dereference in zd_mac_tx_to_dev()
authorDaniil Dulov <d.dulov@aladdin.ru>
Thu, 26 Jun 2025 11:46:19 +0000 (14:46 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 30 Jun 2025 13:34:43 +0000 (15:34 +0200)
There is a potential NULL pointer dereference in zd_mac_tx_to_dev(). For
example, the following is possible:

     T0      T1
zd_mac_tx_to_dev()
  /* len == skb_queue_len(q) */
  while (len > ZD_MAC_MAX_ACK_WAITERS) {

  filter_ack()
    spin_lock_irqsave(&q->lock, flags);
    /* position == skb_queue_len(q) */
    for (i=1; i<position; i++)
           skb = __skb_dequeue(q)

    if (mac->type == NL80211_IFTYPE_AP)
      skb = __skb_dequeue(q);
    spin_unlock_irqrestore(&q->lock, flags);

    skb_dequeue() -> NULL

Since there is a small gap between checking skb queue length and skb being
unconditionally dequeued in zd_mac_tx_to_dev(), skb_dequeue() can return NULL.
Then the pointer is passed to zd_mac_tx_status() where it is dereferenced.

In order to avoid potential NULL pointer dereference due to situations like
above, check if skb is not NULL before passing it to zd_mac_tx_status().

Found by Linux Verification Center (linuxtesting.org) with SVACE.

Fixes: 459c51ad6e1f ("zd1211rw: port to mac80211")
Signed-off-by: Daniil Dulov <d.dulov@aladdin.ru>
Link: https://patch.msgid.link/20250626114619.172631-1-d.dulov@aladdin.ru
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/zydas/zd1211rw/zd_mac.c

index 9653dbaac3c0590338f340e134146c7ca62ff2e8..781510a3ec6d5a9dbb46ecb90b9fd8aee3b8bb32 100644 (file)
@@ -583,7 +583,11 @@ void zd_mac_tx_to_dev(struct sk_buff *skb, int error)
 
                skb_queue_tail(q, skb);
                while (skb_queue_len(q) > ZD_MAC_MAX_ACK_WAITERS) {
-                       zd_mac_tx_status(hw, skb_dequeue(q),
+                       skb = skb_dequeue(q);
+                       if (!skb)
+                               break;
+
+                       zd_mac_tx_status(hw, skb,
                                         mac->ack_pending ? mac->ack_signal : 0,
                                         NULL);
                        mac->ack_pending = 0;