[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 097846502b)
This commit is contained in:
Bénédikt Tran 2025-03-03 12:01:01 +01:00 committed by GitHub
parent 36e696738b
commit 9643ce9019
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -427,7 +427,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;
@ -442,7 +443,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;
@ -468,12 +468,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 *
@ -506,7 +501,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;
@ -582,17 +577,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]
@ -617,17 +615,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]
@ -695,7 +696,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[] = {
@ -793,21 +798,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]
@ -841,15 +847,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);
@ -857,6 +858,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[] = {
@ -957,7 +963,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;
}
@ -978,7 +984,7 @@ py_evp_fromname(PyObject *module, const char *digestname, PyObject *data_obj,
}
}
exit:
exit:
if (data_obj != NULL) {
PyBuffer_Release(&view);
}
@ -1423,14 +1429,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;
}
@ -1439,22 +1445,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);
@ -1474,8 +1480,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;
}
@ -1531,8 +1536,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);
}
@ -1581,6 +1585,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;
}
@ -1588,7 +1593,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;
}
@ -1626,11 +1631,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;
}
@ -1658,7 +1672,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;
@ -1711,7 +1725,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;
}
@ -1744,18 +1762,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;
@ -1773,7 +1791,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) {
@ -1798,7 +1816,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) {
@ -1812,7 +1830,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);
}
@ -1830,7 +1848,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;
}
@ -1981,7 +2003,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;
}
}