Race Condition bei Write-Once-Attributen

Beschreibung

Race Condition bei Write-Once-Attributen tritt auf, wenn ein Hardware-Design Write-Once-Register oder andere Elemente enthält, die gleichzeitig von Software und Hardware modifiziert werden können, wodurch eine Race Condition entsteht. Write-Once-Register werden häufig für Sicherheitsrichtlinien, Zugriffskontrollen, OTP-Speicher (One-Time Programmable) und sichere Konfigurationen verwendet, die nur einmal während des Boots gesetzt werden sollten. Wenn sowohl Software als auch Hardware um das Setzen dieser Werte konkurrieren können, kann ein Angreifer das Rennen gewinnen und bösartige Werte setzen, bevor legitime Sicherheitskonfigurationen eingerichtet sind.

Risiko

Race Conditions bei Write-Once-Attributen haben schwerwiegende Sicherheitsauswirkungen. Sicherheitsrichtlinien können von Angreifern vor der legitimen Software gesetzt werden. Zugriffskontrollkonfigurationen können böswillig eingerichtet werden. Boot-Sicherheitsmaßnahmen können durch Ausnutzung von Race Conditions umgangen werden. OTP-Fuses können mit Angreiferwerten programmiert werden. Debug-Schnittstellen können vor der Sicherung entsperrt werden. Privilegierungsstufen können für Angreifer günstig gesetzt werden. Vertrauensanker können während der Initialisierung kompromittiert werden.

Lösung

Implementieren Sie eine deterministische Schreibreihenfolge für sicherheitskritische Register. Verwenden Sie Hardware-Arbitrierung, um sicherzustellen, dass vertrauenswürdige Quellen zuerst schreiben. Fügen Sie Zeitgarantien hinzu, die sicherstellen, dass sichere Schreibvorgänge vor nicht vertrauenswürdigem Zugriff abgeschlossen werden. Implementieren Sie Hardware-Sperren, die atomar mit Werten gesetzt werden. Verwenden Sie gestufte Initialisierung mit Sicherheitsprüfpunkten. Trennen Sie Schreibberechtigungen für initialen und nachfolgenden Zugriff. Überprüfen Sie Write-Once-Werte, bevor der Systembetrieb zugelassen wird. Implementieren Sie Hardware-Verriegelungen, die gleichzeitigen Zugriff verhindern. Gestalten Sie Boot-Sequenzen, die Race-Fenster eliminieren.

Häufige Auswirkungen

AuswirkungDetails
Integrität, AutorisierungBereich: Integrität, Autorisierung

Umgehung von Schutzmechanismen, Privilegienerlangung – Angreifer können das Rennen gewinnen, um sicherheitskritische Write-Once-Werte zu setzen, beabsichtigte Schutzmaßnahmen umgehen oder erhöhte Privilegien erlangen.
ZugriffskontrolleBereich: Zugriffskontrolle

Speicher modifizieren – Sicherheitskonfigurationen können auf vom Angreifer kontrollierte Werte gesetzt werden, bevor legitime Software handelt.

Beispielcode und Lösung

Verwundbarer Code

// VERWUNDBAR: Write-Once-Register mit Race Condition

module vulnerable_write_once_register (
    input wire clk,
    input wire reset_n,
    // Software-Schnittstelle
    input wire [31:0] sw_write_data,
    input wire sw_write_enable,
    // Hardware-Schnittstelle (z.B. von Boot-ROM oder Fuse-Controller)
    input wire [31:0] hw_write_data,
    input wire hw_write_enable,
    output reg [31:0] register_value,
    output reg register_locked
);

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            register_value <= 32'h0;
            register_locked <= 1'b0;
        end
        else if (!register_locked) begin
            // VERWUNDBAR: Race Condition zwischen Software und Hardware
            // Wer zuerst schreibt, gewinnt!

            if (sw_write_enable && hw_write_enable) begin
                // Beide versuchen zu schreiben – undefiniertes Verhalten!
                // Könnte je nach Timing einen der Werte annehmen
                register_value <= sw_write_data;  // Oder hw_write_data?
                register_locked <= 1'b1;
            end
            else if (sw_write_enable) begin
                // Software kann das Rennen gewinnen
                register_value <= sw_write_data;
                register_locked <= 1'b1;
            end
            else if (hw_write_enable) begin
                // Hardware setzt Wert
                register_value <= hw_write_data;
                register_locked <= 1'b1;
            end
        end
    end

