[Bug] lwp: sys_sigaction missing signal-number range check allows out-of-bounds read/write in kernel heap (RT-Smart)
Les mainteneurs répondent en général sous 1 jour
Personne n'a encore pris cette issue.
Évaluation
- Difficulté
- 3/5
- Temps estimé
- 1-2 jours
- Accessibilité débutants
- 78/100
- Type d'issue
- Bug
- Clarté
- Clairement spécifiée
- Activité
- Active
- Stack technique
- c
- Domaine
- operating-systems, security
Piste de recherche
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.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
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):
- Arbitrary-offset 8-byte write with fully attacker-controlled value —
sig_action[signo-1] = act->handlerwrites 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. - Kernel heap disclosure — the
oactpath copiessig_action[signo-1]/sig_action_mask[signo-1]from beyond the arrays back to user memory. - 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
howindex insys_sigprocmask/sys_thread_sigprocmask; this report is the unchecked signal number insys_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.
- Langage dominant
- C
- Étoiles
- 12.3k
- Forks
- 5.5k
- Merge moyen
- 7 j 22 h
- PR mergées (30 j)
- 30
Préparer son environnement
Lance le conteneur de développement du projet dans votre navigateur, avec votre propre compte GitHub.
- Aucun Dockerfile ni fichier Docker Compose
- Propose un modèle de pull request
- Lire le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de RT-Thread/rt-thread
-
[bsp][stm32][bluepill] README「快速上手」缺少重新生成 MDK 工程这一步,按文档操作无法编译通过Peut-être pris @moment-NEW l’a pris il y a 16 jours. Ouvertein progress
Difficulté 2/5 1-3 heures Accessibilité débutants 75/100
RT-Thread/rt-thread#11818 · 4 commentaires · 1 personne assignée ·
Les mainteneurs répondent en général sous 1 jour
-
BSP BSP: Loongson bug RT-Smart
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
RT-Thread/rt-thread#11717 · 2 commentaires ·
Les mainteneurs répondent en général sous 1 jour
-
Arch: RISC-V BSP BSP: HPMicro bug
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
RT-Thread/rt-thread#11687 · 3 commentaires ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 68/100
RT-Thread/rt-thread#11472 · 2 commentaires ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 5/5 Plus d'une semaine Accessibilité débutants 25/100
RT-Thread/rt-thread#11898 · 2 commentaires ·
Les mainteneurs répondent en général sous 1 jour
Toutes les issues de RT-Thread/rt-thread
Issues similaires
-
Missing options in yara man pageOuvertebug
Difficulté 1/5 Moins d'une heure Accessibilité débutants 84/100
VirusTotal/yara#2255 ·
-
[BUG] Filename sequence expansion (`+`) panics on numeric values exceeding `i32::MAX`Peut-être pris @muntasir-396 l’a pris aujourd’hui. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 82/100
CCExtractor/ccextractor#2402 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 82/100
FujiNetWIFI/fujinet-lib#204 ·
Les mainteneurs répondent en général sous 1 jour
-
os:linux
Difficulté 2/5 1-3 heures Accessibilité débutants 66/100
mpv-player/mpv#18649 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 85/100
facebookincubator/muse-gadget-sdk#249 ·
Les mainteneurs répondent en général sous 1 jour