Hi Stefan,

 

Thanks for reporting this issue. Yes, it is a bug. I created these patches to fix it and test it. Would you like to help review it?

 

Regards,

Sherry Zhang

 

From: Stefan Krug via TF-M <tf-m@lists.trustedfirmware.org>
Sent: Wednesday, November 2, 2022 11:20 PM
To: TF-M mailing list <tf-m@lists.trustedfirmware.org>
Subject: [TF-M] Lost data when overwriting object using its_set?

 

Hello!

 

While playing around with TF-M I have stumbled upon unexpected behavior:

 

In a sequence of ITS api calls like:

a.) psa_its_set(TEST_UID_1, sizeof(write_data_1), write_data_1, PSA_STORAGE_FLAG_NONE);

b.) psa_its_set(TEST_UID_2, 0, NULL, PSA_STORAGE_FLAG_NONE);

c.) psa_its_remove(TEST_UID_1);

d.) psa_its_set(TEST_UID_2, sizeof(write_data_2), write_data_2, PSA_STORAGE_FLAG_NONE);

e.) psa_its_get(TEST_UID_2, 0, sizeof(read_data_2), read_data_2, &read_data_length);

with

#define TEST_UID_1      2U

#define TEST_UID_2      3U

const uint8_t write_data_1[] = "ONE";

const uint8_t write_data_2[] = "TWO";

It seems that step e) does not return the data written in step d).

 

I believe I have root-caused it to an issue in its_flash_delete_idx() (see below), but since

this is a rather straightforward API call sequence, I wonder whether this is not rather an issue

in my environment and would be glad if someone could confirm it or point me to

a direction of a potential different cause?

 

I am using TF-M version 1.6, a nor flash with (erase) block size 0x1000 bytes and a program unit

size (page size) of 0x100 bytes.

 

Thank you, best regards

  Stefan Krug

 

 

More analysis details:

After step c) there will be the following relevant metadata blocks in the filesystem:

  1.) unused metadata block (used to have the metadata of TEST_UID_1)

  2.) metadata block of TEST_UID_2

 

During step d) the update of TEST_UID_2 is done in two steps - first step is to
write metadata + content of TEST_UID_2. After this step, the metadata blocks look like:

  1.) NEW metadata block of TEST_UID_2

  2.) old metadata block of TEST_UID_2 (indicating TEST_UID_2 to be erased)

The second step is to delete the outdated file, and compact/defragment the data
in the file system. This is done in its_flash_fs_delete_idx().

its_flash_fs_delete_idx will collect the amount of data bytes to preserve.
There are two parts of data to be preserved, a chunk of data before the deleted
file (of size del_file_data_idx) and a chunk of data after the deleted file.
Calculation of del_file_data_idx is done by taking the start offset of the
to-be-deleted file. In this particular situation the start of the old
TEST_UID_2 is the same as the start of the new TEST_UID_2. The subsequent
its_flash_fs_dblock_compact_block will only keep data up to del_file_data_idx -
in this case it will NOT keep the data of the new TEST_UID_2 - this data is
lost.