https://github.com/python/cpython/commit/d25da899535f752be251bee8453b2c6942befaea
commit: d25da899535f752be251bee8453b2c6942befaea
branch: 3.12
author: Bénédikt Tran <10796600+picn...@users.noreply.github.com>
committer: picnixz <10796600+picn...@users.noreply.github.com>
date: 2025-03-03T10:44:42Z
summary:

[3.12] gh-127667: fix memory leaks in `hashlib` (GH-127668) (#130783)

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 097846502b7f33cb327d512e2a396acf4f4de46e)

files:
M Modules/_hashopenssl.c

diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c
index 84afb743ab8c3b..48d7fd03feb16b 100644
--- a/Modules/_hashopenssl.c
+++ b/Modules/_hashopenssl.c
@@ -409,7 +409,8 @@ py_digest_by_name(PyObject *module, const char *name, enum 
Py_hash_type py_ht)
         }
     }
     if (digest == NULL) {
-        _setException(state->unsupported_digestmod_error, "unsupported hash 
type %s", name);
+        (void)_setException(state->unsupported_digestmod_error,
+                            "unsupported hash type %s", name);
         return NULL;
     }
     return digest;
@@ -424,7 +425,6 @@ py_digest_by_name(PyObject *module, const char *name, enum 
Py_hash_type py_ht)
  */
 static PY_EVP_MD*
 py_digest_by_digestmod(PyObject *module, PyObject *digestmod, enum 
Py_hash_type py_ht) {
-    PY_EVP_MD* evp;
     PyObject *name_obj = NULL;
     const char *name;
 
@@ -450,12 +450,7 @@ py_digest_by_digestmod(PyObject *module, PyObject 
*digestmod, enum Py_hash_type
         return NULL;
     }
 
-    evp = py_digest_by_name(module, name, py_ht);
-    if (evp == NULL) {
-        return NULL;
-    }
-
-    return evp;
+    return py_digest_by_name(module, name, py_ht);
 }
 
 static EVPobject *
@@ -489,7 +484,7 @@ EVP_hash(EVPobject *self, const void *vp, Py_ssize_t len)
         else
             process = Py_SAFE_DOWNCAST(len, Py_ssize_t, unsigned int);
         if (!EVP_DigestUpdate(self->ctx, (const void*)cp, process)) {
-            _setException(PyExc_ValueError, NULL);
+            (void)_setException(PyExc_ValueError, NULL);
             return -1;
         }
         len -= process;
@@ -567,17 +562,20 @@ EVP_digest_impl(EVPobject *self)
     }
 
     if (!locked_EVP_MD_CTX_copy(temp_ctx, self)) {
-        return _setException(PyExc_ValueError, NULL);
+        goto error;
     }
     digest_size = EVP_MD_CTX_size(temp_ctx);
     if (!EVP_DigestFinal(temp_ctx, digest, NULL)) {
-        _setException(PyExc_ValueError, NULL);
-        return NULL;
+        goto error;
     }
 
     retval = PyBytes_FromStringAndSize((const char *)digest, digest_size);
     EVP_MD_CTX_free(temp_ctx);
     return retval;
+
+error:
+    EVP_MD_CTX_free(temp_ctx);
+    return _setException(PyExc_ValueError, NULL);
 }
 
 /*[clinic input]
@@ -602,17 +600,20 @@ EVP_hexdigest_impl(EVPobject *self)
 
     /* Get the raw (binary) digest value */
     if (!locked_EVP_MD_CTX_copy(temp_ctx, self)) {
-        return _setException(PyExc_ValueError, NULL);
+        goto error;
     }
     digest_size = EVP_MD_CTX_size(temp_ctx);
     if (!EVP_DigestFinal(temp_ctx, digest, NULL)) {
-        _setException(PyExc_ValueError, NULL);
-        return NULL;
+        goto error;
     }
 
     EVP_MD_CTX_free(temp_ctx);
 
     return _Py_strhex((const char *)digest, (Py_ssize_t)digest_size);
