Improper Handling of Single Event Upsets

Description

Improper Handling of Single Event Upsets occurs when hardware logic does not effectively handle when single-event upsets (SEUs) occur. Modern semiconductor trends—including transistor down-sizing, new materials, and system-on-chip designs—increase system sensitivity to soft errors. Single-event upsets are temporary bit flips caused by charged particles ionizing circuit materials, creating electron-hole pairs that cause transient failures. When these occur in security-sensitive modules, they can compromise chip security guarantees, such as elevating user privileges to root access.

Risk

SEUs in security hardware have severe implications. Privilege levels may be corrupted. Access control bits may flip. Cryptographic operations may produce wrong results. Security state machines may enter invalid states. Authentication decisions may be corrupted. Boot security may be bypassed. Keys stored in SRAM may be modified. System integrity may be silently compromised.

Solution

Implement triple-modular redundancy (TMR) around security-sensitive modules. For SRAMs storing security-critical data, deploy Error-Correcting Codes (ECC) and Address Interleaving. Use parity checking for error detection. Implement redundant voting logic for critical decisions. Design for fail-secure behavior when errors are detected. Add scrubbing mechanisms to correct errors before accumulation. Consider radiation-hardened designs for critical applications.

Common Consequences

ImpactDetails
AvailabilityScope: Availability

DoS: Crash, Exit, or Restart - SEU-induced errors may require system restart or cause instability.
AvailabilityScope: Availability

DoS: Instability - Accumulated errors can cause unpredictable behavior.
Access ControlScope: Access Control

Gain Privileges or Assume Identity - SEU bit flip in privilege register could elevate user to root.
Access ControlScope: Access Control

Bypass Protection Mechanism - Security checks may be bypassed by bit flips.

Example Code

Vulnerable Code

// Vulnerable: Security logic without SEU protection

module vulnerable_privilege_controller (
    input wire clk,
    input wire reset_n,
    input wire [1:0] requested_privilege,
    input wire privilege_request,
    input wire authenticate_success,
    output reg [1:0] current_privilege,
    output reg privilege_granted
);

    // Privilege levels
    parameter USER = 2'b00;
    parameter SUPERVISOR = 2'b01;
    parameter HYPERVISOR = 2'b10;
    parameter SECURE = 2'b11;

    // VULNERABLE: Single register stores privilege level
    // SEU bit flip: 00 (USER) -> 11 (SECURE)
    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            current_privilege <= USER;
            privilege_granted <= 1'b0;
        end
        else if (privilege_request && authenticate_success) begin
            current_privilege <= requested_privilege;
            privilege_granted <= 1'b1;
        end
    end

    // VULNERABLE: No detection of SEU-induced corruption
    // If cosmic ray flips current_privilege from 00 to 11,
    // user gains secure privilege without authentication

endmodule

// Vulnerable: Security decision without redundancy
module vulnerable_access_check (
    input wire clk,
    input wire reset_n,
    input wire access_request,
    input wire [1:0] requester_privilege,
    input wire [1:0] required_privilege,
    output reg access_granted
);

    // VULNERABLE: Single comparison for security decision
    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            access_granted <= 1'b0;
        end
        else if (access_request) begin
            // VULNERABLE: SEU could flip result of comparison
            access_granted <= (requester_privilege >= required_privilege);
        end
    end

    // VULNERABLE: No redundancy to detect/correct error

endmodule

// Vulnerable: SRAM without ECC for security data
module vulnerable_key_storage (
    input wire clk,
    input wire reset_n,
    input wire [7:0] addr,
    input wire [127:0] write_data,
    input wire write_enable,
    input wire read_enable,
    output reg [127:0] read_data
);

    // VULNERABLE: Plain SRAM without ECC
    reg [127:0] key_memory [0:255];

    always @(posedge clk) begin
        if (write_enable) begin
            key_memory[addr] <= write_data;
        end
        if (read_enable) begin
            // VULNERABLE: SEU could have flipped bits in stored key
            // No detection mechanism
            read_data <= key_memory[addr];
        end
    end

endmodule
// Vulnerable: Software without SEU protection

#include <stdint.h>

// VULNERABLE: Single variable stores privilege
volatile uint32_t current_privilege = PRIVILEGE_USER;

// VULNERABLE: No redundancy for security decisions
int vulnerable_check_access(uint32_t resource_id) {
    // If SEU flips current_privilege bits, check may pass incorrectly
    if (current_privilege >= get_required_privilege(resource_id)) {
        return ACCESS_GRANTED;
    }
    return ACCESS_DENIED;
}

// VULNERABLE: Parity only detects, cannot correct
typedef struct {
    uint32_t data;
    uint8_t parity;
} parity_protected_t;

uint32_t vulnerable_parity_read(parity_protected_t* value) {
    // Check parity
    uint8_t computed_parity = compute_parity(value->data);

    if (computed_parity != value->parity) {
        // VULNERABLE: Error detected but cannot correct
        // Must restart system - 2-3 minute downtime
        system_restart();
    }

    return value->data;
}

Fixed Code

