[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:
Tom Roberts 2020-06-29 14:09:44 +01:00 committed by Tom Roberts
parent 93d920118c
commit 03a8ae70d6
3 changed files with 49 additions and 3 deletions

View file

@ -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.

View file

@ -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)

View file

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