Skip to content

Commit a3215e1

Browse files
committed
gh-128657: fix _hashopenssl ref/data race
1 parent 40a4d88 commit a3215e1

File tree

1 file changed

+17
-7
lines changed

1 file changed

+17
-7
lines changed

Modules/_hashopenssl.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "Python.h"
2727
#include "pycore_hashtable.h"
2828
#include "pycore_strhex.h" // _Py_strhex()
29+
#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_PTR_RELAXED
2930
#include "hashlib.h"
3031

3132
/* EVP is the preferred interface to hashing in OpenSSL */
@@ -369,6 +370,7 @@ static PY_EVP_MD*
369370
py_digest_by_name(PyObject *module, const char *name, enum Py_hash_type py_ht)
370371
{
371372
PY_EVP_MD *digest = NULL;
373+
PY_EVP_MD *other_digest = NULL;
372374
_hashlibstate *state = get_hashlib_state(module);
373375
py_hashentry_t *entry = (py_hashentry_t *)_Py_hashtable_get(
374376
state->hashtable, (const void*)name
@@ -379,20 +381,28 @@ py_digest_by_name(PyObject *module, const char *name, enum Py_hash_type py_ht)
379381
case Py_ht_evp:
380382
case Py_ht_mac:
381383
case Py_ht_pbkdf2:
382-
if (entry->evp == NULL) {
383-
entry->evp = PY_EVP_MD_fetch(entry->ossl_name, NULL);
384+
digest = FT_ATOMIC_LOAD_PTR_RELAXED(entry->evp);
385+
if (digest == NULL) {
386+
digest = PY_EVP_MD_fetch(entry->ossl_name, NULL);
387+
// exchange just in case another thread did same thing at same time
388+
other_digest = _Py_atomic_exchange_ptr(&entry->evp, digest);
384389
}
385-
digest = entry->evp;
386390
break;
387391
case Py_ht_evp_nosecurity:
388-
if (entry->evp_nosecurity == NULL) {
389-
entry->evp_nosecurity = PY_EVP_MD_fetch(entry->ossl_name, "-fips");
392+
digest = FT_ATOMIC_LOAD_PTR_RELAXED(entry->evp_nosecurity);
393+
if (digest == NULL) {
394+
digest = PY_EVP_MD_fetch(entry->ossl_name, "-fips");
395+
// exchange just in case another thread did same thing at same time
396+
other_digest = _Py_atomic_exchange_ptr(&entry->evp_nosecurity, digest);
390397
}
391-
digest = entry->evp_nosecurity;
392398
break;
393399
}
400+
// if another thread same thing at same time make sure we got same ptr
401+
assert(other_digest == NULL || other_digest == digest);
394402
if (digest != NULL) {
395-
PY_EVP_MD_up_ref(digest);
403+
if (other_digest == NULL) {
404+
PY_EVP_MD_up_ref(digest);
405+
}
396406
}
397407
} else {
398408
// Fall back for looking up an unindexed OpenSSL specific name.

0 commit comments

Comments
 (0)