Commit 64f09bd826 for openssl.org
commit 64f09bd826e8fdefae67aea68ec1bfacefa1d5f4
Author: Nikola Pajkovsky <nikolap@openssl.org>
Date: Tue Jun 30 08:55:09 2026 +0200
crypto/x509/x509_lu.c: fix memory leak in obj_ht_foreach_object()
when sk_X509_OBJECT_push() fails after x509_object_dup() has already
allocated the duplicate, the dup is neither stored on the destination
stack nor freed: the error path only pop_free()s the stack the dup was
never pushed onto, so it is leaked.
Set env ASAN_OPTIONS in test explicitly to detect_leaks=1 to force
ASAN to fail the test. Otherwise, the test reports ok even with valid
leak.
Fixes: 08cecb4448e9 "Add X509_STORE_get1_objects"
Fixes: https://github.com/openssl/openssl/issues/31771
Signed-off-by: Nikola Pajkovsky <nikolap@openssl.org>
Reviewed-by: Norbert Pocs <norbertp@openssl.org>
Reviewed-by: Bob Beck <beck@openssl.org>
MergeDate: Tue Jul 7 07:42:17 2026
(Merged from https://github.com/openssl/openssl/pull/31784)
diff --git a/crypto/x509/x509_lu.c b/crypto/x509/x509_lu.c
index e9cc7145e3..01e1969d19 100644
--- a/crypto/x509/x509_lu.c
+++ b/crypto/x509/x509_lu.c
@@ -764,6 +764,7 @@ static int obj_ht_foreach_object(HT_VALUE *v, void *arg)
return 1;
err:
+ X509_OBJECT_free(dup);
sk_X509_OBJECT_pop_free(*sk, X509_OBJECT_free);
*sk = NULL;
diff --git a/test/recipes/60-test_x509_load_cert_file.t b/test/recipes/60-test_x509_load_cert_file.t
index e329d7675c..15e9908ce1 100644
--- a/test/recipes/60-test_x509_load_cert_file.t
+++ b/test/recipes/60-test_x509_load_cert_file.t
@@ -8,6 +8,8 @@
use OpenSSL::Test qw/:DEFAULT srctop_file/;
+$ENV{ASAN_OPTIONS} = "detect_leaks=1";
+
setup("test_load_cert_file");
plan tests => 1;
diff --git a/test/x509_load_cert_file_test.c b/test/x509_load_cert_file_test.c
index 0df654559a..f9656aaa31 100644
--- a/test/x509_load_cert_file_test.c
+++ b/test/x509_load_cert_file_test.c
@@ -198,6 +198,38 @@ err:
return ret;
}
+static int test_x509_get1_objects_mfail(void)
+{
+ X509 *cert1 = NULL, *cert2 = NULL;
+ X509_STORE *store = NULL;
+ STACK_OF(X509_OBJECT) *objs = NULL;
+ int ret = 0;
+
+ if (!TEST_ptr(cert1 = X509_from_strings(cn_cert1))
+ || !TEST_ptr(cert2 = X509_from_strings(cn_cert2)))
+ goto err;
+
+ store = X509_STORE_new();
+ if (!TEST_ptr(store))
+ goto err;
+ if (!TEST_true(X509_STORE_add_cert(store, cert1))
+ || !TEST_true(X509_STORE_add_cert(store, cert2)))
+ goto err;
+
+ MFAIL_start();
+ objs = X509_STORE_get1_objects(store);
+ MFAIL_end();
+
+ ret = (objs != NULL);
+
+err:
+ sk_X509_OBJECT_pop_free(objs, X509_OBJECT_free);
+ X509_STORE_free(store);
+ X509_free(cert1);
+ X509_free(cert2);
+ return ret;
+}
+
OPT_TEST_DECLARE_USAGE("cert.pem [crl.pem]\n")
int setup_tests(void)
@@ -216,6 +248,7 @@ int setup_tests(void)
ADD_TEST(test_load_cert_file);
ADD_TEST(test_load_same_cn_certs);
ADD_MFAIL_TEST(test_x509_store_add_mfail);
+ ADD_MFAIL_TEST(test_x509_get1_objects_mfail);
return 1;
}