aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/p54/p54usb.c
diff options
context:
space:
mode:
authorChristian Lamparter <chunkeey@web.de>2009-01-19 18:27:57 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-01-22 13:55:02 -0500
commite2fe154e918276e900067a9d1d3a6a963faee041 (patch)
tree22936f2b3784c4d89c4f1e2263b528167f42e683 /drivers/net/wireless/p54/p54usb.c
parent12da401e0d616f738c8b8a368d1f63f365cc78e4 (diff)
p54usb: fix nasty use after free
In theory, the firmware acks the received a data frame, before signaling the driver to free it again. However Artur Skawina <art.08.09@gmail.com> has shown that it can happen in reverse order as well. This is very bad and could lead to memory corruptions, oopses and panics. Thanks to Artur Skawina <art.08.09@gmail.com> for reporting and debugging this issue. Signed-off-by: Christian Lamparter <chunkeey@web.de> Tested-by: Artur Skawina <art.08.09@gmail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/p54/p54usb.c')
-rw-r--r--drivers/net/wireless/p54/p54usb.c34
1 files changed, 13 insertions, 21 deletions
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index 6a6a72f6f82c..4487cc5c928b 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -144,11 +144,8 @@ static void p54u_tx_cb(struct urb *urb)
144 struct sk_buff *skb = urb->context; 144 struct sk_buff *skb = urb->context;
145 struct ieee80211_hw *dev = (struct ieee80211_hw *) 145 struct ieee80211_hw *dev = (struct ieee80211_hw *)
146 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); 146 usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
147 struct p54u_priv *priv = dev->priv;
148 147
149 skb_pull(skb, priv->common.tx_hdr_len); 148 p54_free_skb(dev, skb);
150 if (FREE_AFTER_TX(skb))
151 p54_free_skb(dev, skb);
152} 149}
153 150
154static void p54u_tx_dummy_cb(struct urb *urb) { } 151static void p54u_tx_dummy_cb(struct urb *urb) { }
@@ -230,7 +227,8 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb)
230 p54u_tx_dummy_cb, dev); 227 p54u_tx_dummy_cb, dev);
231 usb_fill_bulk_urb(data_urb, priv->udev, 228 usb_fill_bulk_urb(data_urb, priv->udev,
232 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), 229 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
233 skb->data, skb->len, p54u_tx_cb, skb); 230 skb->data, skb->len, FREE_AFTER_TX(skb) ?
231 p54u_tx_cb : p54u_tx_dummy_cb, skb);
234 232
235 usb_anchor_urb(addr_urb, &priv->submitted); 233 usb_anchor_urb(addr_urb, &priv->submitted);
236 err = usb_submit_urb(addr_urb, GFP_ATOMIC); 234 err = usb_submit_urb(addr_urb, GFP_ATOMIC);
@@ -269,28 +267,24 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
269{ 267{
270 struct p54u_priv *priv = dev->priv; 268 struct p54u_priv *priv = dev->priv;
271 struct urb *data_urb; 269 struct urb *data_urb;
272 struct lm87_tx_hdr *hdr; 270 struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
273 __le32 checksum;
274 __le32 addr = ((struct p54_hdr *)skb->data)->req_id;
275 271
276 data_urb = usb_alloc_urb(0, GFP_ATOMIC); 272 data_urb = usb_alloc_urb(0, GFP_ATOMIC);
277 if (!data_urb) 273 if (!data_urb)
278 return; 274 return;
279 275
280 checksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len); 276 hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
281 hdr = (struct lm87_tx_hdr *)skb_push(skb, sizeof(*hdr)); 277 hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
282 hdr->chksum = checksum;
283 hdr->device_addr = addr;
284 278
285 usb_fill_bulk_urb(data_urb, priv->udev, 279 usb_fill_bulk_urb(data_urb, priv->udev,
286 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), 280 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
287 skb->data, skb->len, p54u_tx_cb, skb); 281 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
282 p54u_tx_cb : p54u_tx_dummy_cb, skb);
288 data_urb->transfer_flags |= URB_ZERO_PACKET; 283 data_urb->transfer_flags |= URB_ZERO_PACKET;
289 284
290 usb_anchor_urb(data_urb, &priv->submitted); 285 usb_anchor_urb(data_urb, &priv->submitted);
291 if (usb_submit_urb(data_urb, GFP_ATOMIC)) { 286 if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
292 usb_unanchor_urb(data_urb); 287 usb_unanchor_urb(data_urb);
293 skb_pull(skb, sizeof(*hdr));
294 p54_free_skb(dev, skb); 288 p54_free_skb(dev, skb);
295 } 289 }
296 usb_free_urb(data_urb); 290 usb_free_urb(data_urb);
@@ -300,11 +294,9 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
300{ 294{
301 struct p54u_priv *priv = dev->priv; 295 struct p54u_priv *priv = dev->priv;
302 struct urb *int_urb, *data_urb; 296 struct urb *int_urb, *data_urb;
303 struct net2280_tx_hdr *hdr; 297 struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
304 struct net2280_reg_write *reg; 298 struct net2280_reg_write *reg;
305 int err = 0; 299 int err = 0;
306 __le32 addr = ((struct p54_hdr *) skb->data)->req_id;
307 __le16 len = cpu_to_le16(skb->len);
308 300
309 reg = kmalloc(sizeof(*reg), GFP_ATOMIC); 301 reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
310 if (!reg) 302 if (!reg)
@@ -327,10 +319,9 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
327 reg->addr = cpu_to_le32(P54U_DEV_BASE); 319 reg->addr = cpu_to_le32(P54U_DEV_BASE);
328 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA); 320 reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
329 321
330 hdr = (void *)skb_push(skb, sizeof(*hdr));
331 memset(hdr, 0, sizeof(*hdr)); 322 memset(hdr, 0, sizeof(*hdr));
332 hdr->len = len; 323 hdr->len = cpu_to_le16(skb->len);
333 hdr->device_addr = addr; 324 hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
334 325
335 usb_fill_bulk_urb(int_urb, priv->udev, 326 usb_fill_bulk_urb(int_urb, priv->udev,
336 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg), 327 usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
@@ -345,7 +336,8 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
345 336
346 usb_fill_bulk_urb(data_urb, priv->udev, 337 usb_fill_bulk_urb(data_urb, priv->udev,
347 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), 338 usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
348 skb->data, skb->len, p54u_tx_cb, skb); 339 hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
340 p54u_tx_cb : p54u_tx_dummy_cb, skb);
349 341
350 usb_anchor_urb(int_urb, &priv->submitted); 342 usb_anchor_urb(int_urb, &priv->submitted);
351 err = usb_submit_urb(int_urb, GFP_ATOMIC); 343 err = usb_submit_urb(int_urb, GFP_ATOMIC);