diff options
author | Stefan Wahren <stefan.wahren@i2se.com> | 2018-07-15 15:53:20 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-07-16 17:12:56 -0400 |
commit | dea39aca1d7aef1e2b95b07edeacf04cc8863a2e (patch) | |
tree | db097b90902be7acd610d3064edea3f10b67c826 | |
parent | b5d2d75e079a918be686957b1a8d2f6c5cc95a0a (diff) |
net: lan78xx: Fix race in tx pending skb size calculation
The skb size calculation in lan78xx_tx_bh is in race with the start_xmit,
which could lead to rare kernel oopses. So protect the whole skb walk with
a spin lock. As a benefit we can unlink the skb directly.
This patch was tested on Raspberry Pi 3B+
Link: https://github.com/raspberrypi/linux/issues/2608
Fixes: 55d7de9de6c3 ("Microchip's LAN7800 family USB 2/3 to 10/100/1000 Ethernet")
Cc: stable <stable@vger.kernel.org>
Signed-off-by: Floris Bos <bos@je-eigen-domein.nl>
Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/usb/lan78xx.c | 5 |
1 files changed, 4 insertions, 1 deletions
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 2e4130746c40..ed10d49eb5e0 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c | |||
@@ -3344,6 +3344,7 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev) | |||
3344 | pkt_cnt = 0; | 3344 | pkt_cnt = 0; |
3345 | count = 0; | 3345 | count = 0; |
3346 | length = 0; | 3346 | length = 0; |
3347 | spin_lock_irqsave(&tqp->lock, flags); | ||
3347 | for (skb = tqp->next; pkt_cnt < tqp->qlen; skb = skb->next) { | 3348 | for (skb = tqp->next; pkt_cnt < tqp->qlen; skb = skb->next) { |
3348 | if (skb_is_gso(skb)) { | 3349 | if (skb_is_gso(skb)) { |
3349 | if (pkt_cnt) { | 3350 | if (pkt_cnt) { |
@@ -3352,7 +3353,8 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev) | |||
3352 | } | 3353 | } |
3353 | count = 1; | 3354 | count = 1; |
3354 | length = skb->len - TX_OVERHEAD; | 3355 | length = skb->len - TX_OVERHEAD; |
3355 | skb2 = skb_dequeue(tqp); | 3356 | __skb_unlink(skb, tqp); |
3357 | spin_unlock_irqrestore(&tqp->lock, flags); | ||
3356 | goto gso_skb; | 3358 | goto gso_skb; |
3357 | } | 3359 | } |
3358 | 3360 | ||
@@ -3361,6 +3363,7 @@ static void lan78xx_tx_bh(struct lan78xx_net *dev) | |||
3361 | skb_totallen = skb->len + roundup(skb_totallen, sizeof(u32)); | 3363 | skb_totallen = skb->len + roundup(skb_totallen, sizeof(u32)); |
3362 | pkt_cnt++; | 3364 | pkt_cnt++; |
3363 | } | 3365 | } |
3366 | spin_unlock_irqrestore(&tqp->lock, flags); | ||
3364 | 3367 | ||
3365 | /* copy to a single skb */ | 3368 | /* copy to a single skb */ |
3366 | skb = alloc_skb(skb_totallen, GFP_ATOMIC); | 3369 | skb = alloc_skb(skb_totallen, GFP_ATOMIC); |