Skip to content

Commit 1748f6a

Browse files
herbertxdavem330
authored andcommitted
rhashtable: Fix unprotected RCU dereference in __rht_ptr
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: ba6306e ("rhashtable: Remove RCU marking from...") Reported-by: "Gong, Sishuai" <[email protected]> Signed-off-by: Herbert Xu <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 19016d9 commit 1748f6a

File tree

1 file changed

+13
-12
lines changed

1 file changed

+13
-12
lines changed

include/linux/rhashtable.h

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -349,11 +349,11 @@ static inline void rht_unlock(struct bucket_table *tbl,
349349
local_bh_enable();
350350
}
351351

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)
354354
{
355-
return (struct rhash_head __rcu *)
356-
((unsigned long)*bkt & ~BIT(0) ?:
355+
return (struct rhash_head *)
356+
((unsigned long)p & ~BIT(0) ?:
357357
(unsigned long)RHT_NULLS_MARKER(bkt));
358358
}
359359

@@ -365,25 +365,26 @@ static inline struct rhash_head __rcu *__rht_ptr(
365365
* access is guaranteed, such as when destroying the table.
366366
*/
367367
static inline struct rhash_head *rht_ptr_rcu(
368-
struct rhash_lock_head *const *bkt)
368+
struct rhash_lock_head *const *p)
369369
{
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);
373372
}
374373

375374
static inline struct rhash_head *rht_ptr(
376-
struct rhash_lock_head *const *bkt,
375+
struct rhash_lock_head *const *p,
377376
struct bucket_table *tbl,
378377
unsigned int hash)
379378
{
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);
381381
}
382382

383383
static inline struct rhash_head *rht_ptr_exclusive(
384-
struct rhash_lock_head *const *bkt)
384+
struct rhash_lock_head *const *p)
385385
{
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);
387388
}
388389

389390
static inline void rht_assign_locked(struct rhash_lock_head **bkt,

0 commit comments

Comments
 (0)