Repository : ssh://git@open-mesh.org/batman-adv
On branch : maint
commit 1e4a96a4cfdfdf57fecacf1c8fa493345a9fcc03 Author: Sven Eckelmann sven@narfation.org Date: Mon Nov 3 23:16:19 2014 +0100
batman-adv: Fix double fetch in RCU version of hlist_*entry*
The backported (<3.9) version of hlist_for_each_entry_rcu and hlist_for_each_entry_safe uses the new macro hlist_entry_safe. It is called with an ACCESS_ONCE parameter for the first parameter ptr. This disallows merging of the two loads which the current version of the macro uses.
This is problematic because this macro must only generate one load. Otherwise with two contexts (or CPUs) following could happen:
1. context 1 fetches the ptr to the last entry in hlist_entry_safe() and accepts this non-NULL ptr
2. context 2 deletes the last entry and terminates the list with NULL
3. context 1 re-fetches the pointer, doesn't check for zero, calculates the entry based on a NULL pointer
4. context 1 crashes because it tries to load/write data from/to the invalid address
Instead use a single load to a temporary variable and do the NULL-check and calculation based on that one.
Signed-off-by: Sven Eckelmann sven@narfation.org Signed-off-by: Marek Lindner mareklindner@neomailbox.ch
1e4a96a4cfdfdf57fecacf1c8fa493345a9fcc03 compat.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/compat.h b/compat.h index 5eb5fe6..79ba39b 100644 --- a/compat.h +++ b/compat.h @@ -345,7 +345,9 @@ static int __batadv_interface_tx(struct sk_buff *skb, \ dev->master;\ }) #define hlist_entry_safe(ptr, type, member) \ - (ptr) ? hlist_entry(ptr, type, member) : NULL + ({ typeof(ptr) ____ptr = (ptr); \ + ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ + })
#undef hlist_for_each_entry #define hlist_for_each_entry(pos, head, member) \