Fehlende Möglichkeit zum Patchen von ROM-Code

Beschreibung

Die fehlende Möglichkeit zum Patchen von ROM-Code tritt auf, wenn das Fehlen einer Patch-Fähigkeit für ROM-Code Systeme anfällig für nicht behebbare Sicherheitsprobleme macht, die nach der Bereitstellung entdeckt werden. Systeme, die Root-of-Trust (RoT)-Mechanismen verwenden, führen unveränderlichen ROM-Code während des Bootvorgangs aus. Wenn Schwachstellen nach der Auslieferung entdeckt werden, erzeugt die Unfähigkeit, den ROM zu patchen, ein permanentes Sicherheitsrisiko -- alle in dem ROM-Code entdeckten Sicherheitsschwachstellen können für bereits im Einsatz befindliche Systeme niemals behoben werden. Dies ist besonders kritisch für Secure-Boot-Implementierungen und kryptografische Operationen, die im ROM ausgeführt werden.

Risiko

Fehlendes ROM-Patching hat schwerwiegende Auswirkungen. Permanente Sicherheitsschwachstellen. Nicht behebbare Fehler in bereitgestellten Systemen. Root of Trust dauerhaft kompromittiert. Kryptografische Mängel nicht reparierbar. Secure-Boot-Umgehung möglich. Produktrückrufe können erforderlich sein. Reduzierte Systemwartbarkeit. Hohe Wahrscheinlichkeit dauerhafter Kompromittierung.

Lösung

Implementieren Sie sichere Patch-Unterstützung, die das Patchen von ROM-Code bei nachfolgenden Bootvorgängen während der Architektur-, Entwurfs- und Implementierungsphasen ermöglicht. Beachten Sie, dass Hardware-Initialisierung und Signaturverifizierung möglicherweise nicht patchbar bleiben. Unterstützen Sie feldprogrammierbare Patches unter Verwendung von Hardware-Fuses für begrenzte Nachbereitstellungs-Patches. Integrieren Sie das Patch-Laden in die frühe Boot-Sequenz. Verwenden Sie signierte Patches, um nicht autorisierte Änderungen zu verhindern.

Häufige Auswirkungen

AuswirkungDetails
WartbarkeitBereich: Sonstiges

Systeme, die nicht gepatcht werden können, verbleiben auf unbestimmte Zeit in verwundbaren Zuständen, was die Wartbarkeit reduziert.

Beispielcode und Lösung

Verwundbarer Code

// VERWUNDBAR: ROM ohne Patch-Fähigkeit

module vulnerable_boot_rom (
    input  wire        clk,
    input  wire        rst_n,
    input  wire [11:0] rom_addr,
    input  wire        ariane_boot_sel_i,  // Boot-Auswahlsignal
    output wire [31:0] rom_rdata
);

    // Fester ROM-Inhalt - kann nach der Fertigung nicht geändert werden
    reg [31:0] rom_linux [0:4095];
    reg [31:0] rom_rdata_linux;

    // ROM-Initialisierung (synthetisiert als Mask-ROM oder OTP)
    initial begin
        $readmemh("linux_bootrom.hex", rom_linux);
    end

    always @(posedge clk) begin
        rom_rdata_linux <= rom_linux[rom_addr];
    end

    // VERWUNDBAR: Fehler - gibt immer Linux-ROM aus, unabhängig von der Auswahl
    // Dieser Fehler kann nach der Chipfertigung nicht behoben werden!
    assign rom_rdata = (ariane_boot_sel_i) ? rom_rdata_linux : rom_rdata_linux;

    // Wenn eine Sicherheitsschwachstelle in rom_linux gefunden wird:
    // - ROM-Inhalt kann nicht aktualisiert werden
    // - Auswahllogik-Fehler kann nicht behoben werden
    // - Alle bereitgestellten Geräte bleiben verwundbar

endmodule

// VERWUNDBAR: Secure Boot mit nicht patchbarer Verifizierung
module vulnerable_secure_boot_rom (
    input  wire        clk,
    input  wire        rst_n,
    input  wire [31:0] firmware_addr,
    input  wire [31:0] firmware_data,
    input  wire [2047:0] firmware_signature,
    output reg         boot_authorized,
    output reg         boot_error
);

    // VERWUNDBAR: Öffentlicher Schlüssel im ROM eingebettet
    // Kann nicht geändert werden, wenn Schlüssel kompromittiert ist
    reg [2047:0] rom_public_key;

    initial begin
        // Schlüssel ist permanent eingebettet
        rom_public_key = 2048'h<fixed_public_key>;
    end

    // VERWUNDBAR: Signaturverifizierungslogik im ROM
    // Alle Fehler hier sind permanent
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            boot_authorized <= 1'b0;
            boot_error <= 1'b0;
        end else begin
            // VERWUNDBAR: Wenn RSA-Verifizierung einen Fehler hat (z.B. Padding-Oracle),
            // kann er nicht behoben werden
            if (rsa_verify(firmware_data, firmware_signature, rom_public_key)) begin
                boot_authorized <= 1'b1;
            end else begin
                boot_error <= 1'b1;
            end
        end
    end

    // Wenn Schwachstelle entdeckt wird (z.B. Bleichenbacher-Angriff):
    // - Verifizierungsalgorithmus kann nicht aktualisiert werden
    // - Kompromittierter Schlüssel kann nicht widerrufen werden
    // - Alle Geräte dauerhaft verwundbar

endmodule
// VERWUNDBAR: Boot-ROM-Code ohne Patch-Unterstützung

// Dieser Code ist im ROM eingebrannt - kann nach der Fertigung nicht geändert werden

#include <stdint.h>

// VERWUNDBAR: Feste kryptografische Implementierung im ROM
// Wenn Algorithmus Schwachstelle hat, nicht patchbar
void rom_sha256(const uint8_t* data, size_t len, uint8_t* hash) {
    // SHA-256-Implementierung
    // VERWUNDBAR: Wenn hier Fehler gefunden wird, nicht behebbar
}

// VERWUNDBAR: Secure-Boot-Verifizierung im ROM
int rom_verify_firmware(const uint8_t* firmware, size_t size,
                        const uint8_t* signature) {
    // VERWUNDBAR: Fester öffentlicher Schlüssel im ROM
    static const uint8_t rom_public_key[256] = {
        // RSA-2048 öffentlicher Schlüssel
        // Kann nicht geändert werden, wenn kompromittiert
    };

    uint8_t hash[32];
    rom_sha256(firmware, size, hash);

    // VERWUNDBAR: RSA-Verifizierungscode im ROM
    // Padding-Schwachstellen können nicht behoben werden
    return rom_rsa_verify(hash, signature, rom_public_key);
}

// VERWUNDBAR: Haupt-Boot-Sequenz im ROM
void rom_boot(void) {
    // 1. Hardware-Initialisierung (muss typischerweise im ROM sein)
    init_hardware();

    // 2. Firmware aus Speicher laden
    uint8_t* firmware = load_firmware();
    size_t size = get_firmware_size();
    uint8_t* signature = get_firmware_signature();

    // 3. VERWUNDBAR: Verifizierung verwendet potenziell fehlerhaften ROM-Code
    if (!rom_verify_firmware(firmware, size, signature)) {
        // Boot-Fehler
        halt();
    }

    // 4. Firmware ausführen
    // VERWUNDBAR: Keine Möglichkeit, Patches vor diesem Punkt anzuwenden
    jump_to_firmware(firmware);
}

Sichere Lösung

// SICHER: ROM mit Patch-Ladefähigkeit

