aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Wahren <stefan.wahren@i2se.com>2018-07-15 15:53:20 -0400
committerDavid S. Miller <davem@davemloft.net>2018-07-16 17:12:56 -0400
commitdea39aca1d7aef1e2b95b07edeacf04cc8863a2e (patch)
treedb097b90902be7acd610d3064edea3f10b67c826
parentb5d2d75e079a918be686957b1a8d2f6c5cc95a0a (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.c5
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);