Hacktoberfest 2026: as issues que os mantenedores marcaram para outubro, abertas e boas para iniciantes. Ver issues do Hacktoberfest

[Bug] OOB write in OpenAMP virtual UART RX ring buffer on stm32mp157a-st-ev1

Aberta
#11,299 2 comentários 0 reações 1 responsável Ver no GitHub

Mantenedores costumam responder em até 1 dia

@manyangshen já está trabalhando nisso.

Desde 22/9/2026.

  • #11825 de @manyangshen — aberto

Avaliação

Dificuldade
4/5
Tempo estimado
3-5 dias
Facilidade para iniciantes
48/100
Tipo de issue
Bug
Clareza
Razoavelmente clara
Status de atividade
Pouca atividade
Stack de tecnologia
c

Direção de pesquisa

Comece em drv_openamp.c do BSP do STM32MP157A-ST-EV1, em VIRT_UART0_RxCpltCallback() e _read(), e depois analise como VIRT_UART_read_cb() passa os dados rpmsg para o callback de RX. Reproduza o problema com escritas controladas em /dev/ttyRPMSG0, incluindo uma escrita de 255 bytes seguida por uma escrita de 2 bytes. Considera-se concluído quando o anel RX não puder escrever além do próprio buffer, a condição de wrap da leitura for segura e a reprodução não causar mais corrupção nem um fault.

Escrita pelo modelo de indexação a partir do texto da issue.

Descrição

in progress
RT-Thread Version

master at commit fe548e1505

Hardware Type/Architectures

STM32MP157A-ST-EV1 BSP with BSP_USING_OPENAMP enabled.

Develop Toolchain

GCC

Describe the bug

There is a reachable memory-safety issue in the OpenAMP virtual UART receive path of the stm32mp157a-st-ev1 BSP.

VIRT_UART_read_cb() receives rpmsg data from the OpenAMP peer and forwards the externally controlled payload pointer and length into the registered RX callback:

huart->pRxBuffPtr = data;
huart->RxXferSize = len;
huart->RxCpltCallback(huart);

In this BSP, the registered callback is VIRT_UART0_RxCpltCallback() in drv_openamp.c. That callback copies the received payload into a 256-byte ring buffer, but the bounds logic is incorrect:

  1. It checks only if (count < size) once before the copy loop
  2. It does not verify that count + rx_size <= size
  3. It does not wrap offset during the copy loop

As a result, if the ring buffer already contains 255 bytes and a new 2-byte message arrives, the callback writes:

  • The first byte to buf[255]
  • The second byte to buf[256]

This is an out-of-bounds write.

The bug is not limited to the minimal 2-byte case. A larger second message increases the overwrite extent further because the loop continues writing past the end of the 256-byte receive buffer.

In addition, the read path in _read() also contains a wrap bug: it uses if (offset > rbsize) instead of if (offset >= rbsize). Once the ring-buffer state becomes invalid, this can also cause an out-of-bounds read on subsequent reads.

This issue is reachable in the current BSP integration. The input channel is concrete:

  • The BSP is configured with LINUX_RPROC_MASTER
  • CM4 initializes OpenAMP as RPMSG_REMOTE
  • The virtual UART endpoint name is rpmsg-tty-channel
  • The repository already includes tools/rt-thread-shell.py, which writes to /dev/ttyRPMSG0

Therefore, an attacker who can control the OpenAMP peer, or who can send controlled input through the CA7/Linux side into /dev/ttyRPMSG0 or the corresponding rpmsg endpoint, can trigger this bug.


Fix Suggestion

A safe fix should address both the RX callback and the read path.

Suggested changes:

  1. In VIRT_UART0_RxCpltCallback(), compute available space before copying:
    • available = size - count
    • If available == 0, drop the message or return an error
  2. Clamp rx_size to the available space before entering the loop
  3. Wrap offset on each iteration, not only once before the loop
  4. Ensure device->serial.rbuf_count never exceeds device->serial.rbuf_size
  5. In _read(), change the wrap condition from if (offset > rbsize) to if (offset >= rbsize)
  6. Prefer using a common ring-buffer helper instead of open-coded wrap logic

Pseudo-fix direction:

available = size - count;
rx_size = MIN(rx_size, available);

for (i = 0; i < rx_size; i++)
{
    if (offset >= size)
        offset = 0;
    buf[offset++] = huart->pRxBuffPtr[i];
    count++;
}

Exploitation Idea

Precondition: the attacker can control the OpenAMP peer, i.e. the CA7/Linux side can send data to /dev/ttyRPMSG0 or the corresponding rpmsg endpoint.

Minimal PoC idea:

  1. Send 255 bytes from the Linux side to make the CM4-side receive ring buffer nearly full.
  2. Send one more message with length 2.
  3. The second message triggers the out-of-bounds write in VIRT_UART0_RxCpltCallback().

High-level example from the Linux side:

  • Open /dev/ttyRPMSG0
  • Write 255 controlled bytes
  • Then write 2 more controlled bytes

A simple proof-of-concept can be implemented with a short userspace program or script that performs two writes in sequence.

For a more stable reproduction:

  • Make sure the CM4 side is not draining the openamp receive buffer too quickly
  • For example, avoid using openamp as the active console during reproduction, or pause the consumer if applicable

Observation ideas:

  • Monitor for CM4 fault / crash / unexpected behavior
  • Inspect adjacent memory corruption effects after the second write
  • After corrupting the ring state, trigger reads from the openamp device to exercise the buggy _read() wrap logic and observe potential OOB read behavior
Other additional context

No response

Linguagem predominante
C
Estrelas
12.3k
Forks
5.5k
Merge médio
4d 12h
PRs com merge (30d)
32

Preparar o ambiente

Abrir no Codespaces

Inicia o contêiner de desenvolvimento do projeto no navegador, com a sua própria conta do GitHub.

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Mais de RT-Thread/rt-thread

Todas as issues de RT-Thread/rt-thread

Issues semelhantes

Mais issues de C

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.