module secure_boot_rom_with_patch (
    input  wire        clk,
    input  wire        rst_n,
    input  wire [11:0] rom_addr,
    input  wire        ariane_boot_sel_i,

    // Patch-Schnittstelle
    input  wire [11:0] patch_addr,
    input  wire [31:0] patch_data,
    input  wire        patch_valid,
    input  wire        patch_enable,       // Von Fuse oder sicherem Register
    input  wire [2047:0] patch_signature,

    output wire [31:0] rom_rdata,
    output reg         patch_error
);

    // Fester ROM-Inhalt
    reg [31:0] rom_linux [0:4095];
    reg [31:0] rom_patch [0:4095];  // SICHER: Patchbares RAM-Overlay

    reg [31:0] rom_rdata_linux;
    reg [31:0] rom_rdata_patch;
    reg patch_loaded;

    // SICHER: Fuse-Bits, die anzeigen, welche Adressen gepatcht sind
    reg [4095:0] patch_mask;

    // ROM-Initialisierung
    initial begin
        $readmemh("linux_bootrom.hex", rom_linux);
        patch_loaded = 1'b0;
        patch_mask = 4096'b0;
    end

    // SICHER: Patch-Laden mit Signaturverifizierung
    wire patch_sig_valid;

    patch_signature_verifier u_patch_verify (
        .clk(clk),
        .rst_n(rst_n),
        .patch_data(patch_data),
        .patch_signature(patch_signature),
        .signature_valid(patch_sig_valid)
    );

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            patch_loaded <= 1'b0;
            patch_error <= 1'b0;
            patch_mask <= 4096'b0;
        end else if (patch_enable && patch_valid) begin
            // SICHER: Nur signierte Patches laden
            if (patch_sig_valid) begin
                rom_patch[patch_addr] <= patch_data;
                patch_mask[patch_addr] <= 1'b1;
                patch_loaded <= 1'b1;
            end else begin
                patch_error <= 1'b1;
            end
        end
    end

    // ROM-Lesezugriff
    always @(posedge clk) begin
        rom_rdata_linux <= rom_linux[rom_addr];
        rom_rdata_patch <= rom_patch[rom_addr];
    end

    // SICHER: Patch-Daten ausgeben wenn Adresse gepatcht ist, sonst ROM-Daten
    wire use_patch = patch_loaded && patch_mask[rom_addr];

    // SICHER: Korrekte Boot-Auswahl (Fehler behoben)
    wire [31:0] selected_rom_data;
    assign selected_rom_data = ariane_boot_sel_i ? rom_rdata_patch : rom_rdata_linux;

    // SICHER: Patch-Overlay
    assign rom_rdata = use_patch ? rom_rdata_patch : selected_rom_data;

endmodule

// SICHER: Fuse-basiertes Patching für begrenzte Aktualisierungen
module secure_fuse_patchable_rom (
    input  wire        clk,
    input  wire        rst_n,
    input  wire [11:0] rom_addr,
    output wire [31:0] rom_rdata,

    // Fuse-Schnittstelle
    input  wire [31:0] fuse_patch_0,  // Hardware-Fuses - einmal programmierbar
    input  wire [31:0] fuse_patch_1,
    input  wire [31:0] fuse_patch_2,
    input  wire [31:0] fuse_patch_3,
    input  wire [11:0] fuse_patch_addr_0,
    input  wire [11:0] fuse_patch_addr_1,
    input  wire [11:0] fuse_patch_addr_2,
    input  wire [11:0] fuse_patch_addr_3,
    input  wire [3:0]  fuse_patch_valid
);

    reg [31:0] rom_content [0:4095];
    reg [31:0] rom_rdata_reg;

    initial begin
        $readmemh("bootrom.hex", rom_content);
    end

    always @(posedge clk) begin
        // SICHER: Prüfen ob Adresse einem Fuse-Patch entspricht
        if (fuse_patch_valid[0] && rom_addr == fuse_patch_addr_0) begin
            rom_rdata_reg <= fuse_patch_0;
        end else if (fuse_patch_valid[1] && rom_addr == fuse_patch_addr_1) begin
            rom_rdata_reg <= fuse_patch_1;
        end else if (fuse_patch_valid[2] && rom_addr == fuse_patch_addr_2) begin
            rom_rdata_reg <= fuse_patch_2;
        end else if (fuse_patch_valid[3] && rom_addr == fuse_patch_addr_3) begin
            rom_rdata_reg <= fuse_patch_3;
        end else begin
            rom_rdata_reg <= rom_content[rom_addr];
        end
    end

    assign rom_rdata = rom_rdata_reg;

    // SICHER: Fuses ermöglichen begrenztes Feld-Patching
    // Bis zu 4 Befehl-Patches über OTP-Fuses

endmodule
// SICHER: Boot-ROM mit Patch-Ladefähigkeit

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

// Minimaler ROM-Code - gerade genug zum Laden und Verifizieren von Patches
// Größerer Boot-Code ist im Flash und kann gepatcht werden

// Fester ROM-öffentlicher Schlüssel für Patch-Verifizierung
static const uint8_t ROM_PATCH_KEY[256] = {
    // RSA-2048 Schlüssel nur für Patch-Verifizierung
};

// Patch-Speicherstruktur
typedef struct {
    uint32_t patch_address;
    uint32_t patch_size;
    uint8_t  patch_data[4096];
    uint8_t  signature[256];
} rom_patch_t;

