Commit b86b1098fd for openssl.org
commit b86b1098fd7ec47e1c9d43a7566bf4e287b1d390
Author: Eugene Syromiatnikov <esyr@openssl.org>
Date: Wed Oct 7 15:14:31 2026 +0200
crypto/x509/x509_lu.c: avoid freeing X509_OBJECTs in X509_STORE_get0_objects()
The implementation of hash table conversion in commit 04589b59ef50
"x509store: reduce lock contention in X509_STORE" introduced a potential
use-after-free condition when X509_STORE_get0_objects() is called during
X.509 verification. Avoid that by re-using existing X509_OBJECTs
instead of duplicating them.
Resolves: https://github.com/openssl/openssl/issues/33063
Fixes: 04589b59ef50 "x509store: reduce lock contention in X509_STORE"
Signed-off-by: Eugene Syromiatnikov <esyr@openssl.org>
Reviewed-by: Mounir Idrassi <mounir.idrassi@idrix.fr>
Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
Merge-date: Tue Oct 13 13:45:39 2026
Merged-from: https://github.com/openssl/openssl/pull/33147
diff --git a/crypto/x509/x509_lu.c b/crypto/x509/x509_lu.c
index e166110c9b..08c116bf07 100644
--- a/crypto/x509/x509_lu.c
+++ b/crypto/x509/x509_lu.c
@@ -761,47 +761,83 @@ static X509_OBJECT *x509_object_dup(const X509_OBJECT *obj)
return ret;
}
-static int obj_ht_foreach_object(HT_VALUE *v, void *arg)
+#ifndef OPENSSL_NO_DEPRECATED_4_0
+static int obj_ht_to_stack(HT_VALUE *v, void *arg)
{
STACK_OF(X509_OBJECT) **sk = arg;
STACK_OF(X509_OBJECT) *objs = v->value;
- X509_OBJECT *dup, *obj;
+ X509_OBJECT *obj;
int i;
for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
obj = sk_X509_OBJECT_value(objs, i);
- dup = x509_object_dup(obj);
- if (dup == NULL)
- goto err;
- if (sk_X509_OBJECT_push(*sk, dup) == 0)
+ if (sk_X509_OBJECT_push(*sk, obj) == 0)
goto err;
}
return 1;
err:
- X509_OBJECT_free(dup);
- sk_X509_OBJECT_pop_free(*sk, X509_OBJECT_free);
- *sk = NULL;
+ sk_X509_OBJECT_zero(*sk);
return 0;
}
-#ifndef OPENSSL_NO_DEPRECATED_4_0
+static int obj_ht_zero_stacks(HT_VALUE *v, void *arg)
+{
+ STACK_OF(X509_OBJECT) *objs = v->value;
+
+ sk_X509_OBJECT_zero(objs);
+
+ return 1;
+}
+
STACK_OF(X509_OBJECT) *X509_STORE_get0_objects(const X509_STORE *xs)
{
X509_STORE *store = (X509_STORE *)xs;
if (xs->objs_ht != NULL) {
- ossl_ht_foreach_until(xs->objs_ht, obj_ht_foreach_object, &store->objs);
- ossl_ht_free(xs->objs_ht);
- store->objs_ht = NULL;
+ ossl_ht_foreach_until(xs->objs_ht, obj_ht_to_stack, &store->objs);
+ if (sk_X509_OBJECT_num(store->objs) > 0
+ || ossl_ht_count(xs->objs_ht) == 0) {
+ ossl_ht_foreach_until(xs->objs_ht, obj_ht_zero_stacks, NULL);
+ ossl_ht_free(xs->objs_ht);
+ store->objs_ht = NULL;
+ } else {
+ return NULL;
+ }
}
return xs->objs;
}
#endif
+static int obj_ht_foreach_object(HT_VALUE *v, void *arg)
+{
+ STACK_OF(X509_OBJECT) **sk = arg;
+ STACK_OF(X509_OBJECT) *objs = v->value;
+ X509_OBJECT *dup, *obj;
+ int i;
+
+ for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
+ obj = sk_X509_OBJECT_value(objs, i);
+ dup = x509_object_dup(obj);
+ if (dup == NULL)
+ goto err;
+ if (sk_X509_OBJECT_push(*sk, dup) == 0)
+ goto err;
+ }
+
+ return 1;
+
+err:
+ X509_OBJECT_free(dup);
+ sk_X509_OBJECT_pop_free(*sk, X509_OBJECT_free);
+ *sk = NULL;
+
+ return 0;
+}
+
STACK_OF(X509_OBJECT) *X509_STORE_get1_objects(X509_STORE *store)
{
STACK_OF(X509_OBJECT) *objs;
diff --git a/doc/man3/X509_STORE_get0_param.pod b/doc/man3/X509_STORE_get0_param.pod
index cb0cd40d9d..411fd26db7 100644
--- a/doc/man3/X509_STORE_get0_param.pod
+++ b/doc/man3/X509_STORE_get0_param.pod
@@ -55,7 +55,8 @@ X509_STORE_set1_param() returns 1 for success and 0 for failure.
X509_STORE_get1_objects() returns a pointer to a stack of the retrieved
objects on success, else NULL.
-X509_STORE_get0_objects() returns a pointer to a stack of B<X509_OBJECT>.
+X509_STORE_get0_objects() returns a pointer to a stack of B<X509_OBJECT>
+or NULL if the stack construction has failed.
X509_STORE_get1_all_certs() returns a pointer to a stack of the retrieved
certificates on success, else NULL.