Incorrect Conversion of Security Identifiers
Description
Incorrect Conversion of Security Identifiers occurs when a product's bus-transaction signal to security identifier mapping contains conversion errors, potentially allowing untrusted agents unauthorized asset access. In System-on-Chip (SoC) environments, transactions between integrated circuits carry source and destination identities along with security identifiers that enable destination agents to enforce access controls. Protocol bridges connecting incompatible bus types (e.g., AHB-to-OCP, APB-to-AXI) must correctly translate security identifier information between protocols. When these bridges incorrectly convert security identifiers, untrusted agents may bypass access restrictions.
Risk
Incorrect security identifier conversion has severe implications. Untrusted agents bypass access controls. Memory modification possible. Unauthorized reads enabled. Denial of service attacks. Execution of unauthorized code. Privilege escalation. Identity assumption. Complete bypass of access control policies. High likelihood of exploitation when protocol bridges have conversion flaws.
Solution
Security identifier converters/bridges require design review for inconsistency and common weaknesses during architecture and design phase. Ensure protocol mappings preserve security semantics. Access and programming flows must be tested in pre-silicon and post-silicon testing. Create comprehensive test vectors covering all security identifier values across protocol boundaries. Use formal verification to prove conversion correctness. Document security identifier mappings explicitly.
Common Consequences
| Impact | Details |
|---|---|
| Confidentiality | Scope: Confidentiality Unauthorized read access to protected memory and assets. |
| Integrity | Scope: Integrity Memory modification by untrusted agents through protocol bridge. |
| Availability | Scope: Availability Denial of service through resource consumption. |
| Access Control | Scope: Access Control Privilege escalation and identity assumption via incorrect mapping. |
Example Code
Vulnerable Code
// Vulnerable: AHB to OCP bridge with incorrect security ID conversion
module vulnerable_ahb_to_ocp_bridge (
input wire clk,
input wire rst_n,
// AHB signals
input wire [31:0] ahb_haddr,
input wire [2:0] ahb_hburst,
input wire [3:0] ahb_hprot, // AHB protection signals
input wire ahb_hwrite,
input wire [31:0] ahb_hwdata,
input wire [1:0] ahb_htrans,
// OCP signals
output reg [31:0] ocp_maddr,
output reg [2:0] ocp_mburstlength,
output reg [1:0] ocp_mcmd,
output reg [31:0] ocp_mdata,
output reg [7:0] ocp_mtagid, // OCP security tag
output reg ocp_mreqinfo // OCP security info
);
// AHB HPROT bits:
// [0] = Data/Opcode (1=data, 0=opcode)
// [1] = Privileged (1=privileged, 0=user)
// [2] = Bufferable
// [3] = Cacheable
// OCP security model (example):
// mtagid[7:6] = security level (00=untrusted, 01=user, 10=priv, 11=secure)
// mtagid[5:0] = master ID
// VULNERABLE: Incorrect conversion of security identifiers
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
ocp_maddr <= 32'b0;
ocp_mtagid <= 8'b0;
end else begin
ocp_maddr <= ahb_haddr;
// VULNERABLE: Only checking bit [1] of hprot
// Missing bit [3] which indicates secure access in some implementations
if (ahb_hprot[1]) begin
ocp_mtagid[7:6] <= 2'b10; // Privileged
end else begin
ocp_mtagid[7:6] <= 2'b01; // User
end
// VULNERABLE: Master ID not properly converted
// ahb doesn't have explicit master ID, but OCP requires it
ocp_mtagid[5:0] <= 6'b000000; // All masters mapped to ID 0!
end
end
// VULNERABLE: Security info bit not properly set
always @(*) begin
// Should indicate secure/non-secure based on bus master
ocp_mreqinfo = 1'b0; // Always indicates non-secure!
end
endmodule
// Vulnerable: APB to AXI bridge with security mapping issues
module vulnerable_apb_to_axi_bridge (
input wire clk,
input wire rst_n,
// APB signals
input wire [31:0] paddr,
input wire pwrite,
input wire [31:0] pwdata,
input wire psel,
input wire penable,
input wire [2:0] pprot, // APB protection
// AXI signals
output reg [31:0] axi_awaddr,
output reg [2:0] axi_awprot, // AXI protection
output reg [3:0] axi_awcache,
output reg [31:0] axi_wdata,
output reg axi_awvalid
);
// APB PPROT:
// [0] = Normal/Privileged
// [1] = Secure/Non-secure
// [2] = Data/Instruction
// AXI AWPROT:
// [0] = Privileged
// [1] = Non-secure
// [2] = Instruction
// VULNERABLE: Incorrect bit mapping between protocols
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
axi_awprot <= 3'b0;
end else begin
// VULNERABLE: Bits are in different positions!
// APB pprot[0] is privilege, but just copying directly
axi_awprot <= pprot; // WRONG! Bit positions don't match!
// Correct mapping should be:
// axi_awprot[0] = pprot[0] (privilege matches)
// axi_awprot[1] = ~pprot[1] (APB secure=0, AXI non-secure=0, INVERTED!)
// axi_awprot[2] = pprot[2] (data/instruction matches)
end
end
endmodule
// Vulnerable: Software bridge with security ID conversion issues
#include <stdint.h>
#include <stdbool.h>
// Protocol A security levels
#define PROTO_A_UNTRUSTED 0x00
#define PROTO_A_USER 0x01
#define PROTO_A_SUPERVISOR 0x02
#define PROTO_A_SECURE 0x03
// Protocol B security levels (different encoding)
#define PROTO_B_PUBLIC 0x00
#define PROTO_B_NORMAL 0x04
#define PROTO_B_PRIVILEGED 0x08
#define PROTO_B_HYPERVISOR 0x0C
// VULNERABLE: Incorrect mapping table
uint8_t vulnerable_convert_security_id(uint8_t proto_a_id) {
// VULNERABLE: Direct value copy - encodings don't match!
return proto_a_id; // Values mean different things!
// PROTO_A_USER (0x01) becomes PROTO_B_PUBLIC (0x00 + something)
// Security semantics are lost!
}
// VULNERABLE: Bridge request structure
typedef struct {
uint32_t address;
uint32_t data;
uint8_t security_id;
bool is_write;
} bridge_request_t;
void vulnerable_forward_request(bridge_request_t* req) {
// VULNERABLE: Security ID not properly converted
uint8_t proto_b_security = vulnerable_convert_security_id(req->security_id);
// Forward to protocol B endpoint
send_proto_b_request(req->address, req->data, proto_b_security, req->is_write);
}
Fixed Code
// Fixed: AHB to OCP bridge with correct security ID conversion
module secure_ahb_to_ocp_bridge (
input wire clk,
input wire rst_n,
// AHB signals
input wire [31:0] ahb_haddr,
input wire [2:0] ahb_hburst,
input wire [3:0] ahb_hprot,
input wire ahb_hwrite,
input wire [31:0] ahb_hwdata,
input wire [1:0] ahb_htrans,
input wire [3:0] ahb_hmaster, // AHB master ID (implementation specific)
input wire ahb_hnonsec, // AHB non-secure indicator
// OCP signals
output reg [31:0] ocp_maddr,
output reg [2:0] ocp_mburstlength,
output reg [1:0] ocp_mcmd,
output reg [31:0] ocp_mdata,
output reg [7:0] ocp_mtagid,
output reg ocp_mreqinfo
);
// FIXED: Complete security mapping with all relevant signals
reg [1:0] security_level;
always @(*) begin
// FIXED: Comprehensive security level determination
if (!ahb_hnonsec) begin
// Secure access
if (ahb_hprot[1]) begin
security_level = 2'b11; // Secure privileged
end else begin
security_level = 2'b10; // Secure user
end
end else begin
// Non-secure access
if (ahb_hprot[1]) begin
security_level = 2'b01; // Non-secure privileged
end else begin
security_level = 2'b00; // Non-secure user (untrusted)
end
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
ocp_maddr <= 32'b0;
ocp_mtagid <= 8'b0;
ocp_mreqinfo <= 1'b0;
end else begin
ocp_maddr <= ahb_haddr;
// FIXED: Proper security level conversion
ocp_mtagid[7:6] <= security_level;
// FIXED: Master ID properly mapped
ocp_mtagid[5:2] <= ahb_hmaster;
ocp_mtagid[1:0] <= 2'b00; // Reserved
// FIXED: Security info properly indicates secure/non-secure
ocp_mreqinfo <= ahb_hnonsec;
end
end
// FIXED: Assertions to verify conversion
// synthesis translate_off
always @(posedge clk) begin
if (!rst_n) begin
// Reset
end else begin
// Verify secure access maps correctly
if (!ahb_hnonsec && ahb_hprot[1]) begin
assert(ocp_mtagid[7:6] == 2'b11)
else $error("Secure privileged mapping failed");
end
end
end
// synthesis translate_on
endmodule
// Fixed: APB to AXI bridge with correct protection bit mapping
module secure_apb_to_axi_bridge (
input wire clk,
input wire rst_n,
// APB signals
input wire [31:0] paddr,
input wire pwrite,
input wire [31:0] pwdata,
input wire psel,
input wire penable,
input wire [2:0] pprot,
// AXI signals
output reg [31:0] axi_awaddr,
output reg [2:0] axi_awprot,
output reg [3:0] axi_awcache,
output reg [31:0] axi_wdata,
output reg axi_awvalid
);
// APB PPROT:
// [0] = Normal(0)/Privileged(1)
// [1] = Secure(0)/Non-secure(1)
// [2] = Data(0)/Instruction(1)
// AXI AWPROT:
// [0] = Unprivileged(0)/Privileged(1)
// [1] = Secure(0)/Non-secure(1)
// [2] = Data(0)/Instruction(1)
// FIXED: Explicit bit-by-bit mapping with documentation
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
axi_awprot <= 3'b000; // Safe default: unprivileged, secure, data
end else begin
// FIXED: Correct mapping - bits happen to align in this case
// but we explicitly map each one for clarity and maintainability
// Privilege bit: both protocols use same encoding
axi_awprot[0] <= pprot[0];
// Security bit: both protocols use same encoding (1=non-secure)
axi_awprot[1] <= pprot[1];
// Data/Instruction bit: both protocols use same encoding
axi_awprot[2] <= pprot[2];
end
end
// FIXED: Validation logic
// synthesis translate_off
always @(posedge clk) begin
// Verify privileged access preserved
if (pprot[0]) begin
assert(axi_awprot[0]) else $error("Privilege not preserved");
end
// Verify secure/non-secure preserved
assert(axi_awprot[1] == pprot[1]) else $error("Security not preserved");
end
// synthesis translate_on
endmodule
// Fixed: Software bridge with correct security ID conversion
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
// Protocol A security levels
typedef enum {
PROTO_A_UNTRUSTED = 0x00,
PROTO_A_USER = 0x01,
PROTO_A_SUPERVISOR = 0x02,
PROTO_A_SECURE = 0x03
} proto_a_security_t;
// Protocol B security levels (different encoding)
typedef enum {
PROTO_B_PUBLIC = 0x00,
PROTO_B_NORMAL = 0x04,
PROTO_B_PRIVILEGED = 0x08,
PROTO_B_HYPERVISOR = 0x0C
} proto_b_security_t;
// FIXED: Explicit conversion table
static const proto_b_security_t security_conversion_table[] = {
[PROTO_A_UNTRUSTED] = PROTO_B_PUBLIC, // Lowest maps to lowest
[PROTO_A_USER] = PROTO_B_NORMAL, // User maps to normal
[PROTO_A_SUPERVISOR] = PROTO_B_PRIVILEGED, // Supervisor maps to privileged
[PROTO_A_SECURE] = PROTO_B_HYPERVISOR // Highest maps to highest
};
// FIXED: Validated conversion function
proto_b_security_t secure_convert_security_id(proto_a_security_t proto_a_id) {
// FIXED: Validate input
if (proto_a_id > PROTO_A_SECURE) {
// Invalid input - return most restrictive level
log_security_error("Invalid Protocol A security ID: %d", proto_a_id);
return PROTO_B_PUBLIC; // Fail safe
}
// FIXED: Use explicit mapping table
return security_conversion_table[proto_a_id];
}
// FIXED: Bridge with validated conversion
typedef struct {
uint32_t address;
uint32_t data;
proto_a_security_t security_id;
bool is_write;
} bridge_request_t;
bool secure_forward_request(const bridge_request_t* req) {
if (req == NULL) {
return false;
}
// FIXED: Convert security ID with validation
proto_b_security_t proto_b_security = secure_convert_security_id(req->security_id);
// FIXED: Log conversion for audit trail
audit_log("Security conversion: ProtoA=%d -> ProtoB=%d",
req->security_id, proto_b_security);
// Forward to protocol B endpoint
return send_proto_b_request(req->address, req->data,
proto_b_security, req->is_write);
}
// FIXED: Reverse conversion for responses
proto_a_security_t secure_convert_security_id_reverse(proto_b_security_t proto_b_id) {
switch (proto_b_id) {
case PROTO_B_PUBLIC: return PROTO_A_UNTRUSTED;
case PROTO_B_NORMAL: return PROTO_A_USER;
case PROTO_B_PRIVILEGED: return PROTO_A_SUPERVISOR;
case PROTO_B_HYPERVISOR: return PROTO_A_SECURE;
default:
log_security_error("Invalid Protocol B security ID: %d", proto_b_id);
return PROTO_A_UNTRUSTED; // Fail safe
}
}
// FIXED: Bidirectional bridge verification
void verify_security_mapping(void) {
// Verify round-trip conversion preserves security level
for (int i = PROTO_A_UNTRUSTED; i <= PROTO_A_SECURE; i++) {
proto_b_security_t b = secure_convert_security_id(i);
proto_a_security_t a_back = secure_convert_security_id_reverse(b);
assert(a_back == i && "Security mapping is not bijective!");
}
}
CVE Examples
- CVE-2020-24512: Protocol bridge in certain Intel processors incorrectly mapped security attributes during bus transactions.
- CVE-2019-11091: Security identifier conversion error in microarchitectural data sampling.
Related CWEs
- CWE-284: Improper Access Control (parent)
- CWE-1294: Insecure Security Identifier Mechanism (parent)
- CWE-1290: Incorrect Decoding of Security Identifiers (related)
- CWE-863: Incorrect Authorization (related)
References
- MITRE Corporation. "CWE-1292: Incorrect Conversion of Security Identifiers." https://cwe.mitre.org/data/definitions/1292.html
- ARM. "AMBA Protocol Specifications"
- OCP-IP. "Open Core Protocol Specification"