Fehlender Schutz für gespiegelte Bereiche in On-Chip Fabric Firewall

Beschreibung

Der fehlende Schutz für gespiegelte Bereiche in der On-Chip Fabric Firewall tritt auf, wenn die Firewall in einem On-Chip Fabric den adressierten Hauptbereich schützt, aber keine gespiegelten Speicher- oder Memory-Mapped-IO (MMIO)-Bereiche schützt. Systeme setzen manchmal gespiegelten Speicher und Adressbereiche mit Datenkopien zur Fehlertoleranz ein. Wenn Fabric-Firewalls Originalbereiche schützen, aber gespiegelte Bereiche vernachlässigen, können Angreifer Zugriffskontrollen umgehen, indem sie die ungeschützten Spiegel ansteuern. Dies ermöglicht die Umgehung von Lese-/Schreibschutz, um zugrunde liegende Daten zu leaken oder zu beschädigen.

Risiko

Fehlender Spiegelschutz hat schwerwiegende Auswirkungen. Zugriffskontrolle vollständig über Spiegel umgehbar. Geschützter Speicher über ungeschützten Alias lesbar. Speicherbeschädigung durch gespiegelte Schreibzugriffe. Firewall-Sicherheit unwirksam gemacht. Vertrauliche Daten offengelegt. Systemintegrität kompromittiert. Hohe Wahrscheinlichkeit wenn Spiegel existieren und nicht geschützt sind.

Lösung

Die Fabric-Firewall sollte während der Architektur- und Entwurfsphase dieselben Schutzmaßnahmen wie für den Originalbereich auch auf die gespiegelten Bereiche anwenden. Wenden Sie während der Implementierung identischen Schutz auf gespiegelte Bereiche an wie auf Originalbereiche. Erfassen Sie alle Adress-Aliase und Spiegel während des Entwurfs. Konfigurieren Sie Firewall-Regeln, um alle Adressbereiche abzudecken, die auf geschützte Daten abbilden. Verifizieren Sie den Schutz durch Tests mit Spiegel-Adressen.

Häufige Auswirkungen

AuswirkungDetails
VertraulichkeitBereich: Vertraulichkeit

Geschützte Daten über ungeschützte Spiegel-Adressen lesbar.
IntegritätBereich: Integrität

Geschützter Speicher über Spiegel-Schreibzugriffe modifizierbar.
ZugriffskontrolleBereich: Zugriffskontrolle

Firewall-Schutzmechanismus vollständig umgehbar.

Beispielcode und Lösung

Verwundbarer Code

// VERWUNDBAR: Fabric-Firewall ohne Spiegelschutz

module vulnerable_fabric_firewall (
    input  wire        clk,
    input  wire        rst_n,
    input  wire [31:0] addr,
    input  wire [31:0] wdata,
    input  wire        write_en,
    input  wire        read_en,
    input  wire [1:0]  security_level,
    output reg  [31:0] rdata,
    output reg         access_granted,
    output reg         access_denied
);

    // Speicher-Controller erstellt Spiegel über obere Adressbits
    // Originalbereich: 0x0000_0000 - 0x0000_FFFF (Bits [31:16] = 00)
    // Spiegel 1:       0x0001_0000 - 0x0001_FFFF (Bits [31:16] = 01)
    // Spiegel 2:       0x0002_0000 - 0x0002_FFFF (Bits [31:16] = 02)
    // Spiegel 3:       0x0003_0000 - 0x0003_FFFF (Bits [31:16] = 03)

    // Alle Spiegel bilden auf denselben physischen Speicher ab

    // Geschützter Bereich innerhalb des Originalbereichs
    localparam PROTECTED_START = 32'h0000_8000;
    localparam PROTECTED_END   = 32'h0000_8FFF;
    localparam REQUIRED_LEVEL  = 2'b10;  // Privilegierter Zugriff erforderlich

    // VERWUNDBAR: Prüft nur den Originaladressbereich
    wire in_protected_region = (addr >= PROTECTED_START) &&
                               (addr <= PROTECTED_END);

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            access_granted <= 1'b0;
            access_denied <= 1'b0;
        end else begin
            access_granted <= 1'b0;
            access_denied <= 1'b0;

            if (read_en || write_en) begin
                if (in_protected_region) begin
                    // VERWUNDBAR: Schutz nur auf Originalbereich
                    if (security_level >= REQUIRED_LEVEL) begin
                        access_granted <= 1'b1;
                    end else begin
                        access_denied <= 1'b1;
                    end
                end else begin
                    // Nicht-geschützter Bereich - Zugriff erlauben
                    access_granted <= 1'b1;
                end
            end
        end
    end

    // Angriff:
    // Geschützte Adresse: 0x0000_8000 - erfordert Stufe 2
    // Angreifer nutzt Spiegel: 0x0001_8000 - kein Schutz!
    // Zugriff gewährt, weil 0x0001_8000 NICHT im geschützten Bereich liegt
    // Aber Speicher-Controller bildet es auf dieselbe physische Stelle ab!

