Failure to Disable Reserved Bits
Description
Failure to Disable Reserved Bits occurs when reserved bits in hardware designs are not disabled before production release. Reserved bits are allocated in register definitions for potential future capabilities and should perform no function in current designs. However, designers may utilize these bits to expedite time-to-market by controlling undocumented features or for debugging during development. If the associated logic remains enabled in production, attackers could use these bits to induce unwanted or unsupported behavior in the hardware, potentially compromising system security.
Risk
Enabled reserved bits have significant security implications. Attackers can discover and exploit undocumented functionality. Debug features may remain accessible in production. Hidden backdoors may be present. Security controls may be bypassable through reserved bits. Undocumented behavior may compromise system integrity. Firmware updates may not address reserved bit vulnerabilities. Security certifications may be invalidated. Behavior may be unpredictable when reserved bits are set.
Solution
Ensure all reserved bits are tied to safe values (typically 0). Remove or disable all logic controlled by reserved bits before production. Document reserved bits clearly as "must be zero" or "must be one". Implement hardware enforcement that ignores writes to reserved bits. Test that setting reserved bits has no effect. Review all register definitions for active reserved bit logic. Audit reserved bit usage during security reviews. Use static analysis to find reserved bit connections. Verify reserved bit handling in silicon validation.
Common Consequences
| Impact | Details |
|---|---|
| Confidentiality, Integrity, Availability, Access Control | Scope: All Varies By Context - Consequences depend on what capabilities are controlled by the reserved bits. Could range from information disclosure to full system compromise. |
Example Code
Vulnerable Code
// Vulnerable: Reserved bits enable hidden functionality
module vulnerable_control_register (
input wire clk,
input wire reset_n,
input wire [31:0] write_data,
input wire write_enable,
input wire [3:0] register_address,
output reg [31:0] read_data,
output reg gpio_out,
output reg debug_mode,
output reg bypass_security
);
// Control register with "reserved" bits that do something
// Documented bits:
// [0] - Enable feature A
// [1] - Enable feature B
// [7:2] - Reserved (should be 0)
// [15:8] - Configuration value
// [31:16]- Reserved (should be 0)
reg [31:0] control_reg;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
control_reg <= 32'h0;
gpio_out <= 1'b0;
debug_mode <= 1'b0;
bypass_security <= 1'b0;
end
else if (write_enable && register_address == 4'b0001) begin
control_reg <= write_data;
// VULNERABLE: "Reserved" bits actually do things!
// Reserved bit [2] secretly enables GPIO
gpio_out <= write_data[2];
// Reserved bit [3] enables debug mode
debug_mode <= write_data[3];
// Reserved bit [16] bypasses security checks!
bypass_security <= write_data[16];
end
end
// Another vulnerable pattern: reserved address enables hidden function
always @(posedge clk) begin
case (register_address)
4'b0000: read_data <= status_reg;
4'b0001: read_data <= control_reg;
// Address 0x0F is "reserved" but enables backdoor
4'b1111: gpio_out <= 1'b1; // Hidden functionality!
default: read_data <= 32'h0;
endcase
end
endmodule
// Vulnerable: Undocumented debug feature via reserved field
module vulnerable_memory_controller (
input wire clk,
input wire [31:0] command,
input wire [31:0] address,
output reg [31:0] data_out,
output reg command_complete
);
// Command format:
// [3:0] - Operation code
// [7:4] - Reserved (should be 0)
// [31:8] - Parameters
wire [3:0] opcode = command[3:0];
wire [3:0] reserved = command[7:4]; // "Reserved" bits
always @(posedge clk) begin
case (opcode)
4'h1: begin
// Normal read operation
data_out <= memory[address];
command_complete <= 1'b1;
end
4'h2: begin
// Normal write operation
memory[address] <= command[31:8];
command_complete <= 1'b1;
end
default: begin
// VULNERABLE: Reserved bits check for debug backdoor
if (reserved == 4'hA) begin
// Hidden: Dump all memory when reserved = 0xA
dump_all_memory();
end
if (reserved == 4'hB) begin
// Hidden: Bypass access control
bypass_acl <= 1'b1;
end
end
endcase
end
endmodule
// Vulnerable: Firmware with active reserved bit handling
#define CONTROL_REG_ADDR 0x40001000
// Documented register bits
#define CTRL_ENABLE_A (1 << 0)
#define CTRL_ENABLE_B (1 << 1)
// Bits 2-7: Reserved
#define CTRL_CONFIG_MASK 0xFF00
// Bits 16-31: Reserved
// VULNERABLE: Hidden functionality in "reserved" bits
#define CTRL_DEBUG_MODE (1 << 3) // "Reserved" but active
#define CTRL_BYPASS_SEC (1 << 16) // "Reserved" but active
void configure_hardware(uint32_t config) {
// Write to control register
// Reserved bits are written too, enabling hidden features
*(volatile uint32_t*)CONTROL_REG_ADDR = config;
}
// Attacker can exploit by setting reserved bits
void exploit_reserved_bits(void) {
// Enable undocumented debug mode
configure_hardware(CTRL_ENABLE_A | CTRL_DEBUG_MODE);
// Bypass security checks
configure_hardware(CTRL_ENABLE_A | CTRL_BYPASS_SEC);
}
Fixed Code
// Fixed: Reserved bits are properly disabled
module secure_control_register (
input wire clk,
input wire reset_n,
input wire [31:0] write_data,
input wire write_enable,
input wire [3:0] register_address,
output reg [31:0] read_data,
output reg feature_a_enable,
output reg feature_b_enable,
output reg [7:0] config_value
);
// Control register with truly reserved bits
// Documented bits:
// [0] - Enable feature A
// [1] - Enable feature B
// [7:2] - Reserved (MUST BE ZERO)
// [15:8] - Configuration value
// [31:16]- Reserved (MUST BE ZERO)
reg [31:0] control_reg;
// Mask for writable bits only
localparam WRITABLE_MASK = 32'h0000FF03;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
control_reg <= 32'h0;
feature_a_enable <= 1'b0;
feature_b_enable <= 1'b0;
config_value <= 8'h0;
end
else if (write_enable && register_address == 4'b0001) begin
// Only write to documented bits - mask out reserved
control_reg <= write_data & WRITABLE_MASK;
// Only use documented bits
feature_a_enable <= write_data[0];
feature_b_enable <= write_data[1];
config_value <= write_data[15:8];
// Reserved bits [7:2] and [31:16] are ignored
// No hidden functionality
end
end
always @(*) begin
case (register_address)
4'b0000: read_data = status_reg;
4'b0001: read_data = control_reg;
// Reserved addresses return zero, do nothing
default: read_data = 32'h0;
endcase
// No hidden functionality on any address
end
endmodule
// Fixed: No debug backdoors in reserved fields
module secure_memory_controller (
input wire clk,
input wire reset_n,
input wire [31:0] command,
input wire [31:0] address,
input wire command_valid,
output reg [31:0] data_out,
output reg command_complete,
output reg command_error
);
// Command format:
// [3:0] - Operation code
// [7:4] - Reserved (MUST BE ZERO)
// [31:8] - Parameters
wire [3:0] opcode = command[3:0];
wire [3:0] reserved = command[7:4];
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
data_out <= 32'h0;
command_complete <= 1'b0;
command_error <= 1'b0;
end
else if (command_valid) begin
// Check reserved bits are zero
if (reserved != 4'h0) begin
// Reserved bits must be zero - reject command
command_error <= 1'b1;
command_complete <= 1'b1;
end
else begin
command_error <= 1'b0;
case (opcode)
4'h1: begin
// Normal read operation
data_out <= memory[address];
command_complete <= 1'b1;
end
4'h2: begin
// Normal write operation
memory[address] <= command[31:8];
command_complete <= 1'b1;
end
default: begin
// Unknown opcode - error
command_error <= 1'b1;
command_complete <= 1'b1;
end
endcase
end
end
end
// No hidden functionality anywhere
endmodule
// Fixed: Production version with debug removed
module secure_control_register_production (
input wire clk,
input wire reset_n,
input wire [31:0] write_data,
input wire write_enable,
output reg [31:0] control_reg
);
// Production-only bits
localparam PRODUCTION_MASK = 32'h0000FF03;
// Debug functionality completely removed in production
// Not just disabled - the logic doesn't exist
`ifdef PRODUCTION
// Production build: no debug logic synthesized
always @(posedge clk or negedge reset_n) begin
if (!reset_n)
control_reg <= 32'h0;
else if (write_enable)
control_reg <= write_data & PRODUCTION_MASK;
end
`else
// Development build: debug available
// This code is NOT included in production synthesis
always @(posedge clk or negedge reset_n) begin
if (!reset_n)
control_reg <= 32'h0;
else if (write_enable)
control_reg <= write_data;
end
`endif
endmodule
// Fixed: Firmware properly handles reserved bits
#define CONTROL_REG_ADDR 0x40001000
// Documented register bits
#define CTRL_ENABLE_A (1 << 0)
#define CTRL_ENABLE_B (1 << 1)
#define CTRL_CONFIG_MASK 0x0000FF00
// Mask of all valid bits
#define CTRL_VALID_MASK (CTRL_ENABLE_A | CTRL_ENABLE_B | CTRL_CONFIG_MASK)
// Reserved bits - for documentation only
// These bits MUST be written as zero
#define CTRL_RESERVED_MASK (~CTRL_VALID_MASK)
void configure_hardware(uint32_t config) {
// Mask out reserved bits before writing
uint32_t safe_config = config & CTRL_VALID_MASK;
// Verify no reserved bits were set (optional check)
if (config & CTRL_RESERVED_MASK) {
log_warning("Attempt to set reserved bits: 0x%08x", config);
}
// Write only valid bits
*(volatile uint32_t*)CONTROL_REG_ADDR = safe_config;
}
uint32_t read_hardware_config(void) {
uint32_t value = *(volatile uint32_t*)CONTROL_REG_ADDR;
// Mask out reserved bits when reading
return value & CTRL_VALID_MASK;
}
// Validation function for security audit
bool validate_no_reserved_bit_effects(void) {
uint32_t original = read_hardware_config();
// Try setting each reserved bit
for (int bit = 0; bit < 32; bit++) {
if (CTRL_RESERVED_MASK & (1 << bit)) {
// This is a reserved bit - verify it has no effect
*(volatile uint32_t*)CONTROL_REG_ADDR = original | (1 << bit);
// Check system state didn't change unexpectedly
if (detect_state_change()) {
log_error("Reserved bit %d has effect!", bit);
return false;
}
}
}
// Restore original
*(volatile uint32_t*)CONTROL_REG_ADDR = original;
return true;
}
CVE Examples
Reserved bit vulnerabilities have been found in various hardware designs, including processors and embedded controllers, where undocumented bits enable debug or bypass functionality.
Related CWEs
- CWE-710: Improper Adherence to Coding Standards (parent)
- CWE-1199: General Circuit and Logic Design Concerns (category member)
- CWE-1242: Inclusion of Undocumented Features or Chicken Bits (related)
References
- MITRE Corporation. "CWE-1209: Failure to Disable Reserved Bits." https://cwe.mitre.org/data/definitions/1209.html
- Hardware Security Best Practices
- Production vs. Debug Build Guidelines