From cb9cb6158f079e4420323b8e8de986ca4fd9ab27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Mon, 19 Oct 2026 14:29:17 -0700 Subject: [PATCH] gh-155833: GC-untrack MD5/SHA* objects before freeing the HACL* state (GH-155834) (cherry picked from commit 29fd3b8b0988d540e5b679667947523f6039da6c) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- .../2026-08-15-12-08-33.gh-issue-155833.Pi2Yjp.rst | 2 ++ Modules/md5module.c | 5 +++-- Modules/sha1module.c | 5 +++-- Modules/sha2module.c | 10 ++++++---- Modules/sha3module.c | 3 ++- 5 files changed, 16 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-08-15-12-08-33.gh-issue-155833.Pi2Yjp.rst diff --git a/Misc/NEWS.d/next/Library/2026-08-15-12-08-33.gh-issue-155833.Pi2Yjp.rst b/Misc/NEWS.d/next/Library/2026-08-15-12-08-33.gh-issue-155833.Pi2Yjp.rst new file mode 100644 index 000000000000000..96bf5de44bd8361 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-08-15-12-08-33.gh-issue-155833.Pi2Yjp.rst @@ -0,0 +1,2 @@ +Ensure that MD5 and SHA* objects are properly GC-untracked before freeing +their internal HACL* state. Patch by Bénédikt Tran. diff --git a/Modules/md5module.c b/Modules/md5module.c index f3855ec3f37faa1..e920e5895ca7507 100644 --- a/Modules/md5module.c +++ b/Modules/md5module.c @@ -70,6 +70,7 @@ newMD5object(MD5State * st) return NULL; } HASHLIB_INIT_MUTEX(md5); + md5->hash_state = NULL; // PyObject_GC_New() does not zero memory PyObject_GC_Track(md5); return md5; @@ -86,13 +87,13 @@ MD5_traverse(PyObject *ptr, visitproc visit, void *arg) static void MD5_dealloc(PyObject *op) { + PyTypeObject *tp = Py_TYPE(op); + PyObject_GC_UnTrack(op); MD5object *ptr = _MD5object_CAST(op); if (ptr->hash_state != NULL) { Hacl_Hash_MD5_free(ptr->hash_state); ptr->hash_state = NULL; } - PyTypeObject *tp = Py_TYPE(op); - PyObject_GC_UnTrack(ptr); PyObject_GC_Del(ptr); Py_DECREF(tp); } diff --git a/Modules/sha1module.c b/Modules/sha1module.c index a746bf74f8d4c19..e00f697a19b7289 100644 --- a/Modules/sha1module.c +++ b/Modules/sha1module.c @@ -71,6 +71,7 @@ newSHA1object(SHA1State *st) return NULL; } HASHLIB_INIT_MUTEX(sha); + sha->hash_state = NULL; // PyObject_GC_New() does not zero memory PyObject_GC_Track(sha); return sha; @@ -88,13 +89,13 @@ SHA1_traverse(PyObject *ptr, visitproc visit, void *arg) static void SHA1_dealloc(PyObject *op) { + PyTypeObject *tp = Py_TYPE(op); + PyObject_GC_UnTrack(op); SHA1object *ptr = _SHA1object_CAST(op); if (ptr->hash_state != NULL) { Hacl_Hash_SHA1_free(ptr->hash_state); ptr->hash_state = NULL; } - PyTypeObject *tp = Py_TYPE(ptr); - PyObject_GC_UnTrack(ptr); PyObject_GC_Del(ptr); Py_DECREF(tp); } diff --git a/Modules/sha2module.c b/Modules/sha2module.c index 72931910c5d7207..ccc83a010dca103 100644 --- a/Modules/sha2module.c +++ b/Modules/sha2module.c @@ -147,6 +147,7 @@ newSHA384object(sha2_state *state) return NULL; } HASHLIB_INIT_MUTEX(sha); + sha->state = NULL; // PyObject_GC_New() does not zero memory PyObject_GC_Track(sha); return sha; @@ -160,6 +161,7 @@ newSHA512object(sha2_state *state) return NULL; } HASHLIB_INIT_MUTEX(sha); + sha->state = NULL; // PyObject_GC_New() does not zero memory PyObject_GC_Track(sha); return sha; @@ -177,13 +179,13 @@ SHA2_traverse(PyObject *ptr, visitproc visit, void *arg) static void SHA256_dealloc(PyObject *op) { + PyTypeObject *tp = Py_TYPE(op); + PyObject_GC_UnTrack(op); SHA256object *ptr = _SHA256object_CAST(op); if (ptr->state != NULL) { Hacl_Hash_SHA2_free_256(ptr->state); ptr->state = NULL; } - PyTypeObject *tp = Py_TYPE(ptr); - PyObject_GC_UnTrack(ptr); PyObject_GC_Del(ptr); Py_DECREF(tp); } @@ -191,13 +193,13 @@ SHA256_dealloc(PyObject *op) static void SHA512_dealloc(PyObject *op) { + PyTypeObject *tp = Py_TYPE(op); + PyObject_GC_UnTrack(op); SHA512object *ptr = _SHA512object_CAST(op); if (ptr->state != NULL) { Hacl_Hash_SHA2_free_512(ptr->state); ptr->state = NULL; } - PyTypeObject *tp = Py_TYPE(ptr); - PyObject_GC_UnTrack(ptr); PyObject_GC_Del(ptr); Py_DECREF(tp); } diff --git a/Modules/sha3module.c b/Modules/sha3module.c index 1c48a83c99db2c1..8c6cef9fd349217 100644 --- a/Modules/sha3module.c +++ b/Modules/sha3module.c @@ -84,6 +84,7 @@ newSHA3object(PyTypeObject *type) return NULL; } HASHLIB_INIT_MUTEX(newobj); + newobj->hash_state = NULL; // PyObject_GC_New() does not zero memory newobj->digest_size = newobj->block_size = 0; PyObject_GC_Track(newobj); return newobj; @@ -220,7 +221,7 @@ SHA3_dealloc(PyObject *self) PyTypeObject *tp = Py_TYPE(self); PyObject_GC_UnTrack(self); (void)SHA3_clear(self); - tp->tp_free(self); + PyObject_GC_Del(self); Py_DECREF(tp); }