diff options
Diffstat (limited to 'debian/patches/features/all/ena/0017-net-ena-fix-crash-during-ena_remove.patch')
-rw-r--r-- | debian/patches/features/all/ena/0017-net-ena-fix-crash-during-ena_remove.patch | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/debian/patches/features/all/ena/0017-net-ena-fix-crash-during-ena_remove.patch b/debian/patches/features/all/ena/0017-net-ena-fix-crash-during-ena_remove.patch new file mode 100644 index 000000000..59f2b13b7 --- /dev/null +++ b/debian/patches/features/all/ena/0017-net-ena-fix-crash-during-ena_remove.patch @@ -0,0 +1,97 @@ +From: Arthur Kiyanovski <akiyano@amazon.com> +Date: Mon, 19 Nov 2018 12:05:21 +0200 +Subject: [PATCH 18/19] net: ena: fix crash during ena_remove() +Origin: https://git.kernel.org/linus/58a54b9c62e206b8d5f6e59020bcb178fc271d8e + +In ena_remove() we have the following stack call: +ena_remove() + unregister_netdev() + ena_destroy_device() + netif_carrier_off() + +Calling netif_carrier_off() causes linkwatch to try to handle the +link change event on the already unregistered netdev, which leads +to a read from an unreadable memory address. + +This patch switches the order of the two functions, so that +netif_carrier_off() is called on a regiestered netdev. + +To accomplish this fix we also had to: +1. Remove the set bit ENA_FLAG_TRIGGER_RESET +2. Add a sanitiy check in ena_close() +both to prevent double device reset (when calling unregister_netdev() +ena_close is called, but the device was already deleted in +ena_destroy_device()). +3. Set the admin_queue running state to false to avoid using it after +device was reset (for example when calling ena_destroy_all_io_queues() +right after ena_com_dev_reset() in ena_down) + +Fixes: 944b28aa2982 ("net: ena: fix missing lock during device destruction") +Signed-off-by: Arthur Kiyanovski <akiyano@amazon.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +--- + drivers/net/ethernet/amazon/ena/ena_netdev.c | 21 ++++++++++---------- + 1 file changed, 10 insertions(+), 11 deletions(-) + +--- a/drivers/net/ethernet/amazon/ena/ena_netdev.c ++++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c +@@ -1853,6 +1853,8 @@ static void ena_down(struct ena_adapter + rc = ena_com_dev_reset(adapter->ena_dev, adapter->reset_reason); + if (rc) + dev_err(&adapter->pdev->dev, "Device reset failed\n"); ++ /* stop submitting admin commands on a device that was reset */ ++ ena_com_set_admin_running_state(adapter->ena_dev, false); + } + + ena_destroy_all_io_queues(adapter); +@@ -1919,6 +1921,9 @@ static int ena_close(struct net_device * + + netif_dbg(adapter, ifdown, netdev, "%s\n", __func__); + ++ if (!test_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags)) ++ return 0; ++ + if (test_bit(ENA_FLAG_DEV_UP, &adapter->flags)) + ena_down(adapter); + +@@ -2618,9 +2623,7 @@ static void ena_destroy_device(struct en + ena_down(adapter); + + /* Stop the device from sending AENQ events (in case reset flag is set +- * and device is up, ena_close already reset the device +- * In case the reset flag is set and the device is up, ena_down() +- * already perform the reset, so it can be skipped. ++ * and device is up, ena_down() already reset the device. + */ + if (!(test_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags) && dev_up)) + ena_com_dev_reset(adapter->ena_dev, adapter->reset_reason); +@@ -3455,6 +3458,8 @@ err_rss: + ena_com_rss_destroy(ena_dev); + err_free_msix: + ena_com_dev_reset(ena_dev, ENA_REGS_RESET_INIT_ERR); ++ /* stop submitting admin commands on a device that was reset */ ++ ena_com_set_admin_running_state(ena_dev, false); + ena_free_mgmnt_irq(adapter); + ena_disable_msix(adapter); + err_worker_destroy: +@@ -3504,18 +3509,12 @@ static void ena_remove(struct pci_dev *p + del_timer_sync(&adapter->timer_service); + cancel_work_sync(&adapter->reset_task); + +- unregister_netdev(netdev); +- +- /* If the device is running then we want to make sure the device will be +- * reset to make sure no more events will be issued by the device. +- */ +- if (test_bit(ENA_FLAG_DEVICE_RUNNING, &adapter->flags)) +- set_bit(ENA_FLAG_TRIGGER_RESET, &adapter->flags); +- + rtnl_lock(); + ena_destroy_device(adapter, true); + rtnl_unlock(); + ++ unregister_netdev(netdev); ++ + free_netdev(netdev); + + ena_com_rss_destroy(ena_dev); |