PSA PS without TF-M behaves odd after PSA_ERROR_STORAGE_FAILURE

Hello,

Our application image became too large for TF-M and we're investigating the use of PSA Protected Storage without TF-M as described in NCS 2.6.0.

When writing a new slot when the storage size is too small, PSA_ERROR_STORAGE_FAILURE (-146) is returned. After a reset, it looks like all storage space is lost, no space at all anymore.

This is the prj.conf used in the test:

CONFIG_GPIO=y

CONFIG_LOG=y
CONFIG_LOG_DEFAULT_LEVEL=3

CONFIG_TRUSTED_STORAGE=y
CONFIG_SETTINGS=y
CONFIG_NVS=y
CONFIG_FLASH=y
CONFIG_FLASH_MAP=y

CONFIG_HW_UNIQUE_KEY=y
CONFIG_HW_UNIQUE_KEY_RANDOM=y

CONFIG_NRF_SECURITY=y

CONFIG_PSA_CRYPTO_DRIVER_CC3XX=n
CONFIG_PSA_CRYPTO_DRIVER_OBERON=y

CONFIG_MBEDTLS_PSA_CRYPTO_C=y
CONFIG_MBEDTLS_ENABLE_HEAP=y
CONFIG_MBEDTLS_HEAP_SIZE=16384
CONFIG_MAIN_STACK_SIZE=16384

CONFIG_PSA_PROTECTED_STORAGE=y

The code in src/main.c is the following:

/*
 * Copyright (c) 2016 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>
#include <zephyr/settings/settings.h>

#include <hw_unique_key.h>
#include <psa/crypto.h>
#ifdef CONFIG_BUILD_WITH_TFM
#include <tfm_crypto_defs.h>
#else /* CONFIG_BUILD_WITH_TFM */
#include <nrf_cc3xx_platform.h>
#endif /* CONFIG_BUILD_WITH_TFM */

#include <psa/storage_common.h>
#include <psa/protected_storage.h>

/* 1000 msec = 1 sec */
#define SLEEP_TIME_MS   200

/* The devicetree node identifier for the "led0" alias. */
#define LED0_NODE DT_ALIAS(led0)

#define TEST_STRING_1 "The quick brown fox jumps over the lazy dog"

#define APP_SUCCESS		(0)
#define APP_ERROR		(-1)
#define APP_SUCCESS_MESSAGE "Example finished successfully!"
#define APP_ERROR_MESSAGE "Example exited with error!"

LOG_MODULE_REGISTER(app, LOG_LEVEL_DBG);

/*
 * A build error on this line means your board is unsupported.
 * See the sample documentation for information on how to fix this.
 */
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);

int crypto_init(void)
{
#if !defined(CONFIG_BUILD_WITH_TFM)
	int result = nrf_cc3xx_platform_init();

	if (result != NRF_CC3XX_PLATFORM_SUCCESS) {
		LOG_INF("nrf_cc3xx_platform_init returned error: %d", result);
		return APP_ERROR;
	}

	if (!hw_unique_key_are_any_written()) {
		LOG_INF("Writing random keys to KMU");
		result = hw_unique_key_write_random();
		if (result != HW_UNIQUE_KEY_SUCCESS) {
			LOG_INF("hw_unique_key_write_random returned error: %d", result);
			return APP_ERROR;
		}
		LOG_INF("Success!");

#if !defined(HUK_HAS_KMU)
		/* Reboot to allow the bootloader to load the key into CryptoCell. */
		sys_reboot(0);
#endif /* !defined(HUK_HAS_KMU) */
	}
#endif /* !defined(CONFIG_BUILD_WITH_TFM) */

	return APP_SUCCESS;
}


int main(void)
{
	int ret;

	int result = crypto_init();
	if (result != APP_SUCCESS) {
		LOG_INF(APP_ERROR_MESSAGE);
		return APP_ERROR;
	}

	if (!device_is_ready(led.port)) {
		return -1;
	}

	ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
	if (ret < 0) {
		return -1;
	}

	int rc = settings_subsys_init();
	if (rc) {
		printk("settings subsys initialization: fail (err %d)\n", rc);
		return -1;
	}
	printk("settings subsys initialization: OK.\n");

	uint32_t flags = psa_ps_get_support();
	LOG_INF("psa_ps_get_support: %x (%d) - %x", flags, flags, PSA_STORAGE_SUPPORT_SET_EXTENDED);

	psa_status_t status = PSA_SUCCESS;

	int slot = 0;

	// IT SEEMS THAT AFTER A REBOOT, WRITING TO SLOT 2 FAILS IMMEDIATELY???
	// AFTER A REBOOT WRITING TO SLOT 3 FAILS ... AND SO ON ...
	for(slot = 1; ; ++slot) {
		char buf[20];
		int sz = snprintf (buf, sizeof(buf), "slot: %d", slot);
		status = psa_ps_set(slot, strlen(buf), buf, PSA_STORAGE_FLAG_NONE);
		if (status != PSA_SUCCESS) {
			printk("Failed to store data in slot (%d)! (%d)\n", slot, status);
			break;
		}
	}

	printk("Toggling the LED ...");
	while (1) {
		ret = gpio_pin_toggle_dt(&led);
		if (ret < 0) {
			return -1;
		}
		k_msleep(SLEEP_TIME_MS);
	}
}

