aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorJiri Slaby <jirislaby@gmail.com>2008-07-15 11:44:18 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-07-29 16:36:25 -0400
commit3a0f2c871849f23c1070965bf94dec3f9c0b479d (patch)
tree322e7d568d5c45d1abeb4f3424537e3c07209238 /drivers/net/wireless
parent605a0bd66d9d55e9ba46da1a9e5140c68bdf6d85 (diff)
Ath5k: fix memory corruption
When signal is noisy, hardware can use all RX buffers and since the last entry in the list is self-linked, it overwrites the entry until we link new buffers. Ensure that we don't free this last one until we are 100% sure that it is not used by the hardware anymore to not cause memory curruption as can be seen below. This is done by checking next buffer in the list. Even after that we know that the hardware refetched the new link and proceeded further (the next buffer is ready) we can finally free the overwritten buffer. We discard it since the status in its descriptor is overwritten (OR-ed by new status) too. ============================================================================= BUG kmalloc-4096: Poison overwritten ----------------------------------------------------------------------------- INFO: 0xffff810067419060-0xffff810067419667. First byte 0x8 instead of 0x6b INFO: Allocated in dev_alloc_skb+0x18/0x30 age=1118 cpu=1 pid=0 INFO: Freed in skb_release_data+0x85/0xd0 age=1105 cpu=1 pid=3718 INFO: Slab 0xffffe200019d0600 objects=7 used=0 fp=0xffff810067419048 flags=0x40000000000020c3 INFO: Object 0xffff810067419048 @offset=4168 fp=0xffff81006741c120 Bytes b4 0xffff810067419038: 4f 0b 02 00 01 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a O.......ZZZZZZZZ Object 0xffff810067419048: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk Object 0xffff810067419058: 6b 6b 6b 6b 6b 6b 6b 6b 08 42 30 00 00 0b 6b 80 kkkkkkkk.B0...k. Object 0xffff810067419068: f0 5d 00 4f 62 08 a3 64 00 0c 42 16 52 e4 f0 5a 360].Ob.243d..B.R344360Z Object 0xffff810067419078: 68 81 00 00 7b a5 b4 be 7d 3b 8f 53 cd d5 de 12 h...{245264276};.S315325336. Object 0xffff810067419088: 96 10 0b 89 48 54 23 41 0f 4e 2d b9 37 c3 cb 29 ....HT#A.N-2717303313) Object 0xffff810067419098: d1 e0 de 14 8a 57 2a cc 3b 44 0d 78 7a 19 12 15 321340336..W*314;D.xz... Object 0xffff8100674190a8: a9 ec d4 35 a8 10 ec 8c 40 a7 06 0a 51 a7 48 bb 2513543245250.354.@247..Q247H273 Object 0xffff8100674190b8: 3e cf a1 c7 38 60 63 3f 51 15 c7 20 eb ba 65 30 >ϡ3078`c?Q.307.353272e0 Redzone 0xffff81006741a048: bb bb bb bb bb bb bb bb 273273273273273273273273 Padding 0xffff81006741a088: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ Pid: 3297, comm: ath5k_pci Not tainted 2.6.26-rc8-mm1_64 #427 Call Trace: [<ffffffff802a7306>] print_trailer+0xf6/0x150 [<ffffffff802a7485>] check_bytes_and_report+0x125/0x180 [<ffffffff802a75dc>] check_object+0xac/0x260 [<ffffffff802a9308>] __slab_alloc+0x368/0x6d0 [<ffffffff80544f82>] ? wireless_send_event+0x142/0x310 [<ffffffff804b1bd4>] ? __alloc_skb+0x44/0x150 [<ffffffff80544f82>] ? wireless_send_event+0x142/0x310 [<ffffffff802aa853>] __kmalloc_track_caller+0xc3/0xf0 [<ffffffff804b1bfe>] __alloc_skb+0x6e/0x150 [... stack snipped] FIX kmalloc-4096: Restoring 0xffff810067419060-0xffff810067419667=0x6b FIX kmalloc-4096: Marking all objects used Signed-off-by: Jiri Slaby <jirislaby@gmail.com> Acked-by: Nick Kossifidis <mickflemm@gmail.com> Cc: Luis R. Rodriguez <mcgrof@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/ath5k/base.c32
-rw-r--r--drivers/net/wireless/ath5k/base.h2
2 files changed, 26 insertions, 8 deletions
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index d9769c527346..ed51c4a69d43 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -1682,20 +1682,21 @@ ath5k_tasklet_rx(unsigned long data)
1682 struct ath5k_rx_status rs = {}; 1682 struct ath5k_rx_status rs = {};
1683 struct sk_buff *skb; 1683 struct sk_buff *skb;
1684 struct ath5k_softc *sc = (void *)data; 1684 struct ath5k_softc *sc = (void *)data;
1685 struct ath5k_buf *bf; 1685 struct ath5k_buf *bf, *bf_last;
1686 struct ath5k_desc *ds; 1686 struct ath5k_desc *ds;
1687 int ret; 1687 int ret;
1688 int hdrlen; 1688 int hdrlen;
1689 int pad; 1689 int pad;
1690 1690
1691 spin_lock(&sc->rxbuflock); 1691 spin_lock(&sc->rxbuflock);
1692 if (list_empty(&sc->rxbuf)) {
1693 ATH5K_WARN(sc, "empty rx buf pool\n");
1694 goto unlock;
1695 }
1696 bf_last = list_entry(sc->rxbuf.prev, struct ath5k_buf, list);
1692 do { 1697 do {
1693 rxs.flag = 0; 1698 rxs.flag = 0;
1694 1699
1695 if (unlikely(list_empty(&sc->rxbuf))) {
1696 ATH5K_WARN(sc, "empty rx buf pool\n");
1697 break;
1698 }
1699 bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list); 1700 bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
1700 BUG_ON(bf->skb == NULL); 1701 BUG_ON(bf->skb == NULL);
1701 skb = bf->skb; 1702 skb = bf->skb;
@@ -1705,8 +1706,24 @@ ath5k_tasklet_rx(unsigned long data)
1705 pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr, 1706 pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr,
1706 sc->desc_len, PCI_DMA_FROMDEVICE); 1707 sc->desc_len, PCI_DMA_FROMDEVICE);
1707 1708
1708 if (unlikely(ds->ds_link == bf->daddr)) /* this is the end */ 1709 /*
1709 break; 1710 * last buffer must not be freed to ensure proper hardware
1711 * function. When the hardware finishes also a packet next to
1712 * it, we are sure, it doesn't use it anymore and we can go on.
1713 */
1714 if (bf_last == bf)
1715 bf->flags |= 1;
1716 if (bf->flags) {
1717 struct ath5k_buf *bf_next = list_entry(bf->list.next,
1718 struct ath5k_buf, list);
1719 ret = sc->ah->ah_proc_rx_desc(sc->ah, bf_next->desc,
1720 &rs);
1721 if (ret)
1722 break;
1723 bf->flags &= ~1;
1724 /* skip the overwritten one (even status is martian) */
1725 goto next;
1726 }
1710 1727
1711 ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs); 1728 ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs);
1712 if (unlikely(ret == -EINPROGRESS)) 1729 if (unlikely(ret == -EINPROGRESS))
@@ -1816,6 +1833,7 @@ accept:
1816next: 1833next:
1817 list_move_tail(&bf->list, &sc->rxbuf); 1834 list_move_tail(&bf->list, &sc->rxbuf);
1818 } while (ath5k_rxbuf_setup(sc, bf) == 0); 1835 } while (ath5k_rxbuf_setup(sc, bf) == 0);
1836unlock:
1819 spin_unlock(&sc->rxbuflock); 1837 spin_unlock(&sc->rxbuflock);
1820} 1838}
1821 1839
diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h
index 47f414b09e67..d7e03e6b8271 100644
--- a/drivers/net/wireless/ath5k/base.h
+++ b/drivers/net/wireless/ath5k/base.h
@@ -56,7 +56,7 @@
56 56
57struct ath5k_buf { 57struct ath5k_buf {
58 struct list_head list; 58 struct list_head list;
59 unsigned int flags; /* tx descriptor flags */ 59 unsigned int flags; /* rx descriptor flags */
60 struct ath5k_desc *desc; /* virtual addr of desc */ 60 struct ath5k_desc *desc; /* virtual addr of desc */
61 dma_addr_t daddr; /* physical addr of desc */ 61 dma_addr_t daddr; /* physical addr of desc */
62 struct sk_buff *skb; /* skbuff for buf */ 62 struct sk_buff *skb; /* skbuff for buf */