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 */
 

Reply via email to