| From ebaa4b1620bf69f2bc43cb45ea85fbafdaec23c3 Mon Sep 17 00:00:00 2001 |
| From: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com> |
| Date: Mon, 10 Oct 2016 19:51:18 +0530 |
| Subject: ath10k: fix kernel panic due to race in accessing arvif list |
| |
| From: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com> |
| |
| commit ebaa4b1620bf69f2bc43cb45ea85fbafdaec23c3 upstream. |
| |
| arvifs list is traversed within data_lock spin_lock in tasklet |
| context to fill channel information from the corresponding vif. |
| This means any access to arvifs list for add/del operations |
| should also be protected with the same spin_lock to avoid the |
| race. Fix this by performing list add/del on arvfis within the |
| data_lock. This could fix kernel panic something like the below. |
| |
| LR is at ath10k_htt_rx_pktlog_completion_handler+0x100/0xb6c [ath10k_core] |
| PC is at ath10k_htt_rx_pktlog_completion_handler+0x1c0/0xb6c [ath10k_core] |
| Internal error: Oops: 17 [#1] PREEMPT SMP ARM |
| [<bf4857f4>] (ath10k_htt_rx_pktlog_completion_handler+0x2f4/0xb6c [ath10k_core]) |
| [<bf487540>] (ath10k_htt_txrx_compl_task+0x8b4/0x1188 [ath10k_core]) |
| [<c00312d4>] (tasklet_action+0x8c/0xec) |
| [<c00309a8>] (__do_softirq+0xdc/0x208) |
| [<c0030d6c>] (irq_exit+0x84/0xe0) |
| [<c005db04>] (__handle_domain_irq+0x80/0xa0) |
| [<c00085c4>] (gic_handle_irq+0x38/0x5c) |
| [<c0009640>] (__irq_svc+0x40/0x74) |
| |
| (gdb) list *(ath10k_htt_rx_pktlog_completion_handler+0x1c0) |
| 0x136c0 is in ath10k_htt_rx_h_channel (drivers/net/wireless/ath/ath10k/htt_rx.c:769) |
| 764 struct cfg80211_chan_def def; |
| 765 |
| 766 lockdep_assert_held(&ar->data_lock); |
| 767 |
| 768 list_for_each_entry(arvif, &ar->arvifs, list) { |
| 769 if (arvif->vdev_id == vdev_id && |
| 770 ath10k_mac_vif_chan(arvif->vif, &def) == 0) |
| 771 return def.chan; |
| 772 } |
| 773 |
| |
| Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com> |
| Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com> |
| Signed-off-by: Amit Pundir <amit.pundir@linaro.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/net/wireless/ath/ath10k/mac.c | 6 ++++++ |
| 1 file changed, 6 insertions(+) |
| |
| --- a/drivers/net/wireless/ath/ath10k/mac.c |
| +++ b/drivers/net/wireless/ath/ath10k/mac.c |
| @@ -4470,7 +4470,9 @@ static int ath10k_add_interface(struct i |
| } |
| |
| ar->free_vdev_map &= ~(1LL << arvif->vdev_id); |
| + spin_lock_bh(&ar->data_lock); |
| list_add(&arvif->list, &ar->arvifs); |
| + spin_unlock_bh(&ar->data_lock); |
| |
| /* It makes no sense to have firmware do keepalives. mac80211 already |
| * takes care of this with idle connection polling. |
| @@ -4603,7 +4605,9 @@ err_peer_delete: |
| err_vdev_delete: |
| ath10k_wmi_vdev_delete(ar, arvif->vdev_id); |
| ar->free_vdev_map |= 1LL << arvif->vdev_id; |
| + spin_lock_bh(&ar->data_lock); |
| list_del(&arvif->list); |
| + spin_unlock_bh(&ar->data_lock); |
| |
| err: |
| if (arvif->beacon_buf) { |
| @@ -4647,7 +4651,9 @@ static void ath10k_remove_interface(stru |
| arvif->vdev_id, ret); |
| |
| ar->free_vdev_map |= 1LL << arvif->vdev_id; |
| + spin_lock_bh(&ar->data_lock); |
| list_del(&arvif->list); |
| + spin_unlock_bh(&ar->data_lock); |
| |
| if (arvif->vdev_type == WMI_VDEV_TYPE_AP || |
| arvif->vdev_type == WMI_VDEV_TYPE_IBSS) { |