| From c2e703a55245bfff3db53b1f7cbe59f1ee8a4339 Mon Sep 17 00:00:00 2001 |
| From: Johannes Berg <johannes.berg@intel.com> |
| Date: Tue, 17 Nov 2015 14:25:21 +0100 |
| Subject: mac80211: mesh: fix call_rcu() usage |
| |
| commit c2e703a55245bfff3db53b1f7cbe59f1ee8a4339 upstream. |
| |
| When using call_rcu(), the called function may be delayed quite |
| significantly, and without a matching rcu_barrier() there's no |
| way to be sure it has finished. |
| Therefore, global state that could be gone/freed/reused should |
| never be touched in the callback. |
| |
| Fix this in mesh by moving the atomic_dec() into the caller; |
| that's not really a problem since we already unlinked the path |
| and it will be destroyed anyway. |
| |
| This fixes a crash Jouni observed when running certain tests in |
| a certain order, in which the mesh interface was torn down, the |
| memory reused for a function pointer (work struct) and running |
| that then crashed since the pointer had been decremented by 1, |
| resulting in an invalid instruction byte stream. |
| |
| Fixes: eb2b9311fd00 ("mac80211: mesh path table implementation") |
| Reported-by: Jouni Malinen <j@w1.fi> |
| Signed-off-by: Johannes Berg <johannes.berg@intel.com> |
| Signed-off-by: Zefan Li <lizefan@huawei.com> |
| --- |
| net/mac80211/mesh_pathtbl.c | 8 ++++---- |
| 1 file changed, 4 insertions(+), 4 deletions(-) |
| |
| --- a/net/mac80211/mesh_pathtbl.c |
| +++ b/net/mac80211/mesh_pathtbl.c |
| @@ -757,10 +757,8 @@ void mesh_plink_broken(struct sta_info * |
| static void mesh_path_node_reclaim(struct rcu_head *rp) |
| { |
| struct mpath_node *node = container_of(rp, struct mpath_node, rcu); |
| - struct ieee80211_sub_if_data *sdata = node->mpath->sdata; |
| |
| del_timer_sync(&node->mpath->timer); |
| - atomic_dec(&sdata->u.mesh.mpaths); |
| kfree(node->mpath); |
| kfree(node); |
| } |
| @@ -768,8 +766,9 @@ static void mesh_path_node_reclaim(struc |
| /* needs to be called with the corresponding hashwlock taken */ |
| static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node) |
| { |
| - struct mesh_path *mpath; |
| - mpath = node->mpath; |
| + struct mesh_path *mpath = node->mpath; |
| + struct ieee80211_sub_if_data *sdata = node->mpath->sdata; |
| + |
| spin_lock(&mpath->state_lock); |
| mpath->flags |= MESH_PATH_RESOLVING; |
| if (mpath->is_gate) |
| @@ -777,6 +776,7 @@ static void __mesh_path_del(struct mesh_ |
| hlist_del_rcu(&node->list); |
| call_rcu(&node->rcu, mesh_path_node_reclaim); |
| spin_unlock(&mpath->state_lock); |
| + atomic_dec(&sdata->u.mesh.mpaths); |
| atomic_dec(&tbl->entries); |
| } |
| |