This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 1fc6f2bac89 arch/riscv: reject overlapping leaf PTE in riscv_fillpage
1fc6f2bac89 is described below
commit 1fc6f2bac89771a6d4586789998d94e4cc1f20ef
Author: liang.huang <[email protected]>
AuthorDate: Wed Jul 8 09:09:41 2026 +0800
arch/riscv: reject overlapping leaf PTE in riscv_fillpage
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.
Check the leaf PTE's valid bit before allocating; if a mapping already
exists, panic instead of overwriting it.
Signed-off-by: liang.huang <[email protected]>
---
arch/risc-v/src/common/riscv_exception.c | 25 ++++++++++++++++++++++---
1 file changed, 22 insertions(+), 3 deletions(-)
diff --git a/arch/risc-v/src/common/riscv_exception.c
b/arch/risc-v/src/common/riscv_exception.c
index bcfcd34f872..584db45c025 100644
--- a/arch/risc-v/src/common/riscv_exception.c
+++ b/arch/risc-v/src/common/riscv_exception.c
@@ -201,9 +201,7 @@ int riscv_fillpage(int mcause, void *regs, void *args)
else
{
_alert("PANIC!!! virtual address not mappable: %" PRIxPTR "\n", vaddr);
- up_irq_save();
- up_set_interrupt_context(true);
- PANIC_WITH_REGS("panic", regs);
+ goto access_fault;
}
satp = READ_CSR(CSR_SATP);
@@ -234,6 +232,21 @@ int riscv_fillpage(int mcause, void *regs, void *args)
}
ptlast = riscv_pgvaddr(paddr);
+
+ /* LOADPF/STOREPF is also raised when the leaf PTE already exists but its
+ * permission bits don't satisfy the access (e.g. a store to a .text page
+ * whose write access was revoked). That is not a fault this function
+ * should handle: allocating a fresh page here would silently discard the
+ * existing mapping's page.
+ */
+
+ if (mmu_ln_getentry(ARCH_PGT_MAX_LEVELS, ptlast, vaddr) & PTE_VALID)
+ {
+ _alert("PANIC!!! page already mapped, permission violation: %"
+ PRIxPTR "\n", vaddr);
+ goto access_fault;
+ }
+
paddr = mm_pgalloc(1);
if (!paddr)
{
@@ -249,6 +262,12 @@ int riscv_fillpage(int mcause, void *regs, void *args)
mmu_ln_setentry(ARCH_PGT_MAX_LEVELS, ptlast, paddr, vaddr, mmuflags);
return 0;
+
+access_fault:
+ up_irq_save();
+ up_set_interrupt_context(true);
+ PANIC_WITH_REGS("panic", regs);
+ return -EINVAL;
}
#endif /* CONFIG_PAGING */