Commit c84affae0b for openssl.org

commit c84affae0b848b8194a045d26895f47d52199d8d
Author: Nikola Pajkovsky <nikolap@openssl.org>
Date:   Mon May 11 11:43:28 2026 +0200

    evp: avoid function-pointer-type UB in EVP_*_do_all_provided

    evp_generic_do_all() invokes its callback through a fixed pointer type
    of the form "void (*)(void *method, void *arg)". The public
    EVP_*_do_all_provided() wrappers were handing it user callbacks of type
    for example:

       void (*)(EVP_MD *, void *)

    cast to that generic shape:

        evp_generic_do_all(..., (void (*)(void *, void *))fn, arg, ...);

    Calling a function through a pointer whose type does not match the
    function's actual definition is undefined behavior in C and is flagged
    by UBSan's -fsanitize=function.

    Introduce a per-type thunk generated by EVP_DO_ALL_PROVIDED_THUNK that
    has the exact signature evp_generic_do_all() expects. The thunk
    receives the user's typed callback and arg in a small on-stack struct
    and forwards them with the correct types, so every indirect call now
    matches the pointee's real prototype.
    No functional change intended.

    Fixes: https://github.com/openssl/project/issues/1949
    Signed-off-by: Nikola Pajkovsky <nikolap@openssl.org>

    Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
    Reviewed-by: Neil Horman <nhorman@openssl.org>
    MergeDate: Wed May 20 15:53:38 2026
    (Merged from https://github.com/openssl/openssl/pull/31151)

diff --git a/crypto/evp/asymcipher.c b/crypto/evp/asymcipher.c
index b76a144e8a..bdcb8b59dc 100644
--- a/crypto/evp/asymcipher.c
+++ b/crypto/evp/asymcipher.c
@@ -513,8 +513,12 @@ void EVP_ASYM_CIPHER_do_all_provided(OSSL_LIB_CTX *libctx,
         void *arg),
     void *arg)
 {
+    struct EVP_ASYM_CIPHER_do_all_provided_thunk t;
+
+    t.fn = fn;
+    t.arg = arg;
     evp_generic_do_all(libctx, OSSL_OP_ASYM_CIPHER,
-        (void (*)(void *, void *))fn, arg,
+        EVP_ASYM_CIPHER_do_all_provided_thunk, &t,
         evp_asym_cipher_from_algorithm,
         evp_asym_cipher_up_ref,
         evp_asym_cipher_free);
diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c
index 43fa6b1256..b6c01daeee 100644
--- a/crypto/evp/digest.c
+++ b/crypto/evp/digest.c
@@ -1018,8 +1018,12 @@ void EVP_MD_do_all_provided(OSSL_LIB_CTX *libctx,
     void (*fn)(EVP_MD *mac, void *arg),
     void *arg)
 {
+    struct EVP_MD_do_all_provided_thunk t;
+
+    t.fn = fn;
+    t.arg = arg;
     evp_generic_do_all(libctx, OSSL_OP_DIGEST,
-        (void (*)(void *, void *))fn, arg,
+        EVP_MD_do_all_provided_thunk, &t,
         evp_md_from_algorithm, evp_md_up_ref, evp_md_free);
 }

diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c
index 9c27b240bd..a23846fdf1 100644
--- a/crypto/evp/evp_enc.c
+++ b/crypto/evp/evp_enc.c
@@ -1589,8 +1589,12 @@ void EVP_CIPHER_do_all_provided(OSSL_LIB_CTX *libctx,
     void (*fn)(EVP_CIPHER *mac, void *arg),
     void *arg)
 {
+    struct EVP_CIPHER_do_all_provided_thunk t;
+
+    t.fn = fn;
+    t.arg = arg;
     evp_generic_do_all(libctx, OSSL_OP_CIPHER,
-        (void (*)(void *, void *))fn, arg,
+        EVP_CIPHER_do_all_provided_thunk, &t,
         evp_cipher_from_algorithm, evp_cipher_up_ref,
         evp_cipher_free);
 }
diff --git a/crypto/evp/evp_local.h b/crypto/evp/evp_local.h
index fc01b71efc..d4a72b7527 100644
--- a/crypto/evp/evp_local.h
+++ b/crypto/evp/evp_local.h
@@ -398,4 +398,27 @@ int evp_names_do_all(OSSL_PROVIDER *prov, int number,
     void *data);
 int evp_cipher_cache_constants(EVP_CIPHER *cipher);

+#define EVP_DO_ALL_PROVIDED_THUNK(type)                                                       \
+    struct type##_do_all_provided_thunk {                                                     \
+        void (*fn)(type * method, void *arg);                                                 \
+        void *arg;                                                                            \
+    };                                                                                        \
+    static ossl_inline ossl_unused void type##_do_all_provided_thunk(void *method, void *arg) \
+    {                                                                                         \
+        struct type##_do_all_provided_thunk *t = arg;                                         \
+        (*t->fn)((type *)method, t->arg);                                                     \
+    }
+
+EVP_DO_ALL_PROVIDED_THUNK(EVP_ASYM_CIPHER)
+EVP_DO_ALL_PROVIDED_THUNK(EVP_MD)
+EVP_DO_ALL_PROVIDED_THUNK(EVP_CIPHER)
+EVP_DO_ALL_PROVIDED_THUNK(EVP_RAND)
+EVP_DO_ALL_PROVIDED_THUNK(EVP_KEYEXCH)
+EVP_DO_ALL_PROVIDED_THUNK(EVP_KDF)
+EVP_DO_ALL_PROVIDED_THUNK(EVP_KEM)
+EVP_DO_ALL_PROVIDED_THUNK(EVP_KEYMGMT)
+EVP_DO_ALL_PROVIDED_THUNK(EVP_MAC)
+EVP_DO_ALL_PROVIDED_THUNK(EVP_SIGNATURE)
+EVP_DO_ALL_PROVIDED_THUNK(EVP_SKEYMGMT)
+
 #endif /* !defined(OSSL_LIBCRYPTO_EVP_EVP_LOCAL_H) */
