Repository navigation
[Bug] pipe: RT-Smart ioctl writes through an unvalidated user pointer and can corrupt kernel memory #11958
Description
RT-Thread Version
RT-Smart v5.0.0 through v5.3.0 and master (v5.4.0-dev). The raw ioctl argument
boundary entered master with the RT-Smart sync ecf2d8215961; the pipe sink is
still unpatched on current master cbc19778.
Affected area
- Device drivers (POSIX pipe IPC / RT-Smart devfs ioctl)
Hardware-BSP vendor
Other (verified on QEMU vexpress-a9; applies to 32-bit RT-Smart builds exposing
POSIX pipes)
Architecture
- ARM / ARMv7-A
- Other (32-bit RT-Smart builds where pipe FIONREAD/FIONWRITE commands remain
32-bit)
Board and hardware details
QEMU vexpress-a9, Cortex-A9, RT-Smart, official BSP configuration with
RT_USING_POSIX_PIPE=y and pipe buffer size 512.
Develop Toolchain
Official RT-Thread ARM musl toolchain GCC 7.3; QEMU 9.2.3; gdb-multiarch.
Describe the bug
pipe_fops_ioctl() writes a ring-buffer length directly through its args
pointer:
case FIONREAD:
*((int *)args) = rt_ringbuffer_data_len(pipe->fifo);
break;
case FIONWRITE:
*((int *)args) = rt_ringbuffer_space_len(pipe->fifo);
break;RT-Smart sys_ioctl() forwards the original user argument without copyout, and
the pipe fops layer does not check whether it is a userspace address. An
unprivileged process can therefore choose any kernel address as the destination
of a four-byte write. The value is constrained to the pipe data/free-space range
(0..512 in this configuration), so this is a constrained-value arbitrary-address
kernel write, not an unrestricted arbitrary-value write.
Reproduction:
- Boot the audited qemu-vexpress-a9 RT-Smart kernel with an unprivileged
user program as/sbin/init. - Control:
pipe(fds);
int value = -1;
ioctl(fds[1], FIONWRITE, &value);The call returns 0, value becomes 0x200, and the kernel remains alive.
- Attack:
pipe(fds);
ioctl(fds[1], FIONWRITE, 0xc010dd58); /* &rt_malloc_hook */
read(zero_fd, buf, 64); /* invoke rt_malloc */- GDB captures:
Hardware watchpoint: rt_malloc_hook
Old value = 0x0
New value = 0x200
pipe_fops_ioctl (... args=0xc010dd58 <rt_malloc_hook>)
- The next
sys_read -> kmem_get -> rt_malloc(64)calls the corrupted hook.
The kernel reportsprefetch abort,pc=0x204, and enters
rt_hw_trap_pabt -> rt_hw_cpu_shutdown.
Three GDB runs produced identical transcripts.
Expected result: FIONREAD/FIONWRITE must copy their int result through a
bounded kernel buffer, or the syscall boundary must reject kernel addresses with
EFAULT.
Actual result: an unprivileged local process can corrupt four bytes at any
kernel address with a pipe-derived value. The reproduced target corrupts
rt_malloc_hook, causing a deterministic kernel prefetch abort and shutdown.
Other additional context
- CVSS 3.1:
AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H= 7.1 High - CWE-787 / CWE-668
- Attack premise: unprivileged local RT-Smart process; 32-bit build with POSIX
pipe enabled; no race, mount, or driver cooperation required. - This is an incomplete-fix sibling of [Bug] [Smart] terminal tty: ioctl passes raw user pointer into kernel dereference — arbitrary kernel read/write from unprivileged user process #11937 (terminal), [Bug] block: devfs ioctl copies partition data to an unvalidated user-supplied kernel pointer #11952 (block),
and [Bug] Security-related Bug RT-Smart serial ioctl trusts user pointers and can crash the kernel #11429 (serial): all retain the rawsys_ioctlpointer boundary. - PR [HUST CSE] drivers/ipc: validate pipe ioctl args #11373 only added a NULL check to this handler. PR fix(ioctl):
_IOR()overflows inswitch (int)#10650 changed ioctl
command typing but did not add copyout. - Full QEMU control/attack logs, three GDB transcripts, user ELFs, and scripts
are available inaudit/RT_pipe/exp/.
Activity
github-actions commentedon Oct 30, 2026
如需认领并处理此 Issue,请评论
/claim。To claim and work on this issue, comment
/claim.