diff --git a/BUILDING.md b/BUILDING.md index a8988a3fd2e..72d4acdfe36 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -256,18 +256,24 @@ article](https://appleinsider.com/articles/24/03/21/apple-silicon-vulnerability- Building with the option `-DENABLE_DATA_INDEPENDENT_TIMING_AARCH64=ON` will enable the macro `SET_DIT_AUTO_DISABLE`. This macro is present at -the entry of functions that process/load/store secret data to enable -the DIT flag and then set it to its original value on entry. With -this build option, there is an effect on performance that varies by +the entry of functions that process/load/store secret data to set the +DIT flag and then reset it to its original value on entry. With this +build option, there is an effect on performance that varies by function and by processor architecture. The effect is mostly due to -enabling and disabling the DIT flag. If it remains enabled over many -calls, the effect can be largely mitigated. Hence, the macro can be -inserted in the caller's application at the beginning of the code -scope that makes repeated calls to AWS-LC cryptographic -functions. Alternatively, the functions `armv8_enable_dit` and -`armv8_restore_dit` can be placed at the beginning and the end of -the code section, respectively. -An example of that usage is present in the benchmarking function -`Speed()` in `tool/speed.cc` when the `-dit` option is used - - ./tool/bssl speed -dit \ No newline at end of file +setting and resetting the DIT flag. If it remains set over many calls, +the effect can be largely mitigated. Hence, the macro can be inserted +in the caller's application at the beginning of the code scope that +makes repeated calls to AWS-LC cryptographic functions. + +Alternatively, the functions that are invoked by the macro, +`armv8_set_dit` and `armv8_restore_dit`, can be placed at the +beginning and the end of the code section, respectively. An example +of that usage is present in the benchmarking function `Speed()` in +`tool/speed.cc` when the `-dit` option is used. + + ./tool/bssl speed -dit + +The DIT capability, which is checked in `OPENSSL_cpuid_setup` can be masked +out at runtime by calling `armv8_disable_dit`. This would result in having the +functions `armv8_set_dit` and `armv8_restore_dit` being a noop. It can be made +available again at runtime by calling `armv8_enable_dit`. diff --git a/crypto/fipsmodule/cpucap/cpu_aarch64.c b/crypto/fipsmodule/cpucap/cpu_aarch64.c index 8f6c06a17e7..9dddf14655d 100644 --- a/crypto/fipsmodule/cpucap/cpu_aarch64.c +++ b/crypto/fipsmodule/cpucap/cpu_aarch64.c @@ -70,7 +70,7 @@ static uint64_t armv8_get_dit(void) { // Op1 (3 for DIT) , Op2 (5 for DIT) encodes the PSTATE field modified and defines the constraints. // CRm = Imm4 (#0 or #1 below) // Rt = 0x1f -uint64_t armv8_enable_dit(void) { +uint64_t armv8_set_dit(void) { if (CRYPTO_is_ARMv8_DIT_capable()) { uint64_t original_dit = armv8_get_dit(); // Encoding of "msr dit, #1" @@ -82,11 +82,20 @@ uint64_t armv8_enable_dit(void) { } void armv8_restore_dit(volatile uint64_t *original_dit) { - if (CRYPTO_is_ARMv8_DIT_capable() && *original_dit != 1) { + if (*original_dit != 1 && CRYPTO_is_ARMv8_DIT_capable()) { // Encoding of "msr dit, #0" __asm__ volatile(".long 0xd503405f"); } } + +void armv8_disable_dit(void) { + OPENSSL_armcap_P &= ~ARMV8_DIT_ALLOWED; +} + +void armv8_enable_dit(void) { + OPENSSL_armcap_P |= ARMV8_DIT_ALLOWED; +} + #endif // MAKE_DIT_AVAILABLE && !OPENSSL_WINDOWS #endif // OPENSSL_AARCH64 && !OPENSSL_STATIC_ARMCAP diff --git a/crypto/fipsmodule/cpucap/cpu_aarch64_apple.c b/crypto/fipsmodule/cpucap/cpu_aarch64_apple.c index ddf26b84279..5f6866fbda2 100644 --- a/crypto/fipsmodule/cpucap/cpu_aarch64_apple.c +++ b/crypto/fipsmodule/cpucap/cpu_aarch64_apple.c @@ -101,7 +101,7 @@ void OPENSSL_cpuid_setup(void) { #if defined(MAKE_DIT_AVAILABLE) if (has_hw_feature("hw.optional.arm.FEAT_DIT")) { - OPENSSL_armcap_P |= ARMV8_DIT; + OPENSSL_armcap_P |= (ARMV8_DIT | ARMV8_DIT_ALLOWED); } #endif // MAKE_DIT_AVAILABLE diff --git a/crypto/fipsmodule/cpucap/cpu_aarch64_linux.c b/crypto/fipsmodule/cpucap/cpu_aarch64_linux.c index 8d3f803505c..de6a0fcaadd 100644 --- a/crypto/fipsmodule/cpucap/cpu_aarch64_linux.c +++ b/crypto/fipsmodule/cpucap/cpu_aarch64_linux.c @@ -93,9 +93,9 @@ void OPENSSL_cpuid_setup(void) { #if defined(MAKE_DIT_AVAILABLE) static const unsigned long kDIT = 1 << 24; - // Before enabling/disabling the DIT flag, check it's available in HWCAP + // Before setting/resetting the DIT flag, check it's available in HWCAP if (hwcap & kDIT) { - OPENSSL_armcap_P |= ARMV8_DIT; + OPENSSL_armcap_P |= (ARMV8_DIT | ARMV8_DIT_ALLOWED); } #endif // MAKE_DIT_AVAILABLE diff --git a/crypto/fipsmodule/cpucap/internal.h b/crypto/fipsmodule/cpucap/internal.h index f9c44c3b3e4..babd4876260 100644 --- a/crypto/fipsmodule/cpucap/internal.h +++ b/crypto/fipsmodule/cpucap/internal.h @@ -236,7 +236,7 @@ OPENSSL_INLINE int CRYPTO_is_ARMv8_wide_multiplier_capable(void) { } OPENSSL_INLINE int CRYPTO_is_ARMv8_DIT_capable(void) { - return (OPENSSL_armcap_P & ARMV8_DIT) != 0; + return (OPENSSL_armcap_P & (ARMV8_DIT | ARMV8_DIT_ALLOWED)) == (ARMV8_DIT | ARMV8_DIT_ALLOWED); } #endif // OPENSSL_ARM || OPENSSL_AARCH64 diff --git a/include/openssl/arm_arch.h b/include/openssl/arm_arch.h index 5db9bb3aa8a..73c63ae041b 100644 --- a/include/openssl/arm_arch.h +++ b/include/openssl/arm_arch.h @@ -90,7 +90,15 @@ #define ARMV8_NEOVERSE_V2 (1 << 14) // ARMV8_DIT indicates support for the Data-Independent Timing (DIT) flag. -#define ARMV8_DIT (1 << 14) +#define ARMV8_DIT (1 << 15) +// ARMV8_DIT_ALLOWED is a run-time en/disabler for the Data-Independent +// Timing (DIT) flag capability. It makes the DIT capability allowed when it is +// first discovered in |OPENSSL_cpuid_setup|. But that bit position in +// |OPENSSL_armcap_P| can be toggled off and back on at run-time via +// |armv8_disable_dit| and |armv8_enable_dit|, respectively. +#define ARMV8_DIT_ALLOWED (1 << 16) + + // // MIDR_EL1 system register // diff --git a/include/openssl/crypto.h b/include/openssl/crypto.h index fbe6e219572..294feea6dd7 100644 --- a/include/openssl/crypto.h +++ b/include/openssl/crypto.h @@ -89,17 +89,17 @@ OPENSSL_EXPORT int CRYPTO_needs_hwcap2_workaround(void); #if defined(OPENSSL_AARCH64) && !defined(OPENSSL_WINDOWS) && defined(MAKE_DIT_AVAILABLE) // (TODO): See if we can detect the DIT capability in Windows environment -// armv8_enable_dit sets the DIT flag to 1 and returns its original value +// armv8_set_dit sets the DIT flag to 1 and returns its original value // before it was called. -uint64_t armv8_enable_dit(void); +uint64_t armv8_set_dit(void); // armv8_restore_dit takes as input a value to restore the DIT flag to. void armv8_restore_dit(volatile uint64_t *original_dit); // SET_DIT_AUTO_DISABLE can be inserted in the caller's application at -// the beginning of the code section that makes repeated calls to AWS-LC functions. -// The flag will be automatically restored to its original value at the end of the -// scope. +// the beginning of the code section that makes repeated calls to AWS-LC +// functions. The flag will be automatically restored to its original value +// at the end of the scope. // This can minimise the effect on performance of repeatedly setting and // disabling DIT. // Instead of the macro, the functions above can be used. @@ -108,7 +108,17 @@ void armv8_restore_dit(volatile uint64_t *original_dit); #define SET_DIT_AUTO_DISABLE \ volatile uint64_t _dit_restore_orig \ __attribute__((cleanup(armv8_restore_dit))) \ - OPENSSL_UNUSED = armv8_enable_dit(); + OPENSSL_UNUSED = armv8_set_dit(); + +// armv8_disable_dit is a run-time disabler of the DIT capability. +// It results in CRYPTO_is_ARMv8_DIT_capable() returning 0 even if the +// capability exists. +void armv8_disable_dit(void); + +// armv8_enable_dit is a run-time enabler of the DIT capability. If +// |armv8_disable_dit| was used to disable the DIT capability, this function +// makes it available again. +void armv8_enable_dit(void); #else #define SET_DIT_AUTO_DISABLE diff --git a/tool/speed.cc b/tool/speed.cc index 3e8ef0b6362..ce737f05ed7 100644 --- a/tool/speed.cc +++ b/tool/speed.cc @@ -2545,8 +2545,8 @@ static const argument_t kArguments[] = { { "-dit", kBooleanArgument, - "If this flag is set, the DIT flag is enabled before benchmarking and" - "disabled at the end." + "If this flag is set, the DIT flag is set before benchmarking and" + "reset at the end." }, #endif { @@ -2682,10 +2682,12 @@ bool Speed(const std::vector &args) { } } #if defined(DIT_OPTION) + armv8_disable_dit(); // disable DIT capability at run-time + armv8_enable_dit(); // enable back DIT capability at run-time uint64_t original_dit = 0; if (g_dit) { - original_dit = armv8_enable_dit(); + original_dit = armv8_set_dit(); } #endif