Skip to content

Commit 902759f

Browse files
committed
unconditionally lock when performing HASH updates
1 parent 77baa67 commit 902759f

File tree

11 files changed

+228
-644
lines changed

11 files changed

+228
-644
lines changed

Lib/test/support/hashlib_helper.py

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -308,22 +308,3 @@ def sha3_384(self):
308308
@property
309309
def sha3_512(self):
310310
return self._find_constructor_in("_sha3","sha3_512")
311-
312-
313-
def find_gil_minsize(modules_names, default=2048):
314-
"""Get the largest GIL_MINSIZE value for the given cryptographic modules.
315-
316-
The valid module names are the following:
317-
318-
- _hashlib
319-
- _md5, _sha1, _sha2, _sha3, _blake2
320-
- _hmac
321-
"""
322-
sizes = []
323-
for module_name in modules_names:
324-
try:
325-
module = importlib.import_module(module_name)
326-
except ImportError:
327-
continue
328-
sizes.append(getattr(module, '_GIL_MINSIZE', default))
329-
return max(sizes, default=default)

Lib/test/test_hashlib.py

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ def test_large_update(self):
409409
aas = b'a' * 128
410410
bees = b'b' * 127
411411
cees = b'c' * 126
412-
dees = b'd' * 2048 # HASHLIB_GIL_MINSIZE
412+
dees = b'd' * 2048
413413

414414
for cons in self.hash_constructors:
415415
m1 = cons(usedforsecurity=False)
@@ -990,40 +990,6 @@ def test_case_shake256_vector(self):
990990
for msg, md in read_vectors('shake_256'):
991991
self.check('shake_256', msg, md, True)
992992

993-
def test_gil(self):
994-
# Check things work fine with an input larger than the size required
995-
# for multithreaded operation. Currently, all cryptographic modules
996-
# have the same constant value (2048) but in the future it might not
997-
# be the case.
998-
mods = ['_md5', '_sha1', '_sha2', '_sha3', '_blake2', '_hashlib']
999-
gil_minsize = hashlib_helper.find_gil_minsize(mods)
1000-
for cons in self.hash_constructors:
1001-
# constructors belong to one of the above modules
1002-
m = cons(usedforsecurity=False)
1003-
m.update(b'1')
1004-
m.update(b'#' * gil_minsize)
1005-
m.update(b'1')
1006-
1007-
m = cons(b'x' * gil_minsize, usedforsecurity=False)
1008-
m.update(b'1')
1009-
1010-
def test_sha256_gil(self):
1011-
gil_minsize = hashlib_helper.find_gil_minsize(['_sha2', '_hashlib'])
1012-
m = hashlib.sha256()
1013-
m.update(b'1')
1014-
m.update(b'#' * gil_minsize)
1015-
m.update(b'1')
1016-
self.assertEqual(
1017-
m.hexdigest(),
1018-
'1cfceca95989f51f658e3f3ffe7f1cd43726c9e088c13ee10b46f57cef135b94'
1019-
)
1020-
1021-
m = hashlib.sha256(b'1' + b'#' * gil_minsize + b'1')
1022-
self.assertEqual(
1023-
m.hexdigest(),
1024-
'1cfceca95989f51f658e3f3ffe7f1cd43726c9e088c13ee10b46f57cef135b94'
1025-
)
1026-
1027993
@threading_helper.reap_threads
1028994
@threading_helper.requires_working_threading()
1029995
def test_threaded_hashing(self):

Lib/test/test_hmac.py

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,11 +1133,6 @@ def HMAC(self, key, msg=None):
11331133
"""Create a HMAC object."""
11341134
raise NotImplementedError
11351135

1136-
@property
1137-
def gil_minsize(self):
1138-
"""Get the maximal input length for the GIL to be held."""
1139-
raise NotImplementedError
1140-
11411136
def check_update(self, key, chunks):
11421137
chunks = list(chunks)
11431138
msg = b''.join(chunks)
@@ -1155,13 +1150,6 @@ def test_update(self):
11551150
with self.subTest(key=key, msg=msg):
11561151
self.check_update(key, [msg])
11571152

1158-
def test_update_large(self):
1159-
gil_minsize = self.gil_minsize
1160-
key = random.randbytes(16)
1161-
top = random.randbytes(gil_minsize + 1)
1162-
bot = random.randbytes(gil_minsize + 1)
1163-
self.check_update(key, [top, bot])
1164-
11651153
def test_update_exceptions(self):
11661154
h = self.HMAC(b"key")
11671155
for msg in ['invalid msg', 123, (), []]:
@@ -1175,21 +1163,13 @@ class PyUpdateTestCase(PyModuleMixin, UpdateTestCaseMixin, unittest.TestCase):
11751163
def HMAC(self, key, msg=None):
11761164
return self.hmac.HMAC(key, msg, digestmod='sha256')
11771165

