Versäumnis, reservierte Bits zu deaktivieren

Beschreibung

Versäumnis, reservierte Bits zu deaktivieren tritt auf, wenn ein Produkt nicht sicherstellt, dass als "reserviert" gekennzeichnete Hardware-Register-Bitfelder auf erwartete Standardwerte gesetzt werden. Reservierte Bits in Hardware-Registern sind Platzhalter für zukünftige Funktionalität oder für internen Gebrauch bestimmt. Wenn diese Bits beschreibbar und zugänglich bleiben, könnten Angreifer sie manipulieren, um unbeabsichtigte Verhaltensweisen zu aktivieren, Debug-Modi freizuschalten oder Sicherheitsmechanismen zu umgehen.

Risiko

Zugängliche reservierte Bits schaffen erhebliche Sicherheitsrisiken. Versteckte Debug-Modi können aktiviert werden. Undokumentierte Funktionen können freigeschaltet werden. Sicherheitsmechanismen können umgangen werden. Privilegieneskalation kann möglich werden. Hardwareverhalten kann unerwartet modifiziert werden. Geistiges Eigentum kann offengelegt werden. Werksseitige Testmodi können zugänglich werden.

Lösung

Reservierte Bits sollten schreibgeschützt sein und fest auf den erwarteten Wert verdrahtet sein. Wenn beschreibbar, müssen sie auf den erwarteten Wert zurückgesetzt werden. Implementieren Sie Write-Ignored-Verhalten für reservierte Felder. Dokumentieren Sie die richtige Behandlung für reservierte Bits. Testen Sie, dass reservierte Bits keine versteckten Funktionen freischalten. Verwenden Sie Hardware-Durchsetzung, um sicherzustellen, dass reservierte Bits nicht von Software modifiziert werden können.

Häufige Auswirkungen

AuswirkungDetails
VertraulichkeitBereich: Vertraulichkeit

Unautorisierter Zugriff - Reservierte Bits können versteckte Funktionen oder Debug-Zugriff freischalten.
IntegritätBereich: Integrität

Systemverhalten modifizieren - Manipulation kann Hardwareverhalten auf unbeabsichtigte Weise ändern.
ZugriffskontrolleBereich: Zugriffskontrolle

Schutzmechanismus umgehen - Reservierte Bits können Sicherheitskontrollen deaktivieren.

Beispielcode und Lösung

Verwundbarer Code

// Verwundbar: Reservierte Bits aktivieren versteckte Funktionalität

