From 366cc5e1897c0b7c86233de33bf1994fdf63d2d0 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 21 May 2018 04:30:32 -0600 Subject: [PATCH] Exosphere: Fix extremely spooky Security Engine bugs, now makes it to the end of package2loader. --- exosphere/src/bootup.c | 21 ++++++++++++--------- exosphere/src/exocfg.h | 1 + exosphere/src/package2.c | 23 ++++++++++++++++------- exosphere/src/se.c | 15 +++++++++------ exosphere/src/se.h | 3 ++- exosphere/src/start.s | 2 +- exosphere/src/utils.c | 4 ++++ 7 files changed, 45 insertions(+), 24 deletions(-) diff --git a/exosphere/src/bootup.c b/exosphere/src/bootup.c index 534b92f72..c896714a6 100644 --- a/exosphere/src/bootup.c +++ b/exosphere/src/bootup.c @@ -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; diff --git a/exosphere/src/exocfg.h b/exosphere/src/exocfg.h index c3af903d4..15fabc8f6 100644 --- a/exosphere/src/exocfg.h +++ b/exosphere/src/exocfg.h @@ -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)) diff --git a/exosphere/src/package2.c b/exosphere/src/package2.c index 46f667050..cd79feacc 100644 --- a/exosphere/src/package2.c +++ b/exosphere/src/package2.c @@ -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; } diff --git a/exosphere/src/se.c b/exosphere/src/se.c index 5fc883804..9334300e7 100644 --- a/exosphere/src/se.c +++ b/exosphere/src/se.c @@ -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); diff --git a/exosphere/src/se.h b/exosphere/src/se.h index b79e2c0aa..85cada943 100644 --- a/exosphere/src/se.h +++ b/exosphere/src/se.h @@ -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]; diff --git a/exosphere/src/start.s b/exosphere/src/start.s index e7121126a..7730bda95 100644 --- a/exosphere/src/start.s +++ b/exosphere/src/start.s @@ -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 */ diff --git a/exosphere/src/utils.c b/exosphere/src/utils.c index c3d43cfcc..766e43f37 100644 --- a/exosphere/src/utils.c +++ b/exosphere/src/utils.c @@ -1,4 +1,5 @@ #include +#include #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(); }