Insecure Security Identifier Mechanism

Description

Insecure Security Identifier Mechanism occurs when a System-on-Chip (SoC) implements a Security Identifier mechanism to differentiate what actions are allowed or disallowed when a transaction originates from an entity, but the Security Identifiers are not correctly implemented. Systems-on-Chip employ Security Identifiers to distinguish agents and their associated actions (read, write, program, reset, fetch, compute). Each agent receives a unique identifier based on trust level or privileges. Flaws encompass missing identifiers, improper conversion, incorrect generation, and faulty decoding of security identifiers.

Risk

Insecure security identifier mechanisms have severe implications. Memory modification possible. Unauthorized reads enabled. Resource consumption denial-of-service. Unauthorized code execution. Privilege escalation attacks. Identity assumption possible. Quality degradation. Complete bypass of access controls. High likelihood of exploitation when security identifier mechanisms are flawed.

Solution

Review Security Identifier Decoders for design inconsistencies and weaknesses during architecture and design phase. Implement proper identifier generation mechanisms. Test access and programming flows during pre-silicon and post-silicon testing. Use formal verification to validate security identifier logic. Ensure all bus transactions carry appropriate security identifiers. Implement complete and correct decoder logic. Validate conversion between protocols preserves security semantics.

Common Consequences

ImpactDetails
ConfidentialityScope: Confidentiality

Unauthorized read access to protected memory and assets.
IntegrityScope: Integrity

Memory modification by untrusted agents.
AvailabilityScope: Availability

Denial of service through resource consumption.
Access ControlScope: Access Control

Privilege escalation, identity assumption, unauthorized code execution.

Example Code

Vulnerable Code

// Vulnerable: Insecure Security Identifier implementation

module vulnerable_security_id_system (
    input  wire        clk,
    input  wire        rst_n,
    input  wire [31:0] transaction_addr,
    input  wire [31:0] transaction_data,
    input  wire [3:0]  master_id,
    input  wire        read_enable,
    input  wire        write_enable,
    output reg  [31:0] read_data,
    output reg         access_granted,
    output reg         access_denied
);

    // VULNERABLE: No security identifier generation
    // Master ID directly used without security classification

    // Protected memory regions
    localparam SECURE_MEM_START = 32'hFFFF_0000;
    localparam SECURE_MEM_END   = 32'hFFFF_FFFF;

    // VULNERABLE: No security identifier mechanism
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            access_granted <= 1'b0;
            access_denied <= 1'b0;
            read_data <= 32'b0;
        end else begin
            // VULNERABLE: All masters treated equally
            // No security identifier to differentiate trust levels
            access_granted <= read_enable | write_enable;
            access_denied <= 1'b0;

            if (read_enable) begin
                read_data <= memory[transaction_addr[15:0]];
            end
        end
    end

endmodule

