Commit c3883876d3f154d4eb3c9a4406c0489996806e0d
Committed by
Greg Kroah-Hartman
1 parent
b1d629d329
rhashtable: Fix unprotected RCU dereference in __rht_ptr
[ Upstream commit 1748f6a2cbc4694523f16da1c892b59861045b9d ] The rcu_dereference call in rht_ptr_rcu is completely bogus because we've already dereferenced the value in __rht_ptr and operated on it. This causes potential double readings which could be fatal. The RCU dereference must occur prior to the comparison in __rht_ptr. This patch changes the order of RCU dereference so that it is done first and the result is then fed to __rht_ptr. The RCU marking changes have been minimised using casts which will be removed in a follow-up patch. Fixes: ba6306e3f648 ("rhashtable: Remove RCU marking from...") Reported-by: "Gong, Sishuai" <sishuai@purdue.edu> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Sasha Levin <sashal@kernel.org>
Showing 1 changed file with 13 additions and 12 deletions Side-by-side Diff
include/linux/rhashtable.h
... | ... | @@ -349,11 +349,11 @@ |
349 | 349 | local_bh_enable(); |
350 | 350 | } |
351 | 351 | |
352 | -static inline struct rhash_head __rcu *__rht_ptr( | |
353 | - struct rhash_lock_head *const *bkt) | |
352 | +static inline struct rhash_head *__rht_ptr( | |
353 | + struct rhash_lock_head *p, struct rhash_lock_head __rcu *const *bkt) | |
354 | 354 | { |
355 | - return (struct rhash_head __rcu *) | |
356 | - ((unsigned long)*bkt & ~BIT(0) ?: | |
355 | + return (struct rhash_head *) | |
356 | + ((unsigned long)p & ~BIT(0) ?: | |
357 | 357 | (unsigned long)RHT_NULLS_MARKER(bkt)); |
358 | 358 | } |
359 | 359 | |
360 | 360 | |
361 | 361 | |
362 | 362 | |
363 | 363 | |
364 | 364 | |
... | ... | @@ -365,25 +365,26 @@ |
365 | 365 | * access is guaranteed, such as when destroying the table. |
366 | 366 | */ |
367 | 367 | static inline struct rhash_head *rht_ptr_rcu( |
368 | - struct rhash_lock_head *const *bkt) | |
368 | + struct rhash_lock_head *const *p) | |
369 | 369 | { |
370 | - struct rhash_head __rcu *p = __rht_ptr(bkt); | |
371 | - | |
372 | - return rcu_dereference(p); | |
370 | + struct rhash_lock_head __rcu *const *bkt = (void *)p; | |
371 | + return __rht_ptr(rcu_dereference(*bkt), bkt); | |
373 | 372 | } |
374 | 373 | |
375 | 374 | static inline struct rhash_head *rht_ptr( |
376 | - struct rhash_lock_head *const *bkt, | |
375 | + struct rhash_lock_head *const *p, | |
377 | 376 | struct bucket_table *tbl, |
378 | 377 | unsigned int hash) |
379 | 378 | { |
380 | - return rht_dereference_bucket(__rht_ptr(bkt), tbl, hash); | |
379 | + struct rhash_lock_head __rcu *const *bkt = (void *)p; | |
380 | + return __rht_ptr(rht_dereference_bucket(*bkt, tbl, hash), bkt); | |
381 | 381 | } |
382 | 382 | |
383 | 383 | static inline struct rhash_head *rht_ptr_exclusive( |
384 | - struct rhash_lock_head *const *bkt) | |
384 | + struct rhash_lock_head *const *p) | |
385 | 385 | { |
386 | - return rcu_dereference_protected(__rht_ptr(bkt), 1); | |
386 | + struct rhash_lock_head __rcu *const *bkt = (void *)p; | |
387 | + return __rht_ptr(rcu_dereference_protected(*bkt, 1), bkt); | |
387 | 388 | } |
388 | 389 | |
389 | 390 | static inline void rht_assign_locked(struct rhash_lock_head **bkt, |