// Fixed: Security logic with TMR (Triple Modular Redundancy)

module secure_privilege_controller (
    input wire clk,
    input wire reset_n,
    input wire [1:0] requested_privilege,
    input wire privilege_request,
    input wire authenticate_success,
    output reg [1:0] current_privilege,
    output reg privilege_granted,
    output reg seu_detected
);

    // Privilege levels
    parameter USER = 2'b00;
    parameter SUPERVISOR = 2'b01;
    parameter HYPERVISOR = 2'b10;
    parameter SECURE = 2'b11;

    // FIXED: Triple redundant privilege storage
    reg [1:0] privilege_a;
    reg [1:0] privilege_b;
    reg [1:0] privilege_c;

    // FIXED: Majority voting function
    function [1:0] majority_vote;
        input [1:0] a, b, c;
        begin
            majority_vote = (a & b) | (b & c) | (a & c);
        end
    endfunction

    // FIXED: Error detection
    wire error_detected = (privilege_a != privilege_b) ||
                          (privilege_b != privilege_c) ||
                          (privilege_a != privilege_c);

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            privilege_a <= USER;
            privilege_b <= USER;
            privilege_c <= USER;
            privilege_granted <= 1'b0;
            seu_detected <= 1'b0;
        end
        else begin
            // FIXED: Detect and report SEU
            seu_detected <= error_detected;

            if (privilege_request && authenticate_success) begin
                // Update all three copies
                privilege_a <= requested_privilege;
                privilege_b <= requested_privilege;
                privilege_c <= requested_privilege;
                privilege_granted <= 1'b1;
            end
            else if (error_detected) begin
                // FIXED: Self-correct using majority vote
                privilege_a <= majority_vote(privilege_a, privilege_b, privilege_c);
                privilege_b <= majority_vote(privilege_a, privilege_b, privilege_c);
                privilege_c <= majority_vote(privilege_a, privilege_b, privilege_c);
            end
        end
    end

    // FIXED: Output uses voted value
    assign current_privilege = majority_vote(privilege_a, privilege_b, privilege_c);

endmodule

// Fixed: Security decision with redundancy
module secure_access_check (
    input wire clk,
    input wire reset_n,
    input wire access_request,
    input wire [1:0] requester_privilege,
    input wire [1:0] required_privilege,
    output reg access_granted,
    output reg check_error
);

    // FIXED: Perform check three times with different logic
    wire check_a = (requester_privilege >= required_privilege);
    wire check_b = (requester_privilege[1] > required_privilege[1]) ||
                   ((requester_privilege[1] == required_privilege[1]) &&
                    (requester_privilege[0] >= required_privilege[0]));
    wire check_c = ~(requester_privilege < required_privilege);

    // FIXED: Majority vote on result
    wire voted_result = (check_a & check_b) | (check_b & check_c) | (check_a & check_c);

    // FIXED: Error detection
    wire checks_inconsistent = (check_a != check_b) || (check_b != check_c);

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            access_granted <= 1'b0;
            check_error <= 1'b0;
        end
        else if (access_request) begin
            if (checks_inconsistent) begin
                // FIXED: Error detected - fail secure
                check_error <= 1'b1;
                access_granted <= 1'b0;  // Deny on error
            end
            else begin
                check_error <= 1'b0;
                access_granted <= voted_result;
            end
        end
    end

endmodule

