Skip to content

Commit 9643ce9

Browse files
authored
[3.13] gh-127667: fix memory leaks in hashlib (GH-127668) (#130784)
gh-127667: fix memory leaks in `hashlib` (GH-127668) - Correctly handle `NULL` values returned by `EVP_MD_CTX_md`. - Correctly free resources in error branches. - Consistently suppress `_setException()` return value when needed. - Collapse `_setException() + return NULL` into a single statement. (cherry-picked from commit 0978465)
1 parent 36e6967 commit 9643ce9

File tree

1 file changed

+78
-56
lines changed

1 file changed

+78
-56
lines changed

Modules/_hashopenssl.c

Lines changed: 78 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,8 @@ py_digest_by_name(PyObject *module, const char *name, enum Py_hash_type py_ht)
427427
}
428428
}
429429
if (digest == NULL) {
430-
_setException(state->unsupported_digestmod_error, "unsupported hash type %s", name);
430+
(void)_setException(state->unsupported_digestmod_error,
431+
"unsupported hash type %s", name);
431432
return NULL;
432433
}
433434
return digest;
@@ -442,7 +443,6 @@ py_digest_by_name(PyObject *module, const char *name, enum Py_hash_type py_ht)
442443
*/
443444
static PY_EVP_MD*
444445
py_digest_by_digestmod(PyObject *module, PyObject *digestmod, enum Py_hash_type py_ht) {
445-
PY_EVP_MD* evp;
446446
PyObject *name_obj = NULL;
447447
const char *name;
448448

@@ -468,12 +468,7 @@ py_digest_by_digestmod(PyObject *module, PyObject *digestmod, enum Py_hash_type
468468
return NULL;
469469
}
470470

471-
evp = py_digest_by_name(module, name, py_ht);
472-
if (evp == NULL) {
473-
return NULL;
474-
}
475-
476-
return evp;
471+
return py_digest_by_name(module, name, py_ht);
477472
}
478473

479474
static EVPobject *
@@ -506,7 +501,7 @@ EVP_hash(EVPobject *self, const void *vp, Py_ssize_t len)
506501
else
507502
process = Py_SAFE_DOWNCAST(len, Py_ssize_t, unsigned int);
508503
if (!EVP_DigestUpdate(self->ctx, (const void*)cp, process)) {
509-
_setException(PyExc_ValueError, NULL);
504+
(void)_setException(PyExc_ValueError, NULL);
510505
return -1;
511506
}
512507
len -= process;
@@ -582,17 +577,20 @@ EVP_digest_impl(EVPobject *self)
582577
}
583578

584579
if (!locked_EVP_MD_CTX_copy(temp_ctx, self)) {
585-
return _setException(PyExc_ValueError, NULL);
580+
goto error;
586581
}
587582
digest_size = EVP_MD_CTX_size(temp_ctx);
588583
if (!EVP_DigestFinal(temp_ctx, digest, NULL)) {
589-
_setException(PyExc_ValueError, NULL);
590-
return NULL;
584+
goto error;
591585
}
592586

593587
retval = PyBytes_FromStringAndSize((const char *)digest, digest_size);
594588
EVP_MD_CTX_free(temp_ctx);
595589
return retval;
590+
591+
error:
592+
EVP_MD_CTX_free(temp_ctx);
593+
return _setException(PyExc_ValueError, NULL);
596594
}
597595

598596
/*[clinic input]
@@ -617,17 +615,20 @@ EVP_hexdigest_impl(EVPobject *self)
617615

618616
/* Get the raw (binary) digest value */
619617
if (!locked_EVP_MD_CTX_copy(temp_ctx, self)) {
620-
return _setException(PyExc_ValueError, NULL);
618+
goto error;
621619
}
622620
digest_size = EVP_MD_CTX_size(temp_ctx);
623621
if (!EVP_DigestFinal(temp_ctx, digest, NULL)) {
624-
_setException(PyExc_ValueError, NULL);
625-
return NULL;
622+
goto error;
626623
}
627624

628625
EVP_MD_CTX_free(temp_ctx);
629626

630627
return _Py_strhex((const char *)digest, (Py_ssize_t)digest_size);
628+
629+
error:
630+
EVP_MD_CTX_free(temp_ctx);
631+
return _setException(PyExc_ValueError, NULL);
631632
}
632633