endmodule

// VERWUNDBAR: Sicherheitsrichtlinien-Register mit Race-Fenster
module vulnerable_security_policy (
    input wire clk,
    input wire reset_n,
    input wire [31:0] policy_write,
    input wire policy_write_en,
    input wire boot_complete,
    output reg [31:0] security_policy,
    output reg policy_locked
);

    // VERWUNDBAR: Richtlinie kann vor boot_complete von jedem gesetzt werden
    // Race-Fenster existiert zwischen Reset und Boot-Abschluss

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            security_policy <= 32'h0;  // Unsicherer Standard!
            policy_locked <= 1'b0;
        end
        else begin
            if (!policy_locked) begin
                // Jeder kann während des Race-Fensters schreiben
                if (policy_write_en) begin
                    security_policy <= policy_write;
                end
            end

            // Sperre geschieht unabhängig vom Schreibvorgang
            if (boot_complete) begin
                policy_locked <= 1'b1;
            end
        end
    end

    // Angreifer kann:
    // 1. Bösartige Richtlinie schreiben
    // 2. Rennen gewinnen, um vor legitimem Boot-Code fertig zu sein

endmodule

// VERWUNDBAR: OTP-Fuse-Programmierung mit Race Condition
module vulnerable_otp_controller (
    input wire clk,
    input wire [31:0] fuse_data,
    input wire fuse_program,
    input wire [7:0] fuse_address,
    output reg programming_complete
);

    reg [31:0] otp_array [0:255];
    reg [255:0] fuse_programmed;

    always @(posedge clk) begin
        if (fuse_program && !fuse_programmed[fuse_address]) begin
            // VERWUNDBAR: Keine Authentifizierung vor Fuse-Programmierung
            // Keine Reihenfolgegarantie für Sicherheits-Fuses
            otp_array[fuse_address] <= fuse_data;
            fuse_programmed[fuse_address] <= 1'b1;
            programming_complete <= 1'b1;
        end
    end

endmodule
// VERWUNDBAR: Software mit Race Condition bei Write-Once-Konfiguration

// Sicherheitskonfigurationsregister
#define SECURITY_CONFIG_REG 0x40000000
#define SECURITY_LOCK_REG   0x40000004

volatile uint32_t* security_config = (uint32_t*)SECURITY_CONFIG_REG;
volatile uint32_t* security_lock = (uint32_t*)SECURITY_LOCK_REG;

void vulnerable_set_security_policy(void) {
    // Prüfen ob bereits gesperrt
    if (*security_lock) {
        return;  // Bereits gesetzt
    }

    // VERWUNDBAR: Race-Fenster zwischen Prüfung und Schreiben
    // Ein anderer Thread/Prozess/Hardware könnte hier den Wert setzen

    // Unsere Richtlinie setzen
    *security_config = SECURE_POLICY_VALUE;

    // Sperren
    *security_lock = 1;

    // Problem: Angreifer könnte das Rennen gewonnen haben
}

// VERWUNDBAR: Nicht-atomares Prüfen-dann-Handeln
bool vulnerable_init_write_once(uint32_t* reg, uint32_t* lock, uint32_t value) {
    // VERWUNDBAR: TOCTOU Race Condition
    if (*lock == 0) {           // Prüfen
        // Race-Fenster hier!
        *reg = value;           // Schreiben
        *lock = 1;              // Sperren
        return true;
    }
    return false;
}

Sichere Lösung

// SICHER: Write-Once-Register mit Hardware-Priorität und Arbitrierung

