Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:26
erlang
2201-crypto-Avoid-resource-takeovers-between-in...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 2201-crypto-Avoid-resource-takeovers-between-incompatible.patch of Package erlang
From 8f37cca08c18916806df4f5d33509177c1ee7c36 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson <sverker@erlang.org> Date: Tue, 19 Sep 2023 14:34:51 +0200 Subject: [PATCH 1/3] crypto: Avoid resource takeovers between incompatible OpenSSL versions --- lib/crypto/c_src/cipher.c | 6 +- lib/crypto/c_src/cipher.h | 2 +- lib/crypto/c_src/crypto.c | 126 ++++++++++++++++++++++++-------------- lib/crypto/c_src/engine.c | 12 ++-- lib/crypto/c_src/engine.h | 2 +- lib/crypto/c_src/hash.c | 6 +- lib/crypto/c_src/hash.h | 2 +- lib/crypto/c_src/hmac.c | 6 +- lib/crypto/c_src/hmac.h | 2 +- lib/crypto/c_src/info.c | 17 +++++ lib/crypto/c_src/info.h | 12 ++++ lib/crypto/c_src/mac.c | 8 +-- lib/crypto/c_src/mac.h | 2 +- 13 files changed, 136 insertions(+), 67 deletions(-) diff --git a/lib/crypto/c_src/cipher.c b/lib/crypto/c_src/cipher.c index 30c0fbcdb7..30f4c595ff 100644 --- a/lib/crypto/c_src/cipher.c +++ b/lib/crypto/c_src/cipher.c @@ -19,6 +19,7 @@ */ #include "cipher.h" +#include "info.h" #define NOT_AEAD {{0,0,0}} #define AEAD_CTRL {{EVP_CTRL_AEAD_SET_IVLEN,EVP_CTRL_AEAD_GET_TAG,EVP_CTRL_AEAD_SET_TAG}} @@ -164,8 +165,9 @@ static void evp_cipher_ctx_dtor(ErlNifEnv* env, struct evp_cipher_ctx* ctx) { #endif } -int init_cipher_ctx(ErlNifEnv *env) { - evp_cipher_ctx_rtype = enif_open_resource_type(env, NULL, "EVP_CIPHER_CTX", +int init_cipher_ctx(ErlNifEnv *env, ErlNifBinary* rt_buf) { + evp_cipher_ctx_rtype = enif_open_resource_type(env, NULL, + resource_name("EVP_CIPHER_CTX", rt_buf), (ErlNifResourceDtor*) evp_cipher_ctx_dtor, ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER, NULL); diff --git a/lib/crypto/c_src/cipher.h b/lib/crypto/c_src/cipher.h index 82b7ef4d20..71a05738ce 100644 --- a/lib/crypto/c_src/cipher.h +++ b/lib/crypto/c_src/cipher.h @@ -73,7 +73,7 @@ struct evp_cipher_ctx { ERL_NIF_TERM cipher_info_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -int init_cipher_ctx(ErlNifEnv *env); +int init_cipher_ctx(ErlNifEnv *env, ErlNifBinary* rt_buf); void init_cipher_types(ErlNifEnv* env); const struct cipher_type_t* get_cipher_type_no_key(ERL_NIF_TERM type); diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 2a6d5e9d4c..30ee7379ac 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -176,84 +176,107 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info) int tpl_arity; const ERL_NIF_TERM* tpl_array; int vernum; + ErlNifBinary rt_buf = { 0, NULL }; ErlNifBinary lib_bin; #ifdef HAVE_DYNAMIC_CRYPTO_LIB char lib_buf[1000]; void *handle; #endif + int ret = -1; - if (!verify_lib_version()) - return __LINE__; - + if (!verify_lib_version()) { + ret = __LINE__; goto done; + } /* load_info: {302, <<"/full/path/of/this/library">>,true|false} */ - if (!enif_get_tuple(env, load_info, &tpl_arity, &tpl_array)) - return __LINE__; - if (tpl_arity != 3) - return __LINE__; - if (!enif_get_int(env, tpl_array[0], &vernum)) - return __LINE__; - if (vernum != 302) - return __LINE__; - if (!enif_inspect_binary(env, tpl_array[1], &lib_bin)) - return __LINE__; + if (!enif_get_tuple(env, load_info, &tpl_arity, &tpl_array)) { + ret = __LINE__; goto done; + } + if (tpl_arity != 3) { + ret = __LINE__; goto done; + } + if (!enif_get_int(env, tpl_array[0], &vernum)) { + ret = __LINE__; goto done; + } + if (vernum != 302) { + ret = __LINE__; goto done; + } + if (!enif_inspect_binary(env, tpl_array[1], &lib_bin)) { + ret = __LINE__; goto done; + } + if (!enif_alloc_binary(100, &rt_buf)) { + ret = __LINE__; goto done; + } #ifdef HAS_EVP_PKEY_CTX - if (!init_mac_ctx(env)) { - return __LINE__; + if (!init_mac_ctx(env, &rt_buf)) { + ret = __LINE__; goto done; } #else - if (!init_hmac_ctx(env)) { - return __LINE__; + if (!init_hmac_ctx(env, &rt_buf)) { + ret = __LINE__; goto done; } #endif - if (!init_hash_ctx(env)) { - return __LINE__; + if (!init_hash_ctx(env, &rt_buf)) { + ret = __LINE__; goto done; } - if (!init_cipher_ctx(env)) { - return __LINE__; + if (!init_cipher_ctx(env, &rt_buf)) { + ret = __LINE__; goto done; } - if (!init_engine_ctx(env)) { - return __LINE__; + if (!init_engine_ctx(env, &rt_buf)) { + ret = __LINE__; goto done; } if (!create_engine_mutex(env)) { - return __LINE__; + ret = __LINE__; goto done; + } + if (!create_curve_mutex()) { + ret = __LINE__; goto done; } - if (!create_curve_mutex()) - return __LINE__; #ifdef HAS_3_0_API prov_cnt = 0; # ifdef FIPS_SUPPORT - if ((prov_cnt<MAX_NUM_PROVIDERS) && !(prov[prov_cnt++] = OSSL_PROVIDER_load(NULL, "fips"))) return __LINE__; -#endif - if ((prov_cnt<MAX_NUM_PROVIDERS) && !(prov[prov_cnt++] = OSSL_PROVIDER_load(NULL, "default"))) return __LINE__; - if ((prov_cnt<MAX_NUM_PROVIDERS) && !(prov[prov_cnt++] = OSSL_PROVIDER_load(NULL, "base"))) return __LINE__; - if (prov_cnt<MAX_NUM_PROVIDERS) {prov_cnt++; OSSL_PROVIDER_load(NULL, "legacy");} + if (!(prov[prov_cnt++] = OSSL_PROVIDER_load(NULL, "fips"))) { + ret = __LINE__; goto done; + } +# endif + if (!(prov[prov_cnt++] = OSSL_PROVIDER_load(NULL, "default"))) { + ret = __LINE__; goto done; + } + if (!(prov[prov_cnt++] = OSSL_PROVIDER_load(NULL, "base"))) { + ret = __LINE__; goto done; + } + if ((prov[prov_cnt] = OSSL_PROVIDER_load(NULL, "legacy"))) { + /* Don't fail loading if the legacy provider is missing */ + prov_cnt++; + } #endif if (library_initialized) { /* Repeated loading of this library (module upgrade). * Atoms and callbacks are already set, we are done. */ - return 0; + ret = 0; + goto done; } if (!init_atoms(env)) { - return __LINE__; + ret = __LINE__; goto done; } - /* Check if enter FIPS mode at module load (happening now) */ - if (enable_fips_mode(env, tpl_array[2]) != atom_true) - return __LINE__; - + if (enable_fips_mode(env, tpl_array[2]) != atom_true) { + ret = __LINE__; goto done; + } #ifdef HAVE_DYNAMIC_CRYPTO_LIB - if (!change_basename(&lib_bin, lib_buf, sizeof(lib_buf), crypto_callback_name)) - return __LINE__; - if ((handle = enif_dlopen(lib_buf, &error_handler, NULL)) == NULL) - return __LINE__; + if (!change_basename(&lib_bin, lib_buf, sizeof(lib_buf), crypto_callback_name)) { + ret = __LINE__; goto done; + } + if ((handle = enif_dlopen(lib_buf, &error_handler, NULL)) == NULL) { + ret = __LINE__; goto done; + } if ((funcp = (get_crypto_callbacks_t*) enif_dlsym(handle, "get_crypto_callbacks", - &error_handler, NULL)) == NULL) - return __LINE__; + &error_handler, NULL)) == NULL) { + ret = __LINE__; goto done; + } #else /* !HAVE_DYNAMIC_CRYPTO_LIB */ funcp = &get_crypto_callbacks; #endif @@ -272,12 +295,13 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info) if (!ccb || ccb->sizeof_me != sizeof(*ccb)) { PRINTF_ERR0("Invalid 'crypto_callbacks'"); - return __LINE__; + ret = __LINE__; goto done; } #ifdef HAS_CRYPTO_MEM_FUNCTIONS - if (!CRYPTO_set_mem_functions(ccb->crypto_alloc, ccb->crypto_realloc, ccb->crypto_free)) - return __LINE__; + if (!CRYPTO_set_mem_functions(ccb->crypto_alloc, ccb->crypto_realloc, ccb->crypto_free)) { + ret = __LINE__; goto done; + } #endif #if OPENSSL_VERSION_NUMBER < PACKED_OPENSSL_VERSION_PLAIN(1,1,0) @@ -299,7 +323,15 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info) init_algorithms_types(env); library_initialized = 1; - return 0; + ret = 0; + +done: + ASSERT(ret >= 0); + + if (rt_buf.data) + enif_release_binary(&rt_buf); + + return ret; } static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) diff --git a/lib/crypto/c_src/engine.c b/lib/crypto/c_src/engine.c index 6fb195b813..ff35ca614e 100644 --- a/lib/crypto/c_src/engine.c +++ b/lib/crypto/c_src/engine.c @@ -19,6 +19,7 @@ */ #include "engine.h" +#include "info.h" #ifdef HAS_ENGINE_SUPPORT struct engine_ctx { @@ -110,12 +111,13 @@ static int zero_terminate(ErlNifBinary bin, char **buf) { } #endif /* HAS_ENGINE_SUPPORT */ -int init_engine_ctx(ErlNifEnv *env) { +int init_engine_ctx(ErlNifEnv *env, ErlNifBinary* rt_buf) { #ifdef HAS_ENGINE_SUPPORT - engine_ctx_rtype = enif_open_resource_type(env, NULL, "ENGINE_CTX", - (ErlNifResourceDtor*) engine_ctx_dtor, - ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER, - NULL); + engine_ctx_rtype = enif_open_resource_type(env, NULL, + resource_name("ENGINE_CTX", rt_buf), + (ErlNifResourceDtor*) engine_ctx_dtor, + ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER, + NULL); if (engine_ctx_rtype == NULL) { PRINTF_ERR0("CRYPTO: Could not open resource type 'ENGINE_CTX'"); return 0; diff --git a/lib/crypto/c_src/engine.h b/lib/crypto/c_src/engine.h index f6a5a2921b..b1966b4f3d 100644 --- a/lib/crypto/c_src/engine.h +++ b/lib/crypto/c_src/engine.h @@ -28,7 +28,7 @@ int get_engine_and_key_id(ErlNifEnv *env, ERL_NIF_TERM key, char ** id, ENGINE * char *get_key_password(ErlNifEnv *env, ERL_NIF_TERM key); #endif /* HAS_ENGINE_SUPPORT */ -int init_engine_ctx(ErlNifEnv *env); +int init_engine_ctx(ErlNifEnv *env, ErlNifBinary* rt_buf); int create_engine_mutex(ErlNifEnv *env); void destroy_engine_mutex(ErlNifEnv *env); diff --git a/lib/crypto/c_src/hash.c b/lib/crypto/c_src/hash.c index 029dffd44b..e80f2a2522 100644 --- a/lib/crypto/c_src/hash.c +++ b/lib/crypto/c_src/hash.c @@ -20,6 +20,7 @@ #include "hash.h" #include "digest.h" +#include "info.h" #ifdef HAVE_MD5 # define MD5_CTX_LEN (sizeof(MD5_CTX)) @@ -48,9 +49,10 @@ static void evp_md_ctx_dtor(ErlNifEnv* env, struct evp_md_ctx *ctx) { } #endif -int init_hash_ctx(ErlNifEnv* env) { +int init_hash_ctx(ErlNifEnv* env, ErlNifBinary* rt_buf) { #if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0) - evp_md_ctx_rtype = enif_open_resource_type(env, NULL, "EVP_MD_CTX", + evp_md_ctx_rtype = enif_open_resource_type(env, NULL, + resource_name("EVP_MD_CTX", rt_buf), (ErlNifResourceDtor*) evp_md_ctx_dtor, ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER, NULL); diff --git a/lib/crypto/c_src/hash.h b/lib/crypto/c_src/hash.h index 5ac6785a33..093410ed97 100644 --- a/lib/crypto/c_src/hash.h +++ b/lib/crypto/c_src/hash.h @@ -23,7 +23,7 @@ #include "common.h" -int init_hash_ctx(ErlNifEnv *env); +int init_hash_ctx(ErlNifEnv *env, ErlNifBinary* rt_buf); ERL_NIF_TERM hash_info_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); ERL_NIF_TERM hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); diff --git a/lib/crypto/c_src/hmac.c b/lib/crypto/c_src/hmac.c index 86ffb9a5a3..1244069aed 100644 --- a/lib/crypto/c_src/hmac.c +++ b/lib/crypto/c_src/hmac.c @@ -30,6 +30,7 @@ #include "hmac.h" #include "digest.h" +#include "info.h" #if !defined(HAS_EVP_PKEY_CTX) || DISABLE_EVP_HMAC @@ -44,8 +45,9 @@ static ErlNifResourceType* hmac_context_rtype; static void hmac_context_dtor(ErlNifEnv* env, struct hmac_context*); -int init_hmac_ctx(ErlNifEnv *env) { - hmac_context_rtype = enif_open_resource_type(env, NULL, "hmac_context", +int init_hmac_ctx(ErlNifEnv *env, ErlNifBinary* rt_buf) { + hmac_context_rtype = enif_open_resource_type(env, NULL, + resource_name("hmac_context", rt_buf), (ErlNifResourceDtor*) hmac_context_dtor, ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER, NULL); diff --git a/lib/crypto/c_src/hmac.h b/lib/crypto/c_src/hmac.h index 1948ae5b84..f84d08dd38 100644 --- a/lib/crypto/c_src/hmac.h +++ b/lib/crypto/c_src/hmac.h @@ -25,7 +25,7 @@ #if !defined(HAS_EVP_PKEY_CTX) || DISABLE_EVP_HMAC -int init_hmac_ctx(ErlNifEnv *env); +int init_hmac_ctx(ErlNifEnv *env, ErlNifBinary* rt_buf); ERL_NIF_TERM hmac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); ERL_NIF_TERM hmac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); diff --git a/lib/crypto/c_src/info.c b/lib/crypto/c_src/info.c index 1458842b98..f78984b7e6 100644 --- a/lib/crypto/c_src/info.c +++ b/lib/crypto/c_src/info.c @@ -87,6 +87,23 @@ void error_handler(void* null, const char* errstr) } #endif /* HAVE_DYNAMIC_CRYPTO_LIB */ +const char* resource_name(const char *name, ErlNifBinary* buf) +{ + /* + * Add full OpenSSL version string. This is a simlpe but conservative way + * to detect and reject resource takover between different versions + * of OpenSSL that might not be binary compatible. + */ + size_t len; + for (;;) { + len = enif_snprintf((char*)buf->data, buf->size, "%s:%s", + name, OpenSSL_version(OPENSSL_VERSION)); + if (len < buf->size) + return (char*)buf->data; + enif_realloc_binary(buf, len + 1 + 20); + } +} + ERL_NIF_TERM info_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {/* () */ diff --git a/lib/crypto/c_src/info.h b/lib/crypto/c_src/info.h index fd9e9b7374..2ba2583e94 100644 --- a/lib/crypto/c_src/info.h +++ b/lib/crypto/c_src/info.h @@ -30,6 +30,18 @@ int change_basename(ErlNifBinary* bin, char* buf, size_t bufsz, const char* newf void error_handler(void* null, const char* errstr); #endif +/** @brief Construct a versioned name for resource types to try + * avoid takeover of binary incompatible resources. + * @param[in] name The base name of the resource type. + * @param[out] buf Output buffer preallocated with enif_alloc_binary. + * + * @return Pointer to versioned name at buf->data, potentially reallocated. + * + * </>> + * </>> + */ +const char* resource_name(const char *name, ErlNifBinary* buf); + ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); ERL_NIF_TERM info_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); diff --git a/lib/crypto/c_src/mac.c b/lib/crypto/c_src/mac.c index 4223f0567f..69d8be5350 100644 --- a/lib/crypto/c_src/mac.c +++ b/lib/crypto/c_src/mac.c @@ -24,6 +24,7 @@ #include "cmac.h" #include "hmac.h" #include "mac.h" +#include "info.h" /*************************** MAC type declaration @@ -493,8 +494,6 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) * ******************************************************************/ -int init_mac_ctx(ErlNifEnv *env); - struct mac_context { #if defined(HAS_3_0_API) @@ -508,8 +507,9 @@ static ErlNifResourceType* mac_context_rtype; static void mac_context_dtor(ErlNifEnv* env, struct mac_context*); -int init_mac_ctx(ErlNifEnv *env) { - mac_context_rtype = enif_open_resource_type(env, NULL, "mac_context", +int init_mac_ctx(ErlNifEnv *env, ErlNifBinary* rt_buf) { + mac_context_rtype = enif_open_resource_type(env, NULL, + resource_name("mac_context", rt_buf), (ErlNifResourceDtor*) mac_context_dtor, ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER, NULL); diff --git a/lib/crypto/c_src/mac.h b/lib/crypto/c_src/mac.h index 46f8f5d292..87f9ff7938 100644 --- a/lib/crypto/c_src/mac.h +++ b/lib/crypto/c_src/mac.h @@ -23,7 +23,7 @@ #include "common.h" -int init_mac_ctx(ErlNifEnv *env); +int init_mac_ctx(ErlNifEnv *env, ErlNifBinary* rt_buf); void init_mac_types(ErlNifEnv* env); -- 2.35.3
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor