Skip to content

Commit

Permalink
Adding a runtime dis/enabler of DIT Capability on AArch64.
Browse files Browse the repository at this point in the history
  • Loading branch information
nebeid committed Aug 20, 2024
1 parent 8080ce3 commit 8dbca05
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 30 deletions.
34 changes: 20 additions & 14 deletions BUILDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
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`.
13 changes: 11 additions & 2 deletions crypto/fipsmodule/cpucap/cpu_aarch64.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
2 changes: 1 addition & 1 deletion crypto/fipsmodule/cpucap/cpu_aarch64_apple.c
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 2 additions & 2 deletions crypto/fipsmodule/cpucap/cpu_aarch64_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion crypto/fipsmodule/cpucap/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 9 additions & 1 deletion include/openssl/arm_arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
//
Expand Down
22 changes: 16 additions & 6 deletions include/openssl/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down
8 changes: 5 additions & 3 deletions tool/speed.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -2682,10 +2682,12 @@ bool Speed(const std::vector<std::string> &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

Expand Down

0 comments on commit 8dbca05

Please sign in to comment.