aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/b43/main.c
diff options
context:
space:
mode:
authorMichael Büsch <m@bues.ch>2015-01-26 12:26:17 -0500
committerKalle Valo <kvalo@codeaurora.org>2015-01-29 03:28:05 -0500
commita75d46a4f405eb19ff780410b968c8092af3fb1d (patch)
tree0d8bbcae8f9d324ce1aa365a0a1333c9bb906142 /drivers/net/wireless/b43/main.c
parentcf075eac9ca94ec54b5ae0c0ec798839f962be55 (diff)
b43: Fix locking FIXME in beacon update top half
b43 has a FIXME about locking in the mac80211 set-beacon-int callback for a long time. As it turns out there actually is a tiny race window that could result in a use-after-free bug of the 'current_beacon' memory. Nobody ever reported this, so it probably never happened. Fix this by adding a spin lock that protects the current_beacon access. We must not be in atomic context while accessing hardware (due to SDIO), so the beacon update bottom half has to clone the skb and release the lock before writing it to hardware. Let's all hope that this stops the troll who is trying to submit incorrect fixes for this issue repeatedly. And let's hope that I'm not a troll, too, who just hides even more evil code in an even more complex attempt to fix the issue. Signed-off-by: Michael Buesch <m@bues.ch> Tested-by: Larry Finger <Larry.Finger@lwfinger.net> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Diffstat (limited to 'drivers/net/wireless/b43/main.c')
-rw-r--r--drivers/net/wireless/b43/main.c43
1 files changed, 32 insertions, 11 deletions
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 58a2e88631fb..d1c397162a6a 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -1601,12 +1601,26 @@ static void b43_write_beacon_template(struct b43_wldev *dev,
1601 unsigned int rate; 1601 unsigned int rate;
1602 u16 ctl; 1602 u16 ctl;
1603 int antenna; 1603 int antenna;
1604 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon); 1604 struct ieee80211_tx_info *info;
1605 unsigned long flags;
1606 struct sk_buff *beacon_skb;
1605 1607
1606 bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data); 1608 spin_lock_irqsave(&dev->wl->beacon_lock, flags);
1607 len = min_t(size_t, dev->wl->current_beacon->len, 1609 info = IEEE80211_SKB_CB(dev->wl->current_beacon);
1608 0x200 - sizeof(struct b43_plcp_hdr6));
1609 rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value; 1610 rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
1611 /* Clone the beacon, so it cannot go away, while we write it to hw. */
1612 beacon_skb = skb_clone(dev->wl->current_beacon, GFP_ATOMIC);
1613 spin_unlock_irqrestore(&dev->wl->beacon_lock, flags);
1614
1615 if (!beacon_skb) {
1616 b43dbg(dev->wl, "Could not upload beacon. "
1617 "Failed to clone beacon skb.");
1618 return;
1619 }
1620
1621 bcn = (const struct ieee80211_mgmt *)(beacon_skb->data);
1622 len = min_t(size_t, beacon_skb->len,
1623 0x200 - sizeof(struct b43_plcp_hdr6));
1610 1624
1611 b43_write_template_common(dev, (const u8 *)bcn, 1625 b43_write_template_common(dev, (const u8 *)bcn,
1612 len, ram_offset, shm_size_offset, rate); 1626 len, ram_offset, shm_size_offset, rate);
@@ -1674,6 +1688,8 @@ static void b43_write_beacon_template(struct b43_wldev *dev,
1674 B43_SHM_SH_DTIMPER, 0); 1688 B43_SHM_SH_DTIMPER, 0);
1675 } 1689 }
1676 b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset); 1690 b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset);
1691
1692 dev_kfree_skb_any(beacon_skb);
1677} 1693}
1678 1694
1679static void b43_upload_beacon0(struct b43_wldev *dev) 1695static void b43_upload_beacon0(struct b43_wldev *dev)
@@ -1790,13 +1806,13 @@ static void b43_beacon_update_trigger_work(struct work_struct *work)
1790 mutex_unlock(&wl->mutex); 1806 mutex_unlock(&wl->mutex);
1791} 1807}
1792 1808
1793/* Asynchronously update the packet templates in template RAM. 1809/* Asynchronously update the packet templates in template RAM. */
1794 * Locking: Requires wl->mutex to be locked. */
1795static void b43_update_templates(struct b43_wl *wl) 1810static void b43_update_templates(struct b43_wl *wl)
1796{ 1811{
1797 struct sk_buff *beacon; 1812 struct sk_buff *beacon, *old_beacon;
1813 unsigned long flags;
1798 1814
1799 /* This is the top half of the ansynchronous beacon update. 1815 /* This is the top half of the asynchronous beacon update.
1800 * The bottom half is the beacon IRQ. 1816 * The bottom half is the beacon IRQ.
1801 * Beacon update must be asynchronous to avoid sending an 1817 * Beacon update must be asynchronous to avoid sending an
1802 * invalid beacon. This can happen for example, if the firmware 1818 * invalid beacon. This can happen for example, if the firmware
@@ -1810,12 +1826,17 @@ static void b43_update_templates(struct b43_wl *wl)
1810 if (unlikely(!beacon)) 1826 if (unlikely(!beacon))
1811 return; 1827 return;
1812 1828
1813 if (wl->current_beacon) 1829 spin_lock_irqsave(&wl->beacon_lock, flags);
1814 dev_kfree_skb_any(wl->current_beacon); 1830 old_beacon = wl->current_beacon;
1815 wl->current_beacon = beacon; 1831 wl->current_beacon = beacon;
1816 wl->beacon0_uploaded = false; 1832 wl->beacon0_uploaded = false;
1817 wl->beacon1_uploaded = false; 1833 wl->beacon1_uploaded = false;
1834 spin_unlock_irqrestore(&wl->beacon_lock, flags);
1835
1818 ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger); 1836 ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger);
1837
1838 if (old_beacon)
1839 dev_kfree_skb_any(old_beacon);
1819} 1840}
1820 1841
1821static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int) 1842static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
@@ -5095,7 +5116,6 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw,
5095{ 5116{
5096 struct b43_wl *wl = hw_to_b43_wl(hw); 5117 struct b43_wl *wl = hw_to_b43_wl(hw);
5097 5118
5098 /* FIXME: add locking */
5099 b43_update_templates(wl); 5119 b43_update_templates(wl);
5100 5120
5101 return 0; 5121 return 0;
@@ -5585,6 +5605,7 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev)
5585 wl->hw = hw; 5605 wl->hw = hw;
5586 mutex_init(&wl->mutex); 5606 mutex_init(&wl->mutex);
5587 spin_lock_init(&wl->hardirq_lock); 5607 spin_lock_init(&wl->hardirq_lock);
5608 spin_lock_init(&wl->beacon_lock);
5588 INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work); 5609 INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work);
5589 INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work); 5610 INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work);
5590 INIT_WORK(&wl->tx_work, b43_tx_work); 5611 INIT_WORK(&wl->tx_work, b43_tx_work);