633634
/*[clinic input]
@@ -695,7 +696,11 @@ EVP_get_digest_size(EVPobject *self, void *closure)
695696
static PyObject *
696697
EVP_get_name(EVPobject *self, void *closure)
697698
{
698-
return py_digest_name(EVP_MD_CTX_md(self->ctx));
699+
const EVP_MD *md = EVP_MD_CTX_md(self->ctx);
700+
if (md == NULL) {
701+
return _setException(PyExc_ValueError, NULL);
702+
}
703+
return py_digest_name(md);
699704
}
700705

701706
static PyGetSetDef EVP_getseters[] = {
@@ -793,21 +798,22 @@ EVPXOF_digest_impl(EVPobject *self, Py_ssize_t length)
793798
}
794799

795800
if (!locked_EVP_MD_CTX_copy(temp_ctx, self)) {
796-
Py_DECREF(retval);
797-
EVP_MD_CTX_free(temp_ctx);
798-
return _setException(PyExc_ValueError, NULL);
801+
goto error;
799802
}
800803
if (!EVP_DigestFinalXOF(temp_ctx,
801804
(unsigned char*)PyBytes_AS_STRING(retval),
802-
length)) {
803-
Py_DECREF(retval);
804-
EVP_MD_CTX_free(temp_ctx);
805-
_setException(PyExc_ValueError, NULL);
806-
return NULL;
805+
length))
806+
{
807+
goto error;
807808
}
808809

809810
EVP_MD_CTX_free(temp_ctx);
810811
return retval;
812+
813+
error:
814+
Py_DECREF(retval);
815+
EVP_MD_CTX_free(temp_ctx);
816+
return _setException(PyExc_ValueError, NULL);
811817
}
812818

813819
/*[clinic input]
@@ -841,22 +847,22 @@ EVPXOF_hexdigest_impl(EVPobject *self, Py_ssize_t length)
841847

842848
/* Get the raw (binary) digest value */
843849
if (!locked_EVP_MD_CTX_copy(temp_ctx, self)) {
844-
PyMem_Free(digest);
845-
EVP_MD_CTX_free(temp_ctx);
846-
return _setException(PyExc_ValueError, NULL);
850+
goto error;
847851
}
848852
if (!EVP_DigestFinalXOF(temp_ctx, digest, length)) {
849-
PyMem_Free(digest);
850-
EVP_MD_CTX_free(temp_ctx);
851-
_setException(PyExc_ValueError, NULL);
852-
return NULL;
853+
goto error;
853854
}
854855

855856
EVP_MD_CTX_free(temp_ctx);
856857

857858
retval = _Py_strhex((const char *)digest, length);
858859
PyMem_Free(digest);
859860
return retval;
861+
862+
error:
863+
PyMem_Free(digest);
864+
EVP_MD_CTX_free(temp_ctx);
865+
return _setException(PyExc_ValueError, NULL);
860866
}
861867

862868
static PyMethodDef EVPXOF_methods[] = {
@@ -957,7 +963,7 @@ py_evp_fromname(PyObject *module, const char *digestname, PyObject *data_obj,
957963

958964
int result = EVP_DigestInit_ex(self->ctx, digest, NULL);
959965
if (!result) {
960-
_setException(PyExc_ValueError, NULL);
966+
(void)_setException(PyExc_ValueError, NULL);
961967
Py_CLEAR(self);
962968
goto exit;
963969
}
@@ -978,7 +984,7 @@ py_evp_fromname(PyObject *module, const char *digestname, PyObject *data_obj,
978984
}
979985
}
980986

981-
exit:
987+
exit:
982988
if (data_obj != NULL) {
983989
PyBuffer_Release(&view);
984990
}
@@ -1423,14 +1429,14 @@ _hashlib_scrypt_impl(PyObject *module, Py_buffer *password, Py_buffer *salt,
14231429
r = PyLong_AsUnsignedLong(r_obj);
14241430
if (r == (unsigned long) -1 && PyErr_Occurred()) {
14251431
PyErr_SetString(PyExc_TypeError,
1426-
"r is required and must be an unsigned int");
1432+
"r is required and must be an unsigned int");
14271433
return NULL;
14281434
}
14291435

14301436
p = PyLong_AsUnsignedLong(p_obj);
14311437
if (p == (unsigned long) -1 && PyErr_Occurred()) {
14321438
PyErr_SetString(PyExc_TypeError,
1433-
"p is required and must be an unsigned int");
1439+
"p is required and must be an unsigned int");
14341440
return NULL;
14351441
}
14361442

