Unsicherer Sicherheitskennungsmechanismus
Beschreibung
Ein unsicherer Sicherheitskennungsmechanismus tritt auf, wenn ein System-on-Chip (SoC) einen Sicherheitskennungsmechanismus implementiert, um zu unterscheiden, welche Aktionen erlaubt oder verboten sind, wenn eine Transaktion von einer Entität ausgeht, aber die Sicherheitskennungen nicht korrekt implementiert sind. Systems-on-Chip verwenden Sicherheitskennungen, um Agenten und ihre zugehörigen Aktionen zu unterscheiden (Lesen, Schreiben, Programmieren, Zurücksetzen, Abrufen, Berechnen). Jeder Agent erhält eine eindeutige Kennung basierend auf Vertrauensstufe oder Privilegien. Schwachstellen umfassen fehlende Kennungen, unsachgemäße Konvertierung, fehlerhafte Generierung und fehlerhafte Dekodierung von Sicherheitskennungen.
Risiko
Unsichere Sicherheitskennungsmechanismen haben schwerwiegende Auswirkungen. Speichermodifikation möglich. Unbefugte Lesezugriffe aktiviert. Ressourcenverbrauch-Denial-of-Service. Unbefugte Codeausführung. Privilegieneskalationsangriffe. Identitätsübernahme möglich. Qualitätsverschlechterung. Vollständige Umgehung von Zugriffskontrollen. Hohe Ausnutzungswahrscheinlichkeit wenn Sicherheitskennungsmechanismen fehlerhaft sind.
Lösung
Überprüfen Sie Sicherheitskennungs-Dekodierer auf Designinkonsistenzen und Schwachstellen während der Architektur- und Entwurfsphase. Implementieren Sie ordnungsgemäße Kennungsgenerierungsmechanismen. Testen Sie Zugriffs- und Programmierabläufe während Pre-Silicon- und Post-Silicon-Tests. Verwenden Sie formale Verifikation zur Validierung der Sicherheitskennungslogik. Stellen Sie sicher, dass alle Bus-Transaktionen geeignete Sicherheitskennungen tragen. Implementieren Sie vollständige und korrekte Dekodiererlogik. Validieren Sie, dass die Konvertierung zwischen Protokollen die Sicherheitssemantik bewahrt.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Bereich: Vertraulichkeit Unbefugter Lesezugriff auf geschützten Speicher und Assets. |
| Integrität | Bereich: Integrität Speichermodifikation durch nicht vertrauenswürdige Agenten. |
| Verfügbarkeit | Bereich: Verfügbarkeit Denial of Service durch Ressourcenverbrauch. |
| Zugriffskontrolle | Bereich: Zugriffskontrolle Privilegieneskalation, Identitätsübernahme, unbefugte Codeausführung. |
Beispielcode und Lösung
Verwundbarer Code
// VERWUNDBAR: Unsichere Implementierung der Sicherheitskennung
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
);
// VERWUNDBAR: Keine Sicherheitskennungsgenerierung
// Master-ID direkt ohne Sicherheitsklassifikation verwendet
localparam SECURE_MEM_START = 32'hFFFF_0000;
localparam SECURE_MEM_END = 32'hFFFF_FFFF;
// VERWUNDBAR: Kein Sicherheitskennungsmechanismus
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
// VERWUNDBAR: Alle Master gleichbehandelt
// Keine Sicherheitskennung zur Unterscheidung von Vertrauensstufen
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
// VERWUNDBAR: Unvollständige Sicherheitskennungsgenerierung
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
);
// VERWUNDBAR: Sicherheitskennung enthält nicht alle relevanten Faktoren
always @(*) begin
// VERWUNDBAR: Nur master_id verwendet, Privilegien und Welt ignoriert
security_id = {4'b0, master_id}; // Privilegieninfo verloren!
end
// Korrekte Erzeugung sollte enthalten:
// - Master-ID
// - Sichere/Nicht-sichere Welt
// - Berechtigungsstufe
// - Zusätzlicher Kontext nach Bedarf
endmodule
// VERWUNDBAR: Fehlende Sicherheitskennung auf internem 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
// VERWUNDBAR: Kein Sicherheitskennungs-Ausgang!
);
// VERWUNDBAR: Arbiter propagiert Sicherheitsinformation nicht
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;
// VERWUNDBAR: Sicherheitskennung nicht an Transaktion angehängt
end else if (dma_write) begin
bus_addr <= dma_addr;
bus_data <= dma_data;
bus_write <= 1'b1;
// VERWUNDBAR: DMA als gleich vertrauenswürdig wie CPU angenommen
end else begin
bus_write <= 1'b0;
end
end
endmodule
// VERWUNDBAR: Software-Sicherheitskennungsbehandlung
#include <stdint.h>
#include <stdbool.h>
// VERWUNDBAR: Keine Sicherheitskennungsvalidierung
typedef struct {
uint32_t address;
uint32_t data;
// VERWUNDBAR: Fehlendes Sicherheitskennungsfeld
} transaction_t;
bool vulnerable_process_transaction(transaction_t* txn) {
// VERWUNDBAR: Kein Sicherheitskontext verfügbar
// Kann nicht bestimmen, ob Transaktion autorisiert ist
// Transaktion ohne Sicherheitsprüfung verarbeiten
write_memory(txn->address, txn->data);
return true;
}
// VERWUNDBAR: Unvollständige Sicherheitskennungsprüfung
#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) {
// VERWUNDBAR: Nur untere Bits prüfen
uint8_t level = security_id & 0x03; // Obere Bits fehlen!
// Einige Ressourcen erfordern spezifische Master-ID, nicht nur Stufe
// VERWUNDBAR: Master-ID nicht berücksichtigt
return level >= get_resource_required_level(resource_id);
}
// VERWUNDBAR: Sicherheitskennung kann gefälscht werden
void vulnerable_set_security_id(uint32_t new_id) {
// VERWUNDBAR: Keine Validierung wer die ID setzt
// Jeder Code kann den Sicherheitskontext ändern
current_security_id = new_id;
}
Sichere Lösung
// SICHER: Sichere Implementierung der Sicherheitskennung
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, // SICHER: Ordnungsgemäße Sicherheitskennung
input wire read_enable,
input wire write_enable,
output reg [31:0] read_data,
output reg access_granted,
output reg access_denied
);
// Sicherheits-ID-Format:
// [7:6] = Sicherheitsstufe (00=nicht vertrauenswürdig, 01=Benutzer, 10=Kernel, 11=sicher)
// [5:4] = Welt (00=normal, 01=sicher, 10=Hypervisor)
// [3:0] = Master-ID
localparam SECURE_MEM_START = 32'hFFFF_0000;
localparam SECURE_MEM_END = 32'hFFFF_FFFF;
localparam REQUIRED_LEVEL = 2'b11; // Sichere Stufe
localparam REQUIRED_WORLD = 2'b01; // Sichere Welt
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;
// SICHER: Bestimmen ob sicherer Bereich zugegriffen wird
always @(*) begin
is_secure_region = (transaction_addr >= SECURE_MEM_START) &&
(transaction_addr <= SECURE_MEM_END);
end
// SICHER: Vollständige Sicherheitsprüfung
always @(*) begin
if (is_secure_region) begin
// SICHER: Alle Sicherheitsattribute prüfen
access_allowed = (txn_level >= REQUIRED_LEVEL) &&
(txn_world == REQUIRED_WORLD);
end else begin
// Nicht-sicherer Bereich - weniger restriktiv
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
// SICHER: Vollständige Sicherheitskennungsgenerierung
module secure_security_id_generator (
input wire [3:0] master_id,
input wire [1:0] world,
input wire is_privileged,
input wire is_secure_level,
output wire [7:0] security_id
);
wire [1:0] security_level;
// SICHER: Sicherheitsstufe aus allen relevanten Eingaben generieren
assign security_level = is_secure_level ? 2'b11 :
is_privileged ? 2'b10 :
2'b01;
// SICHER: Alle Sicherheitsattribute kombinieren
assign security_id = {security_level, world, master_id};
endmodule
// SICHER: Interner Bus mit Sicherheitskennungspropagierung
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, // SICHER: CPU-Sicherheits-ID
input wire [31:0] dma_addr,
input wire [31:0] dma_data,
input wire dma_write,
input wire [7:0] dma_security_id, // SICHER: DMA-Sicherheits-ID
output reg [31:0] bus_addr,
output reg [31:0] bus_data,
output reg bus_write,
output reg [7:0] bus_security_id // SICHER: Sicherheits-ID-Ausgang
);
// SICHER: Sicherheitskennung mit Transaktion propagieren
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; // SICHER: CPU-Sicherheits-ID anhängen
end else if (dma_write) begin
bus_addr <= dma_addr;
bus_data <= dma_data;
bus_write <= 1'b1;
bus_security_id <= dma_security_id; // SICHER: DMA-Sicherheits-ID anhängen
end else begin
bus_write <= 1'b0;
end
end
endmodule
// SICHER: Sichere Sicherheitskennungsbehandlung
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
// SICHER: Vollständige Sicherheitskennungsstruktur
typedef struct {
uint8_t security_level; // 0-3
uint8_t world; // 0=normal, 1=sicher, 2=Hypervisor
uint8_t master_id;
uint8_t reserved;
} security_id_t;
// SICHER: Transaktion enthält Sicherheitskontext
typedef struct {
uint32_t address;
uint32_t data;
security_id_t security_id; // SICHER: Sicherheitskennung enthalten
} secure_transaction_t;
// SICHER: Zugriffsrichtlinie für Ressourcen
typedef struct {
uint32_t resource_id;
uint8_t required_level;
uint8_t required_world;
uint8_t allowed_masters; // Bitmaske
} access_policy_t;
// SICHER: Sicherheitskennung validieren
bool secure_validate_security_id(const security_id_t* sid) {
if (sid == NULL) {
return false;
}
// Bereiche validieren
if (sid->security_level > 3) {
return false;
}
if (sid->world > 2) {
return false;
}
if (sid->master_id > 15) {
return false;
}
return true;
}
// SICHER: Vollständige Zugriffsprüfung
bool secure_check_access(const security_id_t* sid,
const access_policy_t* policy) {
if (sid == NULL || policy == NULL) {
return false;
}
// SICHER: Sicherheitskennung validieren
if (!secure_validate_security_id(sid)) {
return false;
}
// SICHER: Sicherheitsstufe prüfen
if (sid->security_level < policy->required_level) {
return false;
}
// SICHER: Welt prüfen
if (sid->world < policy->required_world) {
return false;
}
// SICHER: Master ist erlaubt
if (!(policy->allowed_masters & (1 << sid->master_id))) {
return false;
}
return true;
}
// SICHER: Transaktion mit Sicherheitsvalidierung verarbeiten
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;
}
// SICHER: Anwendbare Richtlinie finden
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) {
// Keine Richtlinie - standardmäßig ablehnen
return false;
}
// SICHER: Zugriff mit vollständiger Sicherheitskennung prüfen
if (!secure_check_access(&txn->security_id, applicable_policy)) {
log_access_denied(txn);
return false;
}
// Zugriff gewährt - Transaktion verarbeiten
write_memory(txn->address, txn->data);
return true;
}
// SICHER: Sicherheitskennung kann nur von Hardware/Firmware gesetzt werden
// Diese Funktion sollte nur aus privilegiertem Kontext aufrufbar sein
bool secure_set_security_id(security_id_t* sid,
uint8_t level, uint8_t world, uint8_t master) {
// SICHER: Aufrufer ist privilegiert
if (!is_privileged_context()) {
return false;
}
// SICHER: Eingaben validieren
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-Beispiele
- CVE-2021-33101: Sicherheitskennungsmechanismus in bestimmten Intel-Prozessoren ermöglichte unbefugten Zugriff durch fehlerhafte Kennungsbehandlung.
- CVE-2020-8705: SoC-Sicherheitskennungsvalidierung könnte umgangen werden, was Privilegieneskalation ermöglichte.
Verwandte CWEs
- CWE-284: Unsachgemäße Zugriffskontrolle (übergeordnet)
- CWE-1290: Fehlerhafte Dekodierung von Sicherheitskennungen (untergeordnet)
- CWE-1292: Fehlerhafte Konvertierung von Sicherheitskennungen (untergeordnet)
- CWE-1270: Generierung fehlerhafter Sicherheitstoken (untergeordnet)
- CWE-1302: Fehlende Sicherheitskennung (untergeordnet)
Referenzen
- MITRE Corporation. "CWE-1294: Insecure Security Identifier Mechanism." https://cwe.mitre.org/data/definitions/1294.html
- ARM. "AMBA Security Extensions"
- CAPEC-681: Exploitation of Improperly Controlled Hardware Security Identifiers