Skip to content

[BUG] Instruction fetch bypasses PTE X permission when the UseSharedTlb is enabled #3573

Description

@YangKefan-rk

Code of Conduct

  • I have searched the existing bug issues.
  • I am a human engaging in an interpersonal interaction. During this interaction, my words are my own and are not generated. If relevant, I provide links to my sources.

CVA6 commit affected

81245a4

Bug Description

With UseSharedTlb=1, a load can populate the shared TLB with a readable but non-executable mapping (R=1, X=0). A subsequent instruction fetch from the same virtual page can reuse this mapping without checking its execute permission.

In cva6_mmu.sv, iaccess_err checks the PTE U bit against the current privilege level, but does not check itlb_content.x. The ITLB-hit path therefore does not reject a non-executable mapping when the privilege check passes.

With UseSharedTlb=0, ITLB refills come from instruction page-table walks, where the PTW checks pte.x and rejects X=0 mappings before filling the ITLB. With UseSharedTlb=1, this check is bypassed when an instruction-side miss is satisfied by an existing shared-TLB entry. In cva6_shared_tlb.sv, the matching entry is copied into the ITLB without checking X or distinguishing whether the entry was originally populated by a data access.

The resulting path is:

Load from an R=1, X=0 page
  -> Data page-table walk succeeds
  -> Mapping is installed in the shared TLB
  -> Instruction fetch from the same virtual page misses in the ITLB
  -> Shared-TLB hit fills the ITLB without an X check
  -> ITLB hit passes the U-bit check and accepts the translation

Under the RISC-V virtual-memory translation rules, an instruction fetch from a leaf PTE with X=0 must raise an instruction page fault, regardless of whether the translation comes from a page-table walk or a cached entry.

Specification:

RISC-V Supervisor-Level ISA

Affected source, checked:

Steps to reproduce

Reproduced with Verilator 5.036 under cv64a6_imafdch_sv39 (RVH=1, UseSharedTlb=1).

Spike  a0 = 0xc  (cause=12, INSTR_PAGE_FAULT)   ✓
RTL    a0 = 0x2  (cause=2,  INSTR_ACCESS_FAULT)  ✗

A simple program would reproduce the issue by performing the following steps:

  1. Set up a leaf PTE covering a 4 KiB page with R=1, W=1, X=0, U=0, A=1, D=1.
  2. From S-mode, perform a load from a virtual address that maps to this page. The load succeeds because R=1. The shared TLB now holds this translation, including X=0.
  3. From S-mode, attempt to fetch an instruction from the same page. Because the shared TLB already holds the translation, the ITLB hit path is taken and the PTW is not re-invoked.

Expected behavior

INSTR_PAGE_FAULT (mcause = 12), because X=0 on the PTE forbids instruction fetch.

Observed behavior

INSTR_ACCESS_FAULT (mcause = 2) in this case, or no fault is raised at all. On a cold TLB miss the PTW path correctly enforces the X bit; the bug is exclusive to the warm shared TLB hit path.

Activity

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

    Component:RTLFor issues in the RTL (e.g. for files in the rtl directory)PARAM:MMUMMU relatedStatus:NewNewly created issue, nobody has looked at it yet.Type:BugFor bugs in the RTL, Documentation, Verification environment or Tool and Build systemnotCV32A65XIt is not an CV32A65X issue

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions