Missing Protection Mechanism for Alternate Hardware Interface
Description
Missing Protection Mechanism for Alternate Hardware Interface occurs when assets lack protections across all access paths. Attackers can circumvent primary protections by exploiting unguarded alternate routes. While an asset may have access controls on one interface, vulnerabilities arise when alternate paths remain unprotected. Examples include shadow/mirror registers that alias addresses but lack access controls, multiple external interfaces where only some are protected (e.g., PCIe protected but UART unprotected), and indirect access routes like instruction bus versus data bus.
Risk
Missing alternate interface protection has severe implications. Memory modification via unprotected paths. Unauthorized reads through alternate interfaces. Denial of service possible. Protection mechanisms completely bypassed. Privilege escalation enabled. Unauthorized code execution. Logic alteration through unguarded channels. Shadow registers expose sensitive data. High likelihood of exploitation.
Solution
Protect assets across all potential interfaces and alternate paths during requirements phase. Implement defense-in-depth protections systematically during architecture and design. Ensure access controls comprehensively cover all data paths during implementation. Audit all paths to sensitive assets. Consider shadow/mirror registers as separate access points. Apply consistent protection across all external interfaces.
Common Consequences
| Impact | Details |
|---|---|
| Confidentiality | Scope: Confidentiality Unauthorized reads through alternate interfaces. |
| Integrity | Scope: Integrity Memory modification via unprotected paths. |
| Availability | Scope: Availability Denial of service through resource consumption. |
| Access Control | Scope: Access Control Protection bypass through alternate channels. |
Example Code
Vulnerable Code
// Vulnerable: Protection only on primary address, not shadow
module vulnerable_register_protection (
input wire clk,
input wire rst_n,
input wire [31:0] address,
input wire [31:0] write_data,
input wire write_enable,
input wire is_privileged,
output reg [31:0] read_data,
output reg access_denied
);
// Primary address for secure register
localparam SECURE_REG_ADDR = 32'h0000_0F00;
// VULNERABLE: Shadow address exists but not protected
// localparam SHADOW_REG_ADDR = 32'h0080_0F00;
// Shadow mirrors primary but hardware ignores bit [23]
reg [31:0] secure_register;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
secure_register <= 32'b0;
access_denied <= 1'b0;
end else begin
access_denied <= 1'b0;
// VULNERABLE: Only checking primary address
if (address == SECURE_REG_ADDR) begin
if (is_privileged) begin
if (write_enable) begin
secure_register <= write_data;
end
end else begin
access_denied <= 1'b1;
end
end
// VULNERABLE: Shadow address 0x800F00 not checked!
// Attacker can access register via shadow address
// without privilege check
end
end
// VULNERABLE: Read also doesn't protect shadow
always @(*) begin
if (address == SECURE_REG_ADDR) begin
read_data = is_privileged ? secure_register : 32'b0;
end else if (address[22:0] == SECURE_REG_ADDR[22:0]) begin
// Shadow address matches - but no protection!
read_data = secure_register; // VULNERABLE: No priv check
end else begin
read_data = 32'b0;
end
end
endmodule
// Vulnerable: Multiple interfaces with inconsistent protection
module vulnerable_multi_interface (
input wire clk,
input wire rst_n,
// PCIe interface (protected)
input wire [31:0] pcie_addr,
input wire [31:0] pcie_data,
input wire pcie_write,
input wire pcie_privileged,
// UART interface (VULNERABLE: unprotected)
input wire [31:0] uart_addr,
input wire [31:0] uart_data,
input wire uart_write,
// SMBus interface (VULNERABLE: unprotected)
input wire [31:0] smbus_addr,
input wire [31:0] smbus_data,
input wire smbus_write,
output reg [31:0] config_register
);
localparam CONFIG_ADDR = 32'h0000_1000;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
config_register <= 32'b0;
end else begin
// PCIe interface - protected
if (pcie_write && pcie_addr == CONFIG_ADDR) begin
if (pcie_privileged) begin
config_register <= pcie_data;
end
end
// VULNERABLE: UART interface - no protection!
if (uart_write && uart_addr == CONFIG_ADDR) begin
config_register <= uart_data; // No privilege check!
end
// VULNERABLE: SMBus interface - no protection!
if (smbus_write && smbus_addr == CONFIG_ADDR) begin
config_register <= smbus_data; // No privilege check!
end
end
end
endmodule
// Vulnerable: Instruction bus bypasses data bus protection
module vulnerable_bus_bypass (
input wire clk,
input wire rst_n,
// Data bus (protected)
input wire [31:0] data_addr,
input wire data_read,
input wire data_privileged,
output reg [31:0] data_out,
// Instruction bus (VULNERABLE: unprotected)
input wire [31:0] instr_addr,
input wire instr_fetch,
output reg [31:0] instr_out
);
// Sensitive data/code region
localparam SECRET_START = 32'h1000_0000;
localparam SECRET_END = 32'h1000_FFFF;
reg [31:0] secret_memory [0:4095];
// Data bus - protected
always @(*) begin
data_out = 32'b0;
if (data_read) begin
if (data_addr >= SECRET_START && data_addr <= SECRET_END) begin
if (data_privileged) begin
data_out = secret_memory[data_addr[13:2]];
end
// Unprivileged access denied
end
end
end
// VULNERABLE: Instruction fetch bypasses protection
always @(*) begin
instr_out = 32'b0;
if (instr_fetch) begin
if (instr_addr >= SECRET_START && instr_addr <= SECRET_END) begin
// VULNERABLE: No privilege check on instruction bus!
instr_out = secret_memory[instr_addr[13:2]];
end
end
end
// Attack: Read secret data via instruction fetch
// Execute code from attacker-controlled location that fetches "instructions"
// from secret region
endmodule
Fixed Code
// Fixed: Protection on all addresses including shadow
module secure_register_protection (
input wire clk,
input wire rst_n,
input wire [31:0] address,
input wire [31:0] write_data,
input wire write_enable,
input wire is_privileged,
output reg [31:0] read_data,
output reg access_denied
);
// Primary address for secure register
localparam SECURE_REG_ADDR = 32'h0000_0F00;
// FIXED: Also protect shadow address
localparam SHADOW_REG_ADDR = 32'h0080_0F00;
reg [31:0] secure_register;
// FIXED: Function to check if address matches secure register
function automatic is_secure_reg_address;
input [31:0] addr;
begin
// Check primary address
if (addr == SECURE_REG_ADDR)
is_secure_reg_address = 1'b1;
// FIXED: Check shadow address
else if (addr == SHADOW_REG_ADDR)
is_secure_reg_address = 1'b1;
// FIXED: Check all possible aliases (bit 23 ignored by hardware)
else if (addr[22:0] == SECURE_REG_ADDR[22:0])
is_secure_reg_address = 1'b1;
else
is_secure_reg_address = 1'b0;
end
endfunction
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
secure_register <= 32'b0;
access_denied <= 1'b0;
end else begin
access_denied <= 1'b0;
// FIXED: Check all possible addresses to secure register
if (is_secure_reg_address(address)) begin
if (is_privileged) begin
if (write_enable) begin
secure_register <= write_data;
end
end else begin
access_denied <= 1'b1; // FIXED: Deny on any alias
end
end
end
end
// FIXED: Read protection on all aliases
always @(*) begin
if (is_secure_reg_address(address)) begin
read_data = is_privileged ? secure_register : 32'b0;
end else begin
read_data = 32'b0;
end
end
endmodule
// Fixed: Consistent protection across all interfaces
module secure_multi_interface (
input wire clk,
input wire rst_n,
// PCIe interface
input wire [31:0] pcie_addr,
input wire [31:0] pcie_data,
input wire pcie_write,
input wire pcie_privileged,
// UART interface
input wire [31:0] uart_addr,
input wire [31:0] uart_data,
input wire uart_write,
input wire uart_privileged, // FIXED: Added privilege signal
// SMBus interface
input wire [31:0] smbus_addr,
input wire [31:0] smbus_data,
input wire smbus_write,
input wire smbus_privileged, // FIXED: Added privilege signal
output reg [31:0] config_register,
output reg access_fault
);
localparam CONFIG_ADDR = 32'h0000_1000;
// FIXED: Centralized access control
function automatic access_allowed;
input [31:0] addr;
input privileged;
begin
if (addr == CONFIG_ADDR) begin
access_allowed = privileged;
end else begin
access_allowed = 1'b1; // Other addresses may be public
end
end
endfunction
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
config_register <= 32'b0;
access_fault <= 1'b0;
end else begin
access_fault <= 1'b0;
// FIXED: PCIe interface - protected
if (pcie_write && pcie_addr == CONFIG_ADDR) begin
if (access_allowed(pcie_addr, pcie_privileged)) begin
config_register <= pcie_data;
end else begin
access_fault <= 1'b1;
end
end
// FIXED: UART interface - now protected
if (uart_write && uart_addr == CONFIG_ADDR) begin
if (access_allowed(uart_addr, uart_privileged)) begin
config_register <= uart_data;
end else begin
access_fault <= 1'b1;
end
end
// FIXED: SMBus interface - now protected
if (smbus_write && smbus_addr == CONFIG_ADDR) begin
if (access_allowed(smbus_addr, smbus_privileged)) begin
config_register <= smbus_data;
end else begin
access_fault <= 1'b1;
end
end
end
end
endmodule
// Fixed: Protection on both instruction and data buses
module secure_bus_protection (
input wire clk,
input wire rst_n,
// Data bus
input wire [31:0] data_addr,
input wire data_read,
input wire data_privileged,
output reg [31:0] data_out,
output reg data_fault,
// Instruction bus
input wire [31:0] instr_addr,
input wire instr_fetch,
input wire instr_privileged, // FIXED: Privilege for instr fetch
output reg [31:0] instr_out,
output reg instr_fault
);
// Sensitive region
localparam SECRET_START = 32'h1000_0000;
localparam SECRET_END = 32'h1000_FFFF;
reg [31:0] secret_memory [0:4095];
// FIXED: Centralized region check
function automatic is_secret_region;
input [31:0] addr;
begin
is_secret_region = (addr >= SECRET_START) && (addr <= SECRET_END);
end
endfunction
// Data bus - protected
always @(*) begin
data_out = 32'b0;
data_fault = 1'b0;
if (data_read) begin
if (is_secret_region(data_addr)) begin
if (data_privileged) begin
data_out = secret_memory[data_addr[13:2]];
end else begin
data_fault = 1'b1; // Access denied
end
end
end
end
// FIXED: Instruction bus - also protected
always @(*) begin
instr_out = 32'b0;
instr_fault = 1'b0;
if (instr_fetch) begin
if (is_secret_region(instr_addr)) begin
// FIXED: Privilege check on instruction fetch too
if (instr_privileged) begin
instr_out = secret_memory[instr_addr[13:2]];
end else begin
instr_fault = 1'b1; // Access denied
end
end
end
end
endmodule
CVE Examples
- CVE-2022-38399: Unauthenticated serial access enabled arbitrary command execution.
- CVE-2020-8004: Flash protection bypassed via instruction bus.
- CVE-2017-18293: GPIO protection circumvented through banked registers.
Related CWEs
- CWE-288: Authentication Bypass Using an Alternate Path or Channel (parent)
- CWE-420: Unprotected Alternate Channel (parent)
- CWE-1191: On-Chip Debug and Test Interface With Improper Access Control (peer)
- CWE-1314: Missing Write Protection for Parametric Data Values (peer)
References
- MITRE Corporation. "CWE-1299: Missing Protection Mechanism for Alternate Hardware Interface." https://cwe.mitre.org/data/definitions/1299.html
- ARM. "AMBA AXI and ACE Protocol Specification"
- IEEE. "Secure Hardware Design Guidelines"