module secure_write_once_register (
    input wire clk,
    input wire reset_n,
    // Software-Schnittstelle
    input wire [31:0] sw_write_data,
    input wire sw_write_enable,
    input wire sw_authenticated,
    // Hardware-Schnittstelle (vertrauenswürdiges Boot-ROM)
    input wire [31:0] hw_write_data,
    input wire hw_write_enable,
    // Boot-Phasen-Verfolgung
    input wire secure_boot_phase,
    output reg [31:0] register_value,
    output reg register_locked,
    output reg write_error
);

    // Zustandsmaschine für geordnete Initialisierung
    localparam STATE_HW_PHASE = 2'b00;
    localparam STATE_SW_PHASE = 2'b01;
    localparam STATE_LOCKED   = 2'b10;

    reg [1:0] state;

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            register_value <= 32'h0;
            register_locked <= 1'b0;
            write_error <= 1'b0;
            state <= STATE_HW_PHASE;
        end
        else begin
            case (state)
                STATE_HW_PHASE: begin
                    // Nur Hardware kann in dieser Phase schreiben
                    if (hw_write_enable) begin
                        register_value <= hw_write_data;
                        register_locked <= 1'b1;
                        state <= STATE_LOCKED;
                    end
                    else if (sw_write_enable) begin
                        // Software versuchte zu früh zu schreiben – Fehler
                        write_error <= 1'b1;
                    end

                    // Nur nach HW-Phase in SW-Phase wechseln
                    if (secure_boot_phase && !hw_write_enable) begin
                        state <= STATE_SW_PHASE;
                    end
                end

                STATE_SW_PHASE: begin
                    // Software kann schreiben wenn authentifiziert und noch nicht gesperrt
                    if (sw_write_enable && sw_authenticated && !register_locked) begin
                        register_value <= sw_write_data;
                        register_locked <= 1'b1;
                        state <= STATE_LOCKED;
                    end
                    else if (sw_write_enable && !sw_authenticated) begin
                        write_error <= 1'b1;
                    end
                end

                STATE_LOCKED: begin
                    // Keine weiteren Schreibvorgänge erlaubt
                    if (sw_write_enable || hw_write_enable) begin
                        write_error <= 1'b1;
                    end
                end
            endcase
        end
    end

endmodule

// SICHER: Atomarer Schreib-und-Sperr-Mechanismus
module secure_atomic_write_once (
    input wire clk,
    input wire reset_n,
    input wire [31:0] write_data,
    input wire write_and_lock,  // Einzelsignal für atomare Operation
    input wire trusted_source,
    output reg [31:0] register_value,
    output reg locked,
    output reg write_rejected
);

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            register_value <= 32'h0;
            locked <= 1'b0;
            write_rejected <= 1'b0;
        end
        else begin
            write_rejected <= 1'b0;

            if (write_and_lock) begin
                if (!locked && trusted_source) begin
                    // Atomar: Wert setzen UND sperren im selben Takt
                    register_value <= write_data;
                    locked <= 1'b1;
                end
                else begin
                    // Bereits gesperrt oder nicht vertrauenswürdig
                    write_rejected <= 1'b1;
                end
            end
        end
    end

endmodule

// SICHER: Sicherheitsrichtlinie mit gestufter Initialisierung
module secure_security_policy (
    input wire clk,
    input wire reset_n,
    input wire [31:0] policy_write,
    input wire policy_write_en,
    input wire boot_rom_phase,
    input wire trusted_firmware_phase,
    input wire untrusted_phase,
    output reg [31:0] security_policy,
    output reg policy_locked
);

    // Gestufte Initialisierung verhindert Race Conditions
    reg [1:0] init_stage;

    localparam STAGE_BOOT_ROM = 2'b00;
    localparam STAGE_FIRMWARE = 2'b01;
    localparam STAGE_LOCKED   = 2'b10;

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            // Sichere Standard-Richtlinie
            security_policy <= 32'hFFFFFFFF;  // Restriktivste
            policy_locked <= 1'b0;
            init_stage <= STAGE_BOOT_ROM;
        end
        else begin
            case (init_stage)
                STAGE_BOOT_ROM: begin
                    // Nur Boot-ROM kann modifizieren
                    if (boot_rom_phase && policy_write_en) begin
                        security_policy <= policy_write;
                    end
                    // Übergang wenn Boot-ROM Abschluss signalisiert
                    if (trusted_firmware_phase) begin
                        init_stage <= STAGE_FIRMWARE;
                    end
                end

                STAGE_FIRMWARE: begin
                    // Vertrauenswürdige Firmware kann verfeinern (aber nicht abschwächen)
                    if (trusted_firmware_phase && policy_write_en) begin
                        // Kann Richtlinie nur restriktiver machen
                        security_policy <= security_policy & policy_write;
                    end
                    // Sperren bevor nicht vertrauenswürdiger Code läuft
                    if (untrusted_phase) begin
                        policy_locked <= 1'b1;
                        init_stage <= STAGE_LOCKED;
                    end
                end

                STAGE_LOCKED: begin
                    // Keine Modifikationen erlaubt
                    policy_locked <= 1'b1;
                end
            endcase
        end
    end

