Unauthorized Error Injection Can Degrade Hardware Redundancy

Description

Unauthorized Error Injection Can Degrade Hardware Redundancy occurs when an unauthorized agent can inject errors into a redundant block to deprive the system of redundancy or put the system in a degraded operating mode. Hardware designers implement redundant blocks to maintain performance and reliability when primary components fail. However, if the design permits unauthorized parties to inject errors into these redundant systems, they can disable backup pathways, forcing the system into degraded operational states and potentially enabling subsequent attacks.

Risk

Unauthorized error injection has severe implications. Redundancy eliminated enabling single-point failures. Safety margins removed. Fault tolerance defeated. System reliability degraded. Subsequent attacks enabled. Denial of service through induced failures. Quality degradation. Performance impact. Resource consumption increase. High likelihood when error injection interfaces lack access control.

Solution

Prevent error injection during normal runtime during architecture and design phase. Implement access controls on error-injection interfaces. Disallow error injection in standard operation modes during implementation phase. Add access controls to error-injection mechanisms. Layer access controls over unprotected interfaces during integration phase.

Common Consequences

ImpactDetails
AvailabilityScope: Availability

Denial of service through system crashes, restarts, and instability.
IntegrityScope: Integrity

Quality degradation and reduced performance through disabled redundancy.

Example Code

Vulnerable Code

// Vulnerable: Redundant system without error injection protection

