ci(esp_tee): Add tests for verifying behaviour for illegal flash accesses (SPI0)

This commit is contained in:
Laukik Hase 2024-12-13 14:52:36 +05:30
parent 1499c65754
commit 86125aeb98
No known key found for this signature in database
GPG Key ID: D6F3208C06086AC8
5 changed files with 216 additions and 3 deletions

View File

@ -2,7 +2,7 @@ idf_build_get_property(idf_path IDF_PATH)
set(priv_requires bootloader_support driver esp_tee esp_timer mbedtls spi_flash)
# Test FW related
list(APPEND priv_requires cmock json test_utils unity)
list(APPEND priv_requires cmock json nvs_flash test_utils unity)
# TEE related
list(APPEND priv_requires tee_sec_storage tee_attestation tee_ota_ops test_sec_srv)
@ -13,7 +13,8 @@ list(APPEND srcs "test_esp_tee_ctx_switch.c"
"test_esp_tee_panic.c"
"test_esp_tee_sec_stg.c"
"test_esp_tee_ota.c"
"test_esp_tee_att.c")
"test_esp_tee_att.c"
"test_esp_tee_flash_prot.c")
set(mbedtls_test_srcs_dir "${idf_path}/components/mbedtls/test_apps/main")

View File

@ -5,6 +5,8 @@
*/
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "unity.h"
#include "memory_checks.h"
@ -42,5 +44,6 @@ static void test_task(void *pvParameters)
void app_main(void)
{
ESP_ERROR_CHECK(nvs_flash_init());
xTaskCreatePinnedToCore(test_task, "testTask", CONFIG_UNITY_FREERTOS_STACK_SIZE, NULL, CONFIG_UNITY_FREERTOS_PRIORITY, NULL, CONFIG_UNITY_FREERTOS_CPU);
}

View File

