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

ImpactDetails
Access ControlScope: 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.


  • 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

  1. MITRE Corporation. "CWE-1192: System-on-Chip (SoC) Using Components without Unique Identifiers." https://cwe.mitre.org/data/definitions/1192.html
  2. ARM TrustZone and Component Identification
  3. AMBA AXI Protocol - Transaction IDs