module vulnerable_control_register (
    input wire clk,
    input wire reset_n,
    input wire [31:0] write_data,
    input wire write_enable,
    input wire [3:0] register_address,
    output reg [31:0] read_data,
    output reg gpio_out,
    output reg debug_mode,
    output reg bypass_security
);

    // Steuerregister mit "reservierten" Bits die etwas bewirken
    // Dokumentierte Bits:
    //   [0]    - Feature A aktivieren
    //   [1]    - Feature B aktivieren
    //   [7:2]  - Reserviert (sollte 0 sein)
    //   [15:8] - Konfigurationswert
    //   [31:16]- Reserviert (sollte 0 sein)

    reg [31:0] control_reg;

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            control_reg <= 32'h0;
            gpio_out <= 1'b0;
            debug_mode <= 1'b0;
            bypass_security <= 1'b0;
        end
        else if (write_enable && register_address == 4'b0001) begin
            control_reg <= write_data;

            // VERWUNDBAR: "Reservierte" Bits bewirken tatsächlich etwas!

            // Reserviertes Bit [2] aktiviert heimlich GPIO
            gpio_out <= write_data[2];

            // Reserviertes Bit [3] aktiviert Debug-Modus
            debug_mode <= write_data[3];

            // Reserviertes Bit [16] umgeht Sicherheitsprüfungen!
            bypass_security <= write_data[16];
        end
    end

    // Weiteres verwundbares Muster: reservierte Adresse aktiviert versteckte Funktion
    always @(posedge clk) begin
        case (register_address)
            4'b0000: read_data <= status_reg;
            4'b0001: read_data <= control_reg;
            // Adresse 0x0F ist "reserviert" aber aktiviert Hintertür
            4'b1111: gpio_out <= 1'b1;  // Versteckte Funktionalität!
            default: read_data <= 32'h0;
        endcase
    end

endmodule

// Verwundbar: Undokumentierte Debug-Funktion über reserviertes Feld
module vulnerable_memory_controller (
    input wire clk,
    input wire [31:0] command,
    input wire [31:0] address,
    output reg [31:0] data_out,
    output reg command_complete
);

    // Befehlsformat:
    //   [3:0]   - Operationscode
    //   [7:4]   - Reserviert (sollte 0 sein)
    //   [31:8]  - Parameter

    wire [3:0] opcode = command[3:0];
    wire [3:0] reserved = command[7:4];  // "Reservierte" Bits

    always @(posedge clk) begin
        case (opcode)
            4'h1: begin
                // Normale Leseoperation
                data_out <= memory[address];
                command_complete <= 1'b1;
            end
            4'h2: begin
                // Normale Schreiboperation
                memory[address] <= command[31:8];
                command_complete <= 1'b1;
            end
            default: begin
                // VERWUNDBAR: Reservierte Bits prüfen auf Debug-Hintertür
                if (reserved == 4'hA) begin
                    // Versteckt: Gesamten Speicher ausgeben wenn reserviert = 0xA
                    dump_all_memory();
                end
                if (reserved == 4'hB) begin
                    // Versteckt: Zugriffskontrolle umgehen
                    bypass_acl <= 1'b1;
                end
            end
        endcase
    end

endmodule
// Verwundbar: Firmware mit aktiver Behandlung reservierter Bits

#define CONTROL_REG_ADDR 0x40001000

// Dokumentierte Registerbits
#define CTRL_ENABLE_A    (1 << 0)
#define CTRL_ENABLE_B    (1 << 1)
// Bits 2-7: Reserviert
#define CTRL_CONFIG_MASK 0xFF00
// Bits 16-31: Reserviert

// VERWUNDBAR: Versteckte Funktionalität in "reservierten" Bits
#define CTRL_DEBUG_MODE  (1 << 3)   // "Reserviert" aber aktiv
#define CTRL_BYPASS_SEC  (1 << 16)  // "Reserviert" aber aktiv

void configure_hardware(uint32_t config) {
    // In Steuerregister schreiben
    // Reservierte Bits werden auch geschrieben, aktivieren versteckte Funktionen
    *(volatile uint32_t*)CONTROL_REG_ADDR = config;
}

// Angreifer kann durch Setzen reservierter Bits ausnutzen
void exploit_reserved_bits(void) {
    // Undokumentierten Debug-Modus aktivieren
    configure_hardware(CTRL_ENABLE_A | CTRL_DEBUG_MODE);

    // Sicherheitsprüfungen umgehen
    configure_hardware(CTRL_ENABLE_A | CTRL_BYPASS_SEC);
}

Sichere Lösung

// Sicher: Reservierte Bits sind korrekt deaktiviert

module secure_control_register (
    input wire clk,
    input wire reset_n,
    input wire [31:0] write_data,
    input wire write_enable,
    input wire [3:0] register_address,
    output reg [31:0] read_data,
    output reg feature_a_enable,
    output reg feature_b_enable,
    output reg [7:0] config_value
);

    // Steuerregister mit wirklich reservierten Bits
    // Dokumentierte Bits:
    //   [0]    - Feature A aktivieren
    //   [1]    - Feature B aktivieren
    //   [7:2]  - Reserviert (MUSS NULL SEIN)
    //   [15:8] - Konfigurationswert
    //   [31:16]- Reserviert (MUSS NULL SEIN)

    reg [31:0] control_reg;

    // Maske für nur beschreibbare Bits
    localparam WRITABLE_MASK = 32'h0000FF03;

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            control_reg <= 32'h0;
            feature_a_enable <= 1'b0;
            feature_b_enable <= 1'b0;
            config_value <= 8'h0;
        end
        else if (write_enable && register_address == 4'b0001) begin
            // Nur dokumentierte Bits beschreiben - reservierte ausmaskieren
            control_reg <= write_data & WRITABLE_MASK;

            // Nur dokumentierte Bits verwenden
            feature_a_enable <= write_data[0];
            feature_b_enable <= write_data[1];
            config_value <= write_data[15:8];

            // Reservierte Bits [7:2] und [31:16] werden ignoriert
            // Keine versteckte Funktionalität
        end
    end

    always @(*) begin
        case (register_address)
            4'b0000: read_data = status_reg;
            4'b0001: read_data = control_reg;
            // Reservierte Adressen geben Null zurück, tun nichts
            default: read_data = 32'h0;
        endcase
        // Keine versteckte Funktionalität bei irgendeiner Adresse
    end

endmodule

// Sicher: Keine Debug-Hintertüren in reservierten Feldern
module secure_memory_controller (
    input wire clk,
    input wire reset_n,
    input wire [31:0] command,
    input wire [31:0] address,
    input wire command_valid,
    output reg [31:0] data_out,
    output reg command_complete,
    output reg command_error
);

    // Befehlsformat:
    //   [3:0]   - Operationscode
    //   [7:4]   - Reserviert (MUSS NULL SEIN)
    //   [31:8]  - Parameter

    wire [3:0] opcode = command[3:0];
    wire [3:0] reserved = command[7:4];

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            data_out <= 32'h0;
            command_complete <= 1'b0;
            command_error <= 1'b0;
        end
        else if (command_valid) begin
            // Prüfen ob reservierte Bits null sind
            if (reserved != 4'h0) begin
                // Reservierte Bits müssen null sein - Befehl ablehnen
                command_error <= 1'b1;
                command_complete <= 1'b1;
            end
            else begin
                command_error <= 1'b0;
                case (opcode)
                    4'h1: begin
                        // Normale Leseoperation
                        data_out <= memory[address];
                        command_complete <= 1'b1;
                    end
                    4'h2: begin
                        // Normale Schreiboperation
                        memory[address] <= command[31:8];
                        command_complete <= 1'b1;
                    end
                    default: begin
                        // Unbekannter Opcode - Fehler
                        command_error <= 1'b1;
                        command_complete <= 1'b1;
                    end
                endcase
            end
        end
    end

    // Keine versteckte Funktionalität irgendwo

endmodule

// Sicher: Produktionsversion mit entferntem Debug
module secure_control_register_production (
    input wire clk,
    input wire reset_n,
    input wire [31:0] write_data,
    input wire write_enable,
    output reg [31:0] control_reg
);

    // Nur Produktionsbits
    localparam PRODUCTION_MASK = 32'h0000FF03;

    // Debug-Funktionalität in Produktion vollständig entfernt
    // Nicht nur deaktiviert - die Logik existiert nicht

    `ifdef PRODUCTION
        // Produktions-Build: keine Debug-Logik synthetisiert
        always @(posedge clk or negedge reset_n) begin
            if (!reset_n)
                control_reg <= 32'h0;
            else if (write_enable)
                control_reg <= write_data & PRODUCTION_MASK;
        end
    `else
        // Entwicklungs-Build: Debug verfügbar
        // Dieser Code ist NICHT in der Produktionssynthese enthalten
        always @(posedge clk or negedge reset_n) begin
            if (!reset_n)
                control_reg <= 32'h0;
            else if (write_enable)
                control_reg <= write_data;
        end
    `endif

endmodule
// Sicher: Firmware behandelt reservierte Bits korrekt

#define CONTROL_REG_ADDR 0x40001000

// Dokumentierte Registerbits
#define CTRL_ENABLE_A    (1 << 0)
#define CTRL_ENABLE_B    (1 << 1)
#define CTRL_CONFIG_MASK 0x0000FF00

// Maske aller gültigen Bits
#define CTRL_VALID_MASK  (CTRL_ENABLE_A | CTRL_ENABLE_B | CTRL_CONFIG_MASK)

// Reservierte Bits - nur zur Dokumentation
// Diese Bits MÜSSEN als Null geschrieben werden
#define CTRL_RESERVED_MASK (~CTRL_VALID_MASK)

void configure_hardware(uint32_t config) {
    // Reservierte Bits vor dem Schreiben ausmaskieren
    uint32_t safe_config = config & CTRL_VALID_MASK;

    // Überprüfen ob reservierte Bits gesetzt waren (optionale Prüfung)
    if (config & CTRL_RESERVED_MASK) {
        log_warning("Versuch reservierte Bits zu setzen: 0x%08x", config);
    }

    // Nur gültige Bits schreiben
    *(volatile uint32_t*)CONTROL_REG_ADDR = safe_config;
}

uint32_t read_hardware_config(void) {
    uint32_t value = *(volatile uint32_t*)CONTROL_REG_ADDR;

    // Reservierte Bits beim Lesen ausmaskieren
    return value & CTRL_VALID_MASK;
}

// Validierungsfunktion für Sicherheitsaudit
bool validate_no_reserved_bit_effects(void) {
    uint32_t original = read_hardware_config();

    // Versuchen jedes reservierte Bit zu setzen
    for (int bit = 0; bit < 32; bit++) {
        if (CTRL_RESERVED_MASK & (1 << bit)) {
            // Dies ist ein reserviertes Bit - verifizieren dass es keine Wirkung hat
            *(volatile uint32_t*)CONTROL_REG_ADDR = original | (1 << bit);

            // Prüfen ob sich der Systemzustand unerwartet geändert hat
            if (detect_state_change()) {
                log_error("Reserviertes Bit %d hat Wirkung!", bit);
                return false;
            }
        }
    }

    // Original wiederherstellen
    *(volatile uint32_t*)CONTROL_REG_ADDR = original;
    return true;
}

Ausgenutzt in der Praxis

Intel Management Engine Hintertür (2017)

Forscher entdeckten, dass bestimmte undokumentierte Bits in Intel-Prozessoren verwendet werden könnten, um Management-Engine-Funktionen zu aktivieren oder zu deaktivieren, einschließlich potenzieller Sicherheitsumgehungen.


Tools zum Testen und Ausnutzen

  • Hardware-Debugger (JTAG, SWD) zum Testen von Registerzugriff.

  • Fuzzing-Tools für Hardware-Register.


CVE-Beispiele

  • CVE-2017-5703 — Undokumentierte CPU-Bits ermöglichten Sicherheitsumgehung.

Referenzen

  1. MITRE Corporation. "CWE-1209: Failure to Disable Reserved Bits." https://cwe.mitre.org/data/definitions/1209.html

  2. ARM. "Register Specification Guidelines."

  3. Intel. "Hardware Security Best Practices."