hitHuang opened a new pull request, #19364:
URL: https://github.com/apache/nuttx/pull/19364
## Summary
`riscv_fillpage()` is the LOADPF/STOREPF handler used under `CONFIG_PAGING`.
It checked
whether intermediate page table levels were already allocated, but never
checked the
final leaf PTE before installing a new mapping.
RISC-V raises the same LOADPF/STOREPF cause both when a leaf PTE is absent
(a real fault)
and when it is present but its permission bits don't satisfy the access,
e.g. a store to
a `.text` page whose write access was revoked after ELF loading. The two
cases are
indistinguishable from `mcause` alone.
Treating both cases as "page missing" let `riscv_fillpage` silently allocate
a fresh,
zeroed physical page over an existing mapping, discarding the old page (a
leak) and
defeating whatever permission that mapping was enforcing. Reproduced on real
hardware: a
user-space store to an already-loaded `.text` page got a fresh writable page
instead of
being rejected, silently zeroing out the code at that address.
This PR checks the leaf PTE's valid bit before allocating; if a mapping
already exists,
it panics instead of overwriting it.
## Impact
- Only affects `CONFIG_PAGING` builds (`BUILD_KERNEL && ARCH_USE_MMU &&
!ARCH_ROMPGTABLE && !LEGACY_PAGING`) on RISC-V.
- Behavior change: a LOADPF/STOREPF on an already-mapped leaf PTE (permission
violation) now panics instead of silently reallocating and zeroing the
page. This
turns a silent memory-corruption bug into a detectable failure.
- No Kconfig, API, or build system changes.
## Testing
Verified on qemu rv-virt:
Test app, a modified `hello` that writes to an already-loaded `.text`
address:
```c
int main(int argc, FAR char *argv[])
{
void *p = (void *)0xc0001000;
*(int *)p = 0x5a5a5a5a;
// printf("Hello, World!!\n");
return 0;
}
```
Corresponding disassembly. `c0000068` is the store that hits `0xc0001000`:
```
00000000c000004c <main>:
c000004c: 1101 add sp,sp,-32
c000004e: 87aa mv a5,a0
c0000050: e02e sd a1,0(sp)
c0000052: c63e sw a5,12(sp)
c0000054: 000c07b7 lui a5,0xc0
c0000058: 0785 add a5,a5,1 # c0001
<sig_trampoline-0xbff3ffff>
c000005a: 07b2 sll a5,a5,0xc
c000005c: ec3e sd a5,24(sp)
c000005e: 67e2 ld a5,24(sp)
c0000060: 5a5a6737 lui a4,0x5a5a6
c0000064: a5a70713 add a4,a4,-1446 # 5a5a5a5a
<sig_trampoline-0x65a5a5a6>
-> c0000068: c398 sw a4,0(a5)
c000006a: 4781 li a5,0
c000006c: 853e mv a0,a5
c000006e: 6105 add sp,sp,32
c0000070: 8082 ret
```
**Before this fix**: `hello` runs to completion instead of crashing.
Boot log (loader lazily faulting in `.text` pages via `riscv_fillpage`,
before any
user command is run):
```
ABC[ 0.046000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020f2d8, MTVAL: 00000000c0001000
[ 0.057000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020f2d8, MTVAL: 00000000c0002000
[ 0.059000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020f2d8, MTVAL: 00000000c0003000
[ 0.062000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020f2d8, MTVAL: 00000000c0004000
[ 0.064000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020f2d8, MTVAL: 00000000c0005000
[ 0.066000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020f2d8, MTVAL: 00000000c0006000
[ 0.069000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020f2d8, MTVAL: 00000000c0007000
[ 0.071000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020f2d8, MTVAL: 00000000c0008000
[ 0.073000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020f2d8, MTVAL: 00000000c0009000
[ 0.075000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020f2d8, MTVAL: 00000000c000a000
[ 0.077000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020f2d8, MTVAL: 00000000c000b000
[ 0.079000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020f2d8, MTVAL: 00000000c000c000
[ 0.081000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020f2d8, MTVAL: 00000000c000d000
[ 0.083000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020f2d8, MTVAL: 00000000c000e000
[ 0.086000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020f2d8, MTVAL: 00000000c000f000
[ 0.088000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020f2d8, MTVAL: 00000000c0010000
[ 0.090000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020f2d8, MTVAL: 00000000c0011000
[ 0.093000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020f2d8, MTVAL: 00000000c0012000
[ 0.096000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020f2d8, MTVAL: 00000000c0013000
[ 0.101000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020ff78, MTVAL: 00000000c1000ff8
[ 0.104000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 00000000802106aa, MTVAL: 00000000c08051d0
NuttShell (NSH) NuttX-13.0.0-RC0
```
Running `hello`. The store to `0xc0001000` raises a `Store/AMO page fault`;
`riscv_fillpage` finds the leaf PTE already valid but doesn't check it,
allocates a
fresh zeroed page, and installs it over the existing `.text` mapping.
`hello` returns
normally and the shell stays responsive, i.e. no crash:
```
nsh> hello
[ 1.820000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020f2d8, MTVAL: 00000000c0001000
[ 1.831000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020ff78, MTVAL: 00000000c1000ff8
[ 1.834000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 00000000802106aa, MTVAL: 00000000c08065d0
[ 1.838000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 00000000c0000068, MTVAL: 00000000c0001000
nsh>
nsh>
nsh> ps
TID PID PPID PRI POLICY TYPE NPX STATE EVENT SIGMASK
STACK COMMAND
0 0 0 0 FIFO Kthread - Ready
0000000000000000 0003024 Idle_Task
1 0 0 100 RR Kthread - Waiting Semaphore
0000000000000000 0001936 lpwork 0x80600100 0x80600180
3 3 0 100 RR Task - Running
0000000000000000 0002976 /system/bin/init
```
GDB confirms the code page at `0xc0001000` (containing part of
`nxsem_clockwait`) was
replaced with all zeros after the write:
```
(gdb) add-symbol-file ~/workspace/nuttx-fork/apps/bin_debug/hello
add symbol table from file
"/home/huang/workspace/nuttx-fork/apps/bin_debug/hello"
(y or n) y
Reading symbols from /home/huang/workspace/nuttx-fork/apps/bin_debug/hello...
(gdb) b *0xc0000068
Breakpoint 1 at 0xc0000068: file hello_main.c, line 42.
(gdb) c
Continuing.
Breakpoint 1, 0x00000000c0000068 in main (argc=1, argv=0xc0802030) at
hello_main.c:42
42 *(int *)p = 0x5a5a5a5a;
(gdb) x/16xw 0xC0001000
0xc0001000 <sys_call3+30>: 0x00000073 0x87aa0001 0x6105853e
0x71798082
0xc0001010 <nxsem_clockwait+2>: 0xec2af406 0xe43287ae 0x67e2ca3e
0x66a24752
0xc0001020 <nxsem_clockwait+18>: 0x85be863a 0xf0ef4571
0x87aafbdf 0x853e2781
0xc0001030 <nxsem_clockwait+34>: 0x614570a2 0x11418082
0xe02e87aa 0x6783c63e
(gdb) c
Continuing.
Breakpoint 1, 0x00000000c0000068 in main (argc=1, argv=0xc0802030) at
hello_main.c:42
42 *(int *)p = 0x5a5a5a5a;
(gdb) x/16xw 0xC0001000
0xc0001000 <sys_call3+30>: 0x00000000 0x00000000 0x00000000
0x00000000
0xc0001010 <nxsem_clockwait+2>: 0x00000000 0x00000000 0x00000000
0x00000000
0xc0001020 <nxsem_clockwait+18>: 0x00000000 0x00000000
0x00000000 0x00000000
0xc0001030 <nxsem_clockwait+34>: 0x00000000 0x00000000
0x00000000 0x00000000
```
If the commented-out `printf()` call is re-enabled, `hello` crashes inside
the printf
path, because that path calls into code located in the now-zeroed page at
`0xc0001000` — but that's incidental (it depends on which function happens
to share
the page with the corrupted address), not the expected failure mode.
The root cause is that a write to `.text` raises a Store/AMO page fault, and
because
of the write permission granted in `riscv_fillpage` for the reasons
described in
https://github.com/apache/nuttx/pull/6193, that write to `.text` is allowed
to
succeed instead of being rejected.
**After this fix**: the same write to `0xc0001000` now hits the leaf-PTE
check, and
`riscv_fillpage` panics instead of silently overwriting the mapping:
```
nsh> hello
[ 4.182000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020f2d8, MTVAL: 00000000c0001000
[ 4.190000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 000000008020ff78, MTVAL: 00000000c1000ff8
[ 4.193000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 00000000802106aa, MTVAL: 00000000c08065d0
[ 4.196000] riscv_fillpage: EXCEPTION: Store/AMO page fault. MCAUSE:
000000000000000f, EPC: 00000000c0000068, MTVAL: 00000000c0001000
[ 4.196000] riscv_fillpage: PANIC!!! page already mapped, permission
violation: c0001000
[ 4.196000] dump_assert_info: Current Version: NuttX 13.0.0-RC0
70fd28f73b-dirty Jul 8 2026 09:00:04 risc-v
[ 4.196000] dump_assert_info: Assertion failed panic: at file: :0 task:
hello process: hello 0xc000001c
[ 4.196000] up_dump_register: EPC: 00000000c0000068
[ 4.196000] up_dump_register: A0: 0000000000000001 A1: 00000000c0802030
A2: 0000000000000000 A3: 000000008060b6f0
[ 4.196000] up_dump_register: A4: 000000005a5a5a5a A5: 00000000c0001000
A6: 0000000000000000 A7: 000000008020f942
[ 4.196000] up_dump_register: T0: 0000000080210718 T1: 0000000000000030
T2: 000000008060a000 T3: 0000000200042022
[ 4.196000] up_dump_register: T4: 000000008060b6f0 T5: 0000000000000000
T6: 0000000200042022
[ 4.196000] up_dump_register: S0: 000000008060b718 S1: 0000000000000148
S2: 0000000000000000 S3: 0000000000000030
[ 4.196000] up_dump_register: S4: 0000000000000000 S5: 0000000200042022
S6: 000000008060b6f0 S7: 0000000200042022
[ 4.196000] up_dump_register: S8: 0000000100000000 S9: 00000000806083c8
S10: 0000001600000000 S11: 0000000200042022
[ 4.196000] up_dump_register: SP: 00000000c0803fb0 FP: 000000008060b718
TP: 0000000000000000 RA: 00000000c0000040
[ 4.196000] dump_stackinfo: User Stack:
[ 4.196000] dump_stackinfo: base: 0xc0802050
[ 4.196000] dump_stackinfo: size: 00008112
[ 4.196000] dump_stackinfo: sp: 0xc0803fb0
[ 4.196000] stack_dump: 0xc0803f70: 0000000000000000 0000000000000000
0000000000000000 0000000000000000 0000000000000000 0000000000000000
0000000000000000 0000000000000000
[ 4.196000] stack_dump: 0xc0803fb0: 00000000c0802030 0000000100000000
0000000000000000 00000000c0001000 00000000c0802030 0000000100000000
0000000000000000 0000000000000000
[ 4.196000] stack_dump: 0xc0803ff0: 0000000000000000 00000000802101a2
0000000000000000 0000000000000000 0000000000000000 0000000000000000
0000000000000000 0000000000000000
[ 4.196000] dump_tasks: PID GROUP PRI POLICY TYPE NPX STATE
EVENT SIGMASK STACKBASE STACKSIZE COMMAND
[ 4.196000] dump_tasks: ---- --- --- -------- ------- --- -------
---------- ---------------- 0x80607000 2048 irq
[ 4.196000] dump_task: 0 0 0 FIFO Kthread - Ready
0000000000000000 0x80609430 3024 Idle_Task
[ 4.196000] dump_task: 1 0 100 RR Kthread - Waiting
Semaphore 0000000000000000 0x8060c070 1936 lpwork 0x80600100 0x80600180
[ 4.196000] dump_task: 3 3 100 RR Task - Waiting
Signal 0000000000000000 0xc0802060 2976 /system/bin/init
[ 4.196000] dump_task: 4 4 100 RR Task - Running
0000000000000000 0xc0802050 8112 hello
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]