Preserve ARM registers, reenable ARM assembly

https://github.com/smuellerDD/leancrypto/commit/3c32c1afe3e4653fd4093ed77090c36

Resolves: RHEL-89715
This commit is contained in:
Alexander Sosedkin 2025-05-08 10:22:54 +02:00
parent 8d31a65d90
commit 6e0ba93d2a
2 changed files with 349 additions and 7 deletions

View File

@ -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

View File

@ -0,0 +1,346 @@
From 3c32c1afe3e4653fd4093ed77090c36223bce7a0 Mon Sep 17 00:00:00 2001
From: Stephan Mueller <smueller@chronox.de>
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 <smueller@chronox.de>
---
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 <smueller@chronox.de>
+ *
+ * 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;
}