Fehlender Schutzmechanismus für alternative Hardware-Schnittstelle

Beschreibung

Ein fehlender Schutzmechanismus für alternative Hardware-Schnittstellen tritt auf, wenn Assets nicht über alle Zugriffspfade hinweg geschützt sind. Angreifer können primäre Schutzmechanismen umgehen, indem sie ungeschützte alternative Wege ausnutzen. Während ein Asset auf einer Schnittstelle Zugriffskontrollen haben kann, entstehen Schwachstellen, wenn alternative Pfade ungeschützt bleiben. Beispiele sind Shadow-/Mirror-Register, die Adressen abbilden, aber keine Zugriffskontrollen haben, mehrere externe Schnittstellen, von denen nur einige geschützt sind (z.B. PCIe geschützt, aber UART ungeschützt), und indirekte Zugriffswege wie Instruktionsbus versus Datenbus.

Risiko

Fehlender Schutz alternativer Schnittstellen hat schwerwiegende Auswirkungen. Speicheränderung über ungeschützte Pfade. Unautorisierte Lesezugriffe über alternative Schnittstellen. Denial of Service möglich. Schutzmechanismen vollständig umgangen. Privilege Escalation ermöglicht. Unautorisierte Codeausführung. Logikveränderung über ungeschützte Kanäle. Shadow-Register legen sensible Daten offen. Hohe Wahrscheinlichkeit der Ausnutzung.

Lösung

Schützen Sie Assets über alle potenziellen Schnittstellen und alternativen Pfade während der Anforderungsphase. Implementieren Sie systematisch Defense-in-Depth-Schutzmechanismen während der Architektur und des Entwurfs. Stellen Sie sicher, dass Zugriffskontrollen während der Implementierung alle Datenpfade umfassend abdecken. Prüfen Sie alle Pfade zu sensiblen Assets. Betrachten Sie Shadow-/Mirror-Register als separate Zugriffspunkte. Wenden Sie konsistenten Schutz über alle externen Schnittstellen hinweg an.

Häufige Auswirkungen

AuswirkungDetails
VertraulichkeitBereich: Vertraulichkeit

Unautorisierte Lesezugriffe über alternative Schnittstellen.
IntegritätBereich: Integrität

Speicheränderung über ungeschützte Pfade.
VerfügbarkeitBereich: Verfügbarkeit

Denial of Service durch Ressourcenverbrauch.
ZugriffskontrolleBereich: Zugriffskontrolle

Schutzumgehung durch alternative Kanäle.

Beispielcode und Lösung

Verwundbarer Code

// VERWUNDBAR: Schutz nur auf primärer Adresse, nicht auf Shadow

module vulnerable_register_protection (
    input  wire        clk,
    input  wire        rst_n,
    input  wire [31:0] address,
    input  wire [31:0] write_data,
    input  wire        write_enable,
    input  wire        is_privileged,
    output reg  [31:0] read_data,
    output reg         access_denied
);

    // Primäre Adresse für sicheres Register
    localparam SECURE_REG_ADDR = 32'h0000_0F00;

    // VERWUNDBAR: Shadow-Adresse existiert, ist aber nicht geschützt
    // localparam SHADOW_REG_ADDR = 32'h0080_0F00;
    // Shadow spiegelt die primäre Adresse, aber Hardware ignoriert Bit [23]

    reg [31:0] secure_register;

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

            // VERWUNDBAR: Nur primäre Adresse wird geprüft
            if (address == SECURE_REG_ADDR) begin
                if (is_privileged) begin
                    if (write_enable) begin
                        secure_register <= write_data;
                    end
                end else begin
                    access_denied <= 1'b1;
                end
            end

            // VERWUNDBAR: Shadow-Adresse 0x800F00 wird nicht geprüft!
            // Angreifer kann über Shadow-Adresse auf das Register zugreifen
            // ohne Berechtigungsprüfung
        end
    end

    // VERWUNDBAR: Lesezugriff schützt Shadow ebenfalls nicht
    always @(*) begin
        if (address == SECURE_REG_ADDR) begin
            read_data = is_privileged ? secure_register : 32'b0;
        end else if (address[22:0] == SECURE_REG_ADDR[22:0]) begin
            // Shadow-Adresse stimmt überein - aber kein Schutz!
            read_data = secure_register;  // VERWUNDBAR: Keine Berechtigungsprüfung
        end else begin
            read_data = 32'b0;
        end
    end

endmodule