The UART logging shows this:

*** Booting nRF Connect SDK v3.5.99-ncs1-1 ***
[00:00:00.255,096] <inf> app: Writing random keys to KMU
[00:00:00.317,932] <inf> app: Success!
[00:00:00.323,669] <inf> fs_nvs: 3 Sectors of 4096 bytes
[00:00:00.323,669] <inf> fs_nvs: alloc wra: 0, fe8
[00:00:00.323,669] <inf> fs_nvs: data wra: 0, 0
settings subsys initialization: OK.
[00:00:00.323,730] <inf> app: psa_ps_get_support: 0 (0) - 1
Failed to store data in slot (102)! (-146)
Toggling the LED ...*** Booting nRF Connect SDK v3.5.99-ncs1-1 ***
[00:00:00.307,983] <inf> fs_nvs: 3 Sectors of 4096 bytes
[00:00:00.307,983] <inf> fs_nvs: alloc wra: 2, cc0
[00:00:00.308,013] <inf> fs_nvs: data wra: 2, cb0
settings subsys initialization: OK.
[00:00:00.308,715] <inf> app: psa_ps_get_support: 0 (0) - 1
Failed to store data in slot (1)! (-146)
Toggling the LED ...*** Booting nRF Connect SDK v3.5.99-ncs1-1 ***
[00:00:00.302,154] <inf> fs_nvs: 3 Sectors of 4096 bytes
[00:00:00.302,154] <inf> fs_nvs: alloc wra: 2, cb0
[00:00:00.302,154] <inf> fs_nvs: data wra: 2, c98
settings subsys initialization: OK.
[00:00:00.302,886] <inf> app: psa_ps_get_support: 0 (0) - 1
Failed to store data in slot (2)! (-146)
Toggling the LED ...*** Booting nRF Connect SDK v3.5.99-ncs1-1 ***
[00:00:00.296,234] <inf> fs_nvs: 3 Sectors of 4096 bytes
[00:00:00.296,234] <inf> fs_nvs: alloc wra: 0, cb0
[00:00:00.296,264] <inf> fs_nvs: data wra: 0, c98
settings subsys initialization: OK.
[00:00:00.296,966] <inf> app: psa_ps_get_support: 0 (0) - 1
Failed to store data in slot (3)! (-146)
Toggling the LED ...

As seen from the logging, initially 101 slots can be written (settings_storage partition is 0x3000 in size in static_pm.yml).
Then after the first reset, not even 1 slot can be written.
Then next reset fails after the 2nd slot.
Then next reset fails after the 3rd slot
etc ...

Is there something wrong with prj.conf? Or something with main.c?

Thank you!

Kind regards, francis