1178-
@property
1179-
def gil_minsize(self):
1180-
return sha2._GIL_MINSIZE
1181-
11821166

11831167
@hashlib_helper.requires_openssl_hashdigest('sha256')
11841168
class OpenSSLUpdateTestCase(UpdateTestCaseMixin, unittest.TestCase):
11851169

11861170
def HMAC(self, key, msg=None):
11871171
return _hashlib.hmac_new(key, msg, digestmod='sha256')
11881172

1189-
@property
1190-
def gil_minsize(self):
1191-
return _hashlib._GIL_MINSIZE
1192-
11931173

11941174
class BuiltinUpdateTestCase(BuiltinModuleMixin,
11951175
UpdateTestCaseMixin, unittest.TestCase):
@@ -1199,10 +1179,6 @@ def HMAC(self, key, msg=None):
11991179
# are still built, making it possible to use SHA-2 hashes.
12001180
return self.hmac.new(key, msg, digestmod='sha256')
12011181

1202-
@property
1203-
def gil_minsize(self):
1204-
return self.hmac._GIL_MINSIZE
1205-
12061182

12071183
class CopyBaseTestCase:
12081184

Modules/_hashopenssl.c

Lines changed: 27 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -611,9 +611,9 @@ static int
611611
_hashlib_HASH_copy_locked(HASHobject *self, EVP_MD_CTX *new_ctx_p)
612612
{
613613
int result;
614-
ENTER_HASHLIB(self);
614+
HASHLIB_ACQUIRE_LOCK(self);
615615
result = EVP_MD_CTX_copy(new_ctx_p, self->ctx);
616-
LEAVE_HASHLIB(self);
616+
HASHLIB_RELEASE_LOCK(self);
617617
return result;
618618
}
619619

@@ -733,29 +733,16 @@ static PyObject *
733733
_hashlib_HASH_update_impl(HASHobject *self, PyObject *obj)
734734
/*[clinic end generated code: output=62ad989754946b86 input=aa1ce20e3f92ceb6]*/
735735
{
736-
int result;
736+
int rc;
737737
Py_buffer view;
738-
739738
GET_BUFFER_VIEW_OR_ERROUT(obj, &view);
740-
741-
if (!self->use_mutex && view.len >= HASHLIB_GIL_MINSIZE) {
742-
self->use_mutex = true;
743-
}
744-
if (self->use_mutex) {
745-
Py_BEGIN_ALLOW_THREADS
746-
PyMutex_Lock(&self->mutex);
747-
result = _hashlib_HASH_hash(self, view.buf, view.len);
748-
PyMutex_Unlock(&self->mutex);
749-
Py_END_ALLOW_THREADS
750-
} else {
751-
result = _hashlib_HASH_hash(self, view.buf, view.len);
752-
}
753-
739+
Py_BEGIN_ALLOW_THREADS
740+
HASHLIB_ACQUIRE_LOCK(self);
741+
rc = _hashlib_HASH_hash(self, view.buf, view.len);
742+
HASHLIB_RELEASE_LOCK(self);
743+
Py_END_ALLOW_THREADS
754744
PyBuffer_Release(&view);
755-
756-
if (result == -1)
757-
return NULL;
758-
Py_RETURN_NONE;
745+
return rc < 0 ? NULL : Py_None;
759746
}
760747

761748
static PyMethodDef HASH_methods[] = {
@@ -1060,15 +1047,11 @@ _hashlib_HASH(PyObject *module, const char *digestname, PyObject *data_obj,
10601047
}
10611048

10621049
if (view.buf && view.len) {
1063-
if (view.len >= HASHLIB_GIL_MINSIZE) {
1064-
/* We do not initialize self->lock here as this is the constructor
1065-
* where it is not yet possible to have concurrent access. */
1066-
Py_BEGIN_ALLOW_THREADS
1067-
result = _hashlib_HASH_hash(self, view.buf, view.len);
1068-
Py_END_ALLOW_THREADS
1069-
} else {
1050+
/* Do not use self->mutex here as this is the constructor
1051+
* where it is not yet possible to have concurrent access. */
1052+
Py_BEGIN_ALLOW_THREADS
10701053
result = _hashlib_HASH_hash(self, view.buf, view.len);
1071-
}
1054+
Py_END_ALLOW_THREADS
10721055
if (result == -1) {
10731056
assert(PyErr_Occurred());
10741057
Py_CLEAR(self);
@@ -1701,7 +1684,7 @@ _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj,
17011684
HASHLIB_INIT_MUTEX(self);
17021685

17031686
if ((msg_obj != NULL) && (msg_obj != Py_None)) {
1704-
if (!_hmac_update(self, msg_obj)) {
1687+
if (_hmac_update(self, msg_obj) < 0) {
17051688
goto error;
17061689
}
17071690
}
@@ -1718,9 +1701,9 @@ static int
17181701
locked_HMAC_CTX_copy(HMAC_CTX *new_ctx_p, HMACobject *self)
17191702
{
17201703
int result;
1721-
ENTER_HASHLIB(self);
1704+
HASHLIB_ACQUIRE_LOCK(self);
17221705
result = HMAC_CTX_copy(new_ctx_p, self->ctx);
1723-
LEAVE_HASHLIB(self);
1706+
HASHLIB_RELEASE_LOCK(self);
17241707
return result;
17251708
}
17261709

@@ -1743,35 +1726,26 @@ _hashlib_hmac_digest_size(HMACobject *self)
17431726
static int
17441727
_hmac_update(HMACobject *self, PyObject *obj)
17451728
{
1746-
int r;
1729+
int r = 1;
17471730
Py_buffer view = {0};
17481731

1749-
GET_BUFFER_VIEW_OR_ERROR(obj, &view, return 0);
1750-
1751-
if (!self->use_mutex && view.len >= HASHLIB_GIL_MINSIZE) {
1752-
self->use_mutex = true;
1753-
}
1754-
if (self->use_mutex) {
1732+
GET_BUFFER_VIEW_OR_ERROR(obj, &view, return -1);
1733+
if (view.len > 0) {
17551734
Py_BEGIN_ALLOW_THREADS
1756-
PyMutex_Lock(&self->mutex);
1757-
r = HMAC_Update(self->ctx,
1758-
(const unsigned char *)view.buf,
1759-
(size_t)view.len);
1760-
PyMutex_Unlock(&self->mutex);
1735+
HASHLIB_ACQUIRE_LOCK(self);
1736+
r = HMAC_Update(self->ctx,
1737+
(const unsigned char *)view.buf,
1738+
(size_t)view.len);
1739+
HASHLIB_RELEASE_LOCK(self);
17611740
Py_END_ALLOW_THREADS
1762-
} else {
1763-
r = HMAC_Update(self->ctx,
1764-
(const unsigned char *)view.buf,
1765-
(size_t)view.len);
17661741
}
1767-
17681742
PyBuffer_Release(&view);
17691743

17701744
if (r == 0) {
17711745
notify_ssl_error_occurred();
1772-
return 0;
1746+
return -1;
17731747
}
1774-
return 1;
1748+
return 0;
17751749
}
17761750

17771751
/*[clinic input]
@@ -1845,7 +1819,7 @@ static PyObject *
18451819
_hashlib_HMAC_update_impl(HMACobject *self, PyObject *msg)
18461820
/*[clinic end generated code: output=f31f0ace8c625b00 input=1829173bb3cfd4e6]*/
18471821
{
1848-
if (!_hmac_update(self, msg)) {
1822+
if (_hmac_update(self, msg) < 0) {
18491823
return NULL;
18501824
}
18511825
Py_RETURN_NONE;
@@ -2412,17 +2386,6 @@ hashlib_exception(PyObject *module)
24122386
return 0;
24132387
}
24142388

2415-
static int
2416-
hashlib_constants(PyObject *module)
2417-
{
2418-
if (PyModule_AddIntConstant(module, "_GIL_MINSIZE",
2419-
HASHLIB_GIL_MINSIZE) < 0)
2420-
{
2421-
return -1;
2422-
}
2423-
return 0;
2424-
}
2425-
24262389
static PyModuleDef_Slot hashlib_slots[] = {
24272390
{Py_mod_exec, hashlib_init_hashtable},
24282391
{Py_mod_exec, hashlib_init_HASH_type},
@@ -2431,7 +2394,6 @@ static PyModuleDef_Slot hashlib_slots[] = {
24312394
{Py_mod_exec, hashlib_md_meth_names},
24322395
{Py_mod_exec, hashlib_init_constructors},
24332396
{Py_mod_exec, hashlib_exception},
2434-
{Py_mod_exec, hashlib_constants},
24352397
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
24362398
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
24372399
{0, NULL}

0 commit comments

Comments
 (0)