Add an OPENSSL_ia32cap_get() function for C code. OPENSSL_ia32cap_addr avoids any relocations within the module, at the cost of a runtime TEXTREL, which causes problems in some cases. (Notably, if someone links us into a binary which uses the GCC "ifunc" attribute, the loader crashes.) Fix C references of OPENSSL_ia32cap_addr with a function. This is analogous to the BSS getters. A follow-up commit will fix perlasm with a different scheme which avoids calling into a function (clobbering registers and complicating unwind directives.) Change-Id: I09d6cda4cec35b693e16b5387611167da8c7a6de Reviewed-on: https://boringssl-review.googlesource.com/15525 Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/fipsmodule/delocate.go b/crypto/fipsmodule/delocate.go index 983f42f..07e6583 100644 --- a/crypto/fipsmodule/delocate.go +++ b/crypto/fipsmodule/delocate.go
@@ -169,6 +169,10 @@ // referenced and thus needs to be emitted outside the module. ia32capAddrNeeded := false + // ia32capGetNeeded is true iff OPENSSL_ia32cap_get has been referenced + // and thus needs to be emitted outside the module. + ia32capGetNeeded := false + // bssAccessorsNeeded maps the names of BSS variables for which // accessor functions need to be emitted outside of the module, to the // BSS symbols they point to. For example, “EVP_sha256_once” could map @@ -188,11 +192,6 @@ break } - // References to OPENSSL_ia32cap_P via the GOT result from C - // code. The OPENSSL_ia32cap_addr symbol, generated by this - // script, is just like a GOT entry, but at a known offset. - line = strings.Replace(line, "OPENSSL_ia32cap_P@GOTPCREL(%rip)", "OPENSSL_ia32cap_addr(%rip)", -1) - if referencesIA32CapDirectly(line) { panic("reference to OPENSSL_ia32cap_P needs to be changed to indirect via OPENSSL_ia32cap_addr") } @@ -201,6 +200,10 @@ ia32capAddrNeeded = true } + if strings.Contains(line, "OPENSSL_ia32cap_get@PLT") { + ia32capGetNeeded = true + } + line = strings.Replace(line, "@PLT", "", -1) parts := strings.Fields(strings.TrimSpace(line)) @@ -393,6 +396,14 @@ ret = append(ret, "\tret") } + // Emit an OPENSSL_ia32cap_get accessor. + if ia32capGetNeeded { + ret = append(ret, ".type OPENSSL_ia32cap_get, @function") + ret = append(ret, "OPENSSL_ia32cap_get:") + ret = append(ret, "\tleaq OPENSSL_ia32cap_P(%rip), %rax") + ret = append(ret, "\tret") + } + // Emit an indirect reference to OPENSSL_ia32cap_P. if ia32capAddrNeeded { ret = append(ret, ".extern OPENSSL_ia32cap_P")
diff --git a/crypto/fipsmodule/modes/gcm.c b/crypto/fipsmodule/modes/gcm.c index dbc798e..90f5ab4 100644 --- a/crypto/fipsmodule/modes/gcm.c +++ b/crypto/fipsmodule/modes/gcm.c
@@ -365,7 +365,7 @@ #if defined(GHASH_ASM_X86_64) if (crypto_gcm_clmul_enabled()) { - if (((OPENSSL_ia32cap_P[1] >> 22) & 0x41) == 0x41) { /* AVX+MOVBE */ + if (((OPENSSL_ia32cap_get()[1] >> 22) & 0x41) == 0x41) { /* AVX+MOVBE */ gcm_init_avx(out_table, H.u); *out_mult = gcm_gmult_avx; *out_hash = gcm_ghash_avx; @@ -1064,8 +1064,9 @@ #if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) int crypto_gcm_clmul_enabled(void) { #ifdef GHASH_ASM - return (OPENSSL_ia32cap_P[0] & (1 << 24)) && /* check FXSR bit */ - (OPENSSL_ia32cap_P[1] & (1 << 1)); /* check PCLMULQDQ bit */ + const uint32_t *ia32cap = OPENSSL_ia32cap_get(); + return (ia32cap[0] & (1 << 24)) && /* check FXSR bit */ + (ia32cap[1] & (1 << 1)); /* check PCLMULQDQ bit */ #else return 0; #endif
diff --git a/crypto/fipsmodule/rand/rand.c b/crypto/fipsmodule/rand/rand.c index e42ad46..4f5e579 100644 --- a/crypto/fipsmodule/rand/rand.c +++ b/crypto/fipsmodule/rand/rand.c
@@ -82,7 +82,7 @@ extern int CRYPTO_rdrand_multiple8_buf(uint8_t *buf, size_t len); static int have_rdrand(void) { - return (OPENSSL_ia32cap_P[1] & (1u << 30)) != 0; + return (OPENSSL_ia32cap_get()[1] & (1u << 30)) != 0; } static int hwrand(uint8_t *buf, size_t len) {
diff --git a/include/openssl/cpu.h b/include/openssl/cpu.h index 1a4294a..81cc5ba 100644 --- a/include/openssl/cpu.h +++ b/include/openssl/cpu.h
@@ -91,6 +91,15 @@ * Note: the CPUID bits are pre-adjusted for the OSXSAVE bit and the YMM and XMM * bits in XCR0, so it is not necessary to check those. */ extern uint32_t OPENSSL_ia32cap_P[4]; + +#if defined(BORINGSSL_FIPS) +const uint32_t *OPENSSL_ia32cap_get(void); +#else +static inline const uint32_t *OPENSSL_ia32cap_get(void) { + return OPENSSL_ia32cap_P; +} +#endif + #endif #if defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)