Exosphere: Fix extremely spooky Security Engine bugs, now makes it to the end of package2loader.

This commit is contained in:
Michael Scire 2018-05-21 04:30:32 -06:00
parent ac7ee45493
commit 366cc5e189
7 changed files with 45 additions and 24 deletions

View file

@ -33,7 +33,7 @@ static bool g_has_booted_up = false;
void bootup_misc_mmio(void) {
/* Initialize Fuse registers. */
fuse_init();
/* Verify Security Engine sanity. */
se_set_in_context_save_mode(false);
/* TODO: se_verify_keys_unreadable(); */
@ -82,6 +82,8 @@ void bootup_misc_mmio(void) {
MC_SECURITY_CFG1_0 = 0;
MC_SECURITY_CFG3_0 = 3;
configure_default_carveouts();
/* Mark registers secure world only. */
/* Mark SATA_AUX, DTV, QSPI, SE, SATA, LA secure only. */
@ -111,14 +113,15 @@ void bootup_misc_mmio(void) {
MAKE_MC_REG(0x230) = 0xFFFFFFFF;
MAKE_MC_REG(0x234) = 0xFFFFFFFF;
MAKE_MC_REG(0xB98) = 0xFFFFFFFF;
MAKE_MC_REG(0x038) = 0;
MAKE_MC_REG(0x038) = 0xE;
MAKE_MC_REG(0x03C) = 0;
MAKE_MC_REG(0x0E0) = 0;
MAKE_MC_REG(0x0E4) = 0;
MAKE_MC_REG(0x0E8) = 0;
MAKE_MC_REG(0x0EC) = 0;
MAKE_MC_REG(0x0F0) = 0;
MAKE_MC_REG(0x0F4) = 0;
MAKE_MC_REG(0x9E0) = 0;
MAKE_MC_REG(0x9E4) = 0;
MAKE_MC_REG(0x9E8) = 0;
MAKE_MC_REG(0x9EC) = 0;
MAKE_MC_REG(0x9F0) = 0;
MAKE_MC_REG(0x9F4) = 0;
MAKE_MC_REG(0x01C) = 0;
MAKE_MC_REG(0x020) = 0;
MAKE_MC_REG(0x014) = 0x30000030;
MAKE_MC_REG(0x018) = 0x2800003F;
@ -129,7 +132,7 @@ void bootup_misc_mmio(void) {
(void)(MAKE_MC_REG(0x014));
MAKE_MC_REG(0x010) = 1;
(void)(MAKE_MC_REG(0x014));
/* Clear RESET Vector, setup CPU Secure Boot RESET Vectors. */
uint32_t reset_vec = TZRAM_GET_SEGMENT_PA(TZRAM_SEGMENT_ID_WARMBOOT_CRT0_AND_MAIN);
EVP_CPU_RESET_VECTOR_0 = 0;

View file

@ -19,6 +19,7 @@
/* TODO: What should this be, for release? */
#define EXOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG EXOSPHERE_TARGET_FIRMWARE_100
#define EXOSPHERE_LOOSEN_PACKAGE2_RESTRICTIONS_FOR_DEBUG 1
#define MAILBOX_BASE_PHYS (MMIO_GET_DEVICE_PA(MMIO_DEVID_NXBOOTLOADER_MAILBOX))

View file

@ -58,6 +58,10 @@ static void setup_se(void) {
/* Perform some sanity initialization. */
volatile security_engine_t *p_security_engine = get_security_engine();
p_security_engine->_0x0 &= 0xFFFEFFFF; /* Clear bit 16. */
(void)(SECURITY_ENGINE->FLAGS_REG);
__dsb_sy();
p_security_engine->_0x4 = 0;
p_security_engine->AES_KEY_READ_DISABLE_REG = 0;
p_security_engine->RSA_KEY_READ_DISABLE_REG = 0;
@ -107,6 +111,7 @@ static void setup_se(void) {
/* Generate test vector for our keys. */
se_generate_stored_vector();
}
static void setup_boot_config(void) {
@ -178,7 +183,8 @@ static void verify_header_signature(package2_header_t *header) {
}
/* This is normally only allowed on dev units, but we'll allow it anywhere. */
if (bootconfig_is_package2_unsigned() == 0 && se_rsa2048_pss_verify(header->signature, 0x100, modulus, 0x100, header->encrypted_header, 0x100) == 0) {
bool is_unsigned = EXOSPHERE_LOOSEN_PACKAGE2_RESTRICTIONS_FOR_DEBUG || bootconfig_is_package2_unsigned();
if (!is_unsigned && se_rsa2048_pss_verify(header->signature, 0x100, modulus, 0x100, header->encrypted_header, 0x100) == 0) {
panic(0xF0000001); /* Invalid PK21 signature. */
}
}
@ -191,6 +197,7 @@ static bool validate_package2_metadata(package2_meta_t *metadata) {
if (metadata->magic != MAGIC_PK21) {
return false;
}
/* Package2 size, version number is stored XORed in header CTR. */
/* Nintendo, what the fuck? */
@ -246,13 +253,14 @@ static bool validate_package2_metadata(package2_meta_t *metadata) {
}
}
bool check_hash = EXOSPHERE_LOOSEN_PACKAGE2_RESTRICTIONS_FOR_DEBUG == 0;
/* Validate section hashes. */
if (metadata->section_sizes[section]) {
void *section_data = (void *)((uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS + sizeof(package2_header_t) + cur_section_offset);
uint8_t calculated_hash[0x20];
flush_dcache_range((uint8_t *)section_data, (uint8_t *)section_data + metadata->section_sizes[section]);
se_calculate_sha256(calculated_hash, section_data, metadata->section_sizes[section]);
if (memcmp(calculated_hash, metadata->section_hashes[section], sizeof(metadata->section_hashes[section])) != 0) {
if (check_hash && memcmp(calculated_hash, metadata->section_hashes[section], sizeof(metadata->section_hashes[section])) != 0) {
return false;
}
cur_section_offset += metadata->section_sizes[section];
@ -288,6 +296,7 @@ static uint32_t decrypt_and_validate_header(package2_header_t *header) {
memcpy(metadata.ctr, header->metadata.ctr, sizeof(header->metadata.ctr));
/* See if this is the correct key. */
if (validate_package2_metadata(&metadata)) {
se_calculate_sha256(metadata.ctr, &header->metadata, sizeof(package2_meta_t));
header->metadata = metadata;
return mkey_rev;
}
@ -446,7 +455,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
flush_dcache_range((uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, (uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS + sizeof(header));
memcpy(&header, NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, sizeof(header));
flush_dcache_range((uint8_t *)&header, (uint8_t *)&header + sizeof(header));
/* Perform signature checks. */
/* Special exosphere patching enable: All-zeroes signature + decrypted header implies unsigned and decrypted package2. */
if (header.signature[0] == 0 && memcmp(header.signature, header.signature + 1, sizeof(header.signature) - 1) == 0 && header.metadata.magic == MAGIC_PK21) {
@ -457,7 +466,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Decrypt header, get key revision required. */
uint32_t package2_mkey_rev = decrypt_and_validate_header(&header);
/* Copy hash, if necessary. */
if (bootconfig_is_recovery_boot()) {
bootconfig_set_package2_hash_for_recovery(NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, get_package2_size(&header.metadata));
@ -477,8 +486,6 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
indentity_unmap_dram();
/* Synchronize with NX BOOTLOADER. */
sync_with_nx_bootloader(NX_BOOTLOADER_STATE_FINISHED);
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_400) {
sync_with_nx_bootloader(NX_BOOTLOADER_STATE_FINISHED_4X);
setup_4x_mmio();
@ -490,5 +497,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
set_version_specific_smcs();
/* Update SCR_EL3 depending on value in Bootconfig. */
set_extabt_serror_taken_to_el3(bootconfig_take_extabt_serror_to_el3());
set_extabt_serror_taken_to_el3(bootconfig_take_extabt_serror_to_el3());
strcpy((void *)MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_DEBUG_IRAM), (void *)"PK2LOADED");
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x400ull) = 0x10;
}

View file

@ -32,7 +32,7 @@ void ll_init(se_ll_t *ll, void *buffer, size_t size) {
ll->addr_info.address = 0;
ll->addr_info.size = 0;
}
flush_dcache_range((uint8_t *)ll, (uint8_t *)ll + sizeof(*ll));
}
@ -452,17 +452,20 @@ void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const v
ll_init(&in_ll, (void *)src, src_size);
ll_init(&out_ll, dst, dst_size);
__dsb_sy();
/* Set the LLs. */
SECURITY_ENGINE->IN_LL_ADDR_REG = (uint32_t) get_physical_address(&in_ll);
SECURITY_ENGINE->OUT_LL_ADDR_REG = (uint32_t) get_physical_address(&out_ll);
/* Set registers for operation. */
SECURITY_ENGINE->ERR_STATUS_REG = SECURITY_ENGINE->ERR_STATUS_REG;
SECURITY_ENGINE->INT_STATUS_REG = SECURITY_ENGINE->INT_STATUS_REG;
SECURITY_ENGINE->OPERATION_REG = op;
while (!(SECURITY_ENGINE->INT_STATUS_REG & 0x10)) { /* Wait a while */ }
se_check_for_error();
}
@ -659,14 +662,14 @@ void se_calculate_sha256(void *dst, const void *src, size_t src_size) {
SECURITY_ENGINE->CONFIG_REG = (ENCMODE_SHA256 | ALG_SHA | DST_HASHREG);
SECURITY_ENGINE->SHA_CONFIG_REG = 1;
SECURITY_ENGINE->SHA_MSG_LENGTH_REG = (unsigned int)(src_size << 3);
SECURITY_ENGINE->_0x208 = 0;
SECURITY_ENGINE->_0x20C = 0;
SECURITY_ENGINE->_0x210 = 0;
SECURITY_ENGINE->SHA_MSG_LEFT_REG = 0;
SECURITY_ENGINE->_0x218 = (unsigned int)(src_size << 3);
SECURITY_ENGINE->SHA_MSG_LEFT_REG = (unsigned int)(src_size << 3);
SECURITY_ENGINE->_0x218 = 0;
SECURITY_ENGINE->_0x21C = 0;
SECURITY_ENGINE->_0x220 = 0;
SECURITY_ENGINE->_0x224 = 0;
/* Trigger the operation. */
trigger_se_blocking_op(OP_START, NULL, 0, src, src_size);

View file

@ -100,6 +100,7 @@ typedef struct security_engine {
unsigned char _0x74[0x18C];
unsigned int SHA_CONFIG_REG;
unsigned int SHA_MSG_LENGTH_REG;
unsigned int _0x208;
unsigned int _0x20C;
unsigned int _0x210;
unsigned int SHA_MSG_LEFT_REG;
@ -110,7 +111,7 @@ typedef struct security_engine {
unsigned char _0x228[0x5C];
unsigned int AES_KEY_READ_DISABLE_REG;
unsigned int AES_KEYSLOT_FLAGS[0x10];
unsigned char _0x2C4[0x3C];
unsigned char _0x2C8[0x38];
unsigned int _0x300;
unsigned int CRYPTO_REG;
unsigned int CRYPTO_CTR_REG[4];

View file

@ -201,7 +201,7 @@ __jump_to_main_cold:
bl get_pk2ldr_stack_address
mov sp, x0
mov x0, x19
mov x0, x20
bl load_package2
mov w0, #3 /* use core3 stack temporarily */

View file

@ -1,4 +1,5 @@
#include <stdbool.h>
#include <string.h>
#include "utils.h"
#include "se.h"
#include "fuse.h"
@ -12,10 +13,13 @@ __attribute__ ((noreturn)) void panic(uint32_t code) {
APBDEV_PMC_SCRATCH200_0 = code;
}
strcpy((void *)MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_DEBUG_IRAM), (void *)"PANIC");
MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x400ull) = 0x10;
/* TODO: Custom Panic Driver, which displays to screen without rebooting. */
/* For now, just use NX BOOTLOADER's panic. */
fuse_disable_programming();
APBDEV_PMC_CRYPTO_OP_0 = 1; /* Disable all SE operations. */
while (1) { }
watchdog_reboot();
}