@ -0,0 +1,151 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "esp_log.h"
#include "esp_system.h"
#include "esp_heap_caps.h"
#include "esp_flash.h"
#include "esp_rom_spiflash.h"
#include "spi_flash_mmap.h"
#include "esp_private/cache_utils.h"
#include "esp_partition.h"
#include "nvs_flash.h"
#include "esp_tee.h"
#include "esp_tee_sec_storage.h"
#include "secure_service_num.h"
#include "unity.h"
#define BOOT_COUNT_NAMESPACE "boot_count"
static const char *TAG = "test_esp_tee_flash_prot";
static void set_boot_count_in_nvs(uint8_t boot_count)
{
nvs_handle_t boot_count_handle;
TEST_ESP_OK(nvs_open(BOOT_COUNT_NAMESPACE, NVS_READWRITE, &boot_count_handle));
TEST_ESP_OK(nvs_set_u8(boot_count_handle, "boot_count", boot_count));
TEST_ESP_OK(nvs_commit(boot_count_handle));
nvs_close(boot_count_handle);
}
static uint8_t get_boot_count_from_nvs(void)
{
nvs_handle_t boot_count_handle;
esp_err_t err = nvs_open(BOOT_COUNT_NAMESPACE, NVS_READONLY, &boot_count_handle);
if (err == ESP_ERR_NVS_NOT_FOUND) {
set_boot_count_in_nvs(0);
}
uint8_t boot_count;
TEST_ESP_OK(nvs_get_u8(boot_count_handle, "boot_count", &boot_count));
nvs_close(boot_count_handle);
return boot_count;
}
static void test_initial_boot(void)
{
ESP_LOGI(TAG, "Boot: 1");
set_boot_count_in_nvs(1);
esp_restart();
}
/* ---------------------------------------------- API family 1: esp_partition ------------------------------------------------- */
static void test_esp_partition_mmap_api(void)
{
uint8_t boot_count = get_boot_count_from_nvs();
boot_count++;
set_boot_count_in_nvs(boot_count);
const esp_partition_t *part = NULL;
esp_partition_mmap_handle_t out_handle;
const void *outptr = NULL;
switch (boot_count) {
case 2:
part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_TEE_0, NULL);
TEST_ASSERT_NOT_NULL(part);
TEST_ESP_OK(esp_partition_mmap(part, 0, part->size, ESP_PARTITION_MMAP_DATA, &outptr, &out_handle));
ESP_LOG_BUFFER_HEXDUMP(TAG, outptr, 0x20, ESP_LOG_INFO);
TEST_FAIL_MESSAGE("System fault should have been generated");
break;
case 3:
part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_TEE_1, NULL);
TEST_ASSERT_NOT_NULL(part);
TEST_ESP_OK(esp_partition_mmap(part, 0, part->size, ESP_PARTITION_MMAP_INST, &outptr, &out_handle));
ESP_LOG_BUFFER_HEXDUMP(TAG, outptr, 0x20, ESP_LOG_INFO);
TEST_FAIL_MESSAGE("System fault should have been generated");
break;
case 4:
part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_TEE_OTA, NULL);
TEST_ASSERT_NOT_NULL(part);
TEST_ESP_OK(esp_partition_mmap(part, 0, part->size, ESP_PARTITION_MMAP_DATA, &outptr, &out_handle));
ESP_LOG_BUFFER_HEXDUMP(TAG, outptr, 0x20, ESP_LOG_INFO);
TEST_FAIL_MESSAGE("System fault should have been generated");
break;
case 5:
part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_TEE_SEC_STORAGE, NULL);
TEST_ASSERT_NOT_NULL(part);
TEST_ESP_OK(esp_partition_mmap(part, 0, part->size, ESP_PARTITION_MMAP_DATA, &outptr, &out_handle));
ESP_LOG_BUFFER_HEXDUMP(TAG, outptr, 0x20, ESP_LOG_INFO);
TEST_FAIL_MESSAGE("System fault should have been generated");
break;
default:
TEST_FAIL_MESSAGE("Unexpected stage");
break;
}
}
TEST_CASE_MULTIPLE_STAGES("Test REE-TEE isolation: Flash - SPI0 (esp_partition_mmap)", "[flash_prot][timeout=60]",
test_initial_boot, test_esp_partition_mmap_api, test_esp_partition_mmap_api,
test_esp_partition_mmap_api, test_esp_partition_mmap_api);
/* ---------------------------------------------- API family 2: spi_flash ------------------------------------------------- */
static void test_spi_flash_mmap_api(void)
{
uint8_t boot_count = get_boot_count_from_nvs();
boot_count++;
set_boot_count_in_nvs(boot_count);
const esp_partition_t *part = NULL;
spi_flash_mmap_handle_t handle;
const void *ptr = NULL;
switch (boot_count) {
case 2:
part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_TEE_0, NULL);
TEST_ASSERT_NOT_NULL(part);
TEST_ESP_OK(spi_flash_mmap(part->address, part->size, SPI_FLASH_MMAP_DATA, &ptr, &handle));
ESP_LOG_BUFFER_HEXDUMP(TAG, ptr, 0x20, ESP_LOG_INFO);
TEST_FAIL_MESSAGE("System fault should have been generated");
break;
case 3:
part = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_TEE_1, NULL);
TEST_ASSERT_NOT_NULL(part);
TEST_ESP_OK(spi_flash_mmap(part->address, part->size, SPI_FLASH_MMAP_INST, &ptr, &handle));
ESP_LOG_BUFFER_HEXDUMP(TAG, ptr, 0x20, ESP_LOG_INFO);
TEST_FAIL_MESSAGE("System fault should have been generated");
break;
case 4:
part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_TEE_OTA, NULL);
TEST_ASSERT_NOT_NULL(part);
TEST_ESP_OK(spi_flash_mmap(part->address, part->size, SPI_FLASH_MMAP_DATA, &ptr, &handle));
ESP_LOG_BUFFER_HEXDUMP(TAG, ptr, 0x20, ESP_LOG_INFO);
TEST_FAIL_MESSAGE("System fault should have been generated");
break;
default:
TEST_FAIL_MESSAGE("Unexpected stage");
break;
}
}
TEST_CASE_MULTIPLE_STAGES("Test REE-TEE isolation: Flash - SPI0 (spi_flash_mmap)", "[flash_prot][timeout=60]",
test_initial_boot, test_spi_flash_mmap_api, test_spi_flash_mmap_api,
test_spi_flash_mmap_api);

