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;
         }