From: Nikola Pajkovsky Date: Mon, 11 May 2026 09:43:28 +0000 (+0200) Subject: evp: avoid function-pointer-type UB in EVP_*_do_all_provided X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=c84affae0b848b8194a045d26895f47d52199d8d;p=thirdparty%2Fopenssl.git 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 Reviewed-by: Eugene Syromiatnikov Reviewed-by: Neil Horman 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 b76a144e8ac..bdcb8b59dc0 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 43fa6b1256b..b6c01daeee6 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 9c27b240bd3..a23846fdf13 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 fc01b71efc7..d4a72b7527c 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 689243ef100..623b87135af 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 a5eea9af1d0..3928c08ec38 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 5ac6a94013b..31680ee6647 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 d0cf696b322..317db87b52a 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 d37ddcbaf87..e7f00d091fc 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 ee29f58b3e2..ba47e958703 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 4ca52810ee5..51a5f0c4df5 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 80e1abf8836..75c4fef6751 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);