Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ba7c95ea authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller
Browse files

rhashtable: Fix sleeping inside RCU critical section in walk_stop



The commit 963ecbd4 ("rhashtable:
Fix use-after-free in rhashtable_walk_stop") fixed a real bug
but created another one because we may end up sleeping inside an
RCU critical section.

This patch fixes it properly by replacing the mutex with a spin
lock that specifically protects the walker lists.

Reported-by: default avatarSasha Levin <sasha.levin@oracle.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ce046c56
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -133,6 +133,7 @@ struct rhashtable_params {
 * @p: Configuration parameters
 * @run_work: Deferred worker to expand/shrink asynchronously
 * @mutex: Mutex to protect current/future table swapping
 * @lock: Spin lock to protect walker list
 * @being_destroyed: True if table is set up for destruction
 */
struct rhashtable {
@@ -144,6 +145,7 @@ struct rhashtable {
	struct rhashtable_params	p;
	struct work_struct		run_work;
	struct mutex                    mutex;
	spinlock_t			lock;
};

/**
+5 −2
Original line number Diff line number Diff line
@@ -256,8 +256,10 @@ static int rhashtable_rehash_table(struct rhashtable *ht)
	/* Publish the new table pointer. */
	rcu_assign_pointer(ht->tbl, new_tbl);

	spin_lock(&ht->lock);
	list_for_each_entry(walker, &old_tbl->walkers, list)
		walker->tbl = NULL;
	spin_unlock(&ht->lock);

	/* Wait for readers. All new readers will see the new
	 * table, and thus no references to the old table will
@@ -635,12 +637,12 @@ void rhashtable_walk_stop(struct rhashtable_iter *iter)

	ht = iter->ht;

	mutex_lock(&ht->mutex);
	spin_lock(&ht->lock);
	if (tbl->rehash < tbl->size)
		list_add(&iter->walker->list, &tbl->walkers);
	else
		iter->walker->tbl = NULL;
	mutex_unlock(&ht->mutex);
	spin_unlock(&ht->lock);

	iter->p = NULL;

@@ -723,6 +725,7 @@ int rhashtable_init(struct rhashtable *ht,

	memset(ht, 0, sizeof(*ht));
	mutex_init(&ht->mutex);
	spin_lock_init(&ht->lock);
	memcpy(&ht->p, params, sizeof(*params));

	if (params->min_size)