RCU: Ensure that qp's are actually retired in order
The current retirement code for rcu qp's has a race condition,
which can cause use-after-free errors, but only if more than
3 QPs are allocated, which is not the default configuration.
This fixes an oversight in commit 5949918f9a
("Rework and
simplify RCU code")
Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/26952)
This commit is contained in:
parent
bcb8eae1af
commit
6e7be995fd
3 changed files with 16 additions and 8 deletions
|
@ -464,9 +464,6 @@ void ossl_synchronize_rcu(CRYPTO_RCU_LOCK *lock)
|
|||
pthread_mutex_lock(&lock->prior_lock);
|
||||
while (lock->next_to_retire != curr_id)
|
||||
pthread_cond_wait(&lock->prior_signal, &lock->prior_lock);
|
||||
lock->next_to_retire++;
|
||||
pthread_cond_broadcast(&lock->prior_signal);
|
||||
pthread_mutex_unlock(&lock->prior_lock);
|
||||
|
||||
/*
|
||||
* wait for the reader count to reach zero
|
||||
|
@ -479,6 +476,10 @@ void ossl_synchronize_rcu(CRYPTO_RCU_LOCK *lock)
|
|||
count = ATOMIC_LOAD_N(uint64_t, &qp->users, __ATOMIC_ACQUIRE);
|
||||
} while (count != (uint64_t)0);
|
||||
|
||||
lock->next_to_retire++;
|
||||
pthread_cond_broadcast(&lock->prior_signal);
|
||||
pthread_mutex_unlock(&lock->prior_lock);
|
||||
|
||||
retire_qp(lock, qp);
|
||||
|
||||
/* handle any callbacks that we have */
|
||||
|
|
|
@ -383,15 +383,15 @@ void ossl_synchronize_rcu(CRYPTO_RCU_LOCK *lock)
|
|||
while (lock->next_to_retire != curr_id)
|
||||
ossl_crypto_condvar_wait(lock->prior_signal, lock->prior_lock);
|
||||
|
||||
lock->next_to_retire++;
|
||||
ossl_crypto_condvar_broadcast(lock->prior_signal);
|
||||
ossl_crypto_mutex_unlock(lock->prior_lock);
|
||||
|
||||
/* wait for the reader count to reach zero */
|
||||
do {
|
||||
CRYPTO_atomic_load(&qp->users, &count, lock->rw_lock);
|
||||
} while (count != (uint64_t)0);
|
||||
|
||||
lock->next_to_retire++;
|
||||
ossl_crypto_condvar_broadcast(lock->prior_signal);
|
||||
ossl_crypto_mutex_unlock(lock->prior_lock);
|
||||
|
||||
retire_qp(lock, qp);
|
||||
|
||||
/* handle any callbacks that we have */
|
||||
|
|
|
@ -434,7 +434,7 @@ static int _torture_rcu(void)
|
|||
writer2_done = 0;
|
||||
rcu_torture_result = 1;
|
||||
|
||||
rcu_lock = ossl_rcu_lock_new(1, NULL);
|
||||
rcu_lock = ossl_rcu_lock_new(contention == 2 ? 4 : 1, NULL);
|
||||
if (rcu_lock == NULL)
|
||||
goto out;
|
||||
|
||||
|
@ -491,6 +491,12 @@ static int torture_rcu_high(void)
|
|||
contention = 1;
|
||||
return _torture_rcu();
|
||||
}
|
||||
|
||||
static int torture_rcu_high2(void)
|
||||
{
|
||||
contention = 2;
|
||||
return _torture_rcu();
|
||||
}
|
||||
#endif
|
||||
|
||||
static CRYPTO_ONCE once_run = CRYPTO_ONCE_STATIC_INIT;
|
||||
|
@ -1329,6 +1335,7 @@ int setup_tests(void)
|
|||
ADD_TEST(torture_rw_high);
|
||||
ADD_TEST(torture_rcu_low);
|
||||
ADD_TEST(torture_rcu_high);
|
||||
ADD_TEST(torture_rcu_high2);
|
||||
#endif
|
||||
ADD_TEST(test_once);
|
||||
ADD_TEST(test_thread_local);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue