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

AuswirkungDetails
VertraulichkeitBereich: Vertraulichkeit

Unbefugter Lesezugriff auf geschützten Speicher und Assets.
IntegritätBereich: Integrität

Speichermodifikation durch nicht vertrauenswürdige Agenten.
VerfügbarkeitBereich: Verfügbarkeit

Denial of Service durch Ressourcenverbrauch.
ZugriffskontrolleBereich: 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

  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