// SICHER: Patch-Signatur vor dem Anwenden verifizieren
bool rom_verify_patch(const rom_patch_t* patch) {
    uint8_t hash[32];

    // Patch-Metadaten und Daten hashen
    sha256_context ctx;
    sha256_init(&ctx);
    sha256_update(&ctx, &patch->patch_address, sizeof(patch->patch_address));
    sha256_update(&ctx, &patch->patch_size, sizeof(patch->patch_size));
    sha256_update(&ctx, patch->patch_data, patch->patch_size);
    sha256_final(&ctx, hash);

    // Signatur mit ROM-Schlüssel verifizieren
    return rom_rsa_verify(hash, patch->signature, ROM_PATCH_KEY);
}

// SICHER: Patch-RAM-Overlay
static uint8_t patch_overlay[4096];
static uint32_t patch_base_address;
static uint32_t patch_size;
static bool patch_active = false;

// SICHER: Verifizierten Patch auf RAM-Overlay anwenden
bool rom_apply_patch(const rom_patch_t* patch) {
    // Patch zuerst verifizieren
    if (!rom_verify_patch(patch)) {
        return false;
    }

    // Patch in RAM-Overlay kopieren
    memcpy(patch_overlay, patch->patch_data, patch->patch_size);
    patch_base_address = patch->patch_address;
    patch_size = patch->patch_size;
    patch_active = true;

    return true;
}

// SICHER: ROM-Lesefunktion, die Patch-Overlay prüft
uint32_t rom_read(uint32_t address) {
    // Prüfen ob Adresse im gepatchten Bereich liegt
    if (patch_active &&
        address >= patch_base_address &&
        address < patch_base_address + patch_size) {
        // Gepatchte Daten zurückgeben
        return *(uint32_t*)&patch_overlay[address - patch_base_address];
    }

    // Originale ROM-Daten zurückgeben
    return *(uint32_t*)(ROM_BASE + address);
}

// SICHER: Boot-Sequenz mit Patch-Unterstützung
void rom_boot(void) {
    // 1. Minimale Hardware-Initialisierung (muss im ROM sein)
    init_critical_hardware();

    // 2. SICHER: Patches aus sicherem Speicher laden und verifizieren
    rom_patch_t* patch = load_patch_from_storage();
    if (patch != NULL) {
        if (!rom_apply_patch(patch)) {
            // Patch-Verifizierung fehlgeschlagen
            // Mit ungepatchtem ROM fortfahren
        }
    }

    // 3. Sekundären Bootloader laden (kann gepatcht sein)
    uint8_t* bootloader = load_bootloader();
    size_t size = get_bootloader_size();
    uint8_t* signature = get_bootloader_signature();

    // 4. Bootloader verifizieren (mit potenziell gepatchter Verifizierung)
    if (!verify_bootloader(bootloader, size, signature)) {
        halt();
    }

    // 5. Bootloader ausführen
    jump_to_bootloader(bootloader);
}

// SICHER: Fuse-basierter Notfall-Patch
void apply_fuse_patches(void) {
    // Patch-Daten aus OTP-Fuses lesen
    uint32_t fuse_patch_addr = read_fuse(FUSE_PATCH_ADDR);
    uint32_t fuse_patch_data = read_fuse(FUSE_PATCH_DATA);

    if (fuse_patch_addr != 0xFFFFFFFF) {
        // Einzelbefehl-Fuse-Patch anwenden
        // Begrenzt, aber verfügbar für kritische Korrekturen
        apply_instruction_patch(fuse_patch_addr, fuse_patch_data);
    }
}

CVE-Beispiele

  • CVE-2020-0069: MediaTek-BootROM-Schwachstelle, die nicht gepatcht werden könnte und Millionen von Geräten betraf.
  • CVE-2019-14192: U-Boot-ROM-Schwachstellen, die einen Hardwareaustausch erforderten.
  • CVE-2021-30900: Apple-BootROM (SecureROM)-Schwachstelle im checkm8-Exploit.

Verwandte CWEs

  • CWE-1329: Reliance on Component That is Not Updateable (Eltern)
  • CWE-1196: Security Flow Issues (Kategorie)
  • CWE-693: Protection Mechanism Failure (verwandt)

Referenzen

  1. MITRE Corporation. "CWE-1310: Missing Ability to Patch ROM Code." https://cwe.mitre.org/data/definitions/1310.html
  2. NIST. "Platform Firmware Resiliency Guidelines (SP 800-193)"
  3. OpenTitan. "ROM and ROM Extension Design"