From 6e0ba93d2a658b4a8c31773dc01b93f7d57e97f6 Mon Sep 17 00:00:00 2001 From: Alexander Sosedkin Date: Thu, 8 May 2025 10:22:54 +0200 Subject: [PATCH] Preserve ARM registers, reenable ARM assembly https://github.com/smuellerDD/leancrypto/commit/3c32c1afe3e4653fd4093ed77090c36 Resolves: RHEL-89715 --- gnutls.spec | 10 +- leancrypto-1.3.0-preserve-arm-registers.patch | 346 ++++++++++++++++++ 2 files changed, 349 insertions(+), 7 deletions(-) create mode 100644 leancrypto-1.3.0-preserve-arm-registers.patch diff --git a/gnutls.spec b/gnutls.spec index 40b7648..d7b89f1 100644 --- a/gnutls.spec +++ b/gnutls.spec @@ -176,6 +176,8 @@ Source204: nettle-3.10-hobble-to-configure.patch %if %{with leancrypto} Source300: leancrypto-1.3.0.tar.gz %endif +# Not upstreamed, from a comment in smuellerDD/leancrypto#27 +Source301: leancrypto-1.3.0-preserve-arm-registers.patch # Wildcard bundling exception https://fedorahosted.org/fpc/ticket/174 Provides: bundled(gnulib) = 20130424 @@ -325,6 +327,7 @@ popd mkdir -p bundled_leancrypto pushd bundled_leancrypto tar --strip-components=1 -xf %{SOURCE300} +patch -p1 < %{SOURCE301} popd %endif @@ -380,12 +383,6 @@ export HOGWEED_LIBS="$NETTLE_DIR/libhogweed.a $NETTLE_LIBS $GMP_LIBS" %if %{with leancrypto} pushd bundled_leancrypto %set_build_flags - -# FIXME RHEL-89715 interim countermeasure -%ifarch aarch64 -%define leancrypto_extra_setup_flags -Ddisable-asm=true -%endif - meson setup -Dprefix="$PWD/install" -Dlibdir="$PWD/install/lib" \ -Ddefault_library=static \ -Dascon=disabled -Dascon_keccak=disabled \ @@ -404,7 +401,6 @@ meson setup -Dprefix="$PWD/install" -Dlibdir="$PWD/install/lib" \ -Dhotp=disabled -Dtotp=disabled \ -Daes_block=disabled -Daes_cbc=disabled -Daes_ctr=disabled \ -Daes_kw=disabled -Dapps=disabled \ - %{?leancrypto_extra_setup_flags} \ _build meson compile -v -C _build meson install -C _build diff --git a/leancrypto-1.3.0-preserve-arm-registers.patch b/leancrypto-1.3.0-preserve-arm-registers.patch new file mode 100644 index 0000000..1adf7c0 --- /dev/null +++ b/leancrypto-1.3.0-preserve-arm-registers.patch @@ -0,0 +1,346 @@ +From 3c32c1afe3e4653fd4093ed77090c36223bce7a0 Mon Sep 17 00:00:00 2001 +From: Stephan Mueller +Date: Thu, 8 May 2025 12:34:21 +0200 +Subject: [PATCH] ARMv8: properly save/restore SIMD register v8 through v15 + +Those registers are used by ML-DSA and ML-KEM. + +Signed-off-by: Stephan Mueller +--- + internal/api/armv8_helper.h | 67 ++++++++++++ + ml-dsa/src/armv8/dilithium_signature_armv8.c | 101 +++++++++++++++++-- + ml-kem/src/armv8/kyber_indcpa_armv8.c | 13 +++ + 4 files changed, 173 insertions(+), 10 deletions(-) + create mode 100644 internal/api/armv8_helper.h + +diff --git a/internal/api/armv8_helper.h b/internal/api/armv8_helper.h +new file mode 100644 +index 00000000..456f3239 +--- /dev/null ++++ b/internal/api/armv8_helper.h +@@ -0,0 +1,67 @@ ++/* ++ * Copyright (C) 2025, Stephan Mueller ++ * ++ * License: see LICENSE file in root directory ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF ++ * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE ++ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT ++ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ++ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ++ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE ++ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH ++ * DAMAGE. ++ */ ++ ++#ifndef ARMV8_HELPER_H ++#define ARMV8_HELPER_H ++ ++#include "ext_headers.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* ++ * The ARMv8 Kyber implementation uses the SIMD registers v8 through v15 which ++ * must be preserved by the callee. ++ * ++ * Store only the lower 64 bits of the FP registers v8 through v15 according to ++ * https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#612simd-and-floating-point-registers ++ */ ++static inline void store_fp_regs(uint64_t tmp[8]) ++{ ++ __asm__ volatile("mov %0, v8.d[0]" : "=r"(tmp[0]) : : "memory" ); ++ __asm__ volatile("mov %0, v9.d[0]" : "=r"(tmp[1]) : : "memory" ); ++ __asm__ volatile("mov %0, v10.d[0]" : "=r"(tmp[2]) : : "memory" ); ++ __asm__ volatile("mov %0, v11.d[0]" : "=r"(tmp[3]) : : "memory" ); ++ __asm__ volatile("mov %0, v12.d[0]" : "=r"(tmp[4]) : : "memory" ); ++ __asm__ volatile("mov %0, v13.d[0]" : "=r"(tmp[5]) : : "memory" ); ++ __asm__ volatile("mov %0, v14.d[0]" : "=r"(tmp[6]) : : "memory" ); ++ __asm__ volatile("mov %0, v15.d[0]" : "=r"(tmp[7]) : : "memory" ); ++} ++ ++/* ++ * Reload the stored register content into the SIMD registers ++ */ ++static inline void reload_fp_regs(uint64_t tmp[8]) ++{ ++ __asm__ volatile("mov v8.d[0], %0" : : "r"(tmp[0]) : "memory" ); ++ __asm__ volatile("mov v9.d[0], %0" : : "r"(tmp[1]) : "memory" ); ++ __asm__ volatile("mov v10.d[0], %0" : : "r"(tmp[2]) : "memory" ); ++ __asm__ volatile("mov v11.d[0], %0" : : "r"(tmp[3]) : "memory" ); ++ __asm__ volatile("mov v12.d[0], %0" : : "r"(tmp[4]) : "memory" ); ++ __asm__ volatile("mov v13.d[0], %0" : : "r"(tmp[5]) : "memory" ); ++ __asm__ volatile("mov v14.d[0], %0" : : "r"(tmp[6]) : "memory" ); ++ __asm__ volatile("mov v15.d[0], %0" : : "r"(tmp[7]) : "memory" ); ++} ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* ARMV8_HELPER_H */ +diff --git a/ml-dsa/src/armv8/dilithium_signature_armv8.c b/ml-dsa/src/armv8/dilithium_signature_armv8.c +index a661ffe9..5bc64387 100644 +--- a/ml-dsa/src/armv8/dilithium_signature_armv8.c ++++ b/ml-dsa/src/armv8/dilithium_signature_armv8.c +@@ -17,6 +17,7 @@ + * DAMAGE. + */ + ++#include "armv8_helper.h" + #include "dilithium_type.h" + #include "dilithium_signature_armv8.h" + #include "visibility.h" +@@ -36,14 +37,30 @@ LC_INTERFACE_FUNCTION(int, lc_dilithium_keypair_from_seed_armv8, + struct lc_dilithium_pk *pk, struct lc_dilithium_sk *sk, + const uint8_t *seed, size_t seedlen) + { +- return lc_dilithium_keypair_from_seed_impl(pk, sk, seed, seedlen); ++ uint64_t saved_regs[8]; ++ int ret; ++ ++ store_fp_regs(saved_regs); ++ ret = lc_dilithium_keypair_from_seed_impl(pk, sk, seed, seedlen); ++ reload_fp_regs(saved_regs); ++ lc_memset_secure(saved_regs, 0, sizeof(saved_regs)); ++ ++ return ret; + } + + LC_INTERFACE_FUNCTION(int, lc_dilithium_keypair_armv8, + struct lc_dilithium_pk *pk, struct lc_dilithium_sk *sk, + struct lc_rng_ctx *rng_ctx) + { +- return lc_dilithium_keypair_impl(pk, sk, rng_ctx); ++ uint64_t saved_regs[8]; ++ int ret; ++ ++ store_fp_regs(saved_regs); ++ ret = lc_dilithium_keypair_impl(pk, sk, rng_ctx); ++ reload_fp_regs(saved_regs); ++ lc_memset_secure(saved_regs, 0, sizeof(saved_regs)); ++ ++ return ret; + } + + LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_armv8, +@@ -51,7 +68,15 @@ LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_armv8, + size_t mlen, const struct lc_dilithium_sk *sk, + struct lc_rng_ctx *rng_ctx) + { +- return lc_dilithium_sign_impl(sig, m, mlen, sk, rng_ctx); ++ uint64_t saved_regs[8]; ++ int ret; ++ ++ store_fp_regs(saved_regs); ++ ret = lc_dilithium_sign_impl(sig, m, mlen, sk, rng_ctx); ++ reload_fp_regs(saved_regs); ++ lc_memset_secure(saved_regs, 0, sizeof(saved_regs)); ++ ++ return ret; + } + + LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_ctx_armv8, +@@ -60,14 +85,30 @@ LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_ctx_armv8, + size_t mlen, const struct lc_dilithium_sk *sk, + struct lc_rng_ctx *rng_ctx) + { +- return lc_dilithium_sign_ctx_impl(sig, ctx, m, mlen, sk, rng_ctx); ++ uint64_t saved_regs[8]; ++ int ret; ++ ++ store_fp_regs(saved_regs); ++ ret = lc_dilithium_sign_ctx_impl(sig, ctx, m, mlen, sk, rng_ctx); ++ reload_fp_regs(saved_regs); ++ lc_memset_secure(saved_regs, 0, sizeof(saved_regs)); ++ ++ return ret; + } + + LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_init_armv8, + struct lc_dilithium_ctx *ctx, + const struct lc_dilithium_sk *sk) + { +- return lc_dilithium_sign_init_impl(ctx, sk); ++ uint64_t saved_regs[8]; ++ int ret; ++ ++ store_fp_regs(saved_regs); ++ ret = lc_dilithium_sign_init_impl(ctx, sk); ++ reload_fp_regs(saved_regs); ++ lc_memset_secure(saved_regs, 0, sizeof(saved_regs)); ++ ++ return ret; + } + + LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_update_armv8, +@@ -83,14 +124,30 @@ LC_INTERFACE_FUNCTION(int, lc_dilithium_sign_final_armv8, + const struct lc_dilithium_sk *sk, + struct lc_rng_ctx *rng_ctx) + { +- return lc_dilithium_sign_final_impl(sig, ctx, sk, rng_ctx); ++ uint64_t saved_regs[8]; ++ int ret; ++ ++ store_fp_regs(saved_regs); ++ ret = lc_dilithium_sign_final_impl(sig, ctx, sk, rng_ctx); ++ reload_fp_regs(saved_regs); ++ lc_memset_secure(saved_regs, 0, sizeof(saved_regs)); ++ ++ return ret; + } + + LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_armv8, + const struct lc_dilithium_sig *sig, const uint8_t *m, + size_t mlen, const struct lc_dilithium_pk *pk) + { +- return lc_dilithium_verify_impl(sig, m, mlen, pk); ++ uint64_t saved_regs[8]; ++ int ret; ++ ++ store_fp_regs(saved_regs); ++ ret = lc_dilithium_verify_impl(sig, m, mlen, pk); ++ reload_fp_regs(saved_regs); ++ lc_memset_secure(saved_regs, 0, sizeof(saved_regs)); ++ ++ return ret; + } + + LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_ctx_armv8, +@@ -98,14 +155,30 @@ LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_ctx_armv8, + struct lc_dilithium_ctx *ctx, const uint8_t *m, + size_t mlen, const struct lc_dilithium_pk *pk) + { +- return lc_dilithium_verify_ctx_impl(sig, ctx, m, mlen, pk); ++ uint64_t saved_regs[8]; ++ int ret; ++ ++ store_fp_regs(saved_regs); ++ ret = lc_dilithium_verify_ctx_impl(sig, ctx, m, mlen, pk); ++ reload_fp_regs(saved_regs); ++ lc_memset_secure(saved_regs, 0, sizeof(saved_regs)); ++ ++ return ret; + } + + LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_init_armv8, + struct lc_dilithium_ctx *ctx, + const struct lc_dilithium_pk *pk) + { +- return lc_dilithium_verify_init_impl(ctx, pk); ++ uint64_t saved_regs[8]; ++ int ret; ++ ++ store_fp_regs(saved_regs); ++ ret = lc_dilithium_verify_init_impl(ctx, pk); ++ reload_fp_regs(saved_regs); ++ lc_memset_secure(saved_regs, 0, sizeof(saved_regs)); ++ ++ return ret; + } + + LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_update_armv8, +@@ -120,5 +193,13 @@ LC_INTERFACE_FUNCTION(int, lc_dilithium_verify_final_armv8, + struct lc_dilithium_ctx *ctx, + const struct lc_dilithium_pk *pk) + { +- return lc_dilithium_verify_final_impl(sig, ctx, pk); ++ uint64_t saved_regs[8]; ++ int ret; ++ ++ store_fp_regs(saved_regs); ++ ret = lc_dilithium_verify_final_impl(sig, ctx, pk); ++ reload_fp_regs(saved_regs); ++ lc_memset_secure(saved_regs, 0, sizeof(saved_regs)); ++ ++ return ret; + } +diff --git a/ml-kem/src/armv8/kyber_indcpa_armv8.c b/ml-kem/src/armv8/kyber_indcpa_armv8.c +index 26b797d8..d6289d73 100644 +--- a/ml-kem/src/armv8/kyber_indcpa_armv8.c ++++ b/ml-kem/src/armv8/kyber_indcpa_armv8.c +@@ -23,6 +23,7 @@ + * That code is released under MIT license. + */ + ++#include "armv8_helper.h" + #include "build_bug_on.h" + #include "kyber_indcpa_armv8.h" + #include "kyber_poly_armv8.h" +@@ -229,6 +230,7 @@ int indcpa_keypair_armv8(uint8_t pk[LC_KYBER_INDCPA_PUBLICKEYBYTES], + uint8_t buf[2 * LC_KYBER_SYMBYTES]; + uint8_t poly_getnoise_eta1_buf[POLY_GETNOISE_ETA1_BUFSIZE]; + polyvec a[LC_KYBER_K], e, pkpv, skpv; ++ uint64_t saved_regs[8]; + }; + static const uint8_t kval = LC_KYBER_K; + unsigned int i; +@@ -239,6 +241,8 @@ int indcpa_keypair_armv8(uint8_t pk[LC_KYBER_INDCPA_PUBLICKEYBYTES], + LC_HASH_CTX_ON_STACK(sha3_512_ctx, lc_sha3_512); + LC_DECLARE_MEM(ws, struct workspace, 32); + ++ store_fp_regs(ws->saved_regs); ++ + buf = ws->buf; + publicseed = ws->buf; + noiseseed = ws->buf + LC_KYBER_SYMBYTES; +@@ -282,6 +286,7 @@ int indcpa_keypair_armv8(uint8_t pk[LC_KYBER_INDCPA_PUBLICKEYBYTES], + unpoison(pk, LC_KYBER_INDCPA_PUBLICKEYBYTES); + + out: ++ reload_fp_regs(ws->saved_regs); + LC_RELEASE_MEM(ws); + return ret; + } +@@ -299,12 +304,15 @@ int indcpa_enc_armv8(uint8_t c[LC_KYBER_INDCPA_BYTES], + //uint8_t poly_getnoise_eta2_buf[POLY_GETNOISE_ETA2_BUFSIZE]; + polyvec sp, pkpv, ep, at[LC_KYBER_K], b; + poly v, k, epp; ++ uint64_t saved_regs[8]; + }; + unsigned int i; + uint8_t nonce = 0, nonce2 = LC_KYBER_K; + int ret; + LC_DECLARE_MEM(ws, struct workspace, sizeof(uint64_t)); + ++ store_fp_regs(ws->saved_regs); ++ + /* + * Use the poly_getnoise_eta1_buf for this operation as seed is smaller + * than poly_getnoise_eta1_buf and has the same alignment. +@@ -354,6 +362,7 @@ int indcpa_enc_armv8(uint8_t c[LC_KYBER_INDCPA_BYTES], + pack_ciphertext(c, &ws->b, &ws->v); + + out: ++ reload_fp_regs(ws->saved_regs); + LC_RELEASE_MEM(ws); + return ret; + } +@@ -365,9 +374,12 @@ int indcpa_dec_armv8(uint8_t m[LC_KYBER_INDCPA_MSGBYTES], + struct workspace { + polyvec b, skpv; + poly v, mp; ++ uint64_t saved_regs[8]; + }; + LC_DECLARE_MEM(ws, struct workspace, sizeof(uint64_t)); + ++ store_fp_regs(ws->saved_regs); ++ + unpack_sk(&ws->skpv, sk); + + /* Validate input */ +@@ -386,6 +398,7 @@ int indcpa_dec_armv8(uint8_t m[LC_KYBER_INDCPA_MSGBYTES], + + poly_tomsg(m, &ws->mp); + ++ reload_fp_regs(ws->saved_regs); + LC_RELEASE_MEM(ws); + return 0; + }