Fehlerhafte Dekodierung von Sicherheitskennungen

Beschreibung

Fehlerhafte Dekodierung von Sicherheitskennungen tritt auf, wenn ein Produkt einen Dekodierungsmechanismus implementiert, der Bus-Transaktionssignale falsch zu Sicherheitskennungen dekodiert. In System-on-Chip (SoC)-Umgebungen enthalten Hardware-Transaktionen typischerweise Quell- und Zielidentitäten zusammen mit Sicherheitskennungen, die bestimmen, welche Agenten Zugriff auf Assets erhalten und welche Aktionen sie ausführen können. Wenn der Dekodierer die Sicherheitskennung eines nicht vertrauenswürdigen Agenten fälschlicherweise einer vertrauenswürdigen zuordnet, gewährt er versehentlich unbefugten Zugriff auf geschützte Ressourcen.

Risiko

Fehlerhafte Dekodierung von Sicherheitskennungen hat schwerwiegende Auswirkungen. Nicht vertrauenswürdige Agenten erhalten unbefugten Zugriff. Speichermodifikation möglich. Unbefugte Lesezugriffe aktiviert. Denial of Service durch Ressourcenverbrauch. Ausführung von unbefugtem Code. Privilegieneskalation möglich. Identitätsübernahme-Angriffe ermöglicht. Vollständige Umgehung von Zugriffskontrollen. Hohe Ausnutzungswahrscheinlichkeit sobald der Fehler existiert.

Lösung

Dekodierer für Sicherheitskennungen erfordern eine Überprüfung auf Designkonsistenz und Identifikation häufiger Schwachstellen während der Architektur- und Entwurfsphase. Stellen Sie eine vollständige Bitfeld-Prüfung statt partieller Prüfungen sicher. Zugriffs- und Programmierabläufe müssen sowohl in Pre-Silicon- als auch in Post-Silicon-Testphasen getestet werden. Implementieren Sie formale Verifikation der Dekodiererlogik. Verwenden Sie umfassende Testvektoren, die alle möglichen Sicherheitskennungswerte abdecken. Überprüfen Sie Dekodierer-Wahrheitstabellen auf Vollständigkeit.

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: Unvollständige Dekodierung der Sicherheitskennung

module vulnerable_security_decoder (
    input  wire [31:0] bus_transaction,
    output reg  [1:0]  security_identifier,
    output reg         access_granted
);

    // Sicherheitskennung ist in Bits [15:14]
    // 00 = Nicht vertrauenswürdig (Master_0)
    // 01 = Eingeschränktes Vertrauen (Master_1)
    // 10 = Vertrauenswürdig (Master_2)
    // 11 = Hoch vertrauenswürdig (Master_3)

    // VERWUNDBAR: Nur Bit [14] wird geprüft, Bit [15] ignoriert
    always @(*) begin
        if (bus_transaction[14] == 1'b1) begin
            // VERWUNDBAR: Gewährt fälschlicherweise vertrauenswürdigen Status
            // Master_1 (01) wird gleich wie Master_3 (11) behandelt
            security_identifier = 2'b01;  // Nimmt eingeschränktes Vertrauen an
        end else begin
            security_identifier = 2'b00;  // Nicht vertrauenswürdig
        end
    end

    // VERWUNDBAR: Vereinfachte Zugriffsprüfung
    always @(*) begin
        // Zugriff gewähren bei jeder Vertrauensstufe
        access_granted = (security_identifier != 2'b00);
    end

    // Angriffsszenario:
    // Master_0 (nicht vertrauenswürdig, bits[15:14] = 00) - korrekt abgelehnt
    // Master_1 (eingeschränkt, bits[15:14] = 01) - gewährt (Bit 14 = 1)
    // Master_2 (vertrauenswürdig, bits[15:14] = 10) - FÄLSCHLICH abgelehnt (Bit 14 = 0)
    // Master_3 (hoch vertrauenswürdig, bits[15:14] = 11) - gewährt (Bit 14 = 1)
    //
    // Dies erlaubt Master_1 den gleichen Zugriff wie Master_3!

endmodule

// VERWUNDBAR: AES-Schlüsselregister-Zugriff mit fehlerhaftem Dekodierer
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-Schlüsselregister an Adresse 0x80
    localparam AES_KEY_ADDR = 8'h80;

    // VERWUNDBAR: Unvollständiger Dekodierer
    always @(*) begin
        // Nur ein Bit wird geprüft!
        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
            // VERWUNDBAR: Fehlerhafte Sicherheitsprüfung
            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
// VERWUNDBAR: Software-Dekodierung der Sicherheitskennung

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

#define SECURITY_UNTRUSTED     0
#define SECURITY_LIMITED       1
#define SECURITY_TRUSTED       2
#define SECURITY_HIGH_TRUST    3

// VERWUNDBAR: Unvollständige Bit-Extraktion
uint8_t vulnerable_decode_security_id(uint32_t transaction) {
    // VERWUNDBAR: Nur Bit 14 wird geprüft, Bit 15 ignoriert
    if (transaction & (1 << 14)) {
        return SECURITY_LIMITED;  // Falsch!
    }
    return SECURITY_UNTRUSTED;
}

// VERWUNDBAR: Zugriffskontrolle mit fehlerhaftem Dekodierer
bool vulnerable_check_access(uint32_t transaction, uint8_t resource_level) {
    uint8_t security_id = vulnerable_decode_security_id(transaction);

    // VERWUNDBAR: Erlaubt Umgehung durch fehlerhafte Dekodierung
    return security_id >= resource_level;
}

// VERWUNDBAR: Maske ist unvollständig
#define SECURITY_ID_MASK_VULNERABLE  (1 << 14)  // Nur ein Bit!

uint8_t vulnerable_extract_security_id(uint32_t transaction) {
    // VERWUNDBAR: Nur ein Bit eines Zwei-Bit-Feldes extrahiert
    return (transaction & SECURITY_ID_MASK_VULNERABLE) >> 14;
}

Sichere Lösung

// SICHER: Vollständige Dekodierung der Sicherheitskennung

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
);

    // Sicherheitskennung ist in Bits [15:14]
    // 00 = Nicht vertrauenswürdig (Master_0)
    // 01 = Eingeschränktes Vertrauen (Master_1)
    // 10 = Vertrauenswürdig (Master_2)
    // 11 = Hoch vertrauenswürdig (Master_3)

    // SICHER: Vollständiges 2-Bit-Feld prüfen
    always @(*) begin
        case (bus_transaction[15:14])
            2'b00: begin
                security_identifier = 2'b00;
                access_level = 4'b0001;  // Stufe 0: Nur öffentliche Ressourcen
            end
            2'b01: begin
                security_identifier = 2'b01;
                access_level = 4'b0011;  // Stufe 1: Eingeschränkter Zugriff
            end
            2'b10: begin
                security_identifier = 2'b10;
                access_level = 4'b0111;  // Stufe 2: Vertrauenswürdiger Zugriff
            end
            2'b11: begin
                security_identifier = 2'b11;
                access_level = 4'b1111;  // Stufe 3: Vollzugriff
            end
            default: begin
                // SICHER: Sicherer Standard für undefinierte Zustände
                security_identifier = 2'b00;
                access_level = 4'b0000;  // Alles verweigern
            end
        endcase
    end

    // SICHER: Explizite Zugriffsentscheidung pro Stufe
    always @(*) begin
        access_granted = (security_identifier != 2'b00);
    end

endmodule

// SICHER: AES-Schlüsselregister-Zugriff mit korrektem Dekodierer
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-Schlüsselregister an Adresse 0x80
    localparam AES_KEY_ADDR = 8'h80;

    // Erforderliche Sicherheitsstufe für AES-Schlüsselzugriff
    localparam REQUIRED_LEVEL = 2'b10;  // Vertrauenswürdig oder höher

    // SICHER: Vollständiger Dekodierer
    always @(*) begin
        decoded_security_id = bus_transaction[15:14];  // Vollständiges 2-Bit-Feld
    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
            // SICHER: Ordnungsgemäße Sicherheitsstufenprüfung
            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

// SICHER: Parametrisierter Dekodierer mit Validierung
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
);

    // SICHER: Vollständiges Feld extrahieren
    assign security_id = bus_transaction[FIELD_MSB:FIELD_LSB];

    // SICHER: Gegen erforderliche Stufe vergleichen
    assign access_granted = (security_id >= required_level);

    // Assertions für Verifikation
    // synthesis translate_off
    initial begin
        // Feldbreite stimmt mit Parameter überein
        if ((FIELD_MSB - FIELD_LSB + 1) != SECURITY_BITS) begin
            $error("Feldbreiten-Nichtübereinstimmung!");
        end
    end
    // synthesis translate_on

endmodule
// SICHER: Vollständige Software-Dekodierung der Sicherheitskennung

#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

// SICHER: Vollständige Bitmaske für 2-Bit-Feld
#define SECURITY_ID_MASK       (0x3 << 14)  // Bits 15:14
#define SECURITY_ID_SHIFT      14

// SICHER: Vollständige Sicherheitskennung extrahieren
uint8_t secure_decode_security_id(uint32_t transaction) {
    // SICHER: Beide Bits des Sicherheitsfeldes extrahieren
    return (transaction & SECURITY_ID_MASK) >> SECURITY_ID_SHIFT;
}

// SICHER: Zugriffskontrolle mit ordnungsgemäßer Dekodierung
bool secure_check_access(uint32_t transaction, uint8_t required_level) {
    // SICHER: required_level validieren
    if (required_level > SECURITY_HIGH_TRUST) {
        return false;  // Ungültige Stufe, Zugriff verweigern
    }

    uint8_t security_id = secure_decode_security_id(transaction);

    // SICHER: Ordnungsgemäßer Vergleich
    return security_id >= required_level;
}

// SICHER: Dekodierer mit Validierung
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;

    // SICHER: Vollständiges Feld extrahieren
    uint8_t raw_id = (transaction & SECURITY_ID_MASK) >> SECURITY_ID_SHIFT;

    switch (raw_id) {
        case SECURITY_UNTRUSTED:
            result.security_level = SECURITY_UNTRUSTED;
            result.description = "Nicht vertrauenswürdig";
            result.valid = true;
            break;
        case SECURITY_LIMITED:
            result.security_level = SECURITY_LIMITED;
            result.description = "Eingeschränktes Vertrauen";
            result.valid = true;
            break;
        case SECURITY_TRUSTED:
            result.security_level = SECURITY_TRUSTED;
            result.description = "Vertrauenswürdig";
            result.valid = true;
            break;
        case SECURITY_HIGH_TRUST:
            result.security_level = SECURITY_HIGH_TRUST;
            result.description = "Hohes Vertrauen";
            result.valid = true;
            break;
        default:
            result.security_level = SECURITY_UNTRUSTED;
            result.description = "Unbekannt - Standard Nicht vertrauenswürdig";
            result.valid = false;
            break;
    }

    return result;
}

