Knowledge · Findings record

A Keil build, read end to end

A public Keil build for a Cortex-M4: which components are inside and where the file shows it, which reported vulnerability has code in the build, which hardening is missing. With the commands that let you check it yourself.

File
ble_freertos_amota.axf
Size
2,503,136 bytes
Format
ELF32 · ARM · EABI 5
Target
Apollo3 · Cortex-M4
Analysed
19 October 2026 · app.legacymind.de
SHA-256
f33f7663bbd8b3fb4da733c57b008e439265ac688438b5c637da3c890e19fd13
Contents
  1. 0Result
  2. 1Components
  3. 2Vulnerabilities
  4. 3Hardening
  5. 4SBOM
  6. 5Verify

0Result

  • 2of 6reported vulnerabilities have code in the buildFreeRTOS 10.4.3 closes both, FreeRTOS 11.3.1 all 6.
  • 3protection mechanisms are missingStack canary, MPU, Privilege separation.
  • 3components without a version in the imageArm Cordio BLE stack, micro-ecc, Ambiq HAL: without a version, no match against known vulnerabilities.

1Components

Annex I, Part II, point (1)

Six components, three of them with a version in the file. Each row gives the file offset of the string that evidences it.

  • FreeRTOS

    RTOS kernel

    10.1.1

    0x1fe9c · .debug_info, only in the AXF
    ../../../../../third_party/FreeRTOSv10.1.1/Source/timers.c
  • Arm Cordio BLE stack

    Bluetooth stack, in LegacyMind as exactle

    no evidence

    0x17f3c · FLASH, also in the BIN
    ../../../../../third_party/exactle/wsf/sources/port/freertos/wsf_trace.c

    Project file: third_party/exactle; Arm Cordio r19.02 according to the SDK readme (cordio_profile_readme.md:14). The image carries no version.

  • micro-ecc

    crypto library, in LegacyMind as uecc

    no evidence

    0x4cd18 · .debug_info, only in the AXF
    ../../../../../third_party/uecc/uECC.h

    Project file: third_party/uecc. The SDK names no version.

  • Ambiq HAL

    vendor driver, in LegacyMind as hal_ambiq

    no evidence

    0x2e14 · FLASH, also in the BIN
    ERROR_CHECK_VOID am_hal_ble_initialize(0, &BLE)

    Project file: mcu/apollo3; AmbiqSuite 2.4.2 according to VERSION.txt. The image carries no version.

  • Arm C library (armlib)

    runtime library, in LegacyMind as Arm C library (armlib)

    5.06 update 6 (build 750)

    0x1dbd5b · .comment, only in the AXF
    C:\Keil_v5\ARM\ARMCC\Bin\..\lib\armlib\c_w.l
  • Arm Compiler

    toolchain

    5.06

    0x1fed7 · .debug_info, only in the AXF
    Component: ARM Compiler 5.06 update 6 (build 750) Tool: ArmCC [4d3637]

2Vulnerabilities

Annex I, Part I, point (2)(a)

The analysis reports six CVEs in FreeRTOS 10.1.1. The symbol table of the same file says for which of them the affected code is linked: for two, not for four.

Code in the build · 2

  • CVE-2021-31571

    CVSS 9.8 · Critical

    Integer overflow in queue.c when a queue is created.

    Fixed in FreeRTOS 10.4.3

    Symbol addressxQueueGenericCreate 0x1fe85

  • CVE-2021-32020

    CVSS 9.8 · Critical

    Insufficient bounds checking in the kernel's heap management.

    Fixed in FreeRTOS 10.4.3

    Symbol addresspvPortMalloc 0x1bfb5

Code not in the build · 4

  • CVE-2021-31572

    CVSS 9.8 · Critical

    Integer overflow in stream_buffer.c when a stream buffer is created.

    Fixed in FreeRTOS 10.4.3

    The build contains no stream buffer: no StreamBuffer function in the symbol table.

  • CVE-2024-28115

    CVSS 8.8 · High

    Insufficient protection against privilege escalation on MPU ports, if another vulnerability injects code.

    Fixed in FreeRTOS 10.6.2

    Affects MPU ports only. The build uses the port portable/Keil/AMapollo2 and contains no MPU_ symbol.

  • CVE-2026-77234

    CVSS 8.8 · High

    Missing input validation lets an unprivileged task run code in kernel context on MPU ports.

    Fixed in FreeRTOS 11.3.1

    Affects MPU ports only. The build uses the port portable/Keil/AMapollo2 and contains no MPU_ symbol.

  • CVE-2026-77237

    CVSS 6.5 · Medium

    Missing type check in xQueueAddToSet() lets an unprivileged task read kernel memory on MPU ports.

    Fixed in FreeRTOS 11.3.1

    Affects MPU ports only. The build uses the port portable/Keil/AMapollo2 and contains no MPU_ symbol.