// VERWUNDBAR: Mehrere Schnittstellen mit inkonsistentem Schutz
module vulnerable_multi_interface (
    input  wire        clk,
    input  wire        rst_n,

    // PCIe-Schnittstelle (geschützt)
    input  wire [31:0] pcie_addr,
    input  wire [31:0] pcie_data,
    input  wire        pcie_write,
    input  wire        pcie_privileged,

    // UART-Schnittstelle (VERWUNDBAR: ungeschützt)
    input  wire [31:0] uart_addr,
    input  wire [31:0] uart_data,
    input  wire        uart_write,

    // SMBus-Schnittstelle (VERWUNDBAR: ungeschützt)
    input  wire [31:0] smbus_addr,
    input  wire [31:0] smbus_data,
    input  wire        smbus_write,

    output reg  [31:0] config_register
);

    localparam CONFIG_ADDR = 32'h0000_1000;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            config_register <= 32'b0;
        end else begin
            // PCIe-Schnittstelle - geschützt
            if (pcie_write && pcie_addr == CONFIG_ADDR) begin
                if (pcie_privileged) begin
                    config_register <= pcie_data;
                end
            end

            // VERWUNDBAR: UART-Schnittstelle - kein Schutz!
            if (uart_write && uart_addr == CONFIG_ADDR) begin
                config_register <= uart_data;  // Keine Berechtigungsprüfung!
            end

            // VERWUNDBAR: SMBus-Schnittstelle - kein Schutz!
            if (smbus_write && smbus_addr == CONFIG_ADDR) begin
                config_register <= smbus_data;  // Keine Berechtigungsprüfung!
            end
        end
    end

endmodule

// VERWUNDBAR: Instruktionsbus umgeht Datenbus-Schutz
module vulnerable_bus_bypass (
    input  wire        clk,
    input  wire        rst_n,

    // Datenbus (geschützt)
    input  wire [31:0] data_addr,
    input  wire        data_read,
    input  wire        data_privileged,
    output reg  [31:0] data_out,

    // Instruktionsbus (VERWUNDBAR: ungeschützt)
    input  wire [31:0] instr_addr,
    input  wire        instr_fetch,
    output reg  [31:0] instr_out
);

    // Sensibler Daten-/Codebereich
    localparam SECRET_START = 32'h1000_0000;
    localparam SECRET_END   = 32'h1000_FFFF;

    reg [31:0] secret_memory [0:4095];

    // Datenbus - geschützt
    always @(*) begin
        data_out = 32'b0;
        if (data_read) begin
            if (data_addr >= SECRET_START && data_addr <= SECRET_END) begin
                if (data_privileged) begin
                    data_out = secret_memory[data_addr[13:2]];
                end
                // Unprivilegierter Zugriff verweigert
            end
        end
    end

    // VERWUNDBAR: Instruktionsabruf umgeht den Schutz
    always @(*) begin
        instr_out = 32'b0;
        if (instr_fetch) begin
            if (instr_addr >= SECRET_START && instr_addr <= SECRET_END) begin
                // VERWUNDBAR: Keine Berechtigungsprüfung auf dem Instruktionsbus!
                instr_out = secret_memory[instr_addr[13:2]];
            end
        end
    end

    // Angriff: Geheime Daten über Instruktionsabruf lesen
    // Code von angreiferkontrolliertem Speicherort ausführen, der "Instruktionen"
    // aus dem geheimen Bereich abruft

endmodule

Sichere Lösung

// SICHER: Schutz auf allen Adressen einschließlich Shadow

module secure_register_protection (
    input  wire        clk,
    input  wire        rst_n,
    input  wire [31:0] address,
    input  wire [31:0] write_data,
    input  wire        write_enable,
    input  wire        is_privileged,
    output reg  [31:0] read_data,
    output reg         access_denied
);

    // Primäre Adresse für sicheres Register
    localparam SECURE_REG_ADDR = 32'h0000_0F00;

    // SICHER: Auch Shadow-Adresse schützen
    localparam SHADOW_REG_ADDR = 32'h0080_0F00;

    reg [31:0] secure_register;

    // SICHER: Funktion zur Prüfung, ob Adresse dem sicheren Register entspricht
    function automatic is_secure_reg_address;
        input [31:0] addr;
        begin
            // Primäre Adresse prüfen
            if (addr == SECURE_REG_ADDR)
                is_secure_reg_address = 1'b1;
            // SICHER: Shadow-Adresse prüfen
            else if (addr == SHADOW_REG_ADDR)
                is_secure_reg_address = 1'b1;
            // SICHER: Alle möglichen Aliase prüfen (Bit 23 wird von Hardware ignoriert)
            else if (addr[22:0] == SECURE_REG_ADDR[22:0])
                is_secure_reg_address = 1'b1;
            else
                is_secure_reg_address = 1'b0;
        end
    endfunction

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

            // SICHER: Alle möglichen Adressen zum sicheren Register prüfen
            if (is_secure_reg_address(address)) begin
                if (is_privileged) begin
                    if (write_enable) begin
                        secure_register <= write_data;
                    end
                end else begin
                    access_denied <= 1'b1;  // SICHER: Bei jedem Alias verweigern
                end
            end
        end
    end

    // SICHER: Leseschutz auf allen Aliasen
    always @(*) begin
        if (is_secure_reg_address(address)) begin
            read_data = is_privileged ? secure_register : 32'b0;
        end else begin
            read_data = 32'b0;
        end
    end

endmodule

// SICHER: Konsistenter Schutz über alle Schnittstellen
module secure_multi_interface (
    input  wire        clk,
    input  wire        rst_n,

    // PCIe-Schnittstelle
    input  wire [31:0] pcie_addr,
    input  wire [31:0] pcie_data,
    input  wire        pcie_write,
    input  wire        pcie_privileged,

    // UART-Schnittstelle
    input  wire [31:0] uart_addr,
    input  wire [31:0] uart_data,
    input  wire        uart_write,
    input  wire        uart_privileged,  // SICHER: Berechtigungssignal hinzugefügt

    // SMBus-Schnittstelle
    input  wire [31:0] smbus_addr,
    input  wire [31:0] smbus_data,
    input  wire        smbus_write,
    input  wire        smbus_privileged,  // SICHER: Berechtigungssignal hinzugefügt

    output reg  [31:0] config_register,
    output reg         access_fault
);

    localparam CONFIG_ADDR = 32'h0000_1000;

    // SICHER: Zentralisierte Zugriffskontrolle
    function automatic access_allowed;
        input [31:0] addr;
        input        privileged;
        begin
            if (addr == CONFIG_ADDR) begin
                access_allowed = privileged;
            end else begin
                access_allowed = 1'b1;  // Andere Adressen können öffentlich sein
            end
        end
    endfunction

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

            // SICHER: PCIe-Schnittstelle - geschützt
            if (pcie_write && pcie_addr == CONFIG_ADDR) begin
                if (access_allowed(pcie_addr, pcie_privileged)) begin
                    config_register <= pcie_data;
                end else begin
                    access_fault <= 1'b1;
                end
            end

            // SICHER: UART-Schnittstelle - jetzt geschützt
            if (uart_write && uart_addr == CONFIG_ADDR) begin
                if (access_allowed(uart_addr, uart_privileged)) begin
                    config_register <= uart_data;
                end else begin
                    access_fault <= 1'b1;
                end
            end

            // SICHER: SMBus-Schnittstelle - jetzt geschützt
            if (smbus_write && smbus_addr == CONFIG_ADDR) begin
                if (access_allowed(smbus_addr, smbus_privileged)) begin
                    config_register <= smbus_data;
                end else begin
                    access_fault <= 1'b1;
                end
            end
        end
    end

endmodule

// SICHER: Schutz auf Instruktions- und Datenbus
module secure_bus_protection (
    input  wire        clk,
    input  wire        rst_n,

    // Datenbus
    input  wire [31:0] data_addr,
    input  wire        data_read,
    input  wire        data_privileged,
    output reg  [31:0] data_out,
    output reg         data_fault,

    // Instruktionsbus
    input  wire [31:0] instr_addr,
    input  wire        instr_fetch,
    input  wire        instr_privileged,  // SICHER: Berechtigung für Instruktionsabruf
    output reg  [31:0] instr_out,
    output reg         instr_fault
);

    // Sensibler Bereich
    localparam SECRET_START = 32'h1000_0000;
    localparam SECRET_END   = 32'h1000_FFFF;

    reg [31:0] secret_memory [0:4095];

    // SICHER: Zentralisierte Bereichsprüfung
    function automatic is_secret_region;
        input [31:0] addr;
        begin
            is_secret_region = (addr >= SECRET_START) && (addr <= SECRET_END);
        end
    endfunction

    // Datenbus - geschützt
    always @(*) begin
        data_out = 32'b0;
        data_fault = 1'b0;

        if (data_read) begin
            if (is_secret_region(data_addr)) begin
                if (data_privileged) begin
                    data_out = secret_memory[data_addr[13:2]];
                end else begin
                    data_fault = 1'b1;  // Zugriff verweigert
                end
            end
        end
    end

    // SICHER: Instruktionsbus - ebenfalls geschützt
    always @(*) begin
        instr_out = 32'b0;
        instr_fault = 1'b0;

        if (instr_fetch) begin
            if (is_secret_region(instr_addr)) begin
                // SICHER: Berechtigungsprüfung auch beim Instruktionsabruf
                if (instr_privileged) begin
                    instr_out = secret_memory[instr_addr[13:2]];
                end else begin
                    instr_fault = 1'b1;  // Zugriff verweigert
                end
            end
        end
    end

endmodule

CVE-Beispiele

  • CVE-2022-38399: Unauthentifizierter serieller Zugriff ermöglichte beliebige Befehlsausführung.
  • CVE-2020-8004: Flash-Schutz über Instruktionsbus umgangen.
  • CVE-2017-18293: GPIO-Schutz über gebankte Register umgangen.

Verwandte CWEs

  • CWE-288: Authentifizierungsumgehung über einen alternativen Pfad oder Kanal (übergeordnet)
  • CWE-420: Ungeschützter alternativer Kanal (übergeordnet)
  • CWE-1191: On-Chip Debug- und Test-Schnittstelle mit unsachgemäßer Zugriffskontrolle (gleichrangig)
  • CWE-1314: Fehlender Schreibschutz für parametrische Datenwerte (gleichrangig)

Referenzen

  1. MITRE Corporation. "CWE-1299: Missing Protection Mechanism for Alternate Hardware Interface." https://cwe.mitre.org/data/definitions/1299.html
  2. ARM. "AMBA AXI and ACE Protocol Specification"
  3. IEEE. "Secure Hardware Design Guidelines"