// Fixed: SRAM with ECC for security data
module secure_key_storage (
    input wire clk,
    input wire reset_n,
    input wire [7:0] addr,
    input wire [127:0] write_data,
    input wire write_enable,
    input wire read_enable,
    output reg [127:0] read_data,
    output reg ecc_error_corrected,
    output reg ecc_error_uncorrectable
);

    // FIXED: Store data with ECC (SECDED - Single Error Correct, Double Error Detect)
    // 128-bit data + 8-bit ECC = 136 bits per entry
    reg [135:0] key_memory [0:255];

    // ECC functions (simplified - real implementation uses proper Hamming code)
    function [7:0] compute_ecc;
        input [127:0] data;
        begin
            // Compute ECC syndrome
            compute_ecc = data[7:0] ^ data[15:8] ^ data[23:16] ^ data[31:24] ^
                         data[39:32] ^ data[47:40] ^ data[55:48] ^ data[63:56] ^
                         data[71:64] ^ data[79:72] ^ data[87:80] ^ data[95:88] ^
                         data[103:96] ^ data[111:104] ^ data[119:112] ^ data[127:120];
        end
    endfunction

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            read_data <= 128'h0;
            ecc_error_corrected <= 1'b0;
            ecc_error_uncorrectable <= 1'b0;
        end
        else begin
            ecc_error_corrected <= 1'b0;
            ecc_error_uncorrectable <= 1'b0;

            if (write_enable) begin
                // FIXED: Store data with ECC
                key_memory[addr] <= {compute_ecc(write_data), write_data};
            end

            if (read_enable) begin
                // FIXED: Read and check/correct ECC
                wire [127:0] stored_data = key_memory[addr][127:0];
                wire [7:0] stored_ecc = key_memory[addr][135:128];
                wire [7:0] computed_ecc = compute_ecc(stored_data);
                wire [7:0] syndrome = stored_ecc ^ computed_ecc;

                if (syndrome == 8'h00) begin
                    // No error
                    read_data <= stored_data;
                end
                else if (/* single bit error */) begin
                    // FIXED: Correct single-bit error
                    read_data <= correct_single_bit(stored_data, syndrome);
                    ecc_error_corrected <= 1'b1;
                    // Also scrub memory
                    key_memory[addr] <= {compute_ecc(read_data), read_data};
                end
                else begin
                    // FIXED: Uncorrectable error
                    ecc_error_uncorrectable <= 1'b1;
                    read_data <= 128'h0;  // Return zero, not corrupted data
                end
            end
        end
    end

    // FIXED: Background scrubbing to prevent error accumulation
    reg [7:0] scrub_addr;
    always @(posedge clk) begin
        // Periodically read and rewrite memory to correct any accumulated errors
        scrub_addr <= scrub_addr + 1;
        // Scrubbing logic would read, check ECC, correct, write back
    end

endmodule
// Fixed: Software with SEU protection

#include <stdint.h>

// FIXED: Triple-redundant privilege storage
typedef struct {
    uint32_t value_a;
    uint32_t value_b;
    uint32_t value_c;
} tmr_uint32_t;

static tmr_uint32_t current_privilege = {
    .value_a = PRIVILEGE_USER,
    .value_b = PRIVILEGE_USER,
    .value_c = PRIVILEGE_USER
};

// FIXED: Majority vote function
static uint32_t majority_vote(tmr_uint32_t* tmr) {
    // Bitwise majority
    return (tmr->value_a & tmr->value_b) |
           (tmr->value_b & tmr->value_c) |
           (tmr->value_a & tmr->value_c);
}

// FIXED: Check and correct SEU errors
static bool check_and_correct_tmr(tmr_uint32_t* tmr) {
    uint32_t voted = majority_vote(tmr);

    bool error = (tmr->value_a != tmr->value_b) ||
                 (tmr->value_b != tmr->value_c);

    if (error) {
        // Self-correct
        tmr->value_a = voted;
        tmr->value_b = voted;
        tmr->value_c = voted;
        log_seu_event("TMR correction applied");
    }

    return error;
}

// FIXED: Access check with redundancy
int secure_check_access(uint32_t resource_id) {
    // Check and correct any SEU errors first
    check_and_correct_tmr(&current_privilege);

    uint32_t privilege = majority_vote(&current_privilege);
    uint32_t required = get_required_privilege(resource_id);

    // FIXED: Perform check three times
    int result_a = (privilege >= required);
    int result_b = (privilege >= required);
    int result_c = (privilege >= required);

    // Memory barriers to prevent optimization
    __asm__ volatile("" ::: "memory");

    // Majority vote on results
    int voted_result = (result_a & result_b) | (result_b & result_c) | (result_a & result_c);

    // Check for inconsistency
    if ((result_a != result_b) || (result_b != result_c)) {
        log_seu_event("Access check inconsistency detected");
        return ACCESS_DENIED;  // Fail secure
    }

    return voted_result ? ACCESS_GRANTED : ACCESS_DENIED;
}

// FIXED: ECC-protected storage instead of parity
typedef struct {
    uint32_t data;
    uint32_t ecc;
} ecc_protected_t;

uint32_t secure_ecc_read(ecc_protected_t* value) {
    uint32_t computed_ecc = compute_hamming_ecc(value->data);
    uint32_t syndrome = computed_ecc ^ value->ecc;

    if (syndrome == 0) {
        // No error
        return value->data;
    }
    else if (is_single_bit_error(syndrome)) {
        // FIXED: Correct single-bit error
        uint32_t corrected = value->data ^ get_error_mask(syndrome);
        value->data = corrected;  // Scrub memory
        value->ecc = compute_hamming_ecc(corrected);
        log_seu_event("ECC correction applied");
        return corrected;
    }
    else {
        // Multi-bit error - cannot correct
        log_seu_event("Uncorrectable ECC error");
        // Return safe value or trigger recovery
        return SAFE_DEFAULT_VALUE;
    }
}

CVE Examples

  • A 2016 pacemaker incident involved a cosmic radiation-induced bit flip at aircraft altitude, triggering safe mode and enabling reverse engineering that exposed hard-coded cryptographic keys.
  • Various satellite and aerospace system failures attributed to SEU-induced bit flips in unprotected memory.

  • CWE-1384: Improper Handling of Physical or Environmental Conditions (parent)
  • CWE-1254: Incorrect Comparison Logic Granularity (peer)
  • CWE-1247: Improper Protection Against Voltage and Clock Glitches (related)

References

  1. MITRE Corporation. "CWE-1261: Improper Handling of Single Event Upsets." https://cwe.mitre.org/data/definitions/1261.html
  2. Baumann, R. "Radiation-Induced Soft Errors in Advanced Semiconductor Technologies"
  3. NASA. "Single Event Effects Mitigation Techniques"