@@ -1439,22 +1445,22 @@ _hashlib_scrypt_impl(PyObject *module, Py_buffer *password, Py_buffer *salt,
14391445
future. The maxmem constant is private to OpenSSL. */
14401446
PyErr_Format(PyExc_ValueError,
14411447
"maxmem must be positive and smaller than %d",
1442-
INT_MAX);
1448+
INT_MAX);
14431449
return NULL;
14441450
}
14451451

14461452
if (dklen < 1 || dklen > INT_MAX) {
14471453
PyErr_Format(PyExc_ValueError,
1448-
"dklen must be greater than 0 and smaller than %d",
1449-
INT_MAX);
1454+
"dklen must be greater than 0 and smaller than %d",
1455+
INT_MAX);
14501456
return NULL;
14511457
}
14521458

14531459
/* let OpenSSL validate the rest */
14541460
retval = EVP_PBE_scrypt(NULL, 0, NULL, 0, n, r, p, maxmem, NULL, 0);
14551461
if (!retval) {
1456-
_setException(PyExc_ValueError, "Invalid parameter combination for n, r, p, maxmem.");
1457-
return NULL;
1462+
return _setException(PyExc_ValueError,
1463+
"Invalid parameter combination for n, r, p, maxmem.");
14581464
}
14591465

14601466
key_obj = PyBytes_FromStringAndSize(NULL, dklen);
@@ -1474,8 +1480,7 @@ _hashlib_scrypt_impl(PyObject *module, Py_buffer *password, Py_buffer *salt,
14741480

14751481
if (!retval) {
14761482
Py_CLEAR(key_obj);
1477-
_setException(PyExc_ValueError, NULL);
1478-
return NULL;
1483+
return _setException(PyExc_ValueError, NULL);
14791484
}
14801485
return key_obj;
14811486
}
@@ -1531,8 +1536,7 @@ _hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer *key,
15311536
PY_EVP_MD_free(evp);
15321537

15331538
if (result == NULL) {
1534-
_setException(PyExc_ValueError, NULL);
1535-
return NULL;
1539+
return _setException(PyExc_ValueError, NULL);
15361540
}
15371541
return PyBytes_FromStringAndSize((const char*)md, md_len);
15381542
}
@@ -1581,14 +1585,15 @@ _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, PyObject *msg_obj,
15811585

15821586
ctx = HMAC_CTX_new();
15831587
if (ctx == NULL) {
1588+
PY_EVP_MD_free(digest);
15841589
PyErr_NoMemory();
15851590
goto error;
15861591
}
15871592

15881593
r = HMAC_Init_ex(ctx, key->buf, (int)key->len, digest, NULL /* impl */);
15891594
PY_EVP_MD_free(digest);
15901595
if (r == 0) {
1591-
_setException(PyExc_ValueError, NULL);
1596+
(void)_setException(PyExc_ValueError, NULL);
15921597
goto error;
15931598
}
15941599

@@ -1626,11 +1631,20 @@ locked_HMAC_CTX_copy(HMAC_CTX *new_ctx_p, HMACobject *self)
16261631
return result;
16271632
}
16281633

1634+
/* returning 0 means that an error occurred and an exception is set */
16291635
static unsigned int
16301636
_hmac_digest_size(HMACobject *self)
16311637
{
1632-
unsigned int digest_size = EVP_MD_size(HMAC_CTX_get_md(self->ctx));
1638+
const EVP_MD *md = HMAC_CTX_get_md(self->ctx);
1639+
if (md == NULL) {
1640+
(void)_setException(PyExc_ValueError, NULL);
1641+
return 0;
1642+
}
1643+
unsigned int digest_size = EVP_MD_size(md);
16331644
assert(digest_size <= EVP_MAX_MD_SIZE);
1645+
if (digest_size == 0) {
1646+
(void)_setException(PyExc_ValueError, NULL);
1647+
}
16341648
return digest_size;
16351649
}
16361650

@@ -1658,7 +1672,7 @@ _hmac_update(HMACobject *self, PyObject *obj)
16581672
PyBuffer_Release(&view);
16591673

