Commit e2fe154e authored by Christian Lamparter's avatar Christian Lamparter Committed by John W. Linville

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: default avatarChristian Lamparter <chunkeey@web.de>
Tested-by: default avatarArtur Skawina <art.08.09@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 12da401e
...@@ -144,10 +144,7 @@ static void p54u_tx_cb(struct urb *urb) ...@@ -144,10 +144,7 @@ static void p54u_tx_cb(struct urb *urb)
struct sk_buff *skb = urb->context; struct sk_buff *skb = urb->context;
struct ieee80211_hw *dev = (struct ieee80211_hw *) struct ieee80211_hw *dev = (struct ieee80211_hw *)
usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
struct p54u_priv *priv = dev->priv;
skb_pull(skb, priv->common.tx_hdr_len);
if (FREE_AFTER_TX(skb))
p54_free_skb(dev, skb); p54_free_skb(dev, skb);
} }
...@@ -230,7 +227,8 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb) ...@@ -230,7 +227,8 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb)
p54u_tx_dummy_cb, dev); p54u_tx_dummy_cb, dev);
usb_fill_bulk_urb(data_urb, priv->udev, usb_fill_bulk_urb(data_urb, priv->udev,
usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
skb->data, skb->len, p54u_tx_cb, skb); skb->data, skb->len, FREE_AFTER_TX(skb) ?
p54u_tx_cb : p54u_tx_dummy_cb, skb);
usb_anchor_urb(addr_urb, &priv->submitted); usb_anchor_urb(addr_urb, &priv->submitted);
err = usb_submit_urb(addr_urb, GFP_ATOMIC); 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,28 +267,24 @@ static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
{ {
struct p54u_priv *priv = dev->priv; struct p54u_priv *priv = dev->priv;
struct urb *data_urb; struct urb *data_urb;
struct lm87_tx_hdr *hdr; struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
__le32 checksum;
__le32 addr = ((struct p54_hdr *)skb->data)->req_id;
data_urb = usb_alloc_urb(0, GFP_ATOMIC); data_urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!data_urb) if (!data_urb)
return; return;
checksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len); hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
hdr = (struct lm87_tx_hdr *)skb_push(skb, sizeof(*hdr)); hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
hdr->chksum = checksum;
hdr->device_addr = addr;
usb_fill_bulk_urb(data_urb, priv->udev, usb_fill_bulk_urb(data_urb, priv->udev,
usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
skb->data, skb->len, p54u_tx_cb, skb); hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
p54u_tx_cb : p54u_tx_dummy_cb, skb);
data_urb->transfer_flags |= URB_ZERO_PACKET; data_urb->transfer_flags |= URB_ZERO_PACKET;
usb_anchor_urb(data_urb, &priv->submitted); usb_anchor_urb(data_urb, &priv->submitted);
if (usb_submit_urb(data_urb, GFP_ATOMIC)) { if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
usb_unanchor_urb(data_urb); usb_unanchor_urb(data_urb);
skb_pull(skb, sizeof(*hdr));
p54_free_skb(dev, skb); p54_free_skb(dev, skb);
} }
usb_free_urb(data_urb); usb_free_urb(data_urb);
...@@ -300,11 +294,9 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb) ...@@ -300,11 +294,9 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
{ {
struct p54u_priv *priv = dev->priv; struct p54u_priv *priv = dev->priv;
struct urb *int_urb, *data_urb; struct urb *int_urb, *data_urb;
struct net2280_tx_hdr *hdr; struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
struct net2280_reg_write *reg; struct net2280_reg_write *reg;
int err = 0; int err = 0;
__le32 addr = ((struct p54_hdr *) skb->data)->req_id;
__le16 len = cpu_to_le16(skb->len);
reg = kmalloc(sizeof(*reg), GFP_ATOMIC); reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
if (!reg) if (!reg)
...@@ -327,10 +319,9 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb) ...@@ -327,10 +319,9 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
reg->addr = cpu_to_le32(P54U_DEV_BASE); reg->addr = cpu_to_le32(P54U_DEV_BASE);
reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA); reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
hdr = (void *)skb_push(skb, sizeof(*hdr));
memset(hdr, 0, sizeof(*hdr)); memset(hdr, 0, sizeof(*hdr));
hdr->len = len; hdr->len = cpu_to_le16(skb->len);
hdr->device_addr = addr; hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
usb_fill_bulk_urb(int_urb, priv->udev, usb_fill_bulk_urb(int_urb, priv->udev,
usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg), 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,7 +336,8 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
usb_fill_bulk_urb(data_urb, priv->udev, usb_fill_bulk_urb(data_urb, priv->udev,
usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
skb->data, skb->len, p54u_tx_cb, skb); hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
p54u_tx_cb : p54u_tx_dummy_cb, skb);
usb_anchor_urb(int_urb, &priv->submitted); usb_anchor_urb(int_urb, &priv->submitted);
err = usb_submit_urb(int_urb, GFP_ATOMIC); err = usb_submit_urb(int_urb, GFP_ATOMIC);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment