Add page protection logic to BCM self test. On Android only, assume code is compiled for Execute-only memory, so add Read permission for the duration of the self test and then mark the pages Execute-only again. NB if libcrypto is not compiled for Execute-only memory, then attempting to change the page permissions to PROT_EXEC at the start of the self test does not cause it to fail, however changing it to PROT_NONE does. Bug: 134580074 Test: m && flashall Test: Manual tests described above. Change-Id: Ibbf8405a5a9b162ce26532127aaf62c539cd9163 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/37644 Commit-Queue: Adam Langley <agl@google.com> Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/fipsmodule/bcm.c b/crypto/fipsmodule/bcm.c index 559ade3..54f113b 100644 --- a/crypto/fipsmodule/bcm.c +++ b/crypto/fipsmodule/bcm.c
@@ -19,6 +19,10 @@ #include <openssl/crypto.h> #include <stdlib.h> +#if defined(BORINGSSL_FIPS) +#include <sys/mman.h> +#include <unistd.h> +#endif #include <openssl/digest.h> #include <openssl/hmac.h> @@ -99,6 +103,7 @@ #if defined(BORINGSSL_FIPS) #if !defined(OPENSSL_ASAN) + // These symbols are filled in by delocate.go (in static builds) or a linker // script (in shared builds). They point to the start and end of the module, and // the location of the integrity hash, respectively. @@ -109,9 +114,31 @@ extern const uint8_t BORINGSSL_bcm_rodata_start[]; extern const uint8_t BORINGSSL_bcm_rodata_end[]; #endif + +#if defined(OPENSSL_ANDROID) +static void BORINGSSL_maybe_set_module_text_permissions(int permission) { + // Android may be compiled in execute-only-memory mode, in which case the + // .text segment cannot be read. That conflicts with the need for a FIPS + // module to hash its own contents, therefore |mprotect| is used to make + // the module's .text readable for the duration of the hashing process. In + // other build configurations this is a no-op. + const uintptr_t page_size = getpagesize(); + const uintptr_t page_start = + ((uintptr_t)BORINGSSL_bcm_text_start) & ~(page_size - 1); + + if (mprotect((void *)page_start, + ((uintptr_t)BORINGSSL_bcm_text_end) - page_start, + permission) != 0) { + perror("BoringSSL: mprotect"); + } +} +#else +static void BORINGSSL_maybe_set_module_text_permissions(int permission) {} +#endif // !ANDROID + #else static const uint8_t BORINGSSL_bcm_text_hash[SHA512_DIGEST_LENGTH] = {0}; -#endif +#endif // !ASAN static void __attribute__((constructor)) BORINGSSL_bcm_power_on_self_test(void) { @@ -138,6 +165,8 @@ fprintf(stderr, "HMAC_Init_ex failed.\n"); goto err; } + + BORINGSSL_maybe_set_module_text_permissions(PROT_READ | PROT_EXEC); #if defined(BORINGSSL_SHARED_LIBRARY) uint64_t length = end - start; HMAC_Update(&hmac_ctx, (const uint8_t *) &length, sizeof(length)); @@ -149,6 +178,8 @@ #else HMAC_Update(&hmac_ctx, start, end - start); #endif + BORINGSSL_maybe_set_module_text_permissions(PROT_EXEC); + if (!HMAC_Final(&hmac_ctx, result, &result_len) || result_len != sizeof(result)) { fprintf(stderr, "HMAC failed.\n");