Improper Handling of Faults that Lead to Instruction Skips
Description
Improper Handling of Faults that Lead to Instruction Skips occurs when the device is missing or incorrectly implements circuitry or sensors that detect and mitigate the skipping of security-critical CPU instructions when they occur. Operating condition changes can cause unexpected hardware behavior including instruction skipping. Security-sensitive conditional branches (like password verification) implemented as single CPU instructions become vulnerable when skipped, potentially reversing the branch logic. Attackers exploit this through fault injection techniques to manipulate hardware operating conditions.
Risk
Instruction skip vulnerabilities have severe implications. Security checks bypassed. Authentication defeated. Conditional branches reversed. Protection mechanisms circumvented. Unauthorized code execution. Arbitrary memory access. Privilege escalation enabled. Cryptographic operations corrupted. High likelihood when fault injection protections are absent.
Solution
Design safe-failure mechanisms for out-of-tolerance input conditions during architecture and design phase. Implement redundant operations with majority voting. Add fault detection canaries or monitoring circuits. Ensure mitigation strength accounts for detection latency. Design critical-secret wiping upon fault detection.
Common Consequences
| Impact | Details |
|---|---|
| Access Control | Scope: Access Control Protection mechanisms bypassed through instruction skip. |
| Integrity | Scope: Integrity Execution logic altered enabling unauthorized actions. |
| Authentication | Scope: Authentication Authentication checks skipped allowing unauthorized access. |
| Confidentiality | Scope: Confidentiality Data protection bypassed through skipped security checks. |
Example Code
Vulnerable Code
// Vulnerable: Single-instruction security check
#include <stdint.h>
#include <stdbool.h>
// VULNERABLE: Single comparison instruction
bool vulnerable_verify_password(const char* input, const char* stored) {
// VULNERABLE: strcmp compiles to single comparison
// Fault injection can skip this, making result always equal
if (strcmp(input, stored) != 0) {
return false; // Can be skipped!
}
return true;
}
// VULNERABLE: Single conditional branch
bool vulnerable_check_signature(uint8_t* data, uint8_t* sig) {
uint8_t computed[32];
sha256(data, strlen(data), computed);
// VULNERABLE: Single branch instruction
if (memcmp(computed, sig, 32) != 0) {
return false; // This instruction can be skipped!
}
return true;
// Attack: Fault injection skips the "return false"
// Invalid signature is accepted
}
// VULNERABLE: Security check with single branch
void vulnerable_secure_boot(void) {
uint8_t* firmware = load_firmware();
uint8_t* signature = load_signature();
// VULNERABLE: Single conditional
if (!verify_signature(firmware, signature)) {
halt_system(); // Can be skipped!
}
// If halt is skipped, unsigned firmware executes
execute_firmware(firmware);
}
// VULNERABLE: Access control with single check
int vulnerable_read_secret(int user_privilege) {
// VULNERABLE: Single branch
if (user_privilege < ADMIN_LEVEL) {
return ERROR_ACCESS_DENIED; // Skippable!
}
return secret_data;
}
// Vulnerable: Hardware without fault detection
module vulnerable_security_check (
input wire clk,
input wire rst_n,
input wire [31:0] password_input,
input wire [31:0] password_stored,
input wire check_password,
output reg access_granted
);
// VULNERABLE: Single comparison
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
access_granted <= 1'b0;
end else if (check_password) begin
// VULNERABLE: Single comparison susceptible to glitch
if (password_input == password_stored) begin
access_granted <= 1'b1;
end else begin
access_granted <= 1'b0;
end
end
end
// Attack: Glitch during comparison
// Comparison skipped, access_granted gets unexpected value
endmodule
// Vulnerable: No voltage/clock glitch detection
module vulnerable_processor (
input wire clk,
input wire rst_n,
input wire [31:0] instruction,
// No glitch detection inputs!
output reg [31:0] result
);
// VULNERABLE: No monitoring of operating conditions
// Voltage glitch can cause instruction skip
always @(posedge clk) begin
// Execute instruction normally
// No fault detection
case (instruction[31:24])
8'h00: result <= instruction[23:0]; // MOV
8'h01: result <= result + instruction[23:0]; // ADD
// Security-critical conditional can be skipped
8'hFF: if (instruction[0]) result <= 32'hDEAD; // Branch
endcase
end
endmodule
Fixed Code
// Fixed: Fault-resistant security checks
#include <stdint.h>
#include <stdbool.h>
// FIXED: Redundant verification with multiple checks
bool secure_verify_password(const char* input, const char* stored) {
volatile int result1, result2, result3;
// FIXED: Multiple redundant comparisons
result1 = strcmp(input, stored);
result2 = strcmp(input, stored);
result3 = strcmp(input, stored);
// FIXED: Majority voting
int match_count = 0;
if (result1 == 0) match_count++;
if (result2 == 0) match_count++;
if (result3 == 0) match_count++;
// FIXED: All three must agree
if (match_count != 3 && match_count != 0) {
// FIXED: Fault detected - results inconsistent
fault_detected();
return false;
}
return (match_count == 3);
}
// FIXED: Redundant signature verification
bool secure_check_signature(uint8_t* data, uint8_t* sig) {
uint8_t computed1[32], computed2[32];
// FIXED: Compute hash twice
sha256(data, strlen(data), computed1);
sha256(data, strlen(data), computed2);
// FIXED: Verify redundant computations match
if (memcmp(computed1, computed2, 32) != 0) {
fault_detected();
return false;
}
// FIXED: Multiple comparison methods
volatile int cmp1 = memcmp(computed1, sig, 32);
volatile int cmp2 = secure_compare(computed1, sig, 32);
volatile int cmp3 = memcmp(computed2, sig, 32);
// FIXED: Check consistency
if (!((cmp1 == 0 && cmp2 == 0 && cmp3 == 0) ||
(cmp1 != 0 && cmp2 != 0 && cmp3 != 0))) {
fault_detected();
return false;
}
return (cmp1 == 0);
}
// FIXED: Secure boot with redundant checks
void secure_boot_protected(void) {
uint8_t* firmware = load_firmware();
uint8_t* signature = load_signature();
// FIXED: Multiple verification passes
volatile bool pass1 = verify_signature(firmware, signature);
volatile bool pass2 = verify_signature(firmware, signature);
volatile bool pass3 = verify_signature(firmware, signature);
// FIXED: Flow integrity variable
volatile uint32_t flow_check = 0;
if (!pass1) flow_check |= 0x01;
if (!pass2) flow_check |= 0x02;
if (!pass3) flow_check |= 0x04;
// FIXED: Verify all checks ran and agreed
if (flow_check != 0x00 && flow_check != 0x07) {
// Inconsistent results - fault detected
fault_detected();
secure_halt();
}
if (flow_check == 0x07) {
// All verifications failed
secure_halt();
}
// FIXED: Additional canary check before execution
if (flow_check != 0x00 || !pass1 || !pass2 || !pass3) {
secure_halt();
}
execute_firmware(firmware);
}
// FIXED: Access control with redundancy
int secure_read_secret(int user_privilege) {
volatile int priv1 = user_privilege;
volatile int priv2 = user_privilege;
// FIXED: Double-check with canary
volatile uint32_t canary = 0xDEADBEEF;
int check1 = (priv1 >= ADMIN_LEVEL);
int check2 = (priv2 >= ADMIN_LEVEL);
// FIXED: Verify canary wasn't corrupted
if (canary != 0xDEADBEEF) {
fault_detected();
return ERROR_FAULT_DETECTED;
}
// FIXED: Both checks must agree
if (check1 != check2) {
fault_detected();
return ERROR_FAULT_DETECTED;
}
if (!check1) {
return ERROR_ACCESS_DENIED;
}
return secret_data;
}
// Fixed: Hardware with fault detection and redundancy
module secure_security_check (
input wire clk,
input wire rst_n,
input wire [31:0] password_input,
input wire [31:0] password_stored,
input wire check_password,
// FIXED: Glitch detection inputs
input wire voltage_ok,
input wire clock_ok,
input wire temp_ok,
output reg access_granted,
output reg fault_detected
);
// FIXED: Redundant comparison registers
reg match1, match2, match3;
reg [31:0] password_copy1, password_copy2;
// FIXED: Operating condition monitoring
wire conditions_ok = voltage_ok && clock_ok && temp_ok;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
access_granted <= 1'b0;
fault_detected <= 1'b0;
match1 <= 1'b0;
match2 <= 1'b0;
match3 <= 1'b0;
end else begin
fault_detected <= 1'b0;
// FIXED: Check operating conditions
if (!conditions_ok) begin
fault_detected <= 1'b1;
access_granted <= 1'b0;
end else if (check_password) begin
// FIXED: Redundant comparisons
password_copy1 <= password_input;
password_copy2 <= password_input;
match1 <= (password_input == password_stored);
match2 <= (password_copy1 == password_stored);
match3 <= (password_copy2 == password_stored);
// FIXED: Majority voting with consistency check
if (match1 && match2 && match3) begin
access_granted <= 1'b1;
end else if (!match1 && !match2 && !match3) begin
access_granted <= 1'b0;
end else begin
// FIXED: Inconsistent results = fault
fault_detected <= 1'b1;
access_granted <= 1'b0;
end
end
end
end
endmodule
// Fixed: Processor with glitch detection
module secure_processor (
input wire clk,
input wire rst_n,
input wire [31:0] instruction,
// FIXED: Glitch detection signals
input wire voltage_monitor_ok,
input wire clock_monitor_ok,
input wire [11:0] temperature,
output reg [31:0] result,
output reg fault_detected
);
// FIXED: Temperature thresholds
localparam TEMP_LOW = 12'h100;
localparam TEMP_HIGH = 12'hD00;
// FIXED: Combined condition check
wire conditions_safe = voltage_monitor_ok &&
clock_monitor_ok &&
(temperature > TEMP_LOW) &&
(temperature < TEMP_HIGH);
// FIXED: Instruction execution with monitoring
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
result <= 32'b0;
fault_detected <= 1'b0;
end else begin
// FIXED: Block execution if conditions unsafe
if (!conditions_safe) begin
fault_detected <= 1'b1;
result <= 32'b0; // Safe output
end else begin
fault_detected <= 1'b0;
case (instruction[31:24])
8'h00: result <= instruction[23:0];
8'h01: result <= result + instruction[23:0];
8'hFF: begin
// FIXED: Security branch with redundant check
if (instruction[0] && instruction[0]) begin
result <= 32'hDEAD;
end
end
default: result <= result;
endcase
end
end
end
endmodule
CVE Examples
- CVE-2019-15894: Fault injection bypassing verification mode enabling arbitrary code execution.
- CVE-2020-0069: Instruction skip allowing secure boot bypass in MediaTek processors.
Related CWEs
- CWE-1384: Improper Handling of Physical or Environmental Conditions (parent)
- CWE-1247: Improper Protection Against Voltage and Clock Glitches (related)
- CWE-1206: Power, Clock, Thermal, and Reset Concerns (category)
- CWE-1388: Physical Access Issues and Concerns (category)
- CAPEC-624: Hardware Fault Injection
- CAPEC-625: Mobile Device Fault Injection
References
- MITRE Corporation. "CWE-1332: Improper Handling of Faults that Lead to Instruction Skips." https://cwe.mitre.org/data/definitions/1332.html
- Riscure. "Fault Injection Attacks and Countermeasures"
- ARM. "Security Considerations for Cortex-M Processors"