+
+error:
+    EVP_MD_CTX_free(temp_ctx);
+    return _setException(PyExc_ValueError, NULL);
 }
 
 /*[clinic input]
@@ -682,7 +683,11 @@ EVP_get_digest_size(EVPobject *self, void *closure)
 static PyObject *
 EVP_get_name(EVPobject *self, void *closure)
 {
-    return py_digest_name(EVP_MD_CTX_md(self->ctx));
+    const EVP_MD *md = EVP_MD_CTX_md(self->ctx);
+    if (md == NULL) {
+        return _setException(PyExc_ValueError, NULL);
+    }
+    return py_digest_name(md);
 }
 
 static PyGetSetDef EVP_getseters[] = {
@@ -780,21 +785,22 @@ EVPXOF_digest_impl(EVPobject *self, Py_ssize_t length)
     }
 
     if (!locked_EVP_MD_CTX_copy(temp_ctx, self)) {
-        Py_DECREF(retval);
-        EVP_MD_CTX_free(temp_ctx);
-        return _setException(PyExc_ValueError, NULL);
+        goto error;
     }
     if (!EVP_DigestFinalXOF(temp_ctx,
                             (unsigned char*)PyBytes_AS_STRING(retval),
-                            length)) {
-        Py_DECREF(retval);
-        EVP_MD_CTX_free(temp_ctx);
-        _setException(PyExc_ValueError, NULL);
-        return NULL;
+                            length))
+    {
+        goto error;
     }
 
     EVP_MD_CTX_free(temp_ctx);
     return retval;
+
+error:
+    Py_DECREF(retval);
+    EVP_MD_CTX_free(temp_ctx);
+    return _setException(PyExc_ValueError, NULL);
 }
 
 /*[clinic input]
@@ -828,15 +834,10 @@ EVPXOF_hexdigest_impl(EVPobject *self, Py_ssize_t length)
 
     /* Get the raw (binary) digest value */
     if (!locked_EVP_MD_CTX_copy(temp_ctx, self)) {
-        PyMem_Free(digest);
-        EVP_MD_CTX_free(temp_ctx);
-        return _setException(PyExc_ValueError, NULL);
+        goto error;
     }
     if (!EVP_DigestFinalXOF(temp_ctx, digest, length)) {
-        PyMem_Free(digest);
-        EVP_MD_CTX_free(temp_ctx);
-        _setException(PyExc_ValueError, NULL);
-        return NULL;
+        goto error;
     }
 
     EVP_MD_CTX_free(temp_ctx);
@@ -844,6 +845,11 @@ EVPXOF_hexdigest_impl(EVPobject *self, Py_ssize_t length)
     retval = _Py_strhex((const char *)digest, length);
     PyMem_Free(digest);
     return retval;
+
+error:
+    PyMem_Free(digest);
+    EVP_MD_CTX_free(temp_ctx);
+    return _setException(PyExc_ValueError, NULL);
 }
 
 static PyMethodDef EVPXOF_methods[] = {
@@ -944,7 +950,7 @@ py_evp_fromname(PyObject *module, const char *digestname, 
PyObject *data_obj,
 
     int result = EVP_DigestInit_ex(self->ctx, digest, NULL);
     if (!result) {
-        _setException(PyExc_ValueError, NULL);
+        (void)_setException(PyExc_ValueError, NULL);
         Py_CLEAR(self);
         goto exit;
     }
@@ -965,7 +971,7 @@ py_evp_fromname(PyObject *module, const char *digestname, 
PyObject *data_obj,
         }
     }
 
-  exit:
+exit:
     if (data_obj != NULL) {
         PyBuffer_Release(&view);
     }
@@ -1410,14 +1416,14 @@ _hashlib_scrypt_impl(PyObject *module, Py_buffer 
*password, Py_buffer *salt,
     r = PyLong_AsUnsignedLong(r_obj);
     if (r == (unsigned long) -1 && PyErr_Occurred()) {
         PyErr_SetString(PyExc_TypeError,
-                         "r is required and must be an unsigned int");
+                        "r is required and must be an unsigned int");
         return NULL;
     }
 
     p = PyLong_AsUnsignedLong(p_obj);
     if (p == (unsigned long) -1 && PyErr_Occurred()) {
         PyErr_SetString(PyExc_TypeError,
-                         "p is required and must be an unsigned int");
+                        "p is required and must be an unsigned int");
         return NULL;
     }
 