// Vulnerable: Incomplete security identifier generation
module vulnerable_security_id_generator (
    input  wire [3:0]  master_id,
    input  wire        is_secure_world,
    input  wire        is_privileged,
    output reg  [7:0]  security_id
);

    // VULNERABLE: Security identifier doesn't include all relevant factors
    always @(*) begin
        // VULNERABLE: Only using master_id, ignoring privilege and world
        security_id = {4'b0, master_id};  // Privilege info lost!
    end

    // Correct generation should include:
    // - Master ID
    // - Secure/Non-secure world
    // - Privilege level
    // - Additional context as needed

endmodule

// Vulnerable: Missing security identifier on internal bus
module vulnerable_internal_bus (
    input  wire        clk,
    input  wire        rst_n,
    input  wire [31:0] cpu_addr,
    input  wire [31:0] cpu_data,
    input  wire        cpu_write,
    input  wire [31:0] dma_addr,
    input  wire [31:0] dma_data,
    input  wire        dma_write,
    output reg  [31:0] bus_addr,
    output reg  [31:0] bus_data,
    output reg         bus_write
    // VULNERABLE: No security identifier output!
);

    // VULNERABLE: Arbiter doesn't propagate security information
    reg cpu_grant;
    reg dma_grant;

    always @(posedge clk) begin
        if (cpu_write) begin
            bus_addr <= cpu_addr;
            bus_data <= cpu_data;
            bus_write <= 1'b1;
            // VULNERABLE: Security identifier not attached to transaction
        end else if (dma_write) begin
            bus_addr <= dma_addr;
            bus_data <= dma_data;
            bus_write <= 1'b1;
            // VULNERABLE: DMA assumed to have same trust as CPU
        end else begin
            bus_write <= 1'b0;
        end
    end

endmodule
// Vulnerable: Software security identifier handling issues

#include <stdint.h>
#include <stdbool.h>

// VULNERABLE: No security identifier validation
typedef struct {
    uint32_t address;
    uint32_t data;
    // VULNERABLE: Missing security identifier field
} transaction_t;

bool vulnerable_process_transaction(transaction_t* txn) {
    // VULNERABLE: No security context available
    // Cannot determine if transaction is authorized

    // Just process the transaction without security check
    write_memory(txn->address, txn->data);
    return true;
}

// VULNERABLE: Incomplete security identifier checking
#define SECURITY_LEVEL_UNTRUSTED 0
#define SECURITY_LEVEL_USER      1
#define SECURITY_LEVEL_KERNEL    2
#define SECURITY_LEVEL_SECURE    3

bool vulnerable_check_access(uint32_t security_id, uint32_t resource_id) {
    // VULNERABLE: Only checking lower bits
    uint8_t level = security_id & 0x03;  // Missing upper bits!

    // Some resources require specific master ID, not just level
    // VULNERABLE: Master ID not considered

    return level >= get_resource_required_level(resource_id);
}

// VULNERABLE: Security identifier can be spoofed
void vulnerable_set_security_id(uint32_t new_id) {
    // VULNERABLE: No validation of who is setting the ID
    // Any code can change security context
    current_security_id = new_id;
}

Fixed Code

// Fixed: Secure Security Identifier implementation

module secure_security_id_system (
    input  wire        clk,
    input  wire        rst_n,
    input  wire [31:0] transaction_addr,
    input  wire [31:0] transaction_data,
    input  wire [7:0]  security_id,      // FIXED: Proper security identifier
    input  wire        read_enable,
    input  wire        write_enable,
    output reg  [31:0] read_data,
    output reg         access_granted,
    output reg         access_denied
);

    // Security ID format:
    // [7:6] = Security level (00=untrusted, 01=user, 10=kernel, 11=secure)
    // [5:4] = World (00=normal, 01=secure, 10=hypervisor)
    // [3:0] = Master ID

    // Protected memory regions with security requirements
    localparam SECURE_MEM_START = 32'hFFFF_0000;
    localparam SECURE_MEM_END   = 32'hFFFF_FFFF;

    // Security requirements for secure memory
    localparam REQUIRED_LEVEL = 2'b11;  // Secure level
    localparam REQUIRED_WORLD = 2'b01;  // Secure world

    wire [1:0] txn_level = security_id[7:6];
    wire [1:0] txn_world = security_id[5:4];
    wire [3:0] txn_master = security_id[3:0];

    reg is_secure_region;
    reg access_allowed;

    // FIXED: Determine if accessing secure region
    always @(*) begin
        is_secure_region = (transaction_addr >= SECURE_MEM_START) &&
                           (transaction_addr <= SECURE_MEM_END);
    end

    // FIXED: Complete security check
    always @(*) begin
        if (is_secure_region) begin
            // FIXED: Check all security attributes
            access_allowed = (txn_level >= REQUIRED_LEVEL) &&
                             (txn_world == REQUIRED_WORLD);
        end else begin
            // Non-secure region - less restrictive
            access_allowed = 1'b1;
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            access_granted <= 1'b0;
            access_denied <= 1'b0;
            read_data <= 32'b0;
        end else begin
            if ((read_enable | write_enable) && access_allowed) begin
                access_granted <= 1'b1;
                access_denied <= 1'b0;

                if (read_enable) begin
                    read_data <= memory[transaction_addr[15:0]];
                end
            end else if ((read_enable | write_enable) && !access_allowed) begin
                access_granted <= 1'b0;
                access_denied <= 1'b1;
                read_data <= 32'b0;
            end else begin
                access_granted <= 1'b0;
                access_denied <= 1'b0;
            end
        end
    end

endmodule

// FIXED: Complete security identifier generation
module secure_security_id_generator (
    input  wire [3:0]  master_id,
    input  wire [1:0]  world,          // 00=normal, 01=secure, 10=hypervisor
    input  wire        is_privileged,
    input  wire        is_secure_level,
    output wire [7:0]  security_id
);

    wire [1:0] security_level;

    // FIXED: Generate security level from all relevant inputs
    assign security_level = is_secure_level ? 2'b11 :
                            is_privileged   ? 2'b10 :
                                              2'b01;

    // FIXED: Combine all security attributes
    assign security_id = {security_level, world, master_id};

endmodule

// FIXED: Internal bus with security identifier propagation
module secure_internal_bus (
    input  wire        clk,
    input  wire        rst_n,
    input  wire [31:0] cpu_addr,
    input  wire [31:0] cpu_data,
    input  wire        cpu_write,
    input  wire [7:0]  cpu_security_id,  // FIXED: CPU security ID
    input  wire [31:0] dma_addr,
    input  wire [31:0] dma_data,
    input  wire        dma_write,
    input  wire [7:0]  dma_security_id,  // FIXED: DMA security ID
    output reg  [31:0] bus_addr,
    output reg  [31:0] bus_data,
    output reg         bus_write,
    output reg  [7:0]  bus_security_id   // FIXED: Security ID output
);

    // FIXED: Propagate security identifier with transaction
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            bus_addr <= 32'b0;
            bus_data <= 32'b0;
            bus_write <= 1'b0;
            bus_security_id <= 8'b0;
        end else if (cpu_write) begin
            bus_addr <= cpu_addr;
            bus_data <= cpu_data;
            bus_write <= 1'b1;
            bus_security_id <= cpu_security_id;  // FIXED: Attach CPU's security ID
        end else if (dma_write) begin
            bus_addr <= dma_addr;
            bus_data <= dma_data;
            bus_write <= 1'b1;
            bus_security_id <= dma_security_id;  // FIXED: Attach DMA's security ID
        end else begin
            bus_write <= 1'b0;
        end
    end

endmodule
// Fixed: Secure security identifier handling

#include <stdint.h>
#include <stdbool.h>
#include <string.h>

// FIXED: Complete security identifier structure
typedef struct {
    uint8_t security_level;  // 0-3
    uint8_t world;           // 0=normal, 1=secure, 2=hypervisor
    uint8_t master_id;
    uint8_t reserved;
} security_id_t;

// FIXED: Transaction includes security context
typedef struct {
    uint32_t address;
    uint32_t data;
    security_id_t security_id;  // FIXED: Security identifier included
} secure_transaction_t;

// FIXED: Access policy for resources
typedef struct {
    uint32_t resource_id;
    uint8_t required_level;
    uint8_t required_world;
    uint8_t allowed_masters;  // Bitmask
} access_policy_t;

// FIXED: Validate security identifier
bool secure_validate_security_id(const security_id_t* sid) {
    if (sid == NULL) {
        return false;
    }

    // Validate ranges
    if (sid->security_level > 3) {
        return false;
    }

    if (sid->world > 2) {
        return false;
    }

    if (sid->master_id > 15) {
        return false;
    }

    return true;
}

// FIXED: Complete access check
bool secure_check_access(const security_id_t* sid,
                         const access_policy_t* policy) {
    if (sid == NULL || policy == NULL) {
        return false;
    }

    // FIXED: Validate security identifier first
    if (!secure_validate_security_id(sid)) {
        return false;
    }

    // FIXED: Check security level
    if (sid->security_level < policy->required_level) {
        return false;
    }

    // FIXED: Check world
    if (sid->world < policy->required_world) {
        return false;
    }

    // FIXED: Check if master is allowed
    if (!(policy->allowed_masters & (1 << sid->master_id))) {
        return false;
    }

    return true;
}

// FIXED: Process transaction with security validation
bool secure_process_transaction(const secure_transaction_t* txn,
                                const access_policy_t* policies,
                                size_t policy_count) {
    if (txn == NULL || policies == NULL) {
        return false;
    }

    // FIXED: Find applicable policy
    const access_policy_t* applicable_policy = NULL;
    for (size_t i = 0; i < policy_count; i++) {
        if (address_in_resource(txn->address, policies[i].resource_id)) {
            applicable_policy = &policies[i];
            break;
        }
    }

    if (applicable_policy == NULL) {
        // No policy - deny by default
        return false;
    }

    // FIXED: Check access with complete security identifier
    if (!secure_check_access(&txn->security_id, applicable_policy)) {
        log_access_denied(txn);
        return false;
    }

    // Access granted - process transaction
    write_memory(txn->address, txn->data);
    return true;
}

// FIXED: Security identifier can only be set by hardware/firmware
// This function should only be callable from privileged context
bool secure_set_security_id(security_id_t* sid,
                            uint8_t level,
                            uint8_t world,
                            uint8_t master) {
    // FIXED: Verify caller is privileged
    if (!is_privileged_context()) {
        return false;
    }

    // FIXED: Validate inputs
    if (level > 3 || world > 2 || master > 15) {
        return false;
    }

    sid->security_level = level;
    sid->world = world;
    sid->master_id = master;
    sid->reserved = 0;

    return true;
}

CVE Examples

  • CVE-2021-33101: Security identifier mechanism in certain Intel processors allowed unauthorized access through incorrect identifier handling.
  • CVE-2020-8705: SoC security identifier validation could be bypassed, enabling privilege escalation.

  • CWE-284: Improper Access Control (parent)
  • CWE-1290: Incorrect Decoding of Security Identifiers (child)
  • CWE-1292: Incorrect Conversion of Security Identifiers (child)
  • CWE-1270: Generation of Incorrect Security Tokens (child)
  • CWE-1302: Missing Security Identifier (child)

References

  1. MITRE Corporation. "CWE-1294: Insecure Security Identifier Mechanism." https://cwe.mitre.org/data/definitions/1294.html
  2. ARM. "AMBA Security Extensions"
  3. CAPEC-681: Exploitation of Improperly Controlled Hardware Security Identifiers