Incorrect Decoding of Security Identifiers
Description
Incorrect Decoding of Security Identifiers occurs when a product implements a decoding mechanism to decode bus-transaction signals to security identifiers incorrectly. In System-On-Chip (SoC) environments, hardware transactions typically include source and destination identities alongside security identifiers that determine which agents receive access to assets and what actions they can perform. When the decoder incorrectly maps an untrusted agent's security identifier to a trusted one, it inadvertently grants unauthorized access to protected resources.
Risk
Incorrect security identifier decoding has severe implications. Untrusted agents gain unauthorized access. Memory modification possible. Unauthorized reads enabled. Denial of service through resource consumption. Execution of unauthorized code. Privilege escalation possible. Identity assumption attacks enabled. Complete bypass of access controls. High likelihood of exploitation once the flaw exists.
Solution
Security identifier decoders require review for design consistency and common weaknesses identification during the architecture and design phase. Ensure complete bit-field checking rather than partial checks. Access and programming flows must be tested in both pre-silicon and post-silicon testing phases. Implement formal verification of decoder logic. Use comprehensive test vectors covering all possible security identifier values. Review decoder truth tables for completeness.
Common Consequences
| Impact | Details |
|---|---|
| Confidentiality | Scope: Confidentiality Unauthorized read access to protected memory and assets. |
| Integrity | Scope: Integrity Memory modification by untrusted agents. |
| Availability | Scope: Availability Denial of service through resource consumption. |
| Access Control | Scope: Access Control Privilege escalation, identity assumption, unauthorized code execution. |
Example Code
Vulnerable Code
// Vulnerable: Incomplete security identifier decoding
module vulnerable_security_decoder (
input wire [31:0] bus_transaction,
output reg [1:0] security_identifier,
output reg access_granted
);
// Security identifier is in bits [15:14]
// 00 = Untrusted (Master_0)
// 01 = Limited trust (Master_1)
// 10 = Trusted (Master_2)
// 11 = Highly trusted (Master_3)
// VULNERABLE: Only checking bit [14], ignoring bit [15]
always @(*) begin
if (bus_transaction[14] == 1'b1) begin
// VULNERABLE: This incorrectly grants trusted status
// Master_1 (01) is treated same as Master_3 (11)
security_identifier = 2'b01; // Assumes limited trust
end else begin
security_identifier = 2'b00; // Untrusted
end
end
// VULNERABLE: Simplified access check
always @(*) begin
// Grant access if any trust level
access_granted = (security_identifier != 2'b00);
end
// Attack scenario:
// Master_0 (untrusted, bits[15:14] = 00) - correctly denied
// Master_1 (limited, bits[15:14] = 01) - granted (bit 14 = 1)
// Master_2 (trusted, bits[15:14] = 10) - INCORRECTLY denied (bit 14 = 0)
// Master_3 (high trust, bits[15:14] = 11) - granted (bit 14 = 1)
//
// This allows Master_1 to have same access as Master_3!
endmodule
// VULNERABLE: AES key register access with flawed decoder
module vulnerable_aes_key_access (
input wire clk,
input wire rst_n,
input wire [31:0] bus_transaction,
input wire [7:0] address,
input wire read_enable,
output reg [127:0] aes_key_out,
output reg access_fault
);
reg [127:0] aes_key;
reg [1:0] decoded_security_id;
// AES key register at address 0x80
localparam AES_KEY_ADDR = 8'h80;
// VULNERABLE: Incomplete decoder
always @(*) begin
// Only checking one bit!
decoded_security_id = bus_transaction[14] ? 2'b01 : 2'b00;
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
aes_key_out <= 128'b0;
access_fault <= 1'b0;
end else if (read_enable && (address == AES_KEY_ADDR)) begin
// VULNERABLE: Flawed security check
if (decoded_security_id != 2'b00) begin
aes_key_out <= aes_key;
access_fault <= 1'b0;
end else begin
aes_key_out <= 128'b0;
access_fault <= 1'b1;
end
end
end
endmodule
// Vulnerable: Software security identifier decoding
#include <stdint.h>
#include <stdbool.h>
#define SECURITY_UNTRUSTED 0
#define SECURITY_LIMITED 1
#define SECURITY_TRUSTED 2
#define SECURITY_HIGH_TRUST 3
// VULNERABLE: Incomplete bit extraction
uint8_t vulnerable_decode_security_id(uint32_t transaction) {
// VULNERABLE: Only checking bit 14, ignoring bit 15
if (transaction & (1 << 14)) {
return SECURITY_LIMITED; // Wrong!
}
return SECURITY_UNTRUSTED;
}
// VULNERABLE: Access control using flawed decoder
bool vulnerable_check_access(uint32_t transaction, uint8_t resource_level) {
uint8_t security_id = vulnerable_decode_security_id(transaction);
// VULNERABLE: Allows bypass due to incorrect decoding
return security_id >= resource_level;
}
// VULNERABLE: Mask is incomplete
#define SECURITY_ID_MASK_VULNERABLE (1 << 14) // Only one bit!
uint8_t vulnerable_extract_security_id(uint32_t transaction) {
// VULNERABLE: Extracting only one bit of two-bit field
return (transaction & SECURITY_ID_MASK_VULNERABLE) >> 14;
}
Fixed Code
// Fixed: Complete security identifier decoding
module secure_security_decoder (
input wire [31:0] bus_transaction,
output reg [1:0] security_identifier,
output reg access_granted,
output reg [3:0] access_level
);
// Security identifier is in bits [15:14]
// 00 = Untrusted (Master_0)
// 01 = Limited trust (Master_1)
// 10 = Trusted (Master_2)
// 11 = Highly trusted (Master_3)
// FIXED: Check complete 2-bit field
always @(*) begin
case (bus_transaction[15:14])
2'b00: begin
security_identifier = 2'b00;
access_level = 4'b0001; // Level 0: Public resources only
end
2'b01: begin
security_identifier = 2'b01;
access_level = 4'b0011; // Level 1: Limited access
end
2'b10: begin
security_identifier = 2'b10;
access_level = 4'b0111; // Level 2: Trusted access
end
2'b11: begin
security_identifier = 2'b11;
access_level = 4'b1111; // Level 3: Full access
end
default: begin
// FIXED: Safe default for undefined states
security_identifier = 2'b00;
access_level = 4'b0000; // Deny all
end
endcase
end
// FIXED: Explicit access decision per level
always @(*) begin
access_granted = (security_identifier != 2'b00);
end
endmodule
// FIXED: AES key register access with correct decoder
module secure_aes_key_access (
input wire clk,
input wire rst_n,
input wire [31:0] bus_transaction,
input wire [7:0] address,
input wire read_enable,
output reg [127:0] aes_key_out,
output reg access_fault
);
reg [127:0] aes_key;
reg [1:0] decoded_security_id;
// AES key register at address 0x80
localparam AES_KEY_ADDR = 8'h80;
// Required security level for AES key access
localparam REQUIRED_LEVEL = 2'b10; // Trusted or higher
// FIXED: Complete decoder
always @(*) begin
decoded_security_id = bus_transaction[15:14]; // Full 2-bit field
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
aes_key_out <= 128'b0;
access_fault <= 1'b0;
end else if (read_enable && (address == AES_KEY_ADDR)) begin
// FIXED: Proper security level check
if (decoded_security_id >= REQUIRED_LEVEL) begin
aes_key_out <= aes_key;
access_fault <= 1'b0;
end else begin
aes_key_out <= 128'b0;
access_fault <= 1'b1;
end
end
end
endmodule
// FIXED: Parameterized decoder with validation
module secure_parameterized_decoder #(
parameter SECURITY_BITS = 2,
parameter FIELD_MSB = 15,
parameter FIELD_LSB = 14
) (
input wire [31:0] bus_transaction,
input wire [SECURITY_BITS-1:0] required_level,
output wire [SECURITY_BITS-1:0] security_id,
output wire access_granted
);
// FIXED: Extract complete field
assign security_id = bus_transaction[FIELD_MSB:FIELD_LSB];
// FIXED: Compare against required level
assign access_granted = (security_id >= required_level);
// Assertions for verification
// synthesis translate_off
initial begin
// Verify field width matches parameter
if ((FIELD_MSB - FIELD_LSB + 1) != SECURITY_BITS) begin
$error("Field width mismatch!");
end
end
// synthesis translate_on
endmodule
// Fixed: Complete software security identifier decoding
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#define SECURITY_UNTRUSTED 0
#define SECURITY_LIMITED 1
#define SECURITY_TRUSTED 2
#define SECURITY_HIGH_TRUST 3
// FIXED: Complete bit mask for 2-bit field
#define SECURITY_ID_MASK (0x3 << 14) // Bits 15:14
#define SECURITY_ID_SHIFT 14
// FIXED: Extract complete security identifier
uint8_t secure_decode_security_id(uint32_t transaction) {
// FIXED: Extract both bits of the security field
return (transaction & SECURITY_ID_MASK) >> SECURITY_ID_SHIFT;
}
// FIXED: Access control with proper decoding
bool secure_check_access(uint32_t transaction, uint8_t required_level) {
// FIXED: Validate required_level
if (required_level > SECURITY_HIGH_TRUST) {
return false; // Invalid level, deny access
}
uint8_t security_id = secure_decode_security_id(transaction);
// FIXED: Proper comparison
return security_id >= required_level;
}
// FIXED: Decoder with validation
typedef struct {
uint8_t security_level;
bool valid;
const char* description;
} decoded_security_t;
decoded_security_t secure_decode_with_validation(uint32_t transaction) {
decoded_security_t result;
// FIXED: Extract complete field
uint8_t raw_id = (transaction & SECURITY_ID_MASK) >> SECURITY_ID_SHIFT;
switch (raw_id) {
case SECURITY_UNTRUSTED:
result.security_level = SECURITY_UNTRUSTED;
result.description = "Untrusted";
result.valid = true;
break;
case SECURITY_LIMITED:
result.security_level = SECURITY_LIMITED;
result.description = "Limited Trust";
result.valid = true;
break;
case SECURITY_TRUSTED:
result.security_level = SECURITY_TRUSTED;
result.description = "Trusted";
result.valid = true;
break;
case SECURITY_HIGH_TRUST:
result.security_level = SECURITY_HIGH_TRUST;
result.description = "High Trust";
result.valid = true;
break;
default:
result.security_level = SECURITY_UNTRUSTED;
result.description = "Unknown - Defaulting to Untrusted";
result.valid = false;
break;
}
return result;
}
// FIXED: Resource access with complete validation
typedef struct {
uint32_t address;
uint8_t required_level;
const char* name;
} protected_resource_t;
bool secure_resource_access(uint32_t transaction, const protected_resource_t* resource) {
if (resource == NULL) {
return false;
}
decoded_security_t decoded = secure_decode_with_validation(transaction);
// FIXED: Log access attempts for auditing
log_access_attempt(resource->name, decoded.description,
decoded.security_level >= resource->required_level);
// FIXED: Validate decoding was successful
if (!decoded.valid) {
return false; // Deny on invalid security identifier
}
return decoded.security_level >= resource->required_level;
}
CVE Examples
- CVE-2021-33101: Decoder in certain Intel processors incorrectly interpreted security identifiers, potentially allowing privilege escalation.
Related CWEs
- CWE-284: Improper Access Control (parent)
- CWE-1294: Insecure Security Identifier Mechanism (parent)
- CWE-1292: Incorrect Conversion of Security Identifiers (related)
- CWE-863: Incorrect Authorization (related)
References
- MITRE Corporation. "CWE-1290: Incorrect Decoding of Security Identifiers." https://cwe.mitre.org/data/definitions/1290.html
- ARM. "AMBA Bus Protocol Specifications"
- CERT. "Hardware Security Guidelines"