My static analyzer identified a potential issue in 'net/mac80211/mesh_pathtbl.c': mpath_expired() reads mpath->flags and mpath->exp_time without holding mpath->state_lock, while mesh_path_fix_nexthop() and the other writers update both fields under that lock. In mpath_lookup() and __mesh_path_lookup_by_idx() the unlocked check is followed by taking the lock and clearing MESH_PATH_ACTIVE, so the check and the update are not atomic: CPU0 (mpath_lookup) CPU1 (mesh_path_fix_nexthop) mpath_expired() reads the stale flags/exp_time and returns true spin_lock_bh(&mpath->state_lock) mpath->exp_time = 0; mpath->flags = FIXED|SN_VALID; mesh_path_activate(mpath); spin_unlock_bh(&mpath->state_lock) spin_lock_bh(&mpath->state_lock) mpath->flags &= ~MESH_PATH_ACTIVE; spin_unlock_bh(&mpath->state_lock) A path which mesh_path_fix_nexthop() has just set up as MESH_PATH_FIXED and MESH_PATH_ACTIVE then has MESH_PATH_ACTIVE cleared again, and forwarding to that destination silently stops. Take mpath->state_lock before evaluating mpath_expired() so that the check and the clearing of MESH_PATH_ACTIVE are atomic with respect to the writers. Fixes: 60854fd94573 ("mac80211: mesh: convert path table to rhashtable") Signed-off-by: Ginger Li --- net/mac80211/mesh_pathtbl.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -247,9 +247,10 @@ static struct mesh_path *mpath_lookup(struct mesh_tabl mpath = rhashtable_lookup(&tbl->rhead, dst, mesh_rht_params); - if (mpath && mpath_expired(mpath)) { + if (mpath) { spin_lock_bh(&mpath->state_lock); - mpath->flags &= ~MESH_PATH_ACTIVE; + if (mpath_expired(mpath)) + mpath->flags &= ~MESH_PATH_ACTIVE; spin_unlock_bh(&mpath->state_lock); } return mpath; @@ -290,11 +291,11 @@ __mesh_path_lookup_by_idx(struct mesh_table *tbl, int if (!mpath) return NULL; - if (mpath_expired(mpath)) { - spin_lock_bh(&mpath->state_lock); + spin_lock_bh(&mpath->state_lock); + if (mpath_expired(mpath)) mpath->flags &= ~MESH_PATH_ACTIVE; - spin_unlock_bh(&mpath->state_lock); - } + spin_unlock_bh(&mpath->state_lock); + return mpath; } -- 2.43.0