Skip to content

[Bug] Critical Out-Of-Bounds array access in STM32H7 timer IRQ handlers (Potential HardFault) #11368

@keydu

Description

@keydu

Current Behavior

There is a severe out-of-bounds (OOB) memory access vulnerability in the STM32H7 timer interrupt implementation. It stems from an architectural assumption that timer numbers sequentially map to the timerCtx array indices, which is false for the STM32H7 series due to the absence of TIM9, TIM10, and TIM11.

In timer_impl.h, the IRQ handler macros are defined as:

#define _TIM_IRQ_HANDLER(name, i)                                       \
    void name(void)                                                     \
    {                                                                   \
        impl_timerCaptureCompareHandler(TIM ## i, timerCtx[i - 1]); \
    } struct dummy

This hardcodes the array index to i - 1 (where i is the hardware timer number).

In timer_stm32h7xx.c, the timers are defined using these macros:

_TIM_IRQ_HANDLER(TIM15_IRQHandler, 15);
_TIM_IRQ_HANDLER(TIM16_IRQHandler, 16);
_TIM_IRQ_HANDLER(TIM17_IRQHandler, 17);

However, in timer.c, the context array is allocated based on the total number of defined timers:

timHardwareContext_t * timerCtx[HARDWARE_TIMER_DEFINITION_COUNT];

For STM32H7, HARDWARE_TIMER_DEFINITION_COUNT is typically 14.
When TIM17_IRQHandler is triggered, the macro expands to timerCtx[17 - 1], which evaluates to timerCtx[16]. Accessing index 16 on an array of size 14 results in a direct Out-Of-Bounds memory read. If the garbage value at this memory location is dereferenced inside impl_timerCaptureCompareHandler, it will cause an immediate HardFault.

Note: This bug has likely remained dormant because TIM15/16/17 are usually assigned to outputs (PWM/DShot) which do not enable the timer's global IRQ. However, if a user maps an input capture feature (like RC input or ESC RPM telemetry) to TIM15/16/17 on an H7 board, the FC will crash.

Steps to Reproduce

  1. Take any STM32H7 based flight controller.
  2. In target.c or CLI, assign a receiver input (e.g., PPM/PWM) or ESC RPM Telemetry to a pad that corresponds to TIM15, TIM16, or TIM17 (This forces the initialization of the timer in Input Capture mode, which enables the TIMx_IRQn via NVIC).
  3. Power on the board and feed a signal to that pad.
  4. The hardware triggers the IRQ, the firmware attempts to read timerCtx[14], [15], or [16], leading to memory corruption or an immediate HardFault.

Expected behavior

The IRQ handler should access the correct timerCtx pointer that strictly corresponds to the linear index defined in timerDefinitions[], without exceeding HARDWARE_TIMER_DEFINITION_COUNT.

Suggested solution(s)

There are two ways to fix this architecture limitation:

Option 1: Modify the macro to accept explicit array indices (Recommended)
Update timer_impl.h to decouple the Timer Number from the Array Index:

#define _TIM_IRQ_HANDLER_IDX(name, i, ctxIdx)                           \
    void name(void)                                                     \
    {                                                                   \
        impl_timerCaptureCompareHandler(TIM ## i, timerCtx[ctxIdx]);    \
    } struct dummy

Then in timer_stm32h7xx.c (and potentially others like G4), explicitly pass the index that matches timerDefinitions[]:

// Assuming TIM17 is at index 13 in timerDefinitions

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions