[go: up one dir, main page]

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:

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).

Edited by Vincent Lacroix