Commit 41a2d15da0 for openssl.org
commit 41a2d15da05c6f9d453ff270ea4571f5001c7e4a
Author: Mounir IDRASSI <mounir.idrassi@idrix.fr>
Date: Tue Jun 30 21:55:05 2026 +0900
apps/s_server.c: fix BIO leak in ech_load_dir() on read failure
When loading ECH keys from a directory (-ech_dir or -ech_noretry_dir),
ech_load_dir() allocated a BIO via BIO_new_file(), but only freed it
on the success path. If a file was readable,
yet OSSL_ECHSTORE_read_pem() failed, the continue skipped
BIO_free_all(), leaking the BIO.
OSSL_ECHSTORE_read_pem() does not take ownership of the caller-supplied
BIO. It pushes and pops its own internal buffer BIO, so the caller
remains responsible for freeing the file BIO in all cases.
Fix this by making the BIO local to each loop iteration and freeing
it in the failure branch as well as the success branch.
This also avoids carrying a dangling BIO pointer from one loop iteration
to the next.
Verified with Valgrind against a directory containing invalid ECH PEM
files: definitely lost: 0 bytes, previously leaked 128 bytes per failing
file.
Resolves: https://github.com/openssl/openssl/issues/31770
Fixes: a2e5848d9d11 "s_client and s_server options for ECH"
Reviewed-by: Daniel Kubec <kubec@openssl.foundation>
Reviewed-by: Andrew Dinh <andrewd@openssl.org>
Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
Merge-date: Fri Oct 9 19:55:28 2026
Merged-from: https://github.com/openssl/openssl/pull/31790
diff --git a/apps/s_server.c b/apps/s_server.c
index 3f689b0d13..13b46c613e 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -1594,7 +1594,6 @@ static int ech_load_dir(SSL_CTX *lctx, const char *thedir,
OPENSSL_DIR_CTX *d = NULL;
const char *thisfile = NULL;
OSSL_ECHSTORE *es = NULL;
- BIO *in = NULL;
int loaded = 0;
int ret = 0;
@@ -1622,6 +1621,7 @@ static int ech_load_dir(SSL_CTX *lctx, const char *thedir,
}
while ((thisfile = OPENSSL_DIR_read(&d, thedir))) {
char filepath[PATH_MAX];
+ BIO *in = NULL;
int r;
#ifdef OPENSSL_SYS_VMS
@@ -1638,6 +1638,7 @@ static int ech_load_dir(SSL_CTX *lctx, const char *thedir,
}
if ((in = BIO_new_file(filepath, "r")) == NULL
|| OSSL_ECHSTORE_read_pem(es, in, for_retry) != 1) {
+ BIO_free_all(in);
BIO_printf(bio_err, "Failed reading from: %s\n", filepath);
continue;
}