// SICHER: Ressourcenzugriff mit vollständiger Validierung
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);

    // SICHER: Zugriffsversuche für Audit protokollieren
    log_access_attempt(resource->name, decoded.description,
                       decoded.security_level >= resource->required_level);

    // SICHER: Dekodierung war erfolgreich
    if (!decoded.valid) {
        return false;  // Bei ungültiger Sicherheitskennung verweigern
    }

    return decoded.security_level >= resource->required_level;
}

CVE-Beispiele

  • CVE-2021-33101: Dekodierer in bestimmten Intel-Prozessoren interpretierte Sicherheitskennungen falsch, was möglicherweise Privilegieneskalation ermöglichte.

Verwandte CWEs

  • CWE-284: Unsachgemäße Zugriffskontrolle (übergeordnet)
  • CWE-1294: Unsicherer Sicherheitskennungsmechanismus (übergeordnet)
  • CWE-1292: Fehlerhafte Konvertierung von Sicherheitskennungen (verwandt)
  • CWE-863: Fehlerhafte Autorisierung (verwandt)

Referenzen

  1. MITRE Corporation. "CWE-1290: Incorrect Decoding of Security Identifiers." https://cwe.mitre.org/data/definitions/1290.html
  2. ARM. "AMBA Bus Protocol Specifications"
  3. CERT. "Hardware Security Guidelines"