diff --git a/crypto/fipsmodule/cpucap/cpu_intel.c b/crypto/fipsmodule/cpucap/cpu_intel.c index 5d5fa5eff6..19b6540d02 100644 --- a/crypto/fipsmodule/cpucap/cpu_intel.c +++ b/crypto/fipsmodule/cpucap/cpu_intel.c @@ -133,28 +133,47 @@ static void handle_cpu_env(uint32_t *out, const char *in) { 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 intelcap0 = out[0]; + uint32_t intelcap1 = out[1]; int sscanf_result; uint64_t v; if (hex) { - sscanf_result = sscanf(in + invert + 2, "%" PRIx64, &v); + sscanf_result = sscanf(in + skip_first_byte + 2, "%" PRIx64, &v); } else { - sscanf_result = sscanf(in + invert, "%" PRIu64, &v); + sscanf_result = sscanf(in + skip_first_byte, "%" PRIu64, &v); } if (!sscanf_result) { return; } + uint32_t reqcap0 = (uint32_t)(v & UINT32_MAX); + uint32_t reqcap1 = (uint32_t)(v >> 32); + + // Detect if the user is trying to use the environment variable to set + // a capability that is _not_ available on the CPU. + // The case of invert cannot enable an unexisting capability; + // it can only disable an existing one. + if (!invert && (intelcap0 || intelcap1)) { + // Allow Intel indicator bit to be set for testing + if((~(1u << 30 | intelcap0) & reqcap0) || (~intelcap1 & reqcap1)) { + fprintf(stderr, + "Fatal Error: HW capability found: 0x%02X 0x%02X, but HW capability requested: 0x%02X 0x%02X.\n", + intelcap0, intelcap1, reqcap0, reqcap1); + abort(); + } + } + if (invert) { - out[0] &= ~v; - out[1] &= ~(v >> 32); + out[0] &= ~reqcap0; + out[1] &= ~reqcap1; } else if (or) { - out[0] |= v; - out[1] |= (v >> 32); + out[0] |= reqcap0; + out[1] |= reqcap1; } else { - out[0] = v; - out[1] = v >> 32; + out[0] = reqcap0; + out[1] = reqcap1; } } diff --git a/crypto/fipsmodule/cpucap/cpu_ppc64le.c b/crypto/fipsmodule/cpucap/cpu_ppc64le.c index ab29ec5c93..61fe953846 100644 --- a/crypto/fipsmodule/cpucap/cpu_ppc64le.c +++ b/crypto/fipsmodule/cpucap/cpu_ppc64le.c @@ -24,11 +24,68 @@ #define PPC_FEATURE2_HAS_VCRYPTO 0x02000000 #endif +static void handle_cpu_env(unsigned long *out, const char *in) { + OPENSSL_STATIC_ASSERT(sizeof(unsigned long) == 8, PPC64LE_UNSIGNED_LONG_NOT_8_BYTES); + + const int invert = in[0] == '~'; + const int or = in[0] == '|'; + const int skip_first_byte = (invert || or) ? 1 : 0; + const int hex = in[skip_first_byte] == '0' && in[skip_first_byte+1] == 'x'; + unsigned long ppccap = *out; + + int sscanf_result; + uint64_t reqcap; + if (hex) { + sscanf_result = sscanf(in + skip_first_byte + 2, "%" PRIx64, &reqcap); + } else { + sscanf_result = sscanf(in + skip_first_byte, "%" PRIu64, &reqcap); + } + + 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. + // The case of invert cannot enable an unexisting capability; + // it can only disable an existing one. + if (!invert && ppccap && (~ppccap & reqcap)) { + fprintf(stderr, + "Fatal Error: HW capability found: 0x%02lX, but HW capability requested: 0x%02lX.\n", + ppccap, reqcap); + abort(); + } + + if (invert) { + *out &= ~reqcap; + } else if (or) { + *out |= reqcap; + } else { + *out = reqcap; + } +} + extern uint8_t OPENSSL_cpucap_initialized; void OPENSSL_cpuid_setup(void) { OPENSSL_ppc64le_hwcap2 = getauxval(AT_HWCAP2); OPENSSL_cpucap_initialized = 1; + + // OPENSSL_ppccap is a 64-bit hex string which may start with "0x". + // Prior to the 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_ppccap"); + if (env != NULL) { + handle_cpu_env(&OPENSSL_ppc64le_hwcap2, env); + } + } int CRYPTO_is_PPC64LE_vcrypto_capable(void) {