Skip to content

SecureIbex can issue a spurious data-dependent instruction fetch for a stalled branch #2509

Description

@jimmymtest

Observed Behavior

With SecureIbex=1, WritebackStage=1, BranchTargetALU=0, and runtime data-independent timing enabled, a branch held behind an outstanding writeback load produces an instruction fetch before the ID FSM reaches its target-calculation cycle.

For a not-taken beq x5,x6,+16 at PC 0x1000, with x5=0x100 and x6=0x20, the production decoder, ID controller/FSM, ALU, and prefetch buffer produce:

IBEX_SECURE_PENDING_REDIRECT first_cycle=1 branch_taken=0 target=000000e0 expected=00001004
IBEX_SECURE_INSTR_BUS redirect=000000e0 branch_taken=0 first_cycle=1
IBEX_SECURE_INSTR_BUS redirect=00001004 branch_taken=0 first_cycle=0
BUG_CONFIRMED: SecureIbex exposed a spurious instruction fetch to 0x000000e0 before correcting to PC+4 (0x00001004)

The test also runs the same pending not-taken branch with runtime data-independent timing disabled and observes no early redirect.

Expected Behavior

A branch blocked in its comparison cycle must not expose the comparison ALU result as an instruction address. In fixed-time mode, the not-taken redirect should be PC+4 after the registered branch decision is available.

Impact

The later redirect corrects architectural control flow, so this report does not claim that the branch finally retires to the wrong PC. The defect is the additional externally visible fetch to an address derived from rs1-rs2; it adds unintended instruction-bus traffic and exposes an operand-dependent address in a mode whose documented purpose is data-independent timing and power behavior.

Steps to reproduce the issue

I have provided some scripts to reproduce the bug. From this issue directory, run:

bash test/run.sh

Scripts: test.zip

My Environment

EDA tool and version: Verilator 5.020

Operating system: Linux x86_64

Version of the Ibex source code: 8b8ee086aef72e0833b7f0493d9d33e1f4d3c8e2

Root cause analysis

branch_set_raw_q captures branch_set_raw_d every cycle, while id_fsm_q advances only when instr_executing is true. An outstanding writeback memory access suppresses instr_executing but not the branch-set register update. With data-independent timing enabled, branch_set_raw_d is asserted even for a not-taken branch, so the controller raises pc_set_o while the decoder still selects the first-cycle comparison operands. The source already contains a comment that this register should be qualified with instr_executing.

Possible fix

Qualify the branch_set_raw_q update with instr_executing, consistent with the ID FSM update, or otherwise suppress branch_set until the branch target operands are selected. Add a regression asserting that a blocked first-cycle branch cannot issue an instruction request using the comparison result.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions