From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 4790944182 for ; Fri, 7 Jun 2024 14:48:12 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 3939742D2A; Fri, 7 Jun 2024 14:48:12 +0200 (CEST) Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by mails.dpdk.org (Postfix) with ESMTP id 7A7F14029A; Fri, 7 Jun 2024 14:48:07 +0200 (CEST) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 442D613D5; Fri, 7 Jun 2024 05:48:31 -0700 (PDT) Received: from cesw-amp-gbt-1s-m12830-01.lab.cambridge.arm.com (cesw-amp-gbt-1s-m12830-01.lab.cambridge.arm.com [10.7.10.57]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 017A93F64C; Fri, 7 Jun 2024 05:48:05 -0700 (PDT) From: Jack Bond-Preston To: Kai Ji , Fan Zhang , Akhil Goyal Cc: dev@dpdk.org, stable@dpdk.org, Wathsala Vithanage Subject: [PATCH v4 1/5] crypto/openssl: fix GCM and CCM thread unsafe ctxs Date: Fri, 7 Jun 2024 12:47:52 +0000 Message-Id: <20240607124756.3968704-2-jack.bond-preston@foss.arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240607124756.3968704-1-jack.bond-preston@foss.arm.com> References: <20240603160119.1279476-1-jack.bond-preston@foss.arm.com> <20240607124756.3968704-1-jack.bond-preston@foss.arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: stable@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: patches for DPDK stable branches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: stable-bounces@dpdk.org Commit 67ab783b5d70 ("crypto/openssl: use local copy for session contexts") introduced a fix for concurrency bugs which could occur when using one OpenSSL PMD session across multiple cores simultaneously. The solution was to clone the EVP contexts per-buffer to avoid them being used concurrently. However, part of commit 75adf1eae44f ("crypto/openssl: update HMAC routine with 3.0 EVP API") reverted this fix, only for combined ops (AES-GCM and AES-CCM). Fix the concurrency issue by cloning EVP contexts per-buffer. An extra workaround is required for OpenSSL versions which are >= 3.0.0, and <= 3.2.0. This is because, prior to OpenSSL 3.2.0, EVP_CIPHER_CTX_copy() is not implemented for AES-GCM or AES-CCM. When using these OpenSSL versions, create and initialise the context from scratch, per-buffer. Throughput performance uplift measurements for AES-GCM-128 encrypt on Ampere Altra Max platform: 1 worker lcore | buffer sz (B) | prev (Gbps) | optimised (Gbps) | uplift | |-----------------+---------------+--------------------+----------| | 64 | 2.60 | 1.31 | -49.5% | | 256 | 7.69 | 4.45 | -42.1% | | 1024 | 15.33 | 11.30 | -26.3% | | 2048 | 18.74 | 15.37 | -18.0% | | 4096 | 21.11 | 18.80 | -10.9% | 8 worker lcores | buffer sz (B) | prev (Gbps) | optimised (Gbps) | uplift | |-----------------+---------------+--------------------+----------| | 64 | 19.94 | 2.83 | -85.8% | | 256 | 58.84 | 11.00 | -81.3% | | 1024 | 119.71 | 42.46 | -64.5% | | 2048 | 147.69 | 80.91 | -45.2% | | 4096 | 167.39 | 121.25 | -27.6% | Fixes: 75adf1eae44f ("crypto/openssl: update HMAC routine with 3.0 EVP API") Cc: stable@dpdk.org Signed-off-by: Jack Bond-Preston Reviewed-by: Wathsala Vithanage --- drivers/crypto/openssl/rte_openssl_pmd.c | 84 ++++++++++++++++++------ 1 file changed, 64 insertions(+), 20 deletions(-) diff --git a/drivers/crypto/openssl/rte_openssl_pmd.c b/drivers/crypto/openssl/rte_openssl_pmd.c index e8cb09defc..3f7f4d8c37 100644 --- a/drivers/crypto/openssl/rte_openssl_pmd.c +++ b/drivers/crypto/openssl/rte_openssl_pmd.c @@ -350,7 +350,8 @@ get_aead_algo(enum rte_crypto_aead_algorithm sess_algo, size_t keylen, static int openssl_set_sess_aead_enc_param(struct openssl_session *sess, enum rte_crypto_aead_algorithm algo, - uint8_t tag_len, const uint8_t *key) + uint8_t tag_len, const uint8_t *key, + EVP_CIPHER_CTX **ctx) { int iv_type = 0; unsigned int do_ccm; @@ -378,7 +379,7 @@ openssl_set_sess_aead_enc_param(struct openssl_session *sess, } sess->cipher.mode = OPENSSL_CIPHER_LIB; - sess->cipher.ctx = EVP_CIPHER_CTX_new(); + *ctx = EVP_CIPHER_CTX_new(); if (get_aead_algo(algo, sess->cipher.key.length, &sess->cipher.evp_algo) != 0) @@ -388,19 +389,19 @@ openssl_set_sess_aead_enc_param(struct openssl_session *sess, sess->chain_order = OPENSSL_CHAIN_COMBINED; - if (EVP_EncryptInit_ex(sess->cipher.ctx, sess->cipher.evp_algo, + if (EVP_EncryptInit_ex(*ctx, sess->cipher.evp_algo, NULL, NULL, NULL) <= 0) return -EINVAL; - if (EVP_CIPHER_CTX_ctrl(sess->cipher.ctx, iv_type, sess->iv.length, + if (EVP_CIPHER_CTX_ctrl(*ctx, iv_type, sess->iv.length, NULL) <= 0) return -EINVAL; if (do_ccm) - EVP_CIPHER_CTX_ctrl(sess->cipher.ctx, EVP_CTRL_CCM_SET_TAG, + EVP_CIPHER_CTX_ctrl(*ctx, EVP_CTRL_CCM_SET_TAG, tag_len, NULL); - if (EVP_EncryptInit_ex(sess->cipher.ctx, NULL, NULL, key, NULL) <= 0) + if (EVP_EncryptInit_ex(*ctx, NULL, NULL, key, NULL) <= 0) return -EINVAL; return 0; @@ -410,7 +411,8 @@ openssl_set_sess_aead_enc_param(struct openssl_session *sess, static int openssl_set_sess_aead_dec_param(struct openssl_session *sess, enum rte_crypto_aead_algorithm algo, - uint8_t tag_len, const uint8_t *key) + uint8_t tag_len, const uint8_t *key, + EVP_CIPHER_CTX **ctx) { int iv_type = 0; unsigned int do_ccm = 0; @@ -437,7 +439,7 @@ openssl_set_sess_aead_dec_param(struct openssl_session *sess, } sess->cipher.mode = OPENSSL_CIPHER_LIB; - sess->cipher.ctx = EVP_CIPHER_CTX_new(); + *ctx = EVP_CIPHER_CTX_new(); if (get_aead_algo(algo, sess->cipher.key.length, &sess->cipher.evp_algo) != 0) @@ -447,24 +449,54 @@ openssl_set_sess_aead_dec_param(struct openssl_session *sess, sess->chain_order = OPENSSL_CHAIN_COMBINED; - if (EVP_DecryptInit_ex(sess->cipher.ctx, sess->cipher.evp_algo, + if (EVP_DecryptInit_ex(*ctx, sess->cipher.evp_algo, NULL, NULL, NULL) <= 0) return -EINVAL; - if (EVP_CIPHER_CTX_ctrl(sess->cipher.ctx, iv_type, + if (EVP_CIPHER_CTX_ctrl(*ctx, iv_type, sess->iv.length, NULL) <= 0) return -EINVAL; if (do_ccm) - EVP_CIPHER_CTX_ctrl(sess->cipher.ctx, EVP_CTRL_CCM_SET_TAG, + EVP_CIPHER_CTX_ctrl(*ctx, EVP_CTRL_CCM_SET_TAG, tag_len, NULL); - if (EVP_DecryptInit_ex(sess->cipher.ctx, NULL, NULL, key, NULL) <= 0) + if (EVP_DecryptInit_ex(*ctx, NULL, NULL, key, NULL) <= 0) return -EINVAL; return 0; } +static int openssl_aesni_ctx_clone(EVP_CIPHER_CTX **dest, + struct openssl_session *sess) +{ +#if (OPENSSL_VERSION_NUMBER > 0x30200000L) + *dest = EVP_CIPHER_CTX_dup(sess->ctx); + return 0; +#elif (OPENSSL_VERSION_NUMBER > 0x30000000L) + /* OpenSSL versions 3.0.0 <= V < 3.2.0 have no dupctx() implementation + * for AES-GCM and AES-CCM. In this case, we have to create new empty + * contexts and initialise, as we did the original context. + */ + if (sess->auth.algo == RTE_CRYPTO_AUTH_AES_GMAC) + sess->aead_algo = RTE_CRYPTO_AEAD_AES_GCM; + + if (sess->cipher.direction == RTE_CRYPTO_CIPHER_OP_ENCRYPT) + return openssl_set_sess_aead_enc_param(sess, sess->aead_algo, + sess->auth.digest_length, sess->cipher.key.data, + dest); + else + return openssl_set_sess_aead_dec_param(sess, sess->aead_algo, + sess->auth.digest_length, sess->cipher.key.data, + dest); +#else + *dest = EVP_CIPHER_CTX_new(); + if (EVP_CIPHER_CTX_copy(*dest, sess->cipher.ctx) != 1) + return -EINVAL; + return 0; +#endif +} + /** Set session cipher parameters */ static int openssl_set_session_cipher_parameters(struct openssl_session *sess, @@ -623,12 +655,14 @@ openssl_set_session_auth_parameters(struct openssl_session *sess, return openssl_set_sess_aead_enc_param(sess, RTE_CRYPTO_AEAD_AES_GCM, xform->auth.digest_length, - xform->auth.key.data); + xform->auth.key.data, + &sess->cipher.ctx); else return openssl_set_sess_aead_dec_param(sess, RTE_CRYPTO_AEAD_AES_GCM, xform->auth.digest_length, - xform->auth.key.data); + xform->auth.key.data, + &sess->cipher.ctx); break; case RTE_CRYPTO_AUTH_MD5: @@ -770,10 +804,12 @@ openssl_set_session_aead_parameters(struct openssl_session *sess, /* Select cipher direction */ if (xform->aead.op == RTE_CRYPTO_AEAD_OP_ENCRYPT) return openssl_set_sess_aead_enc_param(sess, xform->aead.algo, - xform->aead.digest_length, xform->aead.key.data); + xform->aead.digest_length, xform->aead.key.data, + &sess->cipher.ctx); else return openssl_set_sess_aead_dec_param(sess, xform->aead.algo, - xform->aead.digest_length, xform->aead.key.data); + xform->aead.digest_length, xform->aead.key.data, + &sess->cipher.ctx); } /** Parse crypto xform chain and set private session parameters */ @@ -1590,6 +1626,12 @@ process_openssl_combined_op return; } + EVP_CIPHER_CTX *ctx; + if (openssl_aesni_ctx_clone(&ctx, sess) != 0) { + op->status = RTE_CRYPTO_OP_STATUS_ERROR; + return; + } + iv = rte_crypto_op_ctod_offset(op, uint8_t *, sess->iv.offset); if (sess->auth.algo == RTE_CRYPTO_AUTH_AES_GMAC) { @@ -1623,12 +1665,12 @@ process_openssl_combined_op status = process_openssl_auth_encryption_gcm( mbuf_src, offset, srclen, aad, aadlen, iv, - dst, tag, sess->cipher.ctx); + dst, tag, ctx); else status = process_openssl_auth_encryption_ccm( mbuf_src, offset, srclen, aad, aadlen, iv, - dst, tag, taglen, sess->cipher.ctx); + dst, tag, taglen, ctx); } else { if (sess->auth.algo == RTE_CRYPTO_AUTH_AES_GMAC || @@ -1636,14 +1678,16 @@ process_openssl_combined_op status = process_openssl_auth_decryption_gcm( mbuf_src, offset, srclen, aad, aadlen, iv, - dst, tag, sess->cipher.ctx); + dst, tag, ctx); else status = process_openssl_auth_decryption_ccm( mbuf_src, offset, srclen, aad, aadlen, iv, - dst, tag, taglen, sess->cipher.ctx); + dst, tag, taglen, ctx); } + EVP_CIPHER_CTX_free(ctx); + if (status != 0) { if (status == (-EFAULT) && sess->auth.operation == -- 2.34.1