No match · 3

  • Arm Cordio BLE stackWithout a version in the image, no match against known vulnerabilities.
  • micro-eccWithout a version in the image, no match against known vulnerabilities.
  • Ambiq HALWithout a version in the image, no match against known vulnerabilities.

We ran the symbol-table check for this record with nm; the report currently matches all six on the version alone. CVSS as in the report, fixed version according to the NVD, none of the six in the CISA KEV catalogue.

3Hardening

Annex I, Part I, point (2)(k)

Measured the way a microcontroller is measured: RELRO, NX and PIE do not exist on a Cortex-M.

  • Stack canary

    missing

    Evidence

    No __stack_chk_guard, no __stack_chk_fail in the symbol table.

    What turns it on

    Compile with --protect_stack (Arm Compiler 5), or with -fstack-protector-strong on armclang.

  • MPU

    missing

    Evidence

    No MPU_ symbol; the build uses the port portable/Keil/AMapollo2.

    0x20e04 · .debug_info, only in the AXF
    ../../../../../third_party/FreeRTOSv10.1.1/Source/portable/Keil/AMapollo2/portmacro.h

    What turns it on

    Use the FreeRTOS MPU port for Cortex-M4 and define the tasks' memory regions.

  • Privilege separation

    missing

    Evidence

    Without the MPU port every task runs privileged; no xPortRaisePrivilege in the symbol table.

    What turns it on

    With the MPU port, create unprivileged tasks (xTaskCreateRestricted).

4SBOM

Annex I, Part II, point (1)

The SBOM as CycloneDX 1.6, exactly as it comes out of the app.

ble_freertos_amota.cdx.json · excerpt
{
  "bomFormat": "CycloneDX",
  "specVersion": "1.6",
  "serialNumber": "urn:uuid:69d14c95-045e-4456-a0d0-c4309e7835c6",
  "metadata": {
    "component": {
      "type": "firmware",
      "name": "ble_freertos_amota.axf"
    }
  },
  "components": [
    {
      "type": "library",
      "name": "FreeRTOS",
      "version": "10.1.1",
      "purl": "pkg:generic/FreeRTOS@10.1.1",
      "cpe": "cpe:2.3:a:amazon:amazon_web_services_freertos:10.1.1:*:*:*:*:*:*:*"
    },
    {
      "type": "library",
      "name": "Arm C library (armlib)",
      "version": "5.06 update 6 (build 750)",
      "purl": "pkg:generic/Arm%20C%20library%20(armlib)@5.06%20update%206%20(build%20750)"
    },
    {
      "type": "application",
      "name": "arm compiler",
      "version": "5.06",
      "purl": "pkg:generic/arm%20compiler@5.06",
      "cpe": "cpe:2.3:a:arm:arm_compiler:5.06:*:*:*:*:*:*:*"
    },
    {
      "type": "library",
      "name": "exactle",
      "purl": "pkg:generic/exactle"
    },
    {
      "type": "library",
      "name": "hal_ambiq",
      "purl": "pkg:generic/hal_ambiq"
    },
    {
      "type": "library",
      "name": "uecc",
      "purl": "pkg:generic/uecc"
    }
  ]
}
The CycloneDX export from the app, cut to the standard fields type, name, version, purl and CPE.

5Verify

Three commands repeat the record on the file from the source above: the checksum, the file offsets with strings, the symbol addresses with nm. Above them, the sections of the file, so every offset has its place.

Sections of the file, read from the ELF header
SectionOffsetSizein the BIN
FLASH0x340x17fb8yes
SRAM0x17fec0x954yes
.debug_abbrev0x189400x5c4no
.debug_frame0x18f040x6f8cno
.debug_info0x1fe900xe68fcno
.debug_line0x10678c0x366e4no
.debug_loc0x13ce700x15a40no
.debug_macinfo0x1528b00x60590no
.debug_pubnames0x1b2e400x8122no
.symtab0x1baf640x10f40no
.strtab0x1cbea40xfd20no
.note0x1dbbc40x1cno
.comment0x1dbbe00x872ccno
.shstrtab0x262eac0x94no
Is it the same file?
sha256sum ble_freertos_amota.axf

Ausgabe

f33f7663bbd8b3fb4da733c57b008e439265ac688438b5c637da3c890e19fd13  ble_freertos_amota.axf
File offsets of the strings from section 1
for s in "FreeRTOSv10.1.1" "third_party/exactle/" "third_party/uecc/" "am_hal_ble_initialize" "armlib\\c_w.l" "Component: ARM Compiler 5.06"; do strings -a -t x ble_freertos_amota.axf | grep -m1 -F "$s"; done

Ausgabe

1fe9c../../../../../third_party/FreeRTOSv10.1.1/Source/timers.c17f3c../../../../../third_party/exactle/wsf/sources/port/freertos/wsf_trace.c4cd18../../../../../third_party/uecc/uECC.h2e14ERROR_CHECK_VOID am_hal_ble_initialize(0, &BLE)1dbd5bC:\Keil_v5\ARM\ARMCC\Bin\..\lib\armlib\c_w.l1fed7Component: ARM Compiler 5.06 update 6 (build 750) Tool: ArmCC [4d3637]
Symbol addresses: which function is linked, which is missing
nm ble_freertos_amota.axf | grep -E "xQueueGenericCreate|pvPortMalloc|StreamBuffer|MPU_|__stack_chk|xPortRaisePrivilege|xTaskCreateRestricted"

Ausgabe

0001bfb5T pvPortMalloc0001fe85T xQueueGenericCreate

Run with GNU nm (GNU Binutils for Ubuntu) 2.42 and GNU strings on the file with the SHA-256 above, on 20 October 2026.

Questions about the record

Why do three components have no version?
For Arm Cordio BLE stack, micro-ecc and Ambiq HAL the file holds source paths and assert strings, but no version number. The record leaves the field blank instead of taking a version from the SDK.
Why only vulnerabilities in FreeRTOS?
Only what carries a version can be matched. For the compiler and the runtime library, the analysis reports no known vulnerabilities in these versions; the three libraries without a version stay unmatched.
Which file should we upload, the AXF or the BIN?
The AXF, ELF or OUT of the build. In this record, FreeRTOS 10.1.1, Arm C library 5.06 update 6 (build 750) and Arm Compiler 5.06 appear only in sections that are not copied into the BIN (.debug_info, .comment); a BIN on its own yields only what its own bytes evidence. Upload both from the same build, and the BIN gets the components of the AXF.
What does the file tell you about the toolchain?
The `.comment` section names ARM Compiler 5.06 update 6 (build 750), the linker command line and five libraries of the Arm C runtime: c_w.l, fz_wm.l, h_w.l, m_wm.l and vfpsupport.l. The compiler invocations also show the Device Family Pack Apollo_DFP 1.1.3 in the include path. The project file names 1.1.0; the build used 1.1.3.
Why is a function from the source code missing from the build?
Because armlink removes unused sections by default, and this build puts every function in its own section. `vTaskEndScheduler` is in tasks.c at line 2061; the symbol table does not have it. That is why the record checks, for every CVE, whether the affected code is linked.
Is there a map file for this build?
The linker ran with `--map` and `--list=.\Listings\ble_freertos_amota.map`; the AXF says so. The Listings folder is not published in the repository. In your own build, the same line in the AXF shows whether the linker wrote a map file, and where. With `--info=sizes` the map file lists code and data per object and per library member.
Do you need our source code or our build system?
No. The analysis runs on the file your build produces, or on the image your customer receives. No repository, no access to your toolchain, no access to the device.
What does this mean for the reporting obligation under CRA Art. 14?
None of the 6 reported vulnerabilities is in the CISA KEV catalogue of actively exploited vulnerabilities. If one of them is exploited, the first question within the 24-hour deadline is which shipped products contain FreeRTOS 10.1.1. With an SBOM per release, that is one search. You file the report yourself.

The same review for your build

In the free CRA readiness check we analyse one file from your build. You get the report and the SBOM within three working days.