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
| Impact | Details |
|---|---|
| Availability | Scope: Availability DoS: Crash, Exit, or Restart - SEU-induced errors may require system restart or cause instability. |
| Availability | Scope: Availability DoS: Instability - Accumulated errors can cause unpredictable behavior. |
| Access Control | Scope: Access Control Gain Privileges or Assume Identity - SEU bit flip in privilege register could elevate user to root. |
| Access Control | Scope: 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(¤t_privilege);
uint32_t privilege = majority_vote(¤t_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.
Related CWEs
- 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
- MITRE Corporation. "CWE-1261: Improper Handling of Single Event Upsets." https://cwe.mitre.org/data/definitions/1261.html
- Baumann, R. "Radiation-Induced Soft Errors in Advanced Semiconductor Technologies"
- NASA. "Single Event Effects Mitigation Techniques"