[PATCH] backport: Fix double fetch in hlist_for_each_entry*_rcu

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxxxx>
---
 backport/backport-include/linux/list.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/backport/backport-include/linux/list.h b/backport/backport-include/linux/list.h
index 9042830..5ac2615 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;					\
-- 
2.1.1

--
To unsubscribe from this list: send the line "unsubscribe backports" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux