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

[Bug] lwp: sys_sigaction missing signal-number range check allows out-of-bounds read/write in kernel heap (RT-Smart)

Aberta
#11,882 1 comentário 0 reações 0 responsáveis Ver no GitHub

Mantenedores costumam responder em até 1 dia

Ninguém assumiu esta issue ainda.

Avaliação

Dificuldade
3/5
Tempo estimado
1-2 dias
Facilidade para iniciantes
78/100
Tipo de issue
Bug
Clareza
Claramente especificada
Status de atividade
Ativa
Stack de tecnologia
c

Direção de pesquisa

Start with components/lwp/lwp_syscall.c at sys_sigaction() and components/lwp/lwp_signal.c at lwp_signal_action(), then trace the existing valid_signo_check() helper and its current caller. Reproduce the behavior with the supplied sigaction ELF on QEMU, including in-range, zero, and out-of-range signal numbers. Done means signal numbers outside [1, _LWP_NSIG] return -EINVAL before any signal-array access, while valid signals retain their existing behavior.

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

Descrição

RT-Thread Version

master @ 5d1fb66d (v5.4.0-dev, verified byte-identical to origin/master as of 2026-10-17). Affected since v5.0.0; introduced by commit ecf2d821 (#6641, "sync branch rt-smart", 2022-12-03).

Affected area

RT-Smart

Hardware/BSP vendor

Not applicable / Other

Architecture

ARM AArch64 (qemu-virt64-aarch64; the bug is architecture-independent C code in components/lwp)

Board and hardware details

QEMU virt machine (Cortex-A/-cpu max, GICv2), RT-Thread Smart build (RT_USING_SMART=y), root filesystem on virtio-blk (elm/FatFS). Any RT-Smart board is expected to be affected.

Develop Toolchain

aarch64-linux-musleabi gcc 7.3.0 (the official RT-Thread CI toolchain, toolchains-ci v1.7)

Describe the bug

sys_sigaction() never validates the sig argument and forwards it to lwp_signal_action(), which also performs no range check before indexing the fixed-size arrays embedded in the heap-allocated struct rt_lwp (_LWP_NSIG = 64):

// components/lwp/lwp_syscall.c:6747
sysret_t sys_sigaction(int sig, const struct k_sigaction *act,
                       struct k_sigaction *oact, size_t sigsetsize)
{ ... ret = lwp_signal_action(lwp, sig, pkact, pkoact); }   // sig unchecked

// components/lwp/lwp_signal.c:1108
rt_err_t lwp_signal_action(struct rt_lwp *lwp, int signo, ...)
{
    ...
    oact->sa_mask                   = lwp->signal.sig_action_mask[signo - 1];  // :1124 OOB read
    oact->__sa_handler._sa_handler  = lwp->signal.sig_action[signo - 1];       // :1125 OOB read
    ...
    lwp->signal.sig_action_mask[signo - 1] = act->sa_mask;                     // :1141 OOB write
    ...
    lwp->signal.sig_action[signo - 1] = act->__sa_handler._sa_handler;         // :1158 OOB write
    _signal_action_flag_u2k(signo, &lwp->signal, act);                         // :1161 more OOB RMW
}

Consequences, all reachable from any unprivileged user-mode program with a single svc (syscall 103):

  1. Arbitrary-offset 8-byte write with fully attacker-controlled value — sig_action[signo-1] = act->handler writes the user-supplied handler pointer at &lwp->signal.sig_action + (sig-1)*8 (offsetof(rt_lwp, signal.sig_action) = 800), for any positive or negative offset (sig = 0 → index −1). sig_action_mask[], and the SA_NODEFER/SA_ONSTACK/SA_RESTART/SA_SIGINFO sigsets give further OOB read-modify-write primitives.
  2. Kernel heap disclosure — the oact path copies sig_action[signo-1]/sig_action_mask[signo-1] from beyond the arrays back to user memory.
  3. Deterministic kernel crash — a far offset hits unmapped kernel VA and kills the whole kernel.

Note the range-check helper valid_signo_check() already exists since #9981 (2025-02) but is only wired into lwp_pgrp_signal_kill(); the sigaction path was missed.

Reproduction (RT-Smart on QEMU virt, full chain: user ELF → svc #0 → kernel):

msh /> sys_log 1
msh /> /sigaction_poc.elf
[poc] control sigaction(10) ret=0x0000000000000000          # in-range call: OK, system alive
[poc] sig=0x48 ... mask0=0x006a626f5f70776c                  # OOB READ: kernel heap string ("lwp_obj") leaked to user
[poc] OOB WRITE sigaction(200) handler=0x4142434445464748
[poc] write ret=0 / readback handler=0x4142434445464748      # OOB WRITE: attacker value written & read back

GDB hardware-watchpoint capture (kernel address, before/after):

Breakpoint: lwp_signal_action (lwp=0xffff000000273e90, signo=200, ...)
  #1 sys_sigaction (sig=200, ...) at lwp_syscall.c:6794
  #2 _SVC_Handler at lwp_gcc.S:177        <- user `svc #0`
&lwp->signal.sig_action[199] = 0xffff0000002747e8    (offsetof = 800)
Old value = 0
New value = 4702394921427289928 (0x4142434445464748)

Far-offset variant (sig = 0x1000000) — instant kernel death, fault address matches the computed target exactly:

Data abort, fault addr = 0xffff0000082741a8
   = lwp(0xffff000000273e90) + 0x320 + (0x1000000-1)*8
  _get_sighandler_locked lwp_signal.c:371  <- sys_sigaction:6794  <- SVC_Handler

Expected behavior

sigaction() with a signal number outside [1, 64] must fail with EINVAL before touching any array, as Linux does.

Suggested fix

sysret_t sys_sigaction(int sig, ...)
{
    if (sig <= 0 || (unsigned long)sig > _LWP_NSIG)
        return -EINVAL;
    ...
}

(or call the existing valid_signo_check() inside lwp_signal_action(), which also protects future callers).

Other additional context

  • Severity: CVSS 3.1 AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H = 7.8 (High); CWE-129 → CWE-787/CWE-125.
  • Attack prerequisite (explicit): attacker can run an unprivileged RT-Smart user program on the device (e.g. a third-party app). No other privilege or race is needed; the primitive is deterministic.
  • Related but distinct: CVE-2025-5866/CVE-2025-5868 are about the unchecked how index in sys_sigprocmask/sys_thread_sigprocmask; this report is the unchecked signal number in sys_sigaction (different parameter, different function) and is not covered by any existing CVE/issue — I found no prior report for it.
  • All evidence above is from a real RT-Thread Smart kernel running under QEMU (no host-side sanitizers involved). Repro sources/logs: kernel components/lwp/{lwp_syscall.c,lwp_signal.c}; happy to attach the freestanding user-space PoC ELF source if wanted.
Linguagem predominante
C
Estrelas
12.3k
Forks
5.5k
Merge médio
7d 22h
PRs com merge (30d)
30

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.