Skip to content

[Bug] PMP cfg reset/readback exposes reserved R/W encoding after reset #3814

Description

@jf-cc727

Bug Description

Official Rocket Chip master can expose a reserved PMP permission encoding on the first machine-mode read of pmpcfg0 after reset.

The minimal PoC reads pmpcfg0, scans each 8-bit PMP configuration byte, and fails if any byte has R=0 and W=1. In the official Verilator emulator run with fixed seed 1, the first application instruction reads:

pmpcfg0 = 0x0007060404030601

The bytes pmp1cfg = 0x06 and pmp5cfg = 0x06 have low R/W bits 0b10, i.e. R=0 and W=1.

This issue intentionally keeps the impact wording conservative. The observed offending entries have A=0, so they are inactive immediately after reset. The issue is that the CSR-visible architectural state exposes a reserved PMP R/W encoding, not that this PoC proves an immediate PMP bypass.

Upstream version confirmation: this issue was validated against the official Rocket Chip master line at revision v1.6-819-g55bcad0f5, confirmed at commit 55bcad0f59436de98ea510334121de8546b9e9d7, using freechips.rocketchip.system.DefaultConfig. No fix revision has been identified yet.

RISC-V Specification Requirement

The RISC-V Privileged ISA, Section 3.1.7.1. Physical Memory Protection CSRs, gives the relevant PMP CSR rules:

  • PMP entries are represented by 8-bit configuration registers plus address registers.
  • PMP CSR fields are WARL and may be read-only zero.
  • The R, W, and X fields are a collective WARL field.
  • The R=0,W=1 permission combination is reserved.

Figure 33 in the same section shows the PMP configuration byte layout.

Reference: RISC-V Privileged ISA v20260120, Machine-Level ISA, Physical Memory Protection CSRs

Because pmpcfg0 is software-visible architectural state, reset/init/readback should not expose the reserved R=0,W=1 encoding. A compliant implementation can reset the R/W/X bits to legal values, make them read-only zero, or otherwise legalize them consistently before they are visible.

Steps to Reproduce

Essential source:

csrr s0, pmpcfg0
mv   t0, s0
li   t1, 8

check_loop:
  andi t2, t0, 0xff
  andi t3, t2, 0x03
  li   t4, 0x02
  beq  t3, t4, fail_reserved_rw

Expected Result

The pmpcfg0 readback should contain only legal PMP R/W encodings. In particular, no PMP configuration byte should expose R=0,W=1.

Actual Result

Rocket reads back an illegal pmpcfg0 value on the very first application instruction:

15970:C0: 72672 [1] pc=[0000000080000000] W[r 8=0007060404030601][1] ... inst=[3a002473]

In that word, pmp1cfg = 0x06 and pmp5cfg = 0x06, so both bytes expose the reserved R=0,W=1 encoding.

The PoC then exits through the fail path:

*** FAILED *** (tohost = 93)
*** FAILED *** via dtm (code = 93, seed 1) after 95786 cycles

RK-1.zip

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