summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSven Eckelmann <sven@narfation.org>2014-11-03 23:38:47 +0100
committerHauke Mehrtens <hauke@hauke-m.de>2014-12-21 19:04:56 +0100
commit5e7e6f1e9ce4dbbc37be8efd7cf7d52a03d73b7b (patch)
tree79b02697f65dfc50f2840ece2575724977bfff4e
parent1f4af51943861539df14c1d1cf6c36c8af65cc9c (diff)
backport: Fix double fetch in hlist_for_each_entry*_rcu
Upstream commit: 3a1429a6e59f0e61720bb523e3b93d015a9fa63a 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. This is also the approach used in the current Linux versions and was introduced by Paul E. McKenney. Signed-off-by: Sven Eckelmann <sven@narfation.org> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
-rw-r--r--backport/backport-include/linux/list.h4
1 files changed, 3 insertions, 1 deletions
diff --git a/backport/backport-include/linux/list.h b/backport/backport-include/linux/list.h
index 90428307..5ac26156 100644
--- a/backport/backport-include/linux/list.h
+++ b/backport/backport-include/linux/list.h
@@ -17,7 +17,9 @@
#undef hlist_entry_safe
#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; \
+ })
#define hlist_for_each_entry4(tpos, pos, head, member) \
for (pos = (head)->first; \