Skip to content

gh-131316: handle NULL values returned by HACL* functions #131324

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 102 additions & 40 deletions Modules/blake2module.c
Original file line number Diff line number Diff line change
Expand Up @@ -395,26 +395,33 @@ new_Blake2Object(PyTypeObject *type)
* 64 bits so we loop in <4gig chunks when needed. */

#if PY_SSIZE_T_MAX > UINT32_MAX
#define HACL_UPDATE_LOOP(update,state,buf,len) \
while (len > UINT32_MAX) { \
update(state, buf, UINT32_MAX); \
len -= UINT32_MAX; \
buf += UINT32_MAX; \
}
# define HACL_UPDATE_LOOP(UPDATE_FUNC, STATE, BUF, LEN) \
do { \
while (LEN > UINT32_MAX) { \
(void)UPDATE_FUNC(STATE, BUF, UINT32_MAX); \
LEN -= UINT32_MAX; \
BUF += UINT32_MAX; \
} \
} while (0)
#else
#define HACL_UPDATE_LOOP(update,state,buf,len)
# define HACL_UPDATE_LOOP(...)
#endif

#define HACL_UPDATE(update,state,buf,len) do { \
/* Note: we explicitly ignore the error code on the basis that it would take >
* 1 billion years to overflow the maximum admissible length for SHA2-256
* (namely, 2^61-1 bytes). */ \
HACL_UPDATE_LOOP(update,state,buf,len) \
/* Cast to uint32_t is safe: len <= UINT32_MAX at this point. */ \
update(state, buf, (uint32_t) len); \
} while (0)
/*
* Note: we explicitly ignore the error code on the basis that it would take
* more than 1 billion years to overflow the maximum admissible length for
* blake2b/2s (2^64 - 1).
*/
#define HACL_UPDATE(UPDATE_FUNC, STATE, BUF, LEN) \
do { \
HACL_UPDATE_LOOP(UPDATE_FUNC, STATE, BUF, LEN); \
/* cast to uint32_t is now safe */ \
(void)UPDATE_FUNC(STATE, BUF, (uint32_t)LEN); \
} while (0)

