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
5949918f9afa ("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)
(cherry picked from commit
6e7be995fd7fd24d38b95982cf90f801ac045743)
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
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 */
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 */
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;
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;
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);