diff --git a/crypto/evp/evp_rand.c b/crypto/evp/evp_rand.c
index 689243ef10..623b87135a 100644
--- a/crypto/evp/evp_rand.c
+++ b/crypto/evp/evp_rand.c
@@ -492,8 +492,12 @@ void EVP_RAND_do_all_provided(OSSL_LIB_CTX *libctx,
     void (*fn)(EVP_RAND *rand, void *arg),
     void *arg)
 {
+    struct EVP_RAND_do_all_provided_thunk t;
+
+    t.fn = fn;
+    t.arg = arg;
     evp_generic_do_all(libctx, OSSL_OP_RAND,
-        (void (*)(void *, void *))fn, arg,
+        EVP_RAND_do_all_provided_thunk, &t,
         evp_rand_from_algorithm, evp_rand_up_ref,
         evp_rand_free);
 }
diff --git a/crypto/evp/exchange.c b/crypto/evp/exchange.c
index a5eea9af1d..3928c08ec3 100644
--- a/crypto/evp/exchange.c
+++ b/crypto/evp/exchange.c
@@ -591,8 +591,12 @@ void EVP_KEYEXCH_do_all_provided(OSSL_LIB_CTX *libctx,
     void (*fn)(EVP_KEYEXCH *keyexch, void *arg),
     void *arg)
 {
+    struct EVP_KEYEXCH_do_all_provided_thunk t;
+
+    t.fn = fn;
+    t.arg = arg;
     evp_generic_do_all(libctx, OSSL_OP_KEYEXCH,
-        (void (*)(void *, void *))fn, arg,
+        EVP_KEYEXCH_do_all_provided_thunk, &t,
         evp_keyexch_from_algorithm,
         evp_keyexch_up_ref,
         evp_keyexch_free);
diff --git a/crypto/evp/kdf_meth.c b/crypto/evp/kdf_meth.c
index 5ac6a94013..31680ee664 100644
--- a/crypto/evp/kdf_meth.c
+++ b/crypto/evp/kdf_meth.c
@@ -235,7 +235,11 @@ void EVP_KDF_do_all_provided(OSSL_LIB_CTX *libctx,
     void (*fn)(EVP_KDF *kdf, void *arg),
     void *arg)
 {
+    struct EVP_KDF_do_all_provided_thunk t;
+
+    t.fn = fn;
+    t.arg = arg;
     evp_generic_do_all(libctx, OSSL_OP_KDF,
-        (void (*)(void *, void *))fn, arg,
+        EVP_KDF_do_all_provided_thunk, &t,
         evp_kdf_from_algorithm, evp_kdf_up_ref, evp_kdf_free);
 }
diff --git a/crypto/evp/kem.c b/crypto/evp/kem.c
index d0cf696b32..317db87b52 100644
--- a/crypto/evp/kem.c
+++ b/crypto/evp/kem.c
@@ -499,7 +499,11 @@ void EVP_KEM_do_all_provided(OSSL_LIB_CTX *libctx,
     void (*fn)(EVP_KEM *kem, void *arg),
     void *arg)
 {
-    evp_generic_do_all(libctx, OSSL_OP_KEM, (void (*)(void *, void *))fn, arg,
+    struct EVP_KEM_do_all_provided_thunk t;
+
+    t.fn = fn;
+    t.arg = arg;
+    evp_generic_do_all(libctx, OSSL_OP_KEM, EVP_KEM_do_all_provided_thunk, &t,
         evp_kem_from_algorithm,
         evp_kem_up_ref,
         evp_kem_free);
diff --git a/crypto/evp/keymgmt_meth.c b/crypto/evp/keymgmt_meth.c
index d37ddcbaf8..e7f00d091f 100644
--- a/crypto/evp/keymgmt_meth.c
+++ b/crypto/evp/keymgmt_meth.c
@@ -350,8 +350,12 @@ void EVP_KEYMGMT_do_all_provided(OSSL_LIB_CTX *libctx,
     void (*fn)(EVP_KEYMGMT *keymgmt, void *arg),
     void *arg)
 {
+    struct EVP_KEYMGMT_do_all_provided_thunk t;
+
+    t.fn = fn;
+    t.arg = arg;
     evp_generic_do_all(libctx, OSSL_OP_KEYMGMT,
-        (void (*)(void *, void *))fn, arg,
+        EVP_KEYMGMT_do_all_provided_thunk, &t,
         keymgmt_from_algorithm,
         evp_keymgmt_up_ref,
         evp_keymgmt_free);
diff --git a/crypto/evp/mac_meth.c b/crypto/evp/mac_meth.c
index ee29f58b3e..ba47e95870 100644
--- a/crypto/evp/mac_meth.c
+++ b/crypto/evp/mac_meth.c
@@ -246,8 +246,12 @@ void EVP_MAC_do_all_provided(OSSL_LIB_CTX *libctx,
     void (*fn)(EVP_MAC *mac, void *arg),
     void *arg)
 {
+    struct EVP_MAC_do_all_provided_thunk t;
+
+    t.fn = fn;
+    t.arg = arg;
     evp_generic_do_all(libctx, OSSL_OP_MAC,
-        (void (*)(void *, void *))fn, arg,
+        EVP_MAC_do_all_provided_thunk, &t,
         evp_mac_from_algorithm, evp_mac_up_ref, evp_mac_free);
 }

diff --git a/crypto/evp/signature.c b/crypto/evp/signature.c
index 4ca52810ee..51a5f0c4df 100644
--- a/crypto/evp/signature.c
+++ b/crypto/evp/signature.c
@@ -532,8 +532,12 @@ void EVP_SIGNATURE_do_all_provided(OSSL_LIB_CTX *libctx,
         void *arg),
     void *arg)
 {
+    struct EVP_SIGNATURE_do_all_provided_thunk t;
+
+    t.fn = fn;
+    t.arg = arg;
     evp_generic_do_all(libctx, OSSL_OP_SIGNATURE,
-        (void (*)(void *, void *))fn, arg,
+        EVP_SIGNATURE_do_all_provided_thunk, &t,
         evp_signature_from_algorithm,
         evp_signature_up_ref,
         evp_signature_free);
diff --git a/crypto/evp/skeymgmt_meth.c b/crypto/evp/skeymgmt_meth.c
index 80e1abf883..75c4fef675 100644
--- a/crypto/evp/skeymgmt_meth.c
+++ b/crypto/evp/skeymgmt_meth.c
@@ -207,8 +207,12 @@ void EVP_SKEYMGMT_do_all_provided(OSSL_LIB_CTX *libctx,
     void (*fn)(EVP_SKEYMGMT *skeymgmt, void *arg),
     void *arg)
 {
+    struct EVP_SKEYMGMT_do_all_provided_thunk t;
+
+    t.fn = fn;
+    t.arg = arg;
     evp_generic_do_all(libctx, OSSL_OP_SKEYMGMT,
-        (void (*)(void *, void *))fn, arg,
+        EVP_SKEYMGMT_do_all_provided_thunk, &t,
         skeymgmt_from_algorithm,
         evp_skeymgmt_up_ref,
         evp_skeymgmt_free);