Improper Lock Behavior After Power State Transition
Description
Improper Lock Behavior After Power State Transition occurs when register lock bit protection disables changes to system configuration once the bit is set, but these protections become programmable after power state transitions. Devices typically rely on trusted firmware or software to configure critical system resources and then lock them via a programmable lock bit. The problem occurs when lock bits become unlocked, protected register values reset, or locks become reprogrammable following power state transitions like entering or waking from low-power sleep modes. This creates a vulnerability window where attackers could modify protected configuration.
Risk
Lock behavior issues after power transitions have severe security implications. Security configurations may be reset to unlocked defaults. Protected registers may become writable after sleep. Attackers can force low-power transitions to clear locks. Boot security settings may be bypassed. Debug interfaces may be re-enabled after wake. Memory protection may be disabled. Firmware integrity checks may be circumvented. Critical system settings may be modified.
Solution
Review security lock bit protections across all supported power state transitions. Ensure locks persist or are securely re-established after power transitions. Initialize lock registers to locked (not unlocked) state on reset. Test lock programming flow and properties during pre-silicon and post-silicon validation including power transition scenarios. Implement lock state persistence across power states. Verify security configuration after wake from low-power modes.
Common Consequences
| Impact | Details |
|---|---|
| Access Control | Scope: Access Control Modify Memory - System configuration protected by lock bit can be modified after power state transitions, compromising access control. High likelihood. |
Example Code
Vulnerable Code
// Vulnerable: Locks reset to unlocked state after power transition
module vulnerable_power_lock (
input wire clk,
input wire reset_n,
input wire sleep_mode,
input wire wake_signal,
input wire [31:0] write_data,
input wire write_enable,
input wire set_lock,
output reg [31:0] config_register,
output reg [31:0] lock_register
);
reg power_state; // 0 = active, 1 = sleep
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
config_register <= 32'h0;
lock_register <= 32'h0; // VULNERABLE: Unlocked by default
power_state <= 1'b0;
end
else if (sleep_mode) begin
// Entering sleep mode
power_state <= 1'b1;
end
else if (wake_signal && power_state) begin
// VULNERABLE: Waking from sleep resets locks!
power_state <= 1'b0;
lock_register <= 32'h0; // Locks cleared on wake!
// Config preserved but now unprotected
end
else begin
// Normal operation
if (set_lock) begin
lock_register <= 32'hFFFFFFFF;
end
if (write_enable && lock_register == 32'h0) begin
config_register <= write_data;
end
end
end
// Attack scenario:
// 1. System boots, locks are set
// 2. Attacker triggers sleep mode
// 3. Attacker triggers wake
// 4. Locks are cleared, config is modifiable!
endmodule
// Vulnerable: Lock defaults to 0 (unlocked) on any reset
module vulnerable_reset_lock (
input wire clk,
input wire reset_n,
input wire power_on_reset,
input wire soft_reset,
input wire sleep_exit_reset,
input wire [31:0] write_data,
input wire write_enable,
output reg [31:0] protected_config,
output reg [31:0] lock_status
);
// Combined reset signal
wire any_reset = !reset_n | power_on_reset | soft_reset | sleep_exit_reset;
always @(posedge clk) begin
if (any_reset) begin
// VULNERABLE: All resets clear locks
lock_status <= 32'h0;
protected_config <= 32'h0;
end
else begin
if (write_enable && lock_status == 32'h0) begin
protected_config <= write_data;
end
end
end
endmodule
// Vulnerable: Firmware doesn't verify locks after power transition
void vulnerable_sleep_handler(void) {
// Save state and enter sleep
save_context();
enter_low_power_mode();
// ... system sleeps ...
// Wake up
restore_context();
// VULNERABLE: Doesn't verify security locks after wake
// Assumes locks are still set - they may not be!
continue_operation();
}
void vulnerable_init(void) {
// Configure and lock
configure_memory_protection();
set_security_locks();
// Assume locks persist - vulnerable assumption
}
Fixed Code
// Fixed: Locks persist across power state transitions
module secure_power_lock (
input wire clk,
input wire reset_n,
input wire power_on_reset, // Full power-on only
input wire sleep_mode,
input wire wake_signal,
input wire [31:0] write_data,
input wire write_enable,
input wire set_lock,
output reg [31:0] config_register,
output reg [31:0] lock_register,
output reg lock_violation
);
reg power_state;
reg [31:0] saved_config;
reg [31:0] saved_locks;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
// Only full reset clears everything
config_register <= 32'h0;
lock_register <= 32'hFFFFFFFF; // FIXED: Locked by default!
power_state <= 1'b0;
lock_violation <= 1'b0;
end
else if (sleep_mode && !power_state) begin
// Entering sleep - save state
power_state <= 1'b1;
saved_config <= config_register;
saved_locks <= lock_register;
end
else if (wake_signal && power_state) begin
// FIXED: Restore locks on wake, don't clear them
power_state <= 1'b0;
lock_register <= saved_locks;
config_register <= saved_config;
end
else begin
// Normal operation
// Lock can only transition to more restrictive
if (set_lock) begin
lock_register <= lock_register | 32'hFFFFFFFF;
end
if (write_enable) begin
if (lock_register == 32'h0) begin
config_register <= write_data;
end else begin
lock_violation <= 1'b1; // Log violation
end
end
end
end
endmodule
// Fixed: Locks default to locked, only power-on-reset clears
module secure_reset_lock (
input wire clk,
input wire reset_n,
input wire power_on_reset,
input wire soft_reset,
input wire sleep_exit_reset,
input wire [31:0] write_data,
input wire write_enable,
input wire set_lock,
output reg [31:0] protected_config,
output reg [31:0] lock_status
);
always @(posedge clk or negedge reset_n) begin
if (!reset_n || power_on_reset) begin
// Only power-on reset clears locks
lock_status <= 32'hFFFFFFFF; // Locked by default
protected_config <= 32'h0;
end
else if (soft_reset) begin
// Soft reset: preserve locks, optionally reset config
// lock_status preserved
// protected_config optionally preserved or reset based on policy
end
else if (sleep_exit_reset) begin
// Sleep exit: preserve both locks and config
// Everything preserved
end
else begin
// Normal operation
if (set_lock) begin
lock_status <= 32'hFFFFFFFF;
end
if (write_enable && lock_status == 32'h0) begin
protected_config <= write_data;
end
end
end
endmodule
// Fixed: Lock state preserved in always-on domain
module secure_always_on_lock (
input wire main_clk,
input wire always_on_clk,
input wire main_reset_n,
input wire power_on_reset,
input wire [31:0] write_data,
input wire write_enable,
input wire set_lock,
output wire [31:0] protected_config,
output wire lock_active
);
// Lock stored in always-on power domain
// Persists through main domain power cycles
reg lock_state_aon; // Always-on flip-flop
always @(posedge always_on_clk or negedge power_on_reset) begin
if (!power_on_reset) begin
lock_state_aon <= 1'b1; // Locked by default
end
else if (set_lock) begin
lock_state_aon <= 1'b1;
end
// Lock persists through sleep - no clear path
end
assign lock_active = lock_state_aon;
endmodule
// Fixed: Firmware verifies locks after power transitions
void secure_sleep_handler(void) {
// Save state
save_context();
// Verify locks before sleep
uint32_t locks_before = get_lock_status();
enter_low_power_mode();
// ... system sleeps ...
// Wake up
restore_context();
// FIXED: Verify locks after wake
uint32_t locks_after = get_lock_status();
if (locks_after != locks_before) {
// Locks changed during sleep - security violation!
log_security_event("Lock state changed after wake");
// Re-establish locks
restore_security_locks(locks_before);
// Verify restoration
if (get_lock_status() != locks_before) {
panic("Cannot restore security locks!");
}
}
// Verify protected config wasn't modified
verify_protected_configuration();
continue_operation();
}
void secure_init(void) {
// Check if this is power-on or resume
if (is_cold_boot()) {
// Full initialization
configure_memory_protection();
set_security_locks();
} else {
// Resuming from low power - verify locks
if (!verify_security_locks()) {
// Locks not set - re-initialize
log_warning("Security locks missing after resume");
configure_memory_protection();
set_security_locks();
}
}
// Final verification
if (!verify_all_security_settings()) {
panic("Security configuration invalid!");
}
}
// Verification function
bool verify_security_locks(void) {
uint32_t expected_locks = REQUIRED_LOCK_MASK;
uint32_t actual_locks = get_lock_status();
if ((actual_locks & expected_locks) != expected_locks) {
log_error("Missing locks: expected 0x%08X, got 0x%08X",
expected_locks, actual_locks);
return false;
}
// Test that locked registers cannot be written
uint32_t test_addr = LOCKED_CONFIG_REG;
uint32_t before = *(volatile uint32_t*)test_addr;
*(volatile uint32_t*)test_addr = ~before;
uint32_t after = *(volatile uint32_t*)test_addr;
if (after != before) {
log_error("Locked register was modified!");
return false;
}
return true;
}
CVE Examples
- Power state transition vulnerabilities have been found in various SoC designs where security locks were cleared or reset during sleep/wake cycles
- CAPEC-166: Force the System to Reset Values
Related CWEs
- CWE-667: Improper Locking (parent)
- CWE-1199: General Circuit and Logic Design Concerns (category member)
- CWE-1206: Power, Clock, Thermal, and Reset Concerns (category member)
- CWE-1231: Improper Prevention of Lock Bit Modification (related)
References
- MITRE Corporation. "CWE-1232: Improper Lock Behavior After Power State Transition." https://cwe.mitre.org/data/definitions/1232.html
- Hack@DAC'21 OpenPiton SoC Security Analysis
- Power Management Security Guidelines