module vulnerable_redundant_system (
    input  wire        clk,
    input  wire        rst_n,

    // Primary and redundant computation paths
    input  wire [31:0] data_in,
    input  wire        compute_start,

    // Error injection interface (VULNERABLE: no protection)
    input  wire        inject_error_primary,
    input  wire        inject_error_redundant,
    input  wire [7:0]  error_pattern,

    output reg  [31:0] result,
    output reg         result_valid,
    output reg         redundancy_mismatch
);

    reg [31:0] primary_result;
    reg [31:0] redundant_result;

    // Primary computation path
    always @(posedge clk) begin
        if (compute_start) begin
            primary_result <= compute_function(data_in);

            // VULNERABLE: Error can be injected without authorization
            if (inject_error_primary) begin
                primary_result <= primary_result ^ {24'b0, error_pattern};
            end
        end
    end

    // Redundant computation path
    always @(posedge clk) begin
        if (compute_start) begin
            redundant_result <= compute_function(data_in);

            // VULNERABLE: Error injection to redundant path
            if (inject_error_redundant) begin
                redundant_result <= redundant_result ^ {24'b0, error_pattern};
            end
        end
    end

    // Comparison logic
    always @(posedge clk) begin
        redundancy_mismatch <= (primary_result != redundant_result);

        if (!redundancy_mismatch) begin
            result <= primary_result;
            result_valid <= 1'b1;
        end else begin
            // System enters degraded mode
            result_valid <= 1'b0;
        end
    end

    // Attack:
    // 1. Inject continuous errors to redundant path
    // 2. System sees constant mismatch
    // 3. Redundancy appears failed
    // 4. System operates in degraded mode
    // 5. Single fault now causes complete failure

endmodule

// Vulnerable: ECC memory without error injection protection
module vulnerable_ecc_memory (
    input  wire        clk,
    input  wire        rst_n,
    input  wire [15:0] addr,
    input  wire [31:0] data_in,
    input  wire        write_en,
    input  wire        read_en,

    // VULNERABLE: Error injection for testing
    input  wire        inject_single_bit_error,
    input  wire        inject_multi_bit_error,
    input  wire [4:0]  error_bit_position,

    output reg  [31:0] data_out,
    output reg         single_bit_corrected,
    output reg         multi_bit_detected
);

    reg [38:0] memory [0:65535];  // 32 data + 7 ECC bits

    always @(posedge clk) begin
        if (write_en) begin
            memory[addr] <= {compute_ecc(data_in), data_in};
        end

        if (read_en) begin
            reg [38:0] raw_data = memory[addr];

            // VULNERABLE: Error injection without access control
            if (inject_single_bit_error) begin
                raw_data[error_bit_position] <= ~raw_data[error_bit_position];
            end

            if (inject_multi_bit_error) begin
                raw_data[error_bit_position] <= ~raw_data[error_bit_position];
                raw_data[error_bit_position + 1] <= ~raw_data[error_bit_position + 1];
            end

            // ECC decode
            {single_bit_corrected, multi_bit_detected, data_out} <= ecc_decode(raw_data);
        end
    end

    // Attack: Continuously inject multi-bit errors
    // System logs failures, may disable ECC protection
    // Memory now vulnerable to actual errors

endmodule

Fixed Code

// Fixed: Redundant system with protected error injection

module secure_redundant_system (
    input  wire        clk,
    input  wire        rst_n,

    // Primary and redundant computation paths
    input  wire [31:0] data_in,
    input  wire        compute_start,

    // Error injection interface (FIXED: protected)
    input  wire        inject_error_primary,
    input  wire        inject_error_redundant,
    input  wire [7:0]  error_pattern,
    input  wire        test_mode_enabled,      // FIXED: Lifecycle signal
    input  wire        privileged_access,      // FIXED: Access control
    input  wire        boot_complete,          // FIXED: Runtime indicator

    output reg  [31:0] result,
    output reg         result_valid,
    output reg         redundancy_mismatch,
    output reg         injection_denied
);

    reg [31:0] primary_result;
    reg [31:0] redundant_result;

    // FIXED: Error injection control
    wire error_injection_allowed = test_mode_enabled &&
                                   privileged_access &&
                                   !boot_complete;

    // Primary computation path
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            primary_result <= 32'b0;
            injection_denied <= 1'b0;
        end else if (compute_start) begin
            primary_result <= compute_function(data_in);
            injection_denied <= 1'b0;

            // FIXED: Error injection only in allowed modes
            if (inject_error_primary) begin
                if (error_injection_allowed) begin
                    primary_result <= primary_result ^ {24'b0, error_pattern};
                end else begin
                    // FIXED: Deny unauthorized injection
                    injection_denied <= 1'b1;
                end
            end
        end
    end

    // Redundant computation path (similar protection)
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            redundant_result <= 32'b0;
        end else if (compute_start) begin
            redundant_result <= compute_function(data_in);

            if (inject_error_redundant && error_injection_allowed) begin
                redundant_result <= redundant_result ^ {24'b0, error_pattern};
            end
        end
    end

    // FIXED: Comparison with injection attempt logging
    always @(posedge clk) begin
        redundancy_mismatch <= (primary_result != redundant_result);

        if (!redundancy_mismatch) begin
            result <= primary_result;
            result_valid <= 1'b1;
        end else begin
            result_valid <= 1'b0;
        end
    end

    // FIXED: Lock out test mode after boot
    always @(posedge boot_complete) begin
        // Test mode automatically disabled after boot
        // Error injection no longer possible
    end

endmodule

// Fixed: ECC memory with protected error injection
module secure_ecc_memory (
    input  wire        clk,
    input  wire        rst_n,
    input  wire [15:0] addr,
    input  wire [31:0] data_in,
    input  wire        write_en,
    input  wire        read_en,

    // FIXED: Protected error injection
    input  wire        inject_single_bit_error,
    input  wire        inject_multi_bit_error,
    input  wire [4:0]  error_bit_position,
    input  wire        test_mode,
    input  wire        secure_debug_enabled,   // FIXED: Debug authentication
    input  wire        manufacturing_mode,      // FIXED: Lifecycle

    output reg  [31:0] data_out,
    output reg         single_bit_corrected,
    output reg         multi_bit_detected,
    output reg         injection_blocked
);

    reg [38:0] memory [0:65535];

    // FIXED: Error injection only during manufacturing test
    wire injection_allowed = manufacturing_mode &&
                            (test_mode || secure_debug_enabled);

    // FIXED: Rate limiting for error injection
    reg [7:0] injection_count;
    localparam MAX_INJECTIONS = 100;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            injection_count <= 8'b0;
            injection_blocked <= 1'b0;
        end else begin
            injection_blocked <= 1'b0;

            if (write_en) begin
                memory[addr] <= {compute_ecc(data_in), data_in};
            end

            if (read_en) begin
                reg [38:0] raw_data;
                raw_data = memory[addr];

                // FIXED: Protected error injection
                if (inject_single_bit_error || inject_multi_bit_error) begin
                    if (injection_allowed && injection_count < MAX_INJECTIONS) begin
                        if (inject_single_bit_error) begin
                            raw_data[error_bit_position] = ~raw_data[error_bit_position];
                        end

                        if (inject_multi_bit_error) begin
                            raw_data[error_bit_position] = ~raw_data[error_bit_position];
                            raw_data[error_bit_position + 1] = ~raw_data[error_bit_position + 1];
                        end

                        injection_count <= injection_count + 1;
                    end else begin
                        // FIXED: Block unauthorized or excessive injection
                        injection_blocked <= 1'b1;
                    end
                end

                // ECC decode
                {single_bit_corrected, multi_bit_detected, data_out} <= ecc_decode(raw_data);
            end
        end
    end

    // FIXED: Lock injection capability in production
    always @(posedge clk) begin
        if (!manufacturing_mode) begin
            injection_count <= MAX_INJECTIONS;  // Effectively disable
        end
    end

endmodule

// Fixed: Redundancy manager with attack detection
module secure_redundancy_manager (
    input  wire        clk,
    input  wire        rst_n,

    // Redundant inputs
    input  wire [31:0] input_a,
    input  wire [31:0] input_b,
    input  wire [31:0] input_c,  // Triple modular redundancy
    input  wire        inputs_valid,

    // Status
    output reg  [31:0] voted_output,
    output reg         output_valid,
    output reg         single_failure,
    output reg         double_failure,
    output reg         attack_detected
);

    // FIXED: Track failure patterns to detect attacks
    reg [15:0] failure_history;
    reg [7:0] failure_count_a;
    reg [7:0] failure_count_b;
    reg [7:0] failure_count_c;

    localparam ATTACK_THRESHOLD = 10;  // Failures in window

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            failure_history <= 16'b0;
            failure_count_a <= 8'b0;
            failure_count_b <= 8'b0;
            failure_count_c <= 8'b0;
            attack_detected <= 1'b0;
        end else if (inputs_valid) begin
            // Triple modular redundancy voting
            reg match_ab = (input_a == input_b);
            reg match_bc = (input_b == input_c);
            reg match_ac = (input_a == input_c);

            // FIXED: Track which channels fail
            if (!match_ab && !match_ac) failure_count_a <= failure_count_a + 1;
            if (!match_ab && !match_bc) failure_count_b <= failure_count_b + 1;
            if (!match_ac && !match_bc) failure_count_c <= failure_count_c + 1;

            // FIXED: Detect attack pattern (consistent failures on one channel)
            if (failure_count_a > ATTACK_THRESHOLD ||
                failure_count_b > ATTACK_THRESHOLD ||
                failure_count_c > ATTACK_THRESHOLD) begin
                attack_detected <= 1'b1;
            end

            // Voting logic
            if (match_ab || match_ac) begin
                voted_output <= input_a;
                output_valid <= 1'b1;
                single_failure <= !(match_ab && match_ac && match_bc);
                double_failure <= 1'b0;
            end else if (match_bc) begin
                voted_output <= input_b;
                output_valid <= 1'b1;
                single_failure <= 1'b1;
                double_failure <= 1'b0;
            end else begin
                // All three disagree
                output_valid <= 1'b0;
                double_failure <= 1'b1;
            end
        end
    end

    // FIXED: Periodic reset of failure counters (sliding window)
    reg [15:0] window_counter;
    localparam WINDOW_SIZE = 10000;

    always @(posedge clk) begin
        window_counter <= window_counter + 1;
        if (window_counter >= WINDOW_SIZE) begin
            window_counter <= 16'b0;
            failure_count_a <= failure_count_a >> 1;  // Decay
            failure_count_b <= failure_count_b >> 1;
            failure_count_c <= failure_count_c >> 1;
        end
    end

endmodule

CVE Examples

  • CVE-2019-11135: TSX Asynchronous Abort (TAA) allowed error injection affecting CPU redundancy mechanisms.
  • CVE-2020-0549: L1D Eviction Sampling vulnerability exploitable through error injection.

  • CWE-284: Improper Access Control (parent)
  • CWE-1198: Privilege Separation and Access Control Issues (category)
  • CAPEC-624: Hardware Fault Injection
  • CAPEC-625: Mobile Device Fault Injection

References

  1. MITRE Corporation. "CWE-1334: Unauthorized Error Injection Can Degrade Hardware Redundancy." https://cwe.mitre.org/data/definitions/1334.html
  2. IEEE. "Fault Tolerance in Digital Systems"
  3. NASA. "Fault Tolerant Design Handbook"