16601674
if (r == 0) {
1661-
_setException(PyExc_ValueError, NULL);
1675+
(void)_setException(PyExc_ValueError, NULL);
16621676
return 0;
16631677
}
16641678
return 1;
@@ -1711,7 +1725,11 @@ _hmac_dealloc(HMACobject *self)
17111725
static PyObject *
17121726
_hmac_repr(HMACobject *self)
17131727
{
1714-
PyObject *digest_name = py_digest_name(HMAC_CTX_get_md(self->ctx));
1728+
const EVP_MD *md = HMAC_CTX_get_md(self->ctx);
1729+
if (md == NULL) {
1730+
return _setException(PyExc_ValueError, NULL);
1731+
}
1732+
PyObject *digest_name = py_digest_name(md);
17151733
if (digest_name == NULL) {
17161734
return NULL;
17171735
}
@@ -1744,18 +1762,18 @@ _hmac_digest(HMACobject *self, unsigned char *buf, unsigned int len)
17441762
{
17451763
HMAC_CTX *temp_ctx = HMAC_CTX_new();
17461764
if (temp_ctx == NULL) {
1747-
PyErr_NoMemory();
1765+
(void)PyErr_NoMemory();
17481766
return 0;
17491767
}
17501768
if (!locked_HMAC_CTX_copy(temp_ctx, self)) {
17511769
HMAC_CTX_free(temp_ctx);
1752-
_setException(PyExc_ValueError, NULL);
1770+
(void)_setException(PyExc_ValueError, NULL);
17531771
return 0;
17541772
}
17551773
int r = HMAC_Final(temp_ctx, buf, &len);
17561774
HMAC_CTX_free(temp_ctx);
17571775
if (r == 0) {
1758-
_setException(PyExc_ValueError, NULL);
1776+
(void)_setException(PyExc_ValueError, NULL);
17591777
return 0;
17601778
}
17611779
return 1;
@@ -1773,7 +1791,7 @@ _hashlib_HMAC_digest_impl(HMACobject *self)
17731791
unsigned char digest[EVP_MAX_MD_SIZE];
17741792
unsigned int digest_size = _hmac_digest_size(self);
17751793
if (digest_size == 0) {
1776-
return _setException(PyExc_ValueError, NULL);
1794+
return NULL;
17771795
}
17781796
int r = _hmac_digest(self, digest, digest_size);
17791797
if (r == 0) {
@@ -1798,7 +1816,7 @@ _hashlib_HMAC_hexdigest_impl(HMACobject *self)
17981816
unsigned char digest[EVP_MAX_MD_SIZE];
17991817
unsigned int digest_size = _hmac_digest_size(self);
18001818
if (digest_size == 0) {
1801-
return _setException(PyExc_ValueError, NULL);
1819+
return NULL;
18021820
}
18031821
int r = _hmac_digest(self, digest, digest_size);
18041822
if (r == 0) {
@@ -1812,7 +1830,7 @@ _hashlib_hmac_get_digest_size(HMACobject *self, void *closure)
18121830
{
18131831
unsigned int digest_size = _hmac_digest_size(self);
18141832
if (digest_size == 0) {
1815-
return _setException(PyExc_ValueError, NULL);
1833+
return NULL;
18161834
}
18171835
return PyLong_FromLong(digest_size);
18181836
}
@@ -1830,7 +1848,11 @@ _hashlib_hmac_get_block_size(HMACobject *self, void *closure)
18301848
static PyObject *
18311849
_hashlib_hmac_get_name(HMACobject *self, void *closure)
18321850
{
1833-
PyObject *digest_name = py_digest_name(HMAC_CTX_get_md(self->ctx));
1851+
const EVP_MD *md = HMAC_CTX_get_md(self->ctx);
1852+
if (md == NULL) {
1853+
return _setException(PyExc_ValueError, NULL);
1854+
}
1855+
PyObject *digest_name = py_digest_name(md);
18341856
if (digest_name == NULL) {
18351857
return NULL;
18361858
}
@@ -1981,7 +2003,7 @@ _hashlib_get_fips_mode_impl(PyObject *module)
19812003
// But 0 is also a valid result value.
19822004
unsigned long errcode = ERR_peek_last_error();
19832005
if (errcode) {
1984-
_setException(PyExc_ValueError, NULL);
2006+
(void)_setException(PyExc_ValueError, NULL);
19852007
return -1;
19862008
}
19872009
}

0 commit comments

Comments
 (0)