Hi everyone!
I am currently integrating TF-M with an IoT OS (RIOT OS) and I have a few problems. I managed to build and link a secure TF-M binary and a non-secure RIOT binary and I can run some application code (print "hello world", turn LEDs on and off, etc) on the nRF9160dk. I can also use the crypto API and call psa_crypto_init. Now I have tried a few things and each of them leads to different problems, some of which I will describe in this mail hoping that someone can help me with this. I have done some debugging and have some ideas on what could be wrong, but I don't really understand how to fix the issues and don't really know how to proceed with either of them.
Formatted Prints Somehow formatted prints are ignored. Calls to printf without formatting default to the stdio puts implementation and are printed without issues. Calls to printf with formatting use the implementation in tfm_sp_log_raw.c and are just ignored. They crashed at first, but I could fix that (RIOT has different implementations of the SVC ISR and I used the wrong one). Now they don't crash anymore, but are also not printed (no error output, application keeps running). Since this function is part of the secure firmware, my guess is that there's a problem with it being called from the NS world. But that should result in a SecureFault, shouldn't it? Does anyone have an idea what the issue could be?
Secure memset called from NS image When calling psa_generate_key, the first step is a struct initialization:
struct tfm_crypto_pack_iovec iov = { .function_id = TFM_CRYPTO_GENERATE_KEY_SID, };
This runs into a SecureFault. It turns out that during struct initialization, memset is called to zeroize the structure. This uses the memset implemented in secure_fw/shared/crt_memset.c and accesses secure RAM (between addresses 0x20015000 and 0x20016000). I found a workaround by moving the start address of NS RAM from 0x20016000 to 0x20020000. Memset now still accesses RAM before NS RAM, but does not run into a SecureFault anymore. This works for now, but I would like to find an actual fix for this. This only occurs when building with RIOT. When building the TF-M NS image and running crypto tests, memset accesses NS RAM, though I don't know if the same implementation is used. Unfortunately I don't get any debug symbols there. Could it be that a different memset implementation should be linked? Can I change it somehow? Can someone tell me which one is linked in the TF-M NS image?
Crypto partition is NULL When using the workaround described above, calling psa_generate_key runs into tfm_core_panic. The stack trace here is:
psa_call (tfm_psa_call.c) tfm_psa_call_pack (backend_sfn.c) tfm_spm_client_psa_call (psa_call_api.c) tfm_spm_is_ns_caller (spm_ipc.c)
The problem is in tfm_spm_is_ns_caller, where
struct partition_t *partition = GET_CURRENT_COMPONENT();
gets a NULL pointer. So somehow there is no crypto partition available. Of course I have enabled the crypto partition in config_base.cmake, as well as protected storage and internal trusted storage. I checked with a debugger and found out that during start up, multiple partitions are initialized and added to the global component list (stored in backend_sfn.c). Can I somehow check what types of partitions are initialized? Did anyone have a similar issue before or has any idea why the partition could be missing? Did I miss any extra steps I need to take?
I know these are pretty much unrelated issues, but they are persistent and I am at a loss at how to fix them. I will take any hints and ideas, including pointers to where I can find relevant information in the docs (those have not been very helpful in these cases, but maybe I've overlooked something).
Best regards, Lena
Hi Lena,
at first glance these issues point to some problem with the specific integration of TF-M with your RIOT OS kernel on NS. It's quite difficult to be comment on the specific issues above, but off the top of my head a few points to consider:
1. Calling psa_crypto_init() from NS is a non-operation in TF-M, in the sense that the PSA Crypto initialization happens during the service init (i.e. on bootup), so calling psa_crypto_init() from NS just returns PSA_SUCCESS. The function is there to comply with the spec itself but I would try for example a call to psa_hash_compute() to double check if the calls are being routed correctly from NS to S and back. 2. Formatted prints: It is not clear from your message if you're seeing this issue within NS prints or S prints? Normally, TF-M own printing (i.e. printing in SPM or partitions) would happen through usage of macros SPMLOG_* and LOG_*. Usage of printf() from the toolchain on S might or might not work based on TF-M Secure side configuration (for example, isolation level). Printing from NS would not require any modification on S and just resolve to the toolchain printf without accessing the S world, unless you're trying to print on a UART which has been reserved to S. 3. Secure memset being called from NS: Also here, this shouldn't happen as that part of the interface would just need to be linked against memset from the toolchain, and not resolve to the secure memset exported by TF-M. Note that the tfm_crypto_api.c for example is built both for the S interface and the NS interface, in two separate steps 4. This I think stems from the workaround for point 3 impacting normal call flow so probably not a real problem to understand. I suggest to have a look at the AN521 platform reference porting either on FVP or Qemu to double check how the reference call flow would work.
Hope this helps to unblock, please feel free to get back here in case of more questions or doubts.
Thanks, Antonio ________________________________ From: Boeckmann, Lena via TF-M tf-m@lists.trustedfirmware.org Sent: Wednesday, December 13, 2023 17:06 To: tf-m@lists.trustedfirmware.org tf-m@lists.trustedfirmware.org Subject: [TF-M] Problems with integrating TF-M with RIOT OS
Hi everyone!
I am currently integrating TF-M with an IoT OS (RIOT OS) and I have a few problems. I managed to build and link a secure TF-M binary and a non-secure RIOT binary and I can run some application code (print "hello world", turn LEDs on and off, etc) on the nRF9160dk. I can also use the crypto API and call psa_crypto_init. Now I have tried a few things and each of them leads to different problems, some of which I will describe in this mail hoping that someone can help me with this. I have done some debugging and have some ideas on what could be wrong, but I don't really understand how to fix the issues and don't really know how to proceed with either of them.
Formatted Prints Somehow formatted prints are ignored. Calls to printf without formatting default to the stdio puts implementation and are printed without issues. Calls to printf with formatting use the implementation in tfm_sp_log_raw.c and are just ignored. They crashed at first, but I could fix that (RIOT has different implementations of the SVC ISR and I used the wrong one). Now they don't crash anymore, but are also not printed (no error output, application keeps running). Since this function is part of the secure firmware, my guess is that there's a problem with it being called from the NS world. But that should result in a SecureFault, shouldn't it? Does anyone have an idea what the issue could be?
Secure memset called from NS image When calling psa_generate_key, the first step is a struct initialization:
struct tfm_crypto_pack_iovec iov = { .function_id = TFM_CRYPTO_GENERATE_KEY_SID, };
This runs into a SecureFault. It turns out that during struct initialization, memset is called to zeroize the structure. This uses the memset implemented in secure_fw/shared/crt_memset.c and accesses secure RAM (between addresses 0x20015000 and 0x20016000). I found a workaround by moving the start address of NS RAM from 0x20016000 to 0x20020000. Memset now still accesses RAM before NS RAM, but does not run into a SecureFault anymore. This works for now, but I would like to find an actual fix for this. This only occurs when building with RIOT. When building the TF-M NS image and running crypto tests, memset accesses NS RAM, though I don't know if the same implementation is used. Unfortunately I don't get any debug symbols there. Could it be that a different memset implementation should be linked? Can I change it somehow? Can someone tell me which one is linked in the TF-M NS image?
Crypto partition is NULL When using the workaround described above, calling psa_generate_key runs into tfm_core_panic. The stack trace here is:
psa_call (tfm_psa_call.c) tfm_psa_call_pack (backend_sfn.c) tfm_spm_client_psa_call (psa_call_api.c) tfm_spm_is_ns_caller (spm_ipc.c)
The problem is in tfm_spm_is_ns_caller, where
struct partition_t *partition = GET_CURRENT_COMPONENT();
gets a NULL pointer. So somehow there is no crypto partition available. Of course I have enabled the crypto partition in config_base.cmake, as well as protected storage and internal trusted storage. I checked with a debugger and found out that during start up, multiple partitions are initialized and added to the global component list (stored in backend_sfn.c). Can I somehow check what types of partitions are initialized? Did anyone have a similar issue before or has any idea why the partition could be missing? Did I miss any extra steps I need to take?
I know these are pretty much unrelated issues, but they are persistent and I am at a loss at how to fix them. I will take any hints and ideas, including pointers to where I can find relevant information in the docs (those have not been very helpful in these cases, but maybe I've overlooked something).
Best regards, Lena
Hi Antonio, thank you for your advice! I could actually fix the printf and memset issue by linking the toolchain implementations instead of the TF-M SPRTL. The documentation, though, states that a TF-M specific runtime library is needed to fulfill security requirements. Isn't it counterproductive to just fall back to the toolchain implementations, then?
I also changed the NS RAM start address back to 0x20016000 and called psa_hash_compute instead of psa_crypto_init. Now it becomes interesting again: hash compute now fails because of the missing crypto partition (same as before).
BUT: psa_generate_key fails, because the psa_call function accesses secure RAM (address 0x20015ff8).
I will keep debugging and looking for information.
Best regards Lena
On 14.12.23 09:03, Antonio De Angelis wrote: Hi Lena,
at first glance these issues point to some problem with the specific integration of TF-M with your RIOT OS kernel on NS. It's quite difficult to be comment on the specific issues above, but off the top of my head a few points to consider:
1. Calling psa_crypto_init() from NS is a non-operation in TF-M, in the sense that the PSA Crypto initialization happens during the service init (i.e. on bootup), so calling psa_crypto_init() from NS just returns PSA_SUCCESS. The function is there to comply with the spec itself but I would try for example a call to psa_hash_compute() to double check if the calls are being routed correctly from NS to S and back. 2. Formatted prints: It is not clear from your message if you're seeing this issue within NS prints or S prints? Normally, TF-M own printing (i.e. printing in SPM or partitions) would happen through usage of macros SPMLOG_* and LOG_*. Usage of printf() from the toolchain on S might or might not work based on TF-M Secure side configuration (for example, isolation level). Printing from NS would not require any modification on S and just resolve to the toolchain printf without accessing the S world, unless you're trying to print on a UART which has been reserved to S. 3. Secure memset being called from NS: Also here, this shouldn't happen as that part of the interface would just need to be linked against memset from the toolchain, and not resolve to the secure memset exported by TF-M. Note that the tfm_crypto_api.c for example is built both for the S interface and the NS interface, in two separate steps 4. This I think stems from the workaround for point 3 impacting normal call flow so probably not a real problem to understand. I suggest to have a look at the AN521 platform reference porting either on FVP or Qemu to double check how the reference call flow would work.
Hope this helps to unblock, please feel free to get back here in case of more questions or doubts.
Thanks, Antonio ________________________________ From: Boeckmann, Lena via TF-M tf-m@lists.trustedfirmware.orgmailto:tf-m@lists.trustedfirmware.org Sent: Wednesday, December 13, 2023 17:06 To: tf-m@lists.trustedfirmware.orgmailto:tf-m@lists.trustedfirmware.org tf-m@lists.trustedfirmware.orgmailto:tf-m@lists.trustedfirmware.org Subject: [TF-M] Problems with integrating TF-M with RIOT OS
Hi everyone!
I am currently integrating TF-M with an IoT OS (RIOT OS) and I have a few problems. I managed to build and link a secure TF-M binary and a non-secure RIOT binary and I can run some application code (print "hello world", turn LEDs on and off, etc) on the nRF9160dk. I can also use the crypto API and call psa_crypto_init. Now I have tried a few things and each of them leads to different problems, some of which I will describe in this mail hoping that someone can help me with this. I have done some debugging and have some ideas on what could be wrong, but I don't really understand how to fix the issues and don't really know how to proceed with either of them.
Formatted Prints Somehow formatted prints are ignored. Calls to printf without formatting default to the stdio puts implementation and are printed without issues. Calls to printf with formatting use the implementation in tfm_sp_log_raw.c and are just ignored. They crashed at first, but I could fix that (RIOT has different implementations of the SVC ISR and I used the wrong one). Now they don't crash anymore, but are also not printed (no error output, application keeps running). Since this function is part of the secure firmware, my guess is that there's a problem with it being called from the NS world. But that should result in a SecureFault, shouldn't it? Does anyone have an idea what the issue could be?
Secure memset called from NS image When calling psa_generate_key, the first step is a struct initialization:
struct tfm_crypto_pack_iovec iov = { .function_id = TFM_CRYPTO_GENERATE_KEY_SID, };
This runs into a SecureFault. It turns out that during struct initialization, memset is called to zeroize the structure. This uses the memset implemented in secure_fw/shared/crt_memset.c and accesses secure RAM (between addresses 0x20015000 and 0x20016000). I found a workaround by moving the start address of NS RAM from 0x20016000 to 0x20020000. Memset now still accesses RAM before NS RAM, but does not run into a SecureFault anymore. This works for now, but I would like to find an actual fix for this. This only occurs when building with RIOT. When building the TF-M NS image and running crypto tests, memset accesses NS RAM, though I don't know if the same implementation is used. Unfortunately I don't get any debug symbols there. Could it be that a different memset implementation should be linked? Can I change it somehow? Can someone tell me which one is linked in the TF-M NS image?
Crypto partition is NULL When using the workaround described above, calling psa_generate_key runs into tfm_core_panic. The stack trace here is:
psa_call (tfm_psa_call.c) tfm_psa_call_pack (backend_sfn.c) tfm_spm_client_psa_call (psa_call_api.c) tfm_spm_is_ns_caller (spm_ipc.c)
The problem is in tfm_spm_is_ns_caller, where
struct partition_t *partition = GET_CURRENT_COMPONENT();
gets a NULL pointer. So somehow there is no crypto partition available. Of course I have enabled the crypto partition in config_base.cmake, as well as protected storage and internal trusted storage. I checked with a debugger and found out that during start up, multiple partitions are initialized and added to the global component list (stored in backend_sfn.c). Can I somehow check what types of partitions are initialized? Did anyone have a similar issue before or has any idea why the partition could be missing? Did I miss any extra steps I need to take?
I know these are pretty much unrelated issues, but they are persistent and I am at a loss at how to fix them. I will take any hints and ideas, including pointers to where I can find relevant information in the docs (those have not been very helpful in these cases, but maybe I've overlooked something).
Best regards, Lena
tf-m@lists.trustedfirmware.org