Knowledge · STM32

Creating an STM32 firmware SBOM for the CRA

From two sources: the STM32Cube package and the build. ST's SBOM does not name FreeRTOS, mbedTLS, LwIP, FatFs or LibJPEG.

You read their versions from the package headers and, in a debug build, from the ELF.

As of 23 October 2026 · 4 min readYou make the conformity statement. This page and our reports provide technical findings as its basis.

The test subject
Project
Oscilloscope on STM32F429I-Discovery, STM32CubeIDE
Chip
STM32F429ZI, Cortex-M4
File
STM32F429I-Oscilloscope.elf, debug build, GCC
SHA-256
2dd3e8b51a97df591055ed0e5211ab977e1f0cf39e3874ff5423268f7901e419

Public on GitHub, commit c3d1f92 (GPL-3.0)

The test subject: Public on GitHub, commit c3d1f92 (GPL-3.0)

What is an STM32 project made of?

A project from STM32CubeMX or STM32CubeIDE takes code from the STM32Cube package of the chip family: the HAL driver, the chip's CMSIS files, board drivers and middlewares. Under Middlewares/Third_Party it holds libraries from other vendors, in STM32CubeF4 for example FreeRTOS, mbedTLS and LwIP. The linker decides which of them end up in the device.

For the SBOM you therefore need two answers: which version of the package the project uses, and which libraries from it are in the build.

PartWhere the version is
Cube packageProject file .ioc, line ProjectManager.FirmwarePackage
HAL driverstm32f4xx_hal.c, macro __STM32F4xx_HAL_VERSION
FreeRTOStask.h, macro tskKERNEL_VERSION_NUMBER
mbedTLSmbedtls/version.h, MBEDTLS_VERSION_STRING
LwIPlwip/init.h, LWIP_VERSION_MAJOR to _REVISION
CompilerSection .comment in the ELF

Step 1: Which Cube package version does my project use?

The STM32CubeMX project file names the chip and the package version. With the package version you know which middleware versions ST shipped.

Chip and Cube package of the test subject
grep -E "FirmwarePackage=|DeviceId=" Discovery_Oscilloscope.ioc

Output

ProjectManager.CustomerFirmwarePackage=
ProjectManager.DeviceId=STM32F429ZITx
ProjectManager.FirmwarePackage=STM32Cube FW_F4 V1.26.2

Step 2: Which middleware versions does the package ship?

The versions of the shipped libraries are in their headers. Shown here on the current release STM32CubeF4 v1.28.3, run in the package directory.

What the package ships under Third_Party
ls Middlewares/Third_Party

Output

FatFs
FreeRTOS
LibJPEG
LwIP
mbedTLS
Versions from the headers
grep -h -m1 -E "tskKERNEL_VERSION_NUMBER|MBEDTLS_VERSION_STRING |FatFs - |JVERSION" Middlewares/Third_Party/FreeRTOS/Source/include/task.h Middlewares/Third_Party/mbedTLS/include/mbedtls/version.h Middlewares/Third_Party/FatFs/src/ff.h Middlewares/Third_Party/LibJPEG/include/jversion.h

Output

#define tskKERNEL_VERSION_NUMBER "V10.3.1"
#define MBEDTLS_VERSION_STRING         "2.16.2"
/  FatFs - Generic FAT file system module  R0.12c                             /
#define JVERSION	"8d  15-Jan-2012"
How often ST's SBOM names these five
jq -r ".components[].name" sbom_cdx.json | grep -ciE "freertos|lwip|mbedtls|fatfs|libjpeg"
Output
0

Step 3: What of it is really in the build?

The ELF symbol table shows which libraries are linked. In the test subject these are the HAL, the CMSIS-RTOS2 layer and the FreeRTOS kernel. A library from the package that leaves no function in the ELF does not belong in this device's SBOM.

Here the FreeRTOS version is in the ELF itself, because the debug build is compiled with -g3. According to GCC this level puts all macro definitions into the debug information; in the test subject the text sits in the .debug_str section. A build without debug information no longer has this line. Then you take the version from step 2.

Linked functions from HAL, CMSIS-RTOS2 and FreeRTOS
nm STM32F429I-Oscilloscope.elf | grep -E " T (HAL_Init|osKernelStart|vTaskStartScheduler|xTaskCreate)$"

Output

08004ee9T HAL_Init08007f31T osKernelStart0800964dT vTaskStartScheduler080095f1T xTaskCreate
FreeRTOS version from the debug information
strings -a STM32F429I-Oscilloscope.elf | grep "tskKERNEL_VERSION_NUMBER"

Output

RTOS_ID_s ("FreeRTOS " tskKERNEL_VERSION_NUMBER)
tskKERNEL_VERSION_NUMBER "V10.3.1"
KERNEL_ID ("FreeRTOS " tskKERNEL_VERSION_NUMBER)
Compiler
strings -a STM32F429I-Oscilloscope.elf | grep -m1 "GCC: "

Output

GCC: (GNU Tools for STM32 9-2020-q2-update.20201001-1621) 9.3.1 20200408 (release)

Step 4: What does the GCC map file show?

STM32CubeIDE compiles with -ffunction-sections -fdata-sections and links with --gc-sections. So every function sits in its own section, and the linker removes every section nothing uses. The map file (-Wl,-Map=) shows both: under “Archive member included” every library member that entered the image, with the symbol that pulled it in, and under “Discarded input sections” everything that was removed.

In the test subject the linker removes 37 functions from FreeRTOS tasks.c alone, among them vTaskGetInfo. For a CVE in FreeRTOS, check here whether the affected function is in the image or among the removed ones.

Compiler and linker options in the build
grep -o -- "-Wl,--gc-sections" makefilegrep -o -- "-ffunction-sections -fdata-sections" subdir.mk | sort -u

Output

-Wl,--gc-sections
-ffunction-sections -fdata-sections
Library members in the image, per library
sed -n '/^Archive member included/,/^Allocating common/p' STM32F429I-Oscilloscope.map | grep -o '[A-Za-z0-9_+-]*\.a(' | sort | uniq -c

Output

76libc_nano.a(6libgcc.a(15libstdc++_nano.a(57libtouchgfx-float-abi-hard.a(
A removed FreeRTOS function
grep -A1 "^ \.text\.vTaskGetInfo" STM32F429I-Oscilloscope.mapnm STM32F429I-Oscilloscope.elf | grep -c "vTaskGetInfo"

Output

 .text.vTaskGetInfo
                0x0000000000000000       0x7c ./Middlewares/FreeRTOS/tasks.o
0
Removed functions from tasks.c
awk '/^Discarded input sections/,/^Memory Configuration/' STM32F429I-Oscilloscope.map | grep -A1 '^ \.text\.' | grep -c 'Middlewares/FreeRTOS/tasks.o'
Output
37

Where does the version of a precompiled library like TouchGFX come from?

The test subject links the TouchGFX graphics library as a finished archive, libtouchgfx-float-abi-hard.a. The ELF carries 1,092 symbols with touchgfx, but no version number. The version is in the project file: X-CUBE-TOUCHGFX 4.17.0.

For the SBOM this means: name from the ELF, version from the .ioc, with a note on where it comes from. The same holds for every library a vendor ships only as .a or .lib.

The BIN of the same build does not name the FreeRTOS version either. In the debug ELF it is only in the debug information.

TouchGFX: version in the .ioc, traces in the ELF
grep -o "X-CUBE-TOUCHGFX\.[0-9.]*[0-9]" Discovery_Oscilloscope.ioc | sort -unm STM32F429I-Oscilloscope.elf | grep -c "touchgfx"strings -a STM32F429I-Oscilloscope.elf | grep -c "4\.17"

Output

X-CUBE-TOUCHGFX.4.17.0
1092
0
FreeRTOS version in the BIN
strings -a STM32F429I-Oscilloscope.bin | grep -c "V10.3.1"
Output
0

Can this run automatically?

Microcontroller builds from Keil MDK, IAR or GNU Arm. It finds the libraries built in, with their versions, for example CMSIS packs, RTX5, FreeRTOS, lwIP, mbedTLS and STM32Cube. Plus hardening (stack canary, MPU, privilege separation) and embedded keys.

Every component with an evidenced version is matched against the vulnerability sources. If the file evidences no version, the field stays blank. You export the SBOM as CycloneDX or SPDX.

Questions

Is the SBOM that ST ships with the Cube package enough?

Not for your device. It describes the package, and in STM32CubeF4 v1.28.3 it lacks the five libraries under Middlewares/Third_Party. Your SBOM names what your build linked, with the version.

Which file from STM32CubeIDE do I use?

The .elf from the build folder, such as Debug or Release. Add the project's .ioc, which names the package version.

Does this apply to Keil and IAR too?

Yes. Keil writes an .axf, IAR an .out, and both are ELF files. The middlewares come from the same Cube package.

What does --gc-sections mean for the SBOM?

The linker removes functions nothing calls. A library is then in the SBOM, but not every one of its functions is in the device. In the example 37 functions from FreeRTOS tasks.c are missing. For a reported vulnerability, map file and symbol table show whether the affected code is linked.

Where does the version of a library shipped only as .a come from?

From the project file, the package or the vendor's release notes. In the example the .ioc names TouchGFX 4.17.0; the ELF names only functions.

Does the HAL driver belong in the SBOM?

Yes. It is third-party code that runs in the device. In Annex I Part II the CRA requires the components to be identified, at least the top-level dependencies.

Sources

  1. [1]STMicroelectronics: STM32CubeF4, release v1.28.3
  2. [2]Test subject: mmahdim/STM32F4-Scope, commit c3d1f92
  3. [3]Regulation (EU) 2024/2847, Cyber Resilience Act
  4. [4]BSI TR-03183-2, version 2.1.0
  5. [5]GNU Binutils: nm and strings
  6. [6]GNU ld: --gc-sections and -Map
  7. [7]GCC: -ffunction-sections, -fdata-sections
  8. [8]GCC: -g3, macros in the debug information

Check your own image

Upload one firmware image, an AXF or a supplier SBOM in your own LegacyMind account. Report and SBOM within three working days, NDA on request. The app and the reports are in German; questions in English are welcome.