endmodule

// VERWUNDBAR: Speicher-Controller mit ungeschützten Aliassen
module vulnerable_memory_controller (
    input  wire        clk,
    input  wire        rst_n,
    input  wire [31:0] addr,
    input  wire [31:0] wdata,
    input  wire        write_en,
    input  wire        read_en,
    output reg  [31:0] rdata
);

    // Physischer Speicher
    reg [31:0] memory [0:65535];

    // Adress-Aliasing - Bits [31:16] ignoriert
    wire [15:0] physical_addr = addr[15:0];

    // VERWUNDBAR: Alle Adressbereiche greifen auf denselben physischen Speicher zu
    // Keine Unterscheidung zwischen Original und Spiegeln
    // Wenn Firewall Spiegel nicht schützt, Sicherheit umgangen

    always @(posedge clk) begin
        if (write_en) begin
            memory[physical_addr] <= wdata;
        end
        if (read_en) begin
            rdata <= memory[physical_addr];
        end
    end

    // Speicher-Map:
    // 0x0000_XXXX -> memory[XXXX] (Original)
    // 0x0001_XXXX -> memory[XXXX] (Spiegel 1)
    // 0x0002_XXXX -> memory[XXXX] (Spiegel 2)
    // 0x0003_XXXX -> memory[XXXX] (Spiegel 3)
    //
    // Alle bilden auf dieselbe physische Stelle ab!

endmodule
// VERWUNDBAR: Software-Firewall-Konfiguration ohne Spiegel

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

typedef struct {
    uint32_t start_addr;
    uint32_t end_addr;
    uint8_t  required_level;
} firewall_rule_t;

// VERWUNDBAR: Schützt nur Originalbereich
static firewall_rule_t firewall_rules[] = {
    {0x00008000, 0x00008FFF, 2},  // Geschützter Bereich
    // VERWUNDBAR: Keine Regeln für Spiegelbereiche
    // 0x00018000-0x00018FFF (Spiegel 1) - ungeschützt!
    // 0x00028000-0x00028FFF (Spiegel 2) - ungeschützt!
    // 0x00038000-0x00038FFF (Spiegel 3) - ungeschützt!
};

bool vulnerable_check_access(uint32_t addr, uint8_t security_level) {
    for (int i = 0; i < sizeof(firewall_rules)/sizeof(firewall_rules[0]); i++) {
        if (addr >= firewall_rules[i].start_addr &&
            addr <= firewall_rules[i].end_addr) {
            // VERWUNDBAR: Prüft nur exakte Adressübereinstimmung
            return security_level >= firewall_rules[i].required_level;
        }
    }

    // Keine passende Regel - Zugriff erlauben
    // VERWUNDBAR: Spiegel-Adressen fallen hier durch
    return true;
}

Sichere Lösung

// SICHER: Fabric-Firewall mit Spiegelschutz

