System-on-Chip (SoC) Using Components without Unique Identifiers
Description
System-on-Chip (SoC) Using Components without Unique Identifiers occurs when a System-on-Chip does not have unique, immutable identifiers for each of its components. SoCs contain multiple intellectual property (IP) blocks with different trust levels that require distinct identification. This weakness manifests in four variants: Missing (no identification mechanism exists), Insufficient (partial defenses only), Misconfigured (mechanisms implemented incorrectly), or Ignored (identifiers exist but policies aren't enforced). These identifiers serve critical functions including transaction routing, component reset, sensitive data retrieval, and authorization actions.
Risk
Missing or improper component identifiers have severe security implications. Unauthorized components can impersonate trusted components. Access control policies cannot be properly enforced. Transaction routing may be manipulated. Sensitive data may be delivered to wrong components. Security boundaries between IP blocks are weakened. Privilege escalation between components becomes possible. Audit and logging of component actions is compromised. System integrity cannot be verified.
Solution
Assign unique, immutable identifiers to all SoC components. Implement identifiers in hardware that cannot be modified by software. Use cryptographic binding of identifiers where appropriate. Enforce identifier verification on all inter-component transactions. Configure firewalls and access control based on component IDs. Implement identifier validation at system boot. Use secure enclaves for identifier management. Audit and log transactions with component identification. Test identifier spoofing resistance. Document all component identifiers and trust levels.
Common Consequences
| Impact | Details |
|---|---|
| Access Control | Scope: Access Control Bypass Protection Mechanism - Without unique identifiers, access control mechanisms cannot distinguish between components with different trust levels. High likelihood in affected systems. |
Example Code
Vulnerable Code
// Vulnerable: SoC interconnect without component identification
module vulnerable_soc_interconnect (
input wire clk,
input wire reset_n,
// Master interfaces - no identification
input wire [31:0] master0_addr,
input wire [31:0] master0_data,
input wire master0_valid,
input wire [31:0] master1_addr,
input wire [31:0] master1_data,
input wire master1_valid,
// Slave interfaces
output reg [31:0] slave_addr,
output reg [31:0] slave_data,
output reg slave_valid
);
// VULNERABLE: No way to identify which master initiated transaction
// All masters appear identical to slaves
// No access control possible based on source
always @(posedge clk) begin
if (master0_valid) begin
// Master 0 could be untrusted, but we can't tell
slave_addr <= master0_addr;
slave_data <= master0_data;
slave_valid <= 1'b1;
end
else if (master1_valid) begin
// Master 1 might have different trust level
// But no identifier to distinguish
slave_addr <= master1_addr;
slave_data <= master1_data;
slave_valid <= 1'b1;
end
end
endmodule
// Vulnerable: Security controller without source identification
module vulnerable_security_controller (
input wire clk,
input wire [31:0] request_addr,
input wire [31:0] request_data,
input wire request_valid,
// No source ID input!
output reg access_granted
);
// Secure memory region
parameter SECURE_START = 32'h8000_0000;
parameter SECURE_END = 32'h8FFF_FFFF;
always @(posedge clk) begin
if (request_valid) begin
// VULNERABLE: Cannot determine if requestor is authorized
// Must grant access to everyone or no one
if (request_addr >= SECURE_START && request_addr <= SECURE_END) begin
// Should check source ID, but there isn't one
access_granted <= 1'b1; // Forced to allow all!
end else begin
access_granted <= 1'b1;
end
end
end
endmodule
// Vulnerable: IP block with spoofable soft identifier
module vulnerable_ip_block (
input wire clk,
input wire [7:0] configured_id, // Software-configurable - can be spoofed!
output reg [7:0] transaction_source_id
);
// VULNERABLE: ID can be changed by software
// Malicious software can impersonate other components
always @(posedge clk) begin
transaction_source_id <= configured_id;
end
endmodule
// Vulnerable: SoC firmware without component identification
// No component ID in transaction structure
struct transaction {
uint32_t address;
uint32_t data;
uint8_t read_write;
// Missing: source_id, dest_id
};
// Cannot enforce access control without IDs
bool check_access(struct transaction* tx) {
// VULNERABLE: No way to know who is making the request
// Must allow or deny for everyone equally
if (is_secure_region(tx->address)) {
// Should check: is requestor authorized?
// But we don't know who the requestor is!
return true; // Forced to allow
}
return true;
}
// Routing without source identification
void route_transaction(struct transaction* tx) {
// VULNERABLE: No audit trail of who sent what
// No way to implement per-component policies
uint32_t dest = get_destination(tx->address);
send_to_slave(dest, tx);
// Cannot log: "Component X accessed address Y"
// Can only log: "Someone accessed address Y"
}
Fixed Code
// Fixed: SoC interconnect with hardware component identifiers
module secure_soc_interconnect (
input wire clk,
input wire reset_n,
// Master interfaces WITH hardware IDs
input wire [31:0] master0_addr,
input wire [31:0] master0_data,
input wire master0_valid,
input wire [7:0] master0_hw_id, // Hardwired, immutable
input wire [31:0] master1_addr,
input wire [31:0] master1_data,
input wire master1_valid,
input wire [7:0] master1_hw_id, // Hardwired, immutable
// Slave interfaces with source tracking
output reg [31:0] slave_addr,
output reg [31:0] slave_data,
output reg [7:0] slave_source_id, // Identifies requestor
output reg slave_valid
);
// Component ID definitions (hardwired at design time)
parameter CPU_SECURE_ID = 8'h01;
parameter CPU_NONSECURE_ID = 8'h02;
parameter DMA_ID = 8'h03;
parameter GPU_ID = 8'h04;
// Access control matrix
wire master0_access_granted;
wire master1_access_granted;
access_control_checker checker0 (
.source_id(master0_hw_id),
.dest_addr(master0_addr),
.access_granted(master0_access_granted)
);
access_control_checker checker1 (
.source_id(master1_hw_id),
.dest_addr(master1_addr),
.access_granted(master1_access_granted)
);
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
slave_valid <= 1'b0;
end
else if (master0_valid && master0_access_granted) begin
slave_addr <= master0_addr;
slave_data <= master0_data;
slave_source_id <= master0_hw_id; // Track source
slave_valid <= 1'b1;
end
else if (master1_valid && master1_access_granted) begin
slave_addr <= master1_addr;
slave_data <= master1_data;
slave_source_id <= master1_hw_id; // Track source
slave_valid <= 1'b1;
end
else begin
slave_valid <= 1'b0;
end
end
endmodule
// Fixed: Security controller with source identification
module secure_security_controller (
input wire clk,
input wire reset_n,
input wire [31:0] request_addr,
input wire [31:0] request_data,
input wire [7:0] source_id, // Hardware component ID
input wire request_valid,
output reg access_granted,
output reg security_violation
);
// Security regions and policies
parameter SECURE_START = 32'h8000_0000;
parameter SECURE_END = 32'h8FFF_FFFF;
// Trusted component IDs (hardwired)
parameter CPU_SECURE_ID = 8'h01;
parameter CRYPTO_ENGINE_ID = 8'h05;
// Check if source is authorized for secure region
function is_trusted_source;
input [7:0] id;
begin
is_trusted_source = (id == CPU_SECURE_ID) ||
(id == CRYPTO_ENGINE_ID);
end
endfunction
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
access_granted <= 1'b0;
security_violation <= 1'b0;
end
else if (request_valid) begin
if (request_addr >= SECURE_START && request_addr <= SECURE_END) begin
// Secure region - check source ID
if (is_trusted_source(source_id)) begin
access_granted <= 1'b1;
security_violation <= 1'b0;
end else begin
access_granted <= 1'b0;
security_violation <= 1'b1; // Log violation
end
end else begin
// Non-secure region - allow
access_granted <= 1'b1;
security_violation <= 1'b0;
end
end
end
endmodule
// Fixed: IP block with immutable hardware identifier
module secure_ip_block #(
parameter [7:0] HARDWARE_ID = 8'h00 // Set at synthesis time
) (
input wire clk,
output wire [7:0] transaction_source_id
);
// ID is hardwired - cannot be changed by software
assign transaction_source_id = HARDWARE_ID;
// Prevent any attempt to modify
// The ID is a parameter, not a register
endmodule
// Fixed: System instantiation with unique IDs
module soc_top (
input wire clk,
input wire reset_n
);
// Each component has unique, hardwired ID
secure_ip_block #(.HARDWARE_ID(8'h01)) cpu_secure (...);
secure_ip_block #(.HARDWARE_ID(8'h02)) cpu_nonsecure (...);
secure_ip_block #(.HARDWARE_ID(8'h03)) dma_controller (...);
secure_ip_block #(.HARDWARE_ID(8'h04)) gpu (...);
secure_ip_block #(.HARDWARE_ID(8'h05)) crypto_engine (...);
// IDs cannot be duplicated or changed after synthesis
endmodule
// Fixed: SoC firmware with component identification
// Transaction structure with component IDs
struct secure_transaction {
uint32_t address;
uint32_t data;
uint8_t read_write;
uint8_t source_id; // Hardware component ID
uint8_t dest_id; // Target component ID
uint8_t security_level; // Transaction security level
};
// Component ID definitions (match hardware)
#define CPU_SECURE_ID 0x01
#define CPU_NONSECURE_ID 0x02
#define DMA_ID 0x03
#define GPU_ID 0x04
#define CRYPTO_ID 0x05
// Access control policy table
struct access_policy {
uint8_t source_id;
uint32_t region_start;
uint32_t region_end;
bool read_allowed;
bool write_allowed;
};
static const struct access_policy policies[] = {
// Secure CPU can access everything
{CPU_SECURE_ID, 0x00000000, 0xFFFFFFFF, true, true},
// Non-secure CPU cannot access secure region
{CPU_NONSECURE_ID, 0x00000000, 0x7FFFFFFF, true, true},
{CPU_NONSECURE_ID, 0x80000000, 0x8FFFFFFF, false, false},
{CPU_NONSECURE_ID, 0x90000000, 0xFFFFFFFF, true, true},
// DMA has limited access
{DMA_ID, 0x00000000, 0x7FFFFFFF, true, true},
{DMA_ID, 0x80000000, 0xFFFFFFFF, false, false},
// Crypto engine can access secure region
{CRYPTO_ID, 0x80000000, 0x8FFFFFFF, true, true},
};
// Check access based on component ID
bool check_access(struct secure_transaction* tx) {
for (int i = 0; i < ARRAY_SIZE(policies); i++) {
if (policies[i].source_id == tx->source_id &&
tx->address >= policies[i].region_start &&
tx->address <= policies[i].region_end) {
if (tx->read_write == READ) {
return policies[i].read_allowed;
} else {
return policies[i].write_allowed;
}
}
}
// Default deny
return false;
}
// Audit logging with component identification
void log_transaction(struct secure_transaction* tx, bool granted) {
audit_log("Component 0x%02X %s address 0x%08X: %s",
tx->source_id,
tx->read_write == READ ? "read" : "write",
tx->address,
granted ? "GRANTED" : "DENIED");
}
CVE Examples
Component identification weaknesses in SoCs have led to various hardware security vulnerabilities, including privilege escalation and secure boot bypass.
Related CWEs
- CWE-657: Violation of Secure Design Principles (parent)
- CWE-1198: Privilege Separation and Access Control Issues (category member)
- CWE-284: Improper Access Control (related)
References
- MITRE Corporation. "CWE-1192: System-on-Chip (SoC) Using Components without Unique Identifiers." https://cwe.mitre.org/data/definitions/1192.html
- ARM TrustZone and Component Identification
- AMBA AXI Protocol - Transaction IDs