mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 21:07:34 -04:00
[rtl] Add security hardened PC
- Checks that PC increments as expected - Raises an alert if not Signed-off-by: Tom Roberts <tomroberts@lowrisc.org>
This commit is contained in:
parent
93d920118c
commit
03a8ae70d6
3 changed files with 49 additions and 3 deletions
|
@ -6,6 +6,13 @@ Security Features
|
|||
Ibex implements a set of extra features (when the SecureIbex parameter is set) to support security-critical applications.
|
||||
All features are runtime configurable via bits in the **cpuctrl** custom CSR.
|
||||
|
||||
Outputs
|
||||
-------
|
||||
|
||||
Ibex has two alert outputs for signalling security issues.
|
||||
The major alert (**alert_major_o**) indicates a critical security issue from which the core cannot recover.
|
||||
The minor alert (**alert_minor_o**) indicates potential security issues which can be monitored over time by a system.
|
||||
|
||||
Data Independent Timing
|
||||
-----------------------
|
||||
|
||||
|
@ -51,3 +58,11 @@ Register file ECC
|
|||
When Ibex is configured with the SecureIbex parameter, ECC checking is added to all reads of the register file.
|
||||
This can be useful to detect fault injection attacks since the register file covers a reasonably large area.
|
||||
No attempt is made to correct detected errors, but an external alert is raised for the system to take action.
|
||||
|
||||
Hardened PC
|
||||
-----------
|
||||
|
||||
This adds a check that the PC driven from the IF stage has not been modified.
|
||||
A check is asserted that the current IF stage PC equals the previous PC plus the correct increment.
|
||||
The check is disabled after branches and after reset.
|
||||
If a mismatch is detected, a major alert is signaled.
|
||||
|
|
|
@ -148,6 +148,7 @@ module ibex_core #(
|
|||
logic [31:0] dummy_instr_seed;
|
||||
logic icache_enable;
|
||||
logic icache_inval;
|
||||
logic pc_mismatch_alert;
|
||||
|
||||
logic instr_first_cycle_id;
|
||||
logic instr_valid_clear;
|
||||
|
@ -395,7 +396,8 @@ module ibex_core #(
|
|||
.DmExceptionAddr ( DmExceptionAddr ),
|
||||
.DummyInstructions ( DummyInstructions ),
|
||||
.ICache ( ICache ),
|
||||
.ICacheECC ( ICacheECC )
|
||||
.ICacheECC ( ICacheECC ),
|
||||
.SecureIbex ( SecureIbex )
|
||||
) if_stage_i (
|
||||
.clk_i ( clk ),
|
||||
.rst_ni ( rst_ni ),
|
||||
|
@ -452,6 +454,7 @@ module ibex_core #(
|
|||
// pipeline stalls
|
||||
.id_in_ready_i ( id_in_ready ),
|
||||
|
||||
.pc_mismatch_alert_o ( pc_mismatch_alert ),
|
||||
.if_busy_o ( if_busy )
|
||||
);
|
||||
|
||||
|
@ -844,7 +847,7 @@ module ibex_core #(
|
|||
assign alert_minor_o = 1'b0;
|
||||
|
||||
// Major alert - core is unrecoverable
|
||||
assign alert_major_o = rf_ecc_err_comb;
|
||||
assign alert_major_o = rf_ecc_err_comb | pc_mismatch_alert;
|
||||
|
||||
`ASSERT_KNOWN(IbexAlertMinorX, alert_minor_o)
|
||||
`ASSERT_KNOWN(IbexAlertMajorX, alert_major_o)
|
||||
|
|
|
@ -17,7 +17,8 @@ module ibex_if_stage #(
|
|||
parameter int unsigned DmExceptionAddr = 32'h1A110808,
|
||||
parameter bit DummyInstructions = 1'b0,
|
||||
parameter bit ICache = 1'b0,
|
||||
parameter bit ICacheECC = 1'b0
|
||||
parameter bit ICacheECC = 1'b0,
|
||||
parameter bit SecureIbex = 1'b0
|
||||
) (
|
||||
input logic clk_i,
|
||||
input logic rst_ni,
|
||||
|
@ -83,6 +84,7 @@ module ibex_if_stage #(
|
|||
input logic id_in_ready_i, // ID stage is ready for new instr
|
||||
|
||||
// misc signals
|
||||
output logic pc_mismatch_alert_o,
|
||||
output logic if_busy_o // IF stage is busy fetching instr
|
||||
);
|
||||
|
||||
|
@ -343,6 +345,32 @@ module ibex_if_stage #(
|
|||
end
|
||||
end
|
||||
|
||||
// Check for expected increments of the PC when security hardening enabled
|
||||
if (SecureIbex) begin : g_secure_pc
|
||||
logic [31:0] prev_instr_addr_incr;
|
||||
logic prev_instr_seq_q, prev_instr_seq_d;
|
||||
|
||||
// Do not check for sequential increase after a branch, jump, exception, interrupt or debug
|
||||
// request, all of which will set branch_req. Also do not check after reset.
|
||||
assign prev_instr_seq_d = (prev_instr_seq_q | instr_new_id_d) & ~branch_req;
|
||||
|
||||
always_ff @(posedge clk_i or negedge rst_ni) begin
|
||||
if (!rst_ni) begin
|
||||
prev_instr_seq_q <= 1'b0;
|
||||
end else begin
|
||||
prev_instr_seq_q <= prev_instr_seq_d;
|
||||
end
|
||||
end
|
||||
|
||||
assign prev_instr_addr_incr = pc_id_o + (instr_is_compressed_id_o ? 32'd2 : 32'd4);
|
||||
|
||||
// Check that the address equals the previous address +2/+4
|
||||
assign pc_mismatch_alert_o = prev_instr_seq_q & (pc_if_o != prev_instr_addr_incr);
|
||||
|
||||
end else begin : g_no_secure_pc
|
||||
assign pc_mismatch_alert_o = 1'b0;
|
||||
end
|
||||
|
||||
////////////////
|
||||
// Assertions //
|
||||
////////////////
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue