0471-enc28j60-Fix-race-condition-in-enc28j60-driver.patch 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. From edfa1131e425e0dafe9561fee792a0d319fa734e Mon Sep 17 00:00:00 2001
  2. From: Sergio Valverde <sergio.valverde@hpe.com>
  3. Date: Fri, 1 Jul 2016 11:44:30 -0600
  4. Subject: [PATCH] enc28j60: Fix race condition in enc28j60 driver
  5. (Upstream commit 373819ec391de0d11f63b10b2fb69ef2854236ca)
  6. The interrupt worker code for the enc28j60 relies only on the TXIF flag to
  7. determinate if the packet transmission was completed. However the datasheet
  8. specifies in section 12.1.3 that TXERIF will clear the TXRTS after a
  9. transmit abort. Also in section 12.1.4 that TXIF will be set
  10. when TXRTS transitions from '1' to '0'. Therefore the TXIF flag is enabled
  11. during transmission errors.
  12. This causes a race condition, since the worker code will invoke
  13. enc28j60_tx_clear() -> netif_wake_queue(), potentially invoking the
  14. ndo_start_xmit function to send a new packet. The enc28j60_send_packet function
  15. uses a workqueue that invokes enc28j60_hw_tx(). In between this function is
  16. called, the worker from the interrupt handler will enter the path for error
  17. handler because of the TXERIF flag, causing to invoke enc28j60_tx_clear() again
  18. and releasing the packet scheduled for transmission, causing a kernel crash with
  19. due a NULL pointer.
  20. These crashes due a NULL pointer were observed under stress conditions of the
  21. device. A BUG_ON() sequence was used to validate the issue was fixed, and has
  22. been running without problems for 2 years now.
  23. Signed-off-by: Diego Dompe <dompe@hpe.com>
  24. Acked-by: Sergio Valverde <sergio.valverde@hpe.com>
  25. Signed-off-by: David S. Miller <davem@davemloft.net>
  26. ---
  27. drivers/net/ethernet/microchip/enc28j60.c | 7 +++++--
  28. 1 file changed, 5 insertions(+), 2 deletions(-)
  29. --- a/drivers/net/ethernet/microchip/enc28j60.c
  30. +++ b/drivers/net/ethernet/microchip/enc28j60.c
  31. @@ -1147,7 +1147,8 @@ static void enc28j60_irq_work_handler(st
  32. enc28j60_phy_read(priv, PHIR);
  33. }
  34. /* TX complete handler */
  35. - if ((intflags & EIR_TXIF) != 0) {
  36. + if (((intflags & EIR_TXIF) != 0) &&
  37. + ((intflags & EIR_TXERIF) == 0)) {
  38. bool err = false;
  39. loop++;
  40. if (netif_msg_intr(priv))
  41. @@ -1199,7 +1200,7 @@ static void enc28j60_irq_work_handler(st
  42. enc28j60_tx_clear(ndev, true);
  43. } else
  44. enc28j60_tx_clear(ndev, true);
  45. - locked_reg_bfclr(priv, EIR, EIR_TXERIF);
  46. + locked_reg_bfclr(priv, EIR, EIR_TXERIF | EIR_TXIF);
  47. }
  48. /* RX Error handler */
  49. if ((intflags & EIR_RXERIF) != 0) {
  50. @@ -1234,6 +1235,8 @@ static void enc28j60_irq_work_handler(st
  51. */
  52. static void enc28j60_hw_tx(struct enc28j60_net *priv)
  53. {
  54. + BUG_ON(!priv->tx_skb);
  55. +
  56. if (netif_msg_tx_queued(priv))
  57. printk(KERN_DEBUG DRV_NAME
  58. ": Tx Packet Len:%d\n", priv->tx_skb->len);