Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: Fix race condition in store_rps_map

There is a race condition in store_rps_map that allows jump label
count in rps_needed to go below zero. This can happen when
concurrently attempting to set and a clear map.

Scenario:

1. rps_needed count is zero
2. New map is assigned by setting thread, but rps_needed count _not_ yet
incremented (rps_needed count still zero)
2. Map is cleared by second thread, old_map set to that just assigned
3. Second thread performs static_key_slow_dec, rps_needed count now goes
negative

Fix is to increment or decrement rps_needed under the spinlock.

Signed-off-by: Tom Herbert <tom@herbertland.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Tom Herbert and committed by
David S. Miller
10e4ea75 e05176a3

+7 -4
+7 -4
net/core/net-sysfs.c
··· 726 726 old_map = rcu_dereference_protected(queue->rps_map, 727 727 lockdep_is_held(&rps_map_lock)); 728 728 rcu_assign_pointer(queue->rps_map, map); 729 - spin_unlock(&rps_map_lock); 730 729 731 730 if (map) 732 731 static_key_slow_inc(&rps_needed); 733 - if (old_map) { 734 - kfree_rcu(old_map, rcu); 732 + if (old_map) 735 733 static_key_slow_dec(&rps_needed); 736 - } 734 + 735 + spin_unlock(&rps_map_lock); 736 + 737 + if (old_map) 738 + kfree_rcu(old_map, rcu); 739 + 737 740 free_cpumask_var(mask); 738 741 return len; 739 742 }