@@ -1426,22 +1432,22 @@ _hashlib_scrypt_impl(PyObject *module, Py_buffer 
*password, Py_buffer *salt,
            future. The maxmem constant is private to OpenSSL. */
         PyErr_Format(PyExc_ValueError,
                      "maxmem must be positive and smaller than %d",
-                      INT_MAX);
+                     INT_MAX);
         return NULL;
     }
 
     if (dklen < 1 || dklen > INT_MAX) {
         PyErr_Format(PyExc_ValueError,
-                    "dklen must be greater than 0 and smaller than %d",
-                    INT_MAX);
+                     "dklen must be greater than 0 and smaller than %d",
+                     INT_MAX);
         return NULL;
     }
 
     /* let OpenSSL validate the rest */
     retval = EVP_PBE_scrypt(NULL, 0, NULL, 0, n, r, p, maxmem, NULL, 0);
     if (!retval) {
-        _setException(PyExc_ValueError, "Invalid parameter combination for n, 
r, p, maxmem.");
-        return NULL;
+        return _setException(PyExc_ValueError,
+                             "Invalid parameter combination for n, r, p, 
maxmem.");
    }
 
     key_obj = PyBytes_FromStringAndSize(NULL, dklen);
@@ -1461,8 +1467,7 @@ _hashlib_scrypt_impl(PyObject *module, Py_buffer 
*password, Py_buffer *salt,
 
     if (!retval) {
         Py_CLEAR(key_obj);
-        _setException(PyExc_ValueError, NULL);
-        return NULL;
+        return _setException(PyExc_ValueError, NULL);
     }
     return key_obj;
 }
@@ -1518,8 +1523,7 @@ _hashlib_hmac_singleshot_impl(PyObject *module, Py_buffer 
*key,
     PY_EVP_MD_free(evp);
 
     if (result == NULL) {
-        _setException(PyExc_ValueError, NULL);
-        return NULL;
+        return _setException(PyExc_ValueError, NULL);
     }
     return PyBytes_FromStringAndSize((const char*)md, md_len);
 }
@@ -1568,6 +1572,7 @@ _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, 
PyObject *msg_obj,
 
     ctx = HMAC_CTX_new();
     if (ctx == NULL) {
+        PY_EVP_MD_free(digest);
         PyErr_NoMemory();
         goto error;
     }
@@ -1575,7 +1580,7 @@ _hashlib_hmac_new_impl(PyObject *module, Py_buffer *key, 
PyObject *msg_obj,
     r = HMAC_Init_ex(ctx, key->buf, (int)key->len, digest, NULL /* impl */);
     PY_EVP_MD_free(digest);
     if (r == 0) {
-        _setException(PyExc_ValueError, NULL);
+        (void)_setException(PyExc_ValueError, NULL);
         goto error;
     }
 
@@ -1613,11 +1618,20 @@ locked_HMAC_CTX_copy(HMAC_CTX *new_ctx_p, HMACobject 
*self)
     return result;
 }
 
+/* returning 0 means that an error occurred and an exception is set */
 static unsigned int
 _hmac_digest_size(HMACobject *self)
 {
-    unsigned int digest_size = EVP_MD_size(HMAC_CTX_get_md(self->ctx));
+    const EVP_MD *md = HMAC_CTX_get_md(self->ctx);
+    if (md == NULL) {
+        (void)_setException(PyExc_ValueError, NULL);
+        return 0;
+    }
+    unsigned int digest_size = EVP_MD_size(md);
     assert(digest_size <= EVP_MAX_MD_SIZE);
+    if (digest_size == 0) {
+        (void)_setException(PyExc_ValueError, NULL);
+    }
     return digest_size;
 }
 
@@ -1647,7 +1661,7 @@ _hmac_update(HMACobject *self, PyObject *obj)
     PyBuffer_Release(&view);
 
     if (r == 0) {
-        _setException(PyExc_ValueError, NULL);
+        (void)_setException(PyExc_ValueError, NULL);
         return 0;
     }
     return 1;
@@ -1703,7 +1717,11 @@ _hmac_dealloc(HMACobject *self)
 static PyObject *
 _hmac_repr(HMACobject *self)
 {
-    PyObject *digest_name = py_digest_name(HMAC_CTX_get_md(self->ctx));
+    const EVP_MD *md = HMAC_CTX_get_md(self->ctx);
+    if (md == NULL) {
+        return _setException(PyExc_ValueError, NULL);
+    }
+    PyObject *digest_name = py_digest_name(md);
     if (digest_name == NULL) {
         return NULL;
     }
@@ -1736,18 +1754,18 @@ _hmac_digest(HMACobject *self, unsigned char *buf, 
unsigned int len)
 {
     HMAC_CTX *temp_ctx = HMAC_CTX_new();
     if (temp_ctx == NULL) {
-        PyErr_NoMemory();
+        (void)PyErr_NoMemory();
         return 0;
     }
     if (!locked_HMAC_CTX_copy(temp_ctx, self)) {
         HMAC_CTX_free(temp_ctx);
-        _setException(PyExc_ValueError, NULL);
+        (void)_setException(PyExc_ValueError, NULL);
         return 0;
     }
     int r = HMAC_Final(temp_ctx, buf, &len);
     HMAC_CTX_free(temp_ctx);
     if (r == 0) {
-        _setException(PyExc_ValueError, NULL);
+        (void)_setException(PyExc_ValueError, NULL);
         return 0;
     }
     return 1;
@@ -1765,7 +1783,7 @@ _hashlib_HMAC_digest_impl(HMACobject *self)
     unsigned char digest[EVP_MAX_MD_SIZE];
     unsigned int digest_size = _hmac_digest_size(self);
     if (digest_size == 0) {
-        return _setException(PyExc_ValueError, NULL);
+        return NULL;
     }
     int r = _hmac_digest(self, digest, digest_size);
     if (r == 0) {
@@ -1790,7 +1808,7 @@ _hashlib_HMAC_hexdigest_impl(HMACobject *self)
     unsigned char digest[EVP_MAX_MD_SIZE];
     unsigned int digest_size = _hmac_digest_size(self);
     if (digest_size == 0) {
-        return _setException(PyExc_ValueError, NULL);
+        return NULL;
     }
     int r = _hmac_digest(self, digest, digest_size);
     if (r == 0) {
@@ -1804,7 +1822,7 @@ _hashlib_hmac_get_digest_size(HMACobject *self, void 
*closure)
 {
     unsigned int digest_size = _hmac_digest_size(self);
     if (digest_size == 0) {
-        return _setException(PyExc_ValueError, NULL);
+        return NULL;
     }
     return PyLong_FromLong(digest_size);
 }
@@ -1822,7 +1840,11 @@ _hashlib_hmac_get_block_size(HMACobject *self, void 
*closure)
 static PyObject *
 _hashlib_hmac_get_name(HMACobject *self, void *closure)
 {
-    PyObject *digest_name = py_digest_name(HMAC_CTX_get_md(self->ctx));
+    const EVP_MD *md = HMAC_CTX_get_md(self->ctx);
+    if (md == NULL) {
+        return _setException(PyExc_ValueError, NULL);
+    }
+    PyObject *digest_name = py_digest_name(md);
     if (digest_name == NULL) {
         return NULL;
     }
@@ -1978,7 +2000,7 @@ _hashlib_get_fips_mode_impl(PyObject *module)
         // But 0 is also a valid result value.
         unsigned long errcode = ERR_peek_last_error();
         if (errcode) {
-            _setException(PyExc_ValueError, NULL);
+            (void)_setException(PyExc_ValueError, NULL);
             return -1;
         }
     }

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to