From 55d988e4163c0c2370c82f82c5079f774452c370 Mon Sep 17 00:00:00 2001 From: William Bo Yang Date: Mon, 31 Jul 2023 07:50:50 -0700 Subject: [PATCH] Support changing OPENSSL_armcap with environment variable on Apple 64-bit ARM systems (#1045) * use handle_cpu_env from cpu_aarch64_linux.c to cpu_aarch64_apple.c * always use OPENSSL_armcap() when detecting hardware capabilities on arm * refactor duplicated into cpu_aarch64.h/c * add ifdefs to cpu_aarch64.h/c * Update comments Co-authored-by: Nevine Ebeid <66388554+nebeid@users.noreply.github.com> * adjust line length of comment * set arm capabilities functions to fillow format of x86 ones * make rest of the arm capability functions in line with x86 ones --------- Co-authored-by: Nevine Ebeid <66388554+nebeid@users.noreply.github.com> Co-authored-by: Bill Yang --- crypto/fipsmodule/bcm.c | 1 + crypto/fipsmodule/cpucap/cpu_aarch64.c | 52 ++++++++++++++++++++ crypto/fipsmodule/cpucap/cpu_aarch64.h | 31 ++++++++++++ crypto/fipsmodule/cpucap/cpu_aarch64_apple.c | 16 ++++++ crypto/fipsmodule/cpucap/cpu_aarch64_linux.c | 35 +------------ 5 files changed, 101 insertions(+), 34 deletions(-) create mode 100644 crypto/fipsmodule/cpucap/cpu_aarch64.c create mode 100644 crypto/fipsmodule/cpucap/cpu_aarch64.h diff --git a/crypto/fipsmodule/bcm.c b/crypto/fipsmodule/bcm.c index 28932bb21d..567890e09e 100644 --- a/crypto/fipsmodule/bcm.c +++ b/crypto/fipsmodule/bcm.c @@ -41,6 +41,7 @@ #include "../internal.h" #include "cpucap/cpucap.c" +#include "cpucap/cpu_aarch64.c" #include "cpucap/cpu_aarch64_apple.c" #include "cpucap/cpu_aarch64_fuchsia.c" #include "cpucap/cpu_aarch64_linux.c" diff --git a/crypto/fipsmodule/cpucap/cpu_aarch64.c b/crypto/fipsmodule/cpucap/cpu_aarch64.c new file mode 100644 index 0000000000..7c085b7e10 --- /dev/null +++ b/crypto/fipsmodule/cpucap/cpu_aarch64.c @@ -0,0 +1,52 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +#if defined(OPENSSL_AARCH64) && !defined(OPENSSL_STATIC_ARMCAP) + +#include "cpu_aarch64.h" + +void handle_cpu_env(uint32_t *out, const char *in) { + const int invert = in[0] == '~'; + const int or = in[0] == '|'; + const int skip_first_byte = invert || or; + const int hex = in[skip_first_byte] == '0' && in[skip_first_byte+1] == 'x'; + uint32_t armcap = out[0]; + + int sscanf_result; + uint32_t v; + if (hex) { + sscanf_result = sscanf(in + skip_first_byte + 2, "%" PRIx32, &v); + } else { + sscanf_result = sscanf(in + skip_first_byte, "%" PRIu32, &v); + } + + if (!sscanf_result) { + return; + } + + // Detect if the user is trying to use the environment variable to set + // a capability that is _not_ available on the CPU: + // If the runtime capability check (e.g via getauxval() on Linux) + // returned a non-zero hwcap in `armcap` (out) + // and a bit set in the requested `v` is not set in `armcap`, + // abort instead of crashing later. + // The case of invert cannot enable an unexisting capability; + // it can only disable an existing one. + if (!invert && armcap && (~armcap & v)) + { + fprintf(stderr, + "Fatal Error: HW capability found: 0x%02X, but HW capability requested: 0x%02X.\n", + armcap, v); + exit(1); + } + + if (invert) { + out[0] &= ~v; + } else if (or) { + out[0] |= v; + } else { + out[0] = v; + } +} + +#endif // OPENSSL_AARCH64 && !OPENSSL_STATIC_ARMCAP diff --git a/crypto/fipsmodule/cpucap/cpu_aarch64.h b/crypto/fipsmodule/cpucap/cpu_aarch64.h new file mode 100644 index 0000000000..0999d58c53 --- /dev/null +++ b/crypto/fipsmodule/cpucap/cpu_aarch64.h @@ -0,0 +1,31 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +#ifndef OPENSSL_HEADER_CPUCAP_CPU_AARCH64_H +#define OPENSSL_HEADER_CPUCAP_CPU_AARCH64_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#include + +#include +#include +#include + +#if defined(OPENSSL_AARCH64) && !defined(OPENSSL_STATIC_ARMCAP) + +// cpu_aarch64 contains common functions used across multiple cpu_aarch64_* files + +// handle_cpu_env applies the value from |in| to the CPUID values in |out[0]|. +// See the comment in |OPENSSL_cpuid_setup| about this. +void handle_cpu_env(uint32_t *out, const char *in); + +#endif // OPENSSL_AARCH64 && !OPENSSL_STATIC_ARMCAP + +#if defined(__cplusplus) +} +#endif + +#endif // OPENSSL_HEADER_CPUCAP_CPU_AARCH64_H diff --git a/crypto/fipsmodule/cpucap/cpu_aarch64_apple.c b/crypto/fipsmodule/cpucap/cpu_aarch64_apple.c index 92a219a985..b27f447383 100644 --- a/crypto/fipsmodule/cpucap/cpu_aarch64_apple.c +++ b/crypto/fipsmodule/cpucap/cpu_aarch64_apple.c @@ -22,6 +22,7 @@ #include +#include "cpu_aarch64.h" extern uint32_t OPENSSL_armcap_P; @@ -67,6 +68,21 @@ void OPENSSL_cpuid_setup(void) { if (has_hw_feature("hw.optional.armv8_2_sha512")) { OPENSSL_armcap_P |= ARMV8_SHA512; } + + // OPENSSL_armcap is a 32-bit, unsigned value which may start with "0x" to + // indicate a hex value. Prior to the 32-bit value, a '~' or '|' may be given. + // + // If the '~' prefix is present: + // the value is inverted and ANDed with the probed CPUID result + // If the '|' prefix is present: + // the value is ORed with the probed CPUID result + // Otherwise: + // the value is taken as the result of the CPUID + const char *env; + env = getenv("OPENSSL_armcap"); + if (env != NULL) { + handle_cpu_env(&OPENSSL_armcap_P, env); + } } #endif // OPENSSL_AARCH64 && OPENSSL_APPLE && !OPENSSL_STATIC_ARMCAP diff --git a/crypto/fipsmodule/cpucap/cpu_aarch64_linux.c b/crypto/fipsmodule/cpucap/cpu_aarch64_linux.c index 3c19956a18..7611dbc678 100644 --- a/crypto/fipsmodule/cpucap/cpu_aarch64_linux.c +++ b/crypto/fipsmodule/cpucap/cpu_aarch64_linux.c @@ -22,46 +22,13 @@ #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS #endif -#include - -#include -#include -#include #include +#include "cpu_aarch64.h" extern uint32_t OPENSSL_armcap_P; -// handle_cpu_env applies the value from |in| to the CPUID values in |out[0]| -// and |out[1]|. See the comment in |OPENSSL_cpuid_setup| about this. -static void handle_cpu_env(uint32_t *out, const char *in) { - const int invert = in[0] == '~'; - const int or = in[0] == '|'; - const int skip_first_byte = invert || or; - const int hex = in[skip_first_byte] == '0' && in[skip_first_byte+1] == 'x'; - - int sscanf_result; - uint32_t v; - if (hex) { - sscanf_result = sscanf(in + invert + 2, "%" PRIx32, &v); - } else { - sscanf_result = sscanf(in + invert, "%" PRIu32, &v); - } - - if (!sscanf_result) { - return; - } - - if (invert) { - out[0] &= ~v; - } else if (or) { - out[0] |= v; - } else { - out[0] = v; - } -} - void OPENSSL_cpuid_setup(void) { unsigned long hwcap = getauxval(AT_HWCAP);