module secure_fabric_firewall (
    input  wire        clk,
    input  wire        rst_n,
    input  wire [31:0] addr,
    input  wire [31:0] wdata,
    input  wire        write_en,
    input  wire        read_en,
    input  wire [1:0]  security_level,
    output reg  [31:0] rdata,
    output reg         access_granted,
    output reg         access_denied
);

    // Speicherlayout mit Spiegeln
    // Originalbereich: 0x0000_0000 - 0x0000_FFFF (Bits [31:16] = 00)
    // Spiegel 1:       0x0001_0000 - 0x0001_FFFF (Bits [31:16] = 01)
    // Spiegel 2:       0x0002_0000 - 0x0002_FFFF (Bits [31:16] = 02)
    // Spiegel 3:       0x0003_0000 - 0x0003_FFFF (Bits [31:16] = 03)

    // Geschützter Bereich (gilt für alle Spiegel)
    localparam PROTECTED_OFFSET_START = 16'h8000;
    localparam PROTECTED_OFFSET_END   = 16'h8FFF;
    localparam REQUIRED_LEVEL         = 2'b10;

    // SICHER: Physische Adresse extrahieren (Spiegel-Bits ignorieren)
    wire [15:0] physical_offset = addr[15:0];

    // SICHER: Prüfen ob physischer Offset im geschützten Bereich liegt
    // Dies erkennt Zugriffe über jede Spiegel-Adresse
    wire in_protected_region = (physical_offset >= PROTECTED_OFFSET_START) &&
                               (physical_offset <= PROTECTED_OFFSET_END);

    // SICHER: Verifizieren, dass Adresse im gültigen Speicherbereich liegt (jeder Spiegel)
    wire in_memory_space = (addr[31:18] == 14'b0);  // Erste 4 Bereiche

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            access_granted <= 1'b0;
            access_denied <= 1'b0;
        end else begin
            access_granted <= 1'b0;
            access_denied <= 1'b0;

            if ((read_en || write_en) && in_memory_space) begin
                if (in_protected_region) begin
                    // SICHER: Schutz gilt für alle Spiegel
                    if (security_level >= REQUIRED_LEVEL) begin
                        access_granted <= 1'b1;
                    end else begin
                        access_denied <= 1'b1;
                    end
                end else begin
                    access_granted <= 1'b1;
                end
            end else if (read_en || write_en) begin
                // Ausserhalb des gültigen Speicherbereichs
                access_denied <= 1'b1;
            end
        end
    end

endmodule

// SICHER: Umfassende Firewall mit Alias-Erkennung
module secure_alias_aware_firewall #(
    parameter NUM_MIRRORS = 4,
    parameter MIRROR_BITS = 2  // Anzahl der Bits für Spiegelauswahl
) (
    input  wire        clk,
    input  wire        rst_n,
    input  wire [31:0] addr,
    input  wire [31:0] wdata,
    input  wire        write_en,
    input  wire        read_en,
    input  wire [1:0]  security_level,
    output reg         access_granted,
    output reg         access_denied
);

    // SICHER: Firewall-Regeln in physischen Adressen definiert
    // Schutz gilt unabhängig davon, welcher Spiegel zugegriffen wird

    // Regelformat: {start_offset, end_offset, required_level}
    reg [47:0] firewall_rules [0:7];
    reg [2:0] num_rules;

    initial begin
        // Geschützter Bereich 1: 0x8000-0x8FFF, Stufe 2
        firewall_rules[0] = {16'h8000, 16'h8FFF, 16'h0002};
        // Geschützter Bereich 2: 0xF000-0xFFFF, Stufe 3
        firewall_rules[1] = {16'hF000, 16'hFFFF, 16'h0003};
        num_rules = 2;
    end

    // SICHER: Jede Adresse in kanonischen physischen Offset umwandeln
    wire [15:0] canonical_offset = addr[15:0];

    // SICHER: Adresse gegen alle Regeln mit kanonischem Offset prüfen
    reg rule_match;
    reg [1:0] required_level;

    integer i;
    always @(*) begin
        rule_match = 1'b0;
        required_level = 2'b00;

        for (i = 0; i < num_rules; i = i + 1) begin
            if (canonical_offset >= firewall_rules[i][47:32] &&
                canonical_offset <= firewall_rules[i][31:16]) begin
                rule_match = 1'b1;
                required_level = firewall_rules[i][1:0];
            end
        end
    end

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            access_granted <= 1'b0;
            access_denied <= 1'b0;
        end else begin
            access_granted <= 1'b0;
            access_denied <= 1'b0;

            if (read_en || write_en) begin
                if (rule_match) begin
                    // SICHER: Für alle Spiegel durchgesetzt
                    if (security_level >= required_level) begin
                        access_granted <= 1'b1;
                    end else begin
                        access_denied <= 1'b1;
                    end
                end else begin
                    access_granted <= 1'b1;
                end
            end
        end
    end

endmodule
// SICHER: Software-Firewall mit Spiegel-Erkennung

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

typedef struct {
    uint16_t start_offset;   // Physischer Offset (nicht vollständige Adresse)
    uint16_t end_offset;
    uint8_t  required_level;
} secure_firewall_rule_t;

// SICHER: Regeln in physischen Offsets definiert
static secure_firewall_rule_t firewall_rules[] = {
    {0x8000, 0x8FFF, 2},  // Geschützter Bereich 1
    {0xF000, 0xFFFF, 3},  // Geschützter Bereich 2
};

// SICHER: Adresse in kanonischen physischen Offset umwandeln
static uint16_t get_physical_offset(uint32_t addr) {
    // Bits [15:0] sind der physische Offset
    // Bits [17:16] wählen den Spiegel (für Schutz ignoriert)
    return addr & 0xFFFF;
}

// SICHER: Adresse auf Speicherbereich validieren
static bool is_valid_memory_address(uint32_t addr) {
    // Speicherbereich ist 0x00000000 - 0x0003FFFF (4 Spiegel von 64KB)
    return addr < 0x00040000;
}

bool secure_check_access(uint32_t addr, uint8_t security_level) {
    // SICHER: Zuerst Adresse validieren
    if (!is_valid_memory_address(addr)) {
        return false;
    }

    // SICHER: Kanonischen physischen Offset ermitteln
    uint16_t offset = get_physical_offset(addr);

    // SICHER: Alle Regeln mit physischem Offset prüfen
    for (size_t i = 0; i < sizeof(firewall_rules)/sizeof(firewall_rules[0]); i++) {
        if (offset >= firewall_rules[i].start_offset &&
            offset <= firewall_rules[i].end_offset) {
            // SICHER: Schutz gilt für alle Spiegel
            return security_level >= firewall_rules[i].required_level;
        }
    }

    // Keine Regel passt - Zugriff erlauben
    return true;
}

// SICHER: Verifizierungsfunktion zum Testen des Spiegelschutzes
bool verify_mirror_protection(void) {
    // Testen, dass Schutz für alle Spiegel funktioniert
    uint32_t protected_offset = 0x8000;

    for (int mirror = 0; mirror < 4; mirror++) {
        uint32_t addr = (mirror << 16) | protected_offset;

        // Stufe 1 sollte für alle Spiegel abgelehnt werden
        if (secure_check_access(addr, 1)) {
            return false;  // Spiegelschutz fehlgeschlagen!
        }

        // Stufe 2 sollte für alle Spiegel erlaubt werden
        if (!secure_check_access(addr, 2)) {
            return false;  // Schutz inkonsistent!
        }
    }

    return true;  // Alle Spiegel gleichmäßig geschützt
}

CVE-Beispiele

  • CVE-2019-0090: Intel-CSME-Speicherbereich über ungeschützte Spiegel-Adressen zugänglich.
  • CVE-2020-0551: Load Value Injection durch ungeschützte Speicher-Aliase.

Verwandte CWEs

  • CWE-284: Improper Access Control (Eltern)
  • CWE-1251: Mirrored Regions with Different Values (Peer)
  • CWE-1203: Peripherals, On-chip Fabric, and Interface/IO Problems (Kategorie)
  • CWE-1299: Missing Protection Mechanism for Alternate Hardware Interface (verwandt)

Referenzen

  1. MITRE Corporation. "CWE-1312: Missing Protection for Mirrored Regions in On-Chip Fabric Firewall." https://cwe.mitre.org/data/definitions/1312.html
  2. ARM. "TrustZone Address Space Controller Technical Reference Manual"
  3. Intel. "System Address Map Configuration"