summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJiri Slaby <jirislaby@gmail.com>2008-08-04 11:37:07 +0200
committerGreg Kroah-Hartman <gregkh@suse.de>2008-08-06 09:03:24 -0700
commit906494c031e2ac4bbbd2a4591179d6df5a1440a0 (patch)
tree4a4188e1afc00ab83b936e34e6b9b398755e117d
parentefd5285ead8cccc76e3a978ffdeadaf86bf7aa17 (diff)
Ath5k: fix memory corruption
commit 3a0f2c871849f23c1070965bf94dec3f9c0b479d upstream 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> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-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 e57905cb5306..d7037391bb9a 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -1774,20 +1774,21 @@ ath5k_tasklet_rx(unsigned long data)
struct ath5k_rx_status rs = {};
struct sk_buff *skb;
struct ath5k_softc *sc = (void *)data;
- struct ath5k_buf *bf;
+ struct ath5k_buf *bf, *bf_last;
struct ath5k_desc *ds;
int ret;
int hdrlen;
int pad;
spin_lock(&sc->rxbuflock);
+ if (list_empty(&sc->rxbuf)) {
+ ATH5K_WARN(sc, "empty rx buf pool\n");
+ goto unlock;
+ }
+ bf_last = list_entry(sc->rxbuf.prev, struct ath5k_buf, list);
do {
rxs.flag = 0;
- if (unlikely(list_empty(&sc->rxbuf))) {
- ATH5K_WARN(sc, "empty rx buf pool\n");
- break;
- }
bf = list_first_entry(&sc->rxbuf, struct ath5k_buf, list);
BUG_ON(bf->skb == NULL);
skb = bf->skb;
@@ -1797,8 +1798,24 @@ ath5k_tasklet_rx(unsigned long data)
pci_dma_sync_single_for_cpu(sc->pdev, sc->desc_daddr,
sc->desc_len, PCI_DMA_FROMDEVICE);
- if (unlikely(ds->ds_link == bf->daddr)) /* this is the end */
- break;
+ /*
+ * last buffer must not be freed to ensure proper hardware
+ * function. When the hardware finishes also a packet next to
+ * it, we are sure, it doesn't use it anymore and we can go on.
+ */
+ if (bf_last == bf)
+ bf->flags |= 1;
+ if (bf->flags) {
+ struct ath5k_buf *bf_next = list_entry(bf->list.next,
+ struct ath5k_buf, list);
+ ret = sc->ah->ah_proc_rx_desc(sc->ah, bf_next->desc,
+ &rs);
+ if (ret)
+ break;
+ bf->flags &= ~1;
+ /* skip the overwritten one (even status is martian) */
+ goto next;
+ }
ret = sc->ah->ah_proc_rx_desc(sc->ah, ds, &rs);
if (unlikely(ret == -EINPROGRESS))
@@ -1921,6 +1938,7 @@ accept:
next:
list_move_tail(&bf->list, &sc->rxbuf);
} while (ath5k_rxbuf_setup(sc, bf) == 0);
+unlock:
spin_unlock(&sc->rxbuflock);
}
diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h
index 3a9755893018..4badca7be94d 100644
--- a/drivers/net/wireless/ath5k/base.h
+++ b/drivers/net/wireless/ath5k/base.h
@@ -55,7 +55,7 @@
struct ath5k_buf {
struct list_head list;
- unsigned int flags; /* tx descriptor flags */
+ unsigned int flags; /* rx descriptor flags */
struct ath5k_desc *desc; /* virtual addr of desc */
dma_addr_t daddr; /* physical addr of desc */
struct sk_buff *skb; /* skbuff for buf */