Atomic operations call can crash on FreeRTOS
Description
Executing SOPC_Atomic_Int_Add function on FreeRTOS with target STM32H723 leads to a hard fault.
Code version and environment identification
This bug is present on the master branch by commit 7d243546aef56874320c3f3dab4ea02616b895f1
FreeRTOS seems to be the only concerned operating systems.
Steps to reproduce
Compile cli_pubsub_server samples for FreeRTOS on boaord cli_pubsub_server.
Connect UAExpert to the server and write a value on a node.
Relevant logs and/or screenshots
When debugging with SMTCube, GDB server leads to the stack trace. It is attached to the ticket.
Analysis
The board crashes when entering into GCC instruction __atomic_fetch_add:
int32_t SOPC_Atomic_Int_Add(int32_t* atomic, int32_t val)
{
#if !defined(__clang__) && (__GNUC__ > 4)
return __atomic_fetch_add(atomic, val, __ATOMIC_SEQ_CST);
#else
return __sync_fetch_and_add(atomic, val);
#endif
}
Using the __atomic_fetch_add instruction as compiled by GCC generates LDREX/STREX binary instructions, which are unsafe for non-cacheable memory regions in ARM architecture (see https://community.arm.com/support-forums/f/architectures-and-processors-forum/52035/m7-atomic-operation-faults-on-non-cacheable-memory for example).
Security impact
There is no direct cyber-security impact.
Possible fixes
The following fixes based on FreeRTOS API (https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/include/atomic.h) avoid the crash. The only drawback is the fact that it comes with a limitation: this implementation does not allow the storage of a negative value (no use case for now in S2OPC).
int32_t SOPC_Atomic_Int_Add(int32_t* atomic, int32_t val)
{
if (val > 0)
{
Atomic_Add_u32(atomic, (uint32_t) val);
}
else
{
Atomic_Subtract_u32(atomic, -(uint32_t)(val));
}
}
Notes:
- all the operations of this module are not ported to FreeRTOS API as it does not provided all elements for that
- trying to use ATOMIC_ENTER_CRITICAL / ATOMIC_EXIT_CRITICAL to use a section results in instability (May be related to https://github.com/FreeRTOS/FreeRTOS-Kernel/pull/940/files#diff-fd39ceff2eed2f612f28be28f2261f217a0fd48960f73deda02b6f561479faa7)
In the long term, it seems necessary to deploy unit test on embedded platform like FreeRTOS and Zephyr to avoid this kind of issues (content of check_helpers for example).