Parents
  • Hi Francis,

    I replaced your prj.conf and main.c into Hello World, compiled with NCS v2.6.1, and could not reproduce your issue.

    What I notice is that write attempts after the first one takes significantly more time.

    Can you tell if there are any other differences between your test setup and the code you have shared?

    For reference, here is my barely modified code, where I only added more log buffer and logging to check what keeps the device hanging for so long before toggling LED.

    CONFIG_GPIO=y
    
    CONFIG_LOG=y
    CONFIG_LOG_DEFAULT_LEVEL=3
    CONFIG_LOG_BUFFER_SIZE=4096
    
    CONFIG_TRUSTED_STORAGE=y
    CONFIG_SETTINGS=y
    CONFIG_NVS=y
    CONFIG_FLASH=y
    CONFIG_FLASH_MAP=y
    
    CONFIG_HW_UNIQUE_KEY=y
    CONFIG_HW_UNIQUE_KEY_RANDOM=y
    
    CONFIG_NRF_SECURITY=y
    
    CONFIG_PSA_CRYPTO_DRIVER_CC3XX=n
    CONFIG_PSA_CRYPTO_DRIVER_OBERON=y
    
    CONFIG_MBEDTLS_PSA_CRYPTO_C=y
    CONFIG_MBEDTLS_ENABLE_HEAP=y
    CONFIG_MBEDTLS_HEAP_SIZE=16384
    CONFIG_MAIN_STACK_SIZE=16384
    
    CONFIG_PSA_PROTECTED_STORAGE=y

    /*
     * Copyright (c) 2016 Intel Corporation
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <zephyr/kernel.h>
    #include <zephyr/drivers/gpio.h>
    #include <zephyr/logging/log.h>
    #include <zephyr/settings/settings.h>
    
    #include <hw_unique_key.h>
    #include <psa/crypto.h>
    #ifdef CONFIG_BUILD_WITH_TFM
    #include <tfm_crypto_defs.h>
    #else /* CONFIG_BUILD_WITH_TFM */
    #include <nrf_cc3xx_platform.h>
    #endif /* CONFIG_BUILD_WITH_TFM */
    
    #include <psa/storage_common.h>
    #include <psa/protected_storage.h>
    
    /* 1000 msec = 1 sec */
    #define SLEEP_TIME_MS   200
    
    /* The devicetree node identifier for the "led0" alias. */
    #define LED0_NODE DT_ALIAS(led0)
    
    #define TEST_STRING_1 "The quick brown fox jumps over the lazy dog"
    
    #define APP_SUCCESS		(0)
    #define APP_ERROR		(-1)
    #define APP_SUCCESS_MESSAGE "Example finished successfully!"
    #define APP_ERROR_MESSAGE "Example exited with error!"
    
    LOG_MODULE_REGISTER(app, LOG_LEVEL_DBG);
    
    /*
     * A build error on this line means your board is unsupported.
     * See the sample documentation for information on how to fix this.
     */
    static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
    
    int crypto_init(void)
    {
    #if !defined(CONFIG_BUILD_WITH_TFM)
    	int result = nrf_cc3xx_platform_init();
    
    	if (result != NRF_CC3XX_PLATFORM_SUCCESS) {
    		LOG_INF("nrf_cc3xx_platform_init returned error: %d", result);
    		return APP_ERROR;
    	}
    
    	if (!hw_unique_key_are_any_written()) {
    		LOG_INF("Writing random keys to KMU");
    		result = hw_unique_key_write_random();
    		if (result != HW_UNIQUE_KEY_SUCCESS) {
    			LOG_INF("hw_unique_key_write_random returned error: %d", result);
    			return APP_ERROR;
    		}
    		LOG_INF("Success!");
    
    #if !defined(HUK_HAS_KMU)
    		/* Reboot to allow the bootloader to load the key into CryptoCell. */
    		sys_reboot(0);
    #endif /* !defined(HUK_HAS_KMU) */
    	}
    #endif /* !defined(CONFIG_BUILD_WITH_TFM) */
    
    	return APP_SUCCESS;
    }
    
    
    int main(void)
    {
    	int ret;
    
    	int result = crypto_init();
    	if (result != APP_SUCCESS) {
    		LOG_INF(APP_ERROR_MESSAGE);
    		return APP_ERROR;
    	}
    
    	if (!device_is_ready(led.port)) {
    		return -1;
    	}
    
    	ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
    	if (ret < 0) {
    		return -1;
    	}
    
    	int rc = settings_subsys_init();
    	if (rc) {
    		printk("settings subsys initialization: fail (err %d)\n", rc);
    		return -1;
    	}
    	printk("settings subsys initialization: OK.\n");
    
    	uint32_t flags = psa_ps_get_support();
    	LOG_INF("psa_ps_get_support: %x (%d) - %x", flags, flags, PSA_STORAGE_SUPPORT_SET_EXTENDED);
    
    	psa_status_t status = PSA_SUCCESS;
    
    	int slot = 0;
    
    	// IT SEEMS THAT AFTER A REBOOT, WRITING TO SLOT 2 FAILS IMMEDIATELY???
    	// AFTER A REBOOT WRITING TO SLOT 3 FAILS ... AND SO ON ...
    	for(slot = 1; ; ++slot) {
    		char buf[20];
    		int sz = snprintf (buf, sizeof(buf), "slot: %d", slot);
    		status = psa_ps_set(slot, strlen(buf), buf, PSA_STORAGE_FLAG_NONE);
    		if (status != PSA_SUCCESS) {
    			printk("Failed to store data in slot (%d)! (%d)\n", slot, status);
    			break;
    		}
    		LOG_INF("%03d", slot);
    	}
    
    	printk("Toggling the LED ...");
    	while (1) {
    		ret = gpio_pin_toggle_dt(&led);
    		if (ret < 0) {
    			return -1;
    		}
    		k_msleep(SLEEP_TIME_MS);
    	}
    }

    Best regards,

    Hieu

  • Hello Hieu,

    Thank you for trying.

    There should not be any significant difference between what I shared and what I use. There's only a pm_static.yml. But I see the same behaviour without that partition file.

    I will test it with another nrf5340DK board tomorrow.

    Kind regards,
    francis

Reply Children
Related