View File

@ -8,6 +8,8 @@
#include "soc/efuse_reg.h"
#include "soc/lp_analog_peri_reg.h"
#include "soc/lp_wdt_reg.h"
#include "soc/spi_mem_reg.h"
#include "soc/ext_mem_defs.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
@ -46,6 +48,15 @@ TEST_CASE("Test APM violation interrupt: eFuse", "[apm_violation]")
TEST_FAIL_MESSAGE("APM violation interrupt should have been generated");
}
TEST_CASE("Test APM violation interrupt: MMU", "[apm_violation]")
{
uint32_t val = UINT32_MAX;
REG_WRITE(SPI_MEM_MMU_ITEM_INDEX_REG(0), SOC_MMU_ENTRY_NUM - 2);
val = REG_READ(SPI_MEM_MMU_ITEM_CONTENT_REG(0));
TEST_ASSERT_EQUAL(0, val);
TEST_FAIL_MESSAGE("APM violation interrupt should have been generated");
}
/* TEE IRAM: Reserved/Vector-table boundary */
TEST_CASE("Test TEE-TEE violation: IRAM (W1)", "[exception]")
{

View File

@ -40,7 +40,7 @@ REE_ISOLATION_TEST_EXC_RSN: Dict[str, Any] = {
}
}
TEE_APM_VIOLATION_EXC_CHK = ['AES', 'eFuse']
TEE_APM_VIOLATION_EXC_CHK = ['AES', 'eFuse', 'MMU']
# ---------------- TEE default tests ----------------
@ -134,6 +134,53 @@ def test_esp_tee_isolation_checks(dut: IdfDut) -> None:
raise RuntimeError('Incorrect exception received!')
dut.expect('Exception origin: U-mode')
def run_multiple_stages(dut: IdfDut, test_case_num: int, stages: int) -> None:
for stage in range(1, stages + 1):
dut.write(str(test_case_num))
dut.expect(r'\s+\((\d+)\)\s+"([^"]+)"\r?\n', timeout=30)
dut.write(str(stage))
if 1 < stage <= stages:
rst_rsn = dut.expect(r"Core ([01]) panic\'ed \(([^)]+)\)", timeout=30).group(2).decode()
if rst_rsn != 'Cache error':
raise RuntimeError('Incorrect reset reason observed after TEE image failure!')
if stage != stages:
dut.expect_exact('Press ENTER to see the list of tests.')
@pytest.mark.generic
@pytest.mark.parametrize('config', CONFIGS_OTA, indirect=True)
@pytest.mark.parametrize('skip_autoflash', ['y'], indirect=True)
def test_esp_tee_flash_prot_esp_partition_mmap(dut: IdfDut) -> None:
# Flash the bootloader, TEE and REE firmware
dut.serial.custom_flash()
# start test
extra_data = dut.parse_test_menu()
for test_case in extra_data:
if test_case.name == 'Test REE-TEE isolation: Flash - SPI1 (esp_partition_mmap)':
run_multiple_stages(dut, test_case.index, len(test_case.subcases))
else:
continue
@pytest.mark.generic
@pytest.mark.parametrize('config', CONFIGS_OTA, indirect=True)
@pytest.mark.parametrize('skip_autoflash', ['y'], indirect=True)
def test_esp_tee_flash_prot_spi_flash_mmap(dut: IdfDut) -> None:
# Flash the bootloader, TEE and REE firmware
dut.serial.custom_flash()
# start test
extra_data = dut.parse_test_menu()
for test_case in extra_data:
if test_case.name == 'Test REE-TEE isolation: Flash - SPI0 (spi_flash_mmap)':
run_multiple_stages(dut, test_case.index, len(test_case.subcases))
else:
continue
# ---------------- TEE Local OTA tests ----------------