diff --git a/doc/security.rst b/doc/security.rst index 6c06682e..f45d71ac 100644 --- a/doc/security.rst +++ b/doc/security.rst @@ -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. diff --git a/rtl/ibex_core.sv b/rtl/ibex_core.sv index 9c6d9a04..370d1a01 100644 --- a/rtl/ibex_core.sv +++ b/rtl/ibex_core.sv @@ -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) diff --git a/rtl/ibex_if_stage.sv b/rtl/ibex_if_stage.sv index dac78365..6b74c2e6 100644 --- a/rtl/ibex_if_stage.sv +++ b/rtl/ibex_if_stage.sv @@ -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 // ////////////////