Commit 77f492f29f for openssl.org
commit 77f492f29f882e07d57e16920138d991dc9af018
Author: Neil Horman <nhorman@openssl.org>
Date: Sat Jul 25 22:23:25 2026 -0400
oqs noted a double free recently:
https://github.com/open-quantum-safe/oqs-provider/pull/805#issuecomment-5034437500
Its happening because, recently we made some fixes to account for
providers that request no-caching fetches, which all seems to work
reasonably well.
Except for the corner case oqs recently exposed, in which the provider
may request the caching of some algorithms, but not others. When this
occurs, the core libcrypto creates a temporary store for those
requested, but stored the cachable ones in the libctx store.
inner_evp_generic_fetch treats the presence of an allocated tmp store as
implying that all algorithms fetched are non-cacheable, even if some
are. The result is that, for those cacheable items, they also get
treated as non-cacheable, missing the extra ref count taken when they
are added to the method store cache. As a result, they get freed while
still in use, and you get the issue referenced above.
Instead of assuming that a tmp_store means all algorithms are
non-cacheable, instead, try to look the method up in the tmp_store
cache, and cache it if its not found (i.e. its not in the temp store)
Fixes https://github.com/open-quantum-safe/oqs-provider/pull/805
Reviewed-by: Saša NedvÄ›dický <sashan@openssl.org>
Reviewed-by: Andrew Dinh <andrewd@openssl.org>
MergeDate: Sat Aug 1 14:30:49 2026
(Merged from https://github.com/openssl/openssl/pull/32077)
diff --git a/crypto/evp/evp_fetch.c b/crypto/evp/evp_fetch.c
index 15204628db..15478f9151 100644
--- a/crypto/evp/evp_fetch.c
+++ b/crypto/evp/evp_fetch.c
@@ -274,6 +274,9 @@ inner_evp_generic_fetch(struct evp_method_data_st *methdata,
uint32_t meth_id = 0;
void *method = NULL;
int unsupported, name_id;
+ int set_in_cache = 1;
+ void *tmp_method;
+ const OSSL_PROVIDER *tmp_prov = prov;
if (store == NULL || namemap == NULL) {
ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_INVALID_ARGUMENT);
@@ -364,7 +367,34 @@ inner_evp_generic_fetch(struct evp_method_data_st *methdata,
* cached end up in ->tmp_store when provider asks not
* to cache the result (see ossl_method_construct_reserve_store())
*/
- if (meth_id != 0 && methdata->tmp_store == NULL) {
+ if (meth_id != 0) {
+ /*
+ * If the method doesn't exist in the tmp_store, either the tmp_store doesn't exist
+ * or the algorithm doesn't exist there, in either case, this is a cacheable entry
+ */
+ if (!ossl_method_store_fetch(methdata->tmp_store, meth_id, propq, &tmp_prov, &tmp_method)) {
+ set_in_cache = 1;
+ } else {
+ /*
+ * We found a matching method in the temp store, don't cache this entry
+ */
+ if (tmp_method == method) {
+ set_in_cache = 0;
+ } else {
+ set_in_cache = 1;
+ }
+
+#ifdef OPENSSL_NO_CACHED_FETCH
+ /*
+ * ossl_method_store_fetch takes a reference on the fetched method
+ * when using NO_CACHED_FETCH, so we need to free it here
+ */
+ free_method(tmp_method);
+#endif
+ }
+ }
+
+ if (set_in_cache == 1) {
ossl_method_store_cache_set(store, prov, meth_id, propq,
method, up_ref_method, free_method);
} else {