static void update(Blake2Object *self, uint8_t *buf, Py_ssize_t len) {
static void
update(Blake2Object *self, uint8_t *buf, Py_ssize_t len)
{
switch (self->impl) {
// These need to be ifdef'd out otherwise it's an unresolved symbol at
// link-time.
Expand Down Expand Up @@ -583,21 +590,41 @@ py_blake2b_or_s_new(PyTypeObject *type, PyObject *data, int digest_size,

switch (self->impl) {
#if HACL_CAN_COMPILE_SIMD256
case Blake2b_256:
case Blake2b_256: {
self->blake2b_256_state = Hacl_Hash_Blake2b_Simd256_malloc_with_params_and_key(&params, last_node, key->buf);
if (self->blake2b_256_state == NULL) {
(void)PyErr_NoMemory();
goto error;
}
break;
}
#endif
#if HACL_CAN_COMPILE_SIMD128
case Blake2s_128:
case Blake2s_128: {
self->blake2s_128_state = Hacl_Hash_Blake2s_Simd128_malloc_with_params_and_key(&params, last_node, key->buf);
if (self->blake2s_128_state == NULL) {
(void)PyErr_NoMemory();
goto error;
}
break;
}
#endif
case Blake2b:
case Blake2b: {
self->blake2b_state = Hacl_Hash_Blake2b_malloc_with_params_and_key(&params, last_node, key->buf);
if (self->blake2b_state == NULL) {
(void)PyErr_NoMemory();
goto error;
}
break;
case Blake2s:
}
case Blake2s: {
self->blake2s_state = Hacl_Hash_Blake2s_malloc_with_params_and_key(&params, last_node, key->buf);
if (self->blake2s_state == NULL) {
(void)PyErr_NoMemory();
goto error;
}
break;
}
default:
Py_UNREACHABLE();
}
Expand All @@ -610,7 +637,8 @@ py_blake2b_or_s_new(PyTypeObject *type, PyObject *data, int digest_size,
Py_BEGIN_ALLOW_THREADS
update(self, buf.buf, buf.len);
Py_END_ALLOW_THREADS
} else {
}
else {
update(self, buf.buf, buf.len);
}
PyBuffer_Release(&buf);
Expand Down Expand Up @@ -688,44 +716,78 @@ py_blake2s_new_impl(PyTypeObject *type, PyObject *data, int digest_size,
return py_blake2b_or_s_new(type, data, digest_size, key, salt, person, fanout, depth, leaf_size, node_offset, node_depth, inner_size, last_node, usedforsecurity);
}

/*[clinic input]
_blake2.blake2b.copy

Return a copy of the hash object.
[clinic start generated code]*/

static PyObject *
_blake2_blake2b_copy_impl(Blake2Object *self)
/*[clinic end generated code: output=622d1c56b91c50d8 input=e383c2d199fd8a2e]*/
static int
blake2_blake2b_copy_locked(Blake2Object *self, Blake2Object *cpy)
{
Blake2Object *cpy;

if ((cpy = new_Blake2Object(Py_TYPE(self))) == NULL)
return NULL;

ENTER_HASHLIB(self);
assert(cpy != NULL);
switch (self->impl) {
#if HACL_CAN_COMPILE_SIMD256
case Blake2b_256:
case Blake2b_256: {
cpy->blake2b_256_state = Hacl_Hash_Blake2b_Simd256_copy(self->blake2b_256_state);
if (cpy->blake2b_256_state == NULL) {
goto error;
}
break;
}
#endif
#if HACL_CAN_COMPILE_SIMD128
case Blake2s_128:
case Blake2s_128: {
cpy->blake2s_128_state = Hacl_Hash_Blake2s_Simd128_copy(self->blake2s_128_state);
if (cpy->blake2s_128_state == NULL) {
goto error;
}
break;
}
#endif
case Blake2b:
case Blake2b: {
cpy->blake2b_state = Hacl_Hash_Blake2b_copy(self->blake2b_state);
if (cpy->blake2b_state == NULL) {
goto error;
}
break;
case Blake2s:
}
case Blake2s: {
cpy->blake2s_state = Hacl_Hash_Blake2s_copy(self->blake2s_state);
if (cpy->blake2s_state == NULL) {
goto error;
}
break;
}
default:
Py_UNREACHABLE();
}
cpy->impl = self->impl;
return 0;

error:
(void)PyErr_NoMemory();
return -1;
}

/*[clinic input]
_blake2.blake2b.copy

Return a copy of the hash object.
[clinic start generated code]*/

static PyObject *
_blake2_blake2b_copy_impl(Blake2Object *self)
/*[clinic end generated code: output=622d1c56b91c50d8 input=e383c2d199fd8a2e]*/
{
int rc;
Blake2Object *cpy;

if ((cpy = new_Blake2Object(Py_TYPE(self))) == NULL) {
return NULL;
}

ENTER_HASHLIB(self);
rc = blake2_blake2b_copy_locked(self, cpy);
LEAVE_HASHLIB(self);
if (rc < 0) {
Py_DECREF(cpy);
return NULL;
}
return (PyObject *)cpy;
}

Expand Down
47 changes: 32 additions & 15 deletions Modules/md5module.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,17 @@ MD5Type_copy_impl(MD5object *self, PyTypeObject *cls)
MD5State *st = PyType_GetModuleState(cls);

MD5object *newobj;
if ((newobj = newMD5object(st))==NULL)
if ((newobj = newMD5object(st)) == NULL) {
return NULL;
}

ENTER_HASHLIB(self);
newobj->hash_state = Hacl_Hash_MD5_copy(self->hash_state);
LEAVE_HASHLIB(self);
if (newobj->hash_state == NULL) {
Py_DECREF(self);
return PyErr_NoMemory();
}
return (PyObject *)newobj;
}

Expand Down Expand Up @@ -173,15 +178,23 @@ MD5Type_hexdigest_impl(MD5object *self)
return PyUnicode_FromStringAndSize(digest_hex, sizeof(digest_hex));
}

static void update(Hacl_Hash_MD5_state_t *state, uint8_t *buf, Py_ssize_t len) {
static void
update(Hacl_Hash_MD5_state_t *state, uint8_t *buf, Py_ssize_t len)
{
/*
* Note: we explicitly ignore the error code on the basis that it would
* take more than 1 billion years to overflow the maximum admissible length
* for MD5 (2^61 - 1).
*/
#if PY_SSIZE_T_MAX > UINT32_MAX
while (len > UINT32_MAX) {
Hacl_Hash_MD5_update(state, buf, UINT32_MAX);
len -= UINT32_MAX;
buf += UINT32_MAX;
}
while (len > UINT32_MAX) {
(void)Hacl_Hash_MD5_update(state, buf, UINT32_MAX);
len -= UINT32_MAX;
buf += UINT32_MAX;
}
#endif
Hacl_Hash_MD5_update(state, buf, (uint32_t) len);
/* cast to uint32_t is now safe */
(void)Hacl_Hash_MD5_update(state, buf, (uint32_t)len);
}

/*[clinic input]
Expand Down Expand Up @@ -286,32 +299,36 @@ _md5_md5_impl(PyObject *module, PyObject *string, int usedforsecurity)
MD5object *new;
Py_buffer buf;

if (string)
if (string) {
GET_BUFFER_VIEW_OR_ERROUT(string, &buf);
}

MD5State *st = md5_get_state(module);
if ((new = newMD5object(st)) == NULL) {
if (string)
if (string) {
PyBuffer_Release(&buf);
}
return NULL;
}

new->hash_state = Hacl_Hash_MD5_malloc();

if (PyErr_Occurred()) {
if (new->hash_state == NULL) {
Py_DECREF(new);
if (string)
if (string) {
PyBuffer_Release(&buf);
return NULL;
}
return PyErr_NoMemory();
}

if (string) {
if (buf.len >= HASHLIB_GIL_MINSIZE) {
/* We do not initialize self->lock here as this is the constructor
* where it is not yet possible to have concurrent access. */
Py_BEGIN_ALLOW_THREADS
update(new->hash_state, buf.buf, buf.len);
Py_END_ALLOW_THREADS
} else {
}
else {
update(new->hash_state, buf.buf, buf.len);
}
PyBuffer_Release(&buf);
Expand Down
Loading
Loading