Skip to content

Commit 45ec585

Browse files
committed
gh-155835: fix digest_size and block_size data races on SHA-3 objects
1 parent c92e2fd commit 45ec585

2 files changed

Lines changed: 23 additions & 14 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:mod:`hashlib`: Fix data races when accessing
2+
:attr:`~hashlib.hash.digest_size` and :attr:`~hashlib.hash.block_size` on
3+
SHA-3 objects. Patch by Bénédikt Tran.

Modules/sha3module.c

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ sha3_get_state(PyObject *module)
6767
typedef struct {
6868
HASHLIB_OBJECT_HEAD
6969
Hacl_Hash_SHA3_state_t *hash_state;
70+
// HACL* update functions entirely replace the state, which can lead
71+
// to races on the free-threaded build. Since the kind of hash is static,
72+
// we can store its corresponding metadata once.
73+
uint32_t digest_size;
74+
uint32_t block_size;
75+
int is_shake;
7076
} SHA3object;
7177

7278
#define _SHA3object_CAST(op) ((SHA3object *)(op))
@@ -96,7 +102,7 @@ newSHA3object(PyTypeObject *type)
96102
return NULL;
97103
}
98104
HASHLIB_INIT_MUTEX(newobj);
99-
105+
newobj->digest_size = newobj->block_size = 0;
100106
PyObject_GC_Track(newobj);
101107
return newobj;
102108
}
@@ -179,6 +185,11 @@ py_sha3_new_impl(PyTypeObject *type, PyObject *data_obj, int usedforsecurity,
179185
goto error;
180186
}
181187

188+
// set the metadata once we know that the state is valid
189+
int is_shake = Hacl_Hash_SHA3_is_shake(self->hash_state);
190+
self->digest_size = is_shake ? 0 : Hacl_Hash_SHA3_hash_len(self->hash_state);
191+
self->block_size = Hacl_Hash_SHA3_block_len(self->hash_state);
192+
182193
if (data) {
183194
GET_BUFFER_VIEW_OR_ERROR(data, &buf, goto error);
184195
/* Do not use self->mutex here as this is the constructor
@@ -253,6 +264,8 @@ _sha3_sha3_224_copy_impl(SHA3object *self, PyTypeObject *cls)
253264
Py_DECREF(newobj);
254265
return PyErr_NoMemory();
255266
}
267+
newobj->digest_size = self->digest_size;
268+
newobj->block_size = self->block_size;
256269
return (PyObject *)newobj;
257270
}
258271

@@ -273,8 +286,7 @@ _sha3_sha3_224_digest_impl(SHA3object *self)
273286
HASHLIB_ACQUIRE_LOCK(self);
274287
(void)Hacl_Hash_SHA3_digest(self->hash_state, digest);
275288
HASHLIB_RELEASE_LOCK(self);
276-
return PyBytes_FromStringAndSize((const char *)digest,
277-
Hacl_Hash_SHA3_hash_len(self->hash_state));
289+
return PyBytes_FromStringAndSize((const char *)digest, self->digest_size);
278290
}
279291

280292

@@ -292,8 +304,7 @@ _sha3_sha3_224_hexdigest_impl(SHA3object *self)
292304
HASHLIB_ACQUIRE_LOCK(self);
293305
(void)Hacl_Hash_SHA3_digest(self->hash_state, digest);
294306
HASHLIB_RELEASE_LOCK(self);
295-
return _Py_strhex((const char *)digest,
296-
Hacl_Hash_SHA3_hash_len(self->hash_state));
307+
return _Py_strhex((const char *)digest, self->digest_size);
297308
}
298309

299310

@@ -334,8 +345,7 @@ static PyObject *
334345
SHA3_get_block_size(PyObject *op, void *Py_UNUSED(closure))
335346
{
336347
SHA3object *self = _SHA3object_CAST(op);
337-
uint32_t rate = Hacl_Hash_SHA3_block_len(self->hash_state);
338-
return PyLong_FromLong(rate);
348+
return PyLong_FromLong(self->block_size);
339349
}
340350

341351

@@ -371,18 +381,15 @@ SHA3_get_digest_size(PyObject *op, void *Py_UNUSED(closure))
371381
{
372382
// Preserving previous behavior: variable-length algorithms return 0
373383
SHA3object *self = _SHA3object_CAST(op);
374-
if (Hacl_Hash_SHA3_is_shake(self->hash_state))
375-
return PyLong_FromLong(0);
376-
else
377-
return PyLong_FromLong(Hacl_Hash_SHA3_hash_len(self->hash_state));
384+
return PyLong_FromLong(self->digest_size);
378385
}
379386

380387

381388
static PyObject *
382389
SHA3_get_capacity_bits(PyObject *op, void *Py_UNUSED(closure))
383390
{
384391
SHA3object *self = _SHA3object_CAST(op);
385-
uint32_t rate = Hacl_Hash_SHA3_block_len(self->hash_state) * 8;
392+
uint32_t rate = self->block_size * 8;
386393
assert(rate <= 1600);
387394
int capacity = 1600 - rate;
388395
return PyLong_FromLong(capacity);
@@ -393,8 +400,7 @@ static PyObject *
393400
SHA3_get_rate_bits(PyObject *op, void *Py_UNUSED(closure))
394401
{
395402
SHA3object *self = _SHA3object_CAST(op);
396-
uint32_t rate = Hacl_Hash_SHA3_block_len(self->hash_state) * 8;
397-
return PyLong_FromLong(rate);
403+
return PyLong_FromLong(self->block_size * 8);
398404
}
399405

400406
static PyObject *

0 commit comments

Comments
 (0)