endmodule
// SICHER: Software mit Race-freier Write-Once-Behandlung

#define SECURITY_CONFIG_REG 0x40000000
#define ATOMIC_WRITE_LOCK_REG 0x40000004

// Hardware unterstützt atomares Schreiben-und-Sperren
typedef struct {
    uint32_t value;
    uint32_t write_and_lock;  // Schreiben hier setzt atomar Wert und sperrt
} atomic_write_once_t;

volatile atomic_write_once_t* security_config =
    (atomic_write_once_t*)SECURITY_CONFIG_REG;

bool secure_set_security_policy(uint32_t policy) {
    // Atomare Schreib-und-Sperr-Operation
    // Hardware stellt sicher, dass keine Race Condition auftritt
    security_config->value = policy;
    security_config->write_and_lock = 1;

    // Überprüfen, dass unser Schreibvorgang erfolgreich war
    if (security_config->value != policy) {
        // Jemand anders hat gewonnen – Sicherheitsverletzung
        panic("Race Condition bei Sicherheitsrichtlinie erkannt!");
        return false;
    }

    return true;
}

// SICHER: Hardware-Mutex für Write-Once-Register verwenden
bool secure_init_with_mutex(void) {
    // Hardware-Mutex vor Zugriff auf Write-Once-Register erwerben
    if (!acquire_hardware_mutex(SECURITY_MUTEX)) {
        return false;  // Konnte nicht erwerben - jemand anders schreibt
    }

    // Prüfen ob bereits konfiguriert
    if (is_security_locked()) {
        release_hardware_mutex(SECURITY_MUTEX);
        return verify_security_config();
    }

    // Sicherheit konfigurieren (wir haben exklusiven Zugriff)
    set_security_policy(SECURE_POLICY_VALUE);

    // Konfiguration sperren
    lock_security_config();

    release_hardware_mutex(SECURITY_MUTEX);

    return verify_security_config();
}

// Verifikation nach dem Schreiben
bool verify_security_config(void) {
    uint32_t config = read_security_config();

    if (config != SECURE_POLICY_VALUE) {
        log_security_violation("Sicherheitskonfig stimmt nicht überein: 0x%08X", config);
        return false;
    }

    if (!is_security_locked()) {
        log_security_violation("Sicherheitskonfig nicht gesperrt!");
        return false;
    }

    return true;
}

CVE-Beispiele

Race Conditions in Write-Once-Registern wurden ausgenutzt, um Secure Boot zu umgehen, Debug-Schnittstellen zu entsperren und Sicherheitsrichtlinien in verschiedenen Hardware-Plattformen zu modifizieren.


Verwandte CWEs

  • CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization (übergeordnet)
  • CWE-1199: General Circuit and Logic Design Concerns (Kategoriemitglied)
  • CWE-1221: Incorrect Register Defaults or Module Parameters (verwandt)

Referenzen

  1. MITRE Corporation. "CWE-1223: Race Condition for Write-Once Attributes." https://cwe.mitre.org/data/definitions/1223.html
  2. Abwehr von Hardware-Race-Conditions
  3. Richtlinien zur Secure-Boot-Implementierung