Security-Sensitive Hardware Controls with Missing Lock Bit Protection
Description
Security-Sensitive Hardware Controls with Missing Lock Bit Protection occurs when a product implements register lock bit protection but fails to ensure the lock bit prevents modification of all system registers that could alter important hardware configuration. Hardware devices often use trusted lock bits to disable writes to protected register sets after initial firmware configuration. This weakness occurs when the lock bit does not effectively write-protect all system registers or controls that could modify the protected system configuration, allowing adversaries to bypass protections through unprotected related registers.
Risk
Missing lock bit protection for sensitive controls has severe security implications. Related configuration registers may be modifiable. Calibration data may be altered to affect protected functions. Indirect control paths may bypass locks. Safety-critical controls may be disabled. Security features may be circumvented through unprotected registers. System behavior may be modified through peripheral settings. Debug or test modes may be enabled. Power management controls may affect locked resources.
Solution
Identify all registers that can affect security-sensitive configuration. Ensure lock bits protect all related registers and controls. Review indirect paths to protected functionality. Test that locked configuration cannot be modified through any means. Document which registers are protected by each lock. Implement comprehensive lock coverage analysis. Verify lock effectiveness during security reviews. Consider transitive dependencies when designing locks.
Common Consequences
| Impact | Details |
|---|---|
| Access Control | Scope: Access Control Modify Memory - System configuration protected by lock bit can be modified through unprotected related registers, violating access control. |
Example Code
Vulnerable Code
// Vulnerable: Lock doesn't protect all related registers
module vulnerable_thermal_sensor (
input wire clk,
input wire reset_n,
input wire [31:0] write_data,
input wire write_enable,
input wire [7:0] register_select,
input wire set_lock,
output reg [31:0] critical_temp_limit, // Protected by lock
output reg [31:0] calibration_offset, // NOT protected by lock!
output reg shutdown_enable, // NOT protected by lock!
output reg sensor_locked,
output reg thermal_shutdown
);
reg [31:0] current_temperature;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
critical_temp_limit <= 32'd100; // 100 degrees
calibration_offset <= 32'd0;
shutdown_enable <= 1'b1;
sensor_locked <= 1'b0;
end
else begin
// Lock only protects critical_temp_limit
if (set_lock) begin
sensor_locked <= 1'b1;
end
if (write_enable) begin
case (register_select)
8'h00: begin
// Critical temp - protected by lock
if (!sensor_locked) begin
critical_temp_limit <= write_data;
end
end
8'h01: begin
// VULNERABLE: Calibration not protected!
// Attacker can offset temperature reading
calibration_offset <= write_data;
end
8'h02: begin
// VULNERABLE: Shutdown enable not protected!
// Attacker can disable thermal shutdown
shutdown_enable <= write_data[0];
end
endcase
end
end
end
// Thermal shutdown logic
wire [31:0] calibrated_temp = current_temperature + calibration_offset;
always @(posedge clk) begin
// Shutdown if calibrated temp exceeds limit AND enabled
thermal_shutdown <= (calibrated_temp > critical_temp_limit) && shutdown_enable;
end
// Attack: Even with critical_temp_limit locked at 100:
// 1. Set calibration_offset to -100 (reading always shows 0)
// 2. Or set shutdown_enable to 0 (never triggers shutdown)
endmodule
// Vulnerable: Memory protection with unprotected region config
module vulnerable_memory_protection (
input wire clk,
input wire reset_n,
input wire [31:0] write_data,
input wire write_enable,
input wire [7:0] register_select,
input wire set_lock,
output reg [31:0] protected_region_start, // Protected
output reg [31:0] protected_region_end, // Protected
output reg [31:0] region_attributes, // NOT protected!
output reg protection_locked
);
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
protected_region_start <= 32'h0;
protected_region_end <= 32'h0;
region_attributes <= 32'h0; // Read-only, no-execute, etc.
protection_locked <= 1'b0;
end
else begin
if (set_lock) begin
protection_locked <= 1'b1;
end
if (write_enable) begin
case (register_select)
8'h00: if (!protection_locked) protected_region_start <= write_data;
8'h01: if (!protection_locked) protected_region_end <= write_data;
8'h02: region_attributes <= write_data; // VULNERABLE: Not locked!
endcase
end
end
end
// Attack: Region boundaries are locked, but attributes aren't
// Change attributes to make protected region writable or executable
endmodule
// Vulnerable: Software assumes complete lock protection
#define CRITICAL_TEMP_REG 0x40002000
#define CALIBRATION_REG 0x40002004
#define SHUTDOWN_ENABLE_REG 0x40002008
#define LOCK_REG 0x4000200C
void vulnerable_thermal_init(void) {
// Set critical temperature
*(volatile uint32_t*)CRITICAL_TEMP_REG = 100;
// Set lock
*(volatile uint32_t*)LOCK_REG = 1;
// Assumes all thermal config is now protected
// But calibration and shutdown_enable are not!
}
// Attacker exploit
void thermal_bypass_attack(void) {
// Can't modify critical_temp - it's locked
// But can modify calibration!
*(volatile uint32_t*)CALIBRATION_REG = (uint32_t)-100;
// Or disable shutdown entirely
*(volatile uint32_t*)SHUTDOWN_ENABLE_REG = 0;
// System will overheat without protection
}
Fixed Code
// Fixed: Lock protects all related security controls
module secure_thermal_sensor (
input wire clk,
input wire reset_n,
input wire [31:0] write_data,
input wire write_enable,
input wire [7:0] register_select,
input wire set_lock,
output reg [31:0] critical_temp_limit,
output reg [31:0] calibration_offset,
output reg shutdown_enable,
output reg sensor_locked,
output reg thermal_shutdown
);
reg [31:0] current_temperature;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
critical_temp_limit <= 32'd100;
calibration_offset <= 32'd0;
shutdown_enable <= 1'b1; // Enabled by default
sensor_locked <= 1'b0;
end
else begin
if (set_lock) begin
sensor_locked <= 1'b1;
end
if (write_enable) begin
case (register_select)
8'h00: begin
// Critical temp - protected
if (!sensor_locked) begin
critical_temp_limit <= write_data;
end
end
8'h01: begin
// FIXED: Calibration protected by same lock
if (!sensor_locked) begin
calibration_offset <= write_data;
end
end
8'h02: begin
// FIXED: Shutdown enable protected by same lock
if (!sensor_locked) begin
shutdown_enable <= write_data[0];
end
end
endcase
end
end
end
// All security-relevant registers now protected
endmodule
// Fixed: Comprehensive protection with multiple lock domains
module secure_comprehensive_lock (
input wire clk,
input wire reset_n,
input wire [31:0] write_data,
input wire write_enable,
input wire [7:0] register_select,
input wire set_security_lock,
input wire set_config_lock,
// Security-critical registers
output reg [31:0] security_policy,
output reg [31:0] access_control,
output reg [31:0] debug_control,
// Configuration registers
output reg [31:0] peripheral_config,
output reg [31:0] power_config,
// Related controls that affect security
output reg [31:0] calibration,
output reg [31:0] timing_config,
// Lock status
output reg security_locked,
output reg config_locked
);
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
// Secure defaults
security_policy <= 32'hFFFFFFFF; // Most restrictive
access_control <= 32'h0;
debug_control <= 32'h0; // Debug disabled
peripheral_config <= 32'h0;
power_config <= 32'h0;
calibration <= 32'h0;
timing_config <= 32'h0;
security_locked <= 1'b0;
config_locked <= 1'b0;
end
else begin
// Lock bits
if (set_security_lock) security_locked <= 1'b1;
if (set_config_lock) config_locked <= 1'b1;
if (write_enable) begin
case (register_select)
// Security domain - requires security lock
8'h00: if (!security_locked) security_policy <= write_data;
8'h01: if (!security_locked) access_control <= write_data;
8'h02: if (!security_locked) debug_control <= write_data;
// Config domain - requires config lock
8'h10: if (!config_locked) peripheral_config <= write_data;
8'h11: if (!config_locked) power_config <= write_data;
// Calibration affects security - requires BOTH locks
8'h20: if (!security_locked && !config_locked) calibration <= write_data;
// Timing can affect security - requires security lock
8'h21: if (!security_locked) timing_config <= write_data;
endcase
end
end
end
endmodule
// Fixed: Lock coverage verification module
module lock_coverage_checker (
input wire clk,
input wire reset_n,
input wire security_locked,
input wire [31:0] security_policy,
input wire [31:0] calibration,
input wire [31:0] shutdown_enable,
output reg coverage_violation
);
// Shadow copies of protected values
reg [31:0] shadow_policy;
reg [31:0] shadow_calibration;
reg [31:0] shadow_shutdown;
reg shadow_valid;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
shadow_valid <= 1'b0;
coverage_violation <= 1'b0;
end
else if (security_locked && !shadow_valid) begin
// Capture values when lock is set
shadow_policy <= security_policy;
shadow_calibration <= calibration;
shadow_shutdown <= shutdown_enable;
shadow_valid <= 1'b1;
end
else if (shadow_valid) begin
// Verify all protected values remain unchanged
if (security_policy != shadow_policy ||
calibration != shadow_calibration ||
shutdown_enable != shadow_shutdown) begin
coverage_violation <= 1'b1; // Something changed that shouldn't!
end
end
end
endmodule
// Fixed: Verify complete lock coverage
#define CRITICAL_TEMP_REG 0x40002000
#define CALIBRATION_REG 0x40002004
#define SHUTDOWN_ENABLE_REG 0x40002008
#define LOCK_REG 0x4000200C
void secure_thermal_init(void) {
// Set all thermal config
*(volatile uint32_t*)CRITICAL_TEMP_REG = 100;
*(volatile uint32_t*)CALIBRATION_REG = 0;
*(volatile uint32_t*)SHUTDOWN_ENABLE_REG = 1;
// Set lock
*(volatile uint32_t*)LOCK_REG = 1;
// Verify ALL related registers are protected
verify_thermal_lock_coverage();
}
bool verify_thermal_lock_coverage(void) {
// Save current values
uint32_t saved_temp = *(volatile uint32_t*)CRITICAL_TEMP_REG;
uint32_t saved_cal = *(volatile uint32_t*)CALIBRATION_REG;
uint32_t saved_shutdown = *(volatile uint32_t*)SHUTDOWN_ENABLE_REG;
bool all_protected = true;
// Try to modify each register
*(volatile uint32_t*)CRITICAL_TEMP_REG = ~saved_temp;
if (*(volatile uint32_t*)CRITICAL_TEMP_REG != saved_temp) {
log_error("CRITICAL_TEMP not protected by lock!");
all_protected = false;
}
*(volatile uint32_t*)CALIBRATION_REG = ~saved_cal;
if (*(volatile uint32_t*)CALIBRATION_REG != saved_cal) {
log_error("CALIBRATION not protected by lock!");
all_protected = false;
}
*(volatile uint32_t*)SHUTDOWN_ENABLE_REG = ~saved_shutdown;
if (*(volatile uint32_t*)SHUTDOWN_ENABLE_REG != saved_shutdown) {
log_error("SHUTDOWN_ENABLE not protected by lock!");
all_protected = false;
}
if (!all_protected) {
panic("Incomplete lock coverage detected!");
}
return all_protected;
}
CVE Examples
- CVE-2018-9085: Write protection lock left unset after boot
- CVE-2014-8273: Race condition between interrupt handler detection and lock bit reset
Related CWEs
- CWE-284: Improper Access Control (parent)
- CWE-667: Improper Locking (related)
- CWE-1231: Improper Prevention of Lock Bit Modification (related)
References
- MITRE Corporation. "CWE-1233: Security-Sensitive Hardware Controls with Missing Lock Bit Protection." https://cwe.mitre.org/data/definitions/1233.html
- Hardware Lock Coverage Analysis
- Security Register Protection Guidelines