Unsachgemäße Behandlung von Single Event Upsets

Beschreibung

Unsachgemäße Behandlung von Single Event Upsets tritt auf, wenn Hardware-Logik nicht effektiv behandelt, wenn Single-Event-Upsets (SEUs) auftreten. Moderne Halbleitertrends – einschließlich Transistorverkleinerung, neuer Materialien und System-on-Chip-Designs – erhöhen die Systemempfindlichkeit gegenüber Soft Errors. Single-Event-Upsets sind temporäre Bit-Flips, die durch geladene Teilchen verursacht werden, die Schaltkreismaterialien ionisieren und Elektron-Loch-Paare erzeugen, die transiente Fehler verursachen. Wenn diese in sicherheitskritischen Modulen auftreten, können sie die Sicherheitsgarantien des Chips kompromittieren, wie z.B. die Erhöhung von Benutzerberechtigungen auf Root-Zugriff.

Risiko

SEUs in Sicherheitshardware haben schwerwiegende Auswirkungen. Privilegstufen können korrumpiert werden. Zugriffskontrollbits können kippen. Kryptographische Operationen können falsche Ergebnisse liefern. Sicherheitszustandsmaschinen können in ungültige Zustände eintreten. Authentifizierungsentscheidungen können korrumpiert werden. Boot-Sicherheit kann umgangen werden. In SRAM gespeicherte Schlüssel können modifiziert werden. Systemintegrität kann stillschweigend kompromittiert werden.

Lösung

Implementieren Sie Triple-Modular-Redundancy (TMR) um sicherheitskritische Module. Für SRAMs, die sicherheitskritische Daten speichern, setzen Sie Error-Correcting Codes (ECC) und Address Interleaving ein. Verwenden Sie Paritätsprüfung zur Fehlererkennung. Implementieren Sie redundante Abstimmungslogik für kritische Entscheidungen. Entwerfen Sie für Fail-Secure-Verhalten bei erkannten Fehlern. Fügen Sie Scrubbing-Mechanismen hinzu, um Fehler vor der Akkumulation zu korrigieren. Erwägen Sie strahlungsgehärtete Designs für kritische Anwendungen.

Häufige Auswirkungen

AuswirkungDetails
VerfügbarkeitBereich: Verfügbarkeit

DoS: Absturz, Beendigung oder Neustart - SEU-induzierte Fehler können einen Systemneustart erfordern oder Instabilität verursachen.
VerfügbarkeitBereich: Verfügbarkeit

DoS: Instabilität - Akkumulierte Fehler können unvorhersehbares Verhalten verursachen.
ZugriffskontrolleBereich: Zugriffskontrolle

Privilegien erlangen oder Identität annehmen - SEU-Bit-Flip im Privilegregister könnte Benutzer auf Root erhöhen.
ZugriffskontrolleBereich: Zugriffskontrolle

Schutzmechanismus umgehen - Sicherheitsprüfungen können durch Bit-Flips umgangen werden.

Beispielcode und Lösung

Verwundbarer Code

// VERWUNDBAR: Sicherheitslogik ohne SEU-Schutz

module vulnerable_privilege_controller (
    input wire clk,
    input wire reset_n,
    input wire [1:0] requested_privilege,
    input wire privilege_request,
    input wire authenticate_success,
    output reg [1:0] current_privilege,
    output reg privilege_granted
);

    // Privilegstufen
    parameter USER = 2'b00;
    parameter SUPERVISOR = 2'b01;
    parameter HYPERVISOR = 2'b10;
    parameter SECURE = 2'b11;

    // VERWUNDBAR: Einzelnes Register speichert Privilegstufe
    // SEU-Bit-Flip: 00 (USER) -> 11 (SECURE)
    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            current_privilege <= USER;
            privilege_granted <= 1'b0;
        end
        else if (privilege_request && authenticate_success) begin
            current_privilege <= requested_privilege;
            privilege_granted <= 1'b1;
        end
    end

    // VERWUNDBAR: Keine Erkennung von SEU-induzierter Korruption
    // Wenn kosmische Strahlung current_privilege von 00 auf 11 flippt,
    // erhält Benutzer sichere Privilegien ohne Authentifizierung

endmodule

// VERWUNDBAR: Sicherheitsentscheidung ohne Redundanz
module vulnerable_access_check (
    input wire clk,
    input wire reset_n,
    input wire access_request,
    input wire [1:0] requester_privilege,
    input wire [1:0] required_privilege,
    output reg access_granted
);

    // VERWUNDBAR: Einzelner Vergleich für Sicherheitsentscheidung
    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            access_granted <= 1'b0;
        end
        else if (access_request) begin
            // VERWUNDBAR: SEU könnte Vergleichsergebnis flippen
            access_granted <= (requester_privilege >= required_privilege);
        end
    end

    // VERWUNDBAR: Keine Redundanz zur Fehlererkennunng/-korrektur

endmodule

// VERWUNDBAR: SRAM ohne ECC für Sicherheitsdaten
module vulnerable_key_storage (
    input wire clk,
    input wire reset_n,
    input wire [7:0] addr,
    input wire [127:0] write_data,
    input wire write_enable,
    input wire read_enable,
    output reg [127:0] read_data
);

    // VERWUNDBAR: Einfaches SRAM ohne ECC
    reg [127:0] key_memory [0:255];

    always @(posedge clk) begin
        if (write_enable) begin
            key_memory[addr] <= write_data;
        end
        if (read_enable) begin
            // VERWUNDBAR: SEU könnte Bits im gespeicherten Schlüssel geflippt haben
            // Kein Erkennungsmechanismus
            read_data <= key_memory[addr];
        end
    end

endmodule
// VERWUNDBAR: Software ohne SEU-Schutz

#include <stdint.h>

// VERWUNDBAR: Einzelne Variable speichert Privileg
volatile uint32_t current_privilege = PRIVILEGE_USER;

// VERWUNDBAR: Keine Redundanz für Sicherheitsentscheidungen
int vulnerable_check_access(uint32_t resource_id) {
    // Wenn SEU current_privilege-Bits flippt, kann Prüfung fälschlich bestehen
    if (current_privilege >= get_required_privilege(resource_id)) {
        return ACCESS_GRANTED;
    }
    return ACCESS_DENIED;
}

// VERWUNDBAR: Parität erkennt nur, kann nicht korrigieren
typedef struct {
    uint32_t data;
    uint8_t parity;
} parity_protected_t;

uint32_t vulnerable_parity_read(parity_protected_t* value) {
    // Parität prüfen
    uint8_t computed_parity = compute_parity(value->data);

    if (computed_parity != value->parity) {
        // VERWUNDBAR: Fehler erkannt, aber kann nicht korrigieren
        // Muss System neustarten - 2-3 Minuten Ausfallzeit
        system_restart();
    }

    return value->data;
}

Sichere Lösung

// SICHER: Sicherheitslogik mit TMR (Triple Modular Redundancy)

module secure_privilege_controller (
    input wire clk,
    input wire reset_n,
    input wire [1:0] requested_privilege,
    input wire privilege_request,
    input wire authenticate_success,
    output reg [1:0] current_privilege,
    output reg privilege_granted,
    output reg seu_detected
);

    // Privilegstufen
    parameter USER = 2'b00;
    parameter SUPERVISOR = 2'b01;
    parameter HYPERVISOR = 2'b10;
    parameter SECURE = 2'b11;

    // SICHER: Dreifach redundante Privilegspeicherung
    reg [1:0] privilege_a;
    reg [1:0] privilege_b;
    reg [1:0] privilege_c;

    // SICHER: Mehrheitsabstimmungsfunktion
    function [1:0] majority_vote;
        input [1:0] a, b, c;
        begin
            majority_vote = (a & b) | (b & c) | (a & c);
        end
    endfunction

    // SICHER: Fehlererkennung
    wire error_detected = (privilege_a != privilege_b) ||
                          (privilege_b != privilege_c) ||
                          (privilege_a != privilege_c);

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            privilege_a <= USER;
            privilege_b <= USER;
            privilege_c <= USER;
            privilege_granted <= 1'b0;
            seu_detected <= 1'b0;
        end
        else begin
            // SICHER: SEU erkennen und melden
            seu_detected <= error_detected;

            if (privilege_request && authenticate_success) begin
                // Alle drei Kopien aktualisieren
                privilege_a <= requested_privilege;
                privilege_b <= requested_privilege;
                privilege_c <= requested_privilege;
                privilege_granted <= 1'b1;
            end
            else if (error_detected) begin
                // SICHER: Selbstkorrektur durch Mehrheitsabstimmung
                privilege_a <= majority_vote(privilege_a, privilege_b, privilege_c);
                privilege_b <= majority_vote(privilege_a, privilege_b, privilege_c);
                privilege_c <= majority_vote(privilege_a, privilege_b, privilege_c);
            end
        end
    end

    // SICHER: Ausgabe verwendet abgestimmten Wert
    assign current_privilege = majority_vote(privilege_a, privilege_b, privilege_c);

endmodule

// SICHER: Sicherheitsentscheidung mit Redundanz
module secure_access_check (
    input wire clk,
    input wire reset_n,
    input wire access_request,
    input wire [1:0] requester_privilege,
    input wire [1:0] required_privilege,
    output reg access_granted,
    output reg check_error
);

    // SICHER: Prüfung dreimal mit unterschiedlicher Logik durchführen
    wire check_a = (requester_privilege >= required_privilege);
    wire check_b = (requester_privilege[1] > required_privilege[1]) ||
                   ((requester_privilege[1] == required_privilege[1]) &&
                    (requester_privilege[0] >= required_privilege[0]));
    wire check_c = ~(requester_privilege < required_privilege);

    // SICHER: Mehrheitsabstimmung über Ergebnis
    wire voted_result = (check_a & check_b) | (check_b & check_c) | (check_a & check_c);

    // SICHER: Fehlererkennung
    wire checks_inconsistent = (check_a != check_b) || (check_b != check_c);

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            access_granted <= 1'b0;
            check_error <= 1'b0;
        end
        else if (access_request) begin
            if (checks_inconsistent) begin
                // SICHER: Fehler erkannt - sicher fehlschlagen
                check_error <= 1'b1;
                access_granted <= 1'b0;  // Bei Fehler verweigern
            end
            else begin
                check_error <= 1'b0;
                access_granted <= voted_result;
            end
        end
    end

endmodule

// SICHER: SRAM mit ECC für Sicherheitsdaten
module secure_key_storage (
    input wire clk,
    input wire reset_n,
    input wire [7:0] addr,
    input wire [127:0] write_data,
    input wire write_enable,
    input wire read_enable,
    output reg [127:0] read_data,
    output reg ecc_error_corrected,
    output reg ecc_error_uncorrectable
);

    // SICHER: Daten mit ECC speichern (SECDED - Single Error Correct, Double Error Detect)
    // 128-Bit Daten + 8-Bit ECC = 136 Bits pro Eintrag
    reg [135:0] key_memory [0:255];

    // ECC-Funktionen (vereinfacht - echte Implementierung verwendet korrekten Hamming-Code)
    function [7:0] compute_ecc;
        input [127:0] data;
        begin
            // ECC-Syndrom berechnen
            compute_ecc = data[7:0] ^ data[15:8] ^ data[23:16] ^ data[31:24] ^
                         data[39:32] ^ data[47:40] ^ data[55:48] ^ data[63:56] ^
                         data[71:64] ^ data[79:72] ^ data[87:80] ^ data[95:88] ^
                         data[103:96] ^ data[111:104] ^ data[119:112] ^ data[127:120];
        end
    endfunction

    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            read_data <= 128'h0;
            ecc_error_corrected <= 1'b0;
            ecc_error_uncorrectable <= 1'b0;
        end
        else begin
            ecc_error_corrected <= 1'b0;
            ecc_error_uncorrectable <= 1'b0;

            if (write_enable) begin
                // SICHER: Daten mit ECC speichern
                key_memory[addr] <= {compute_ecc(write_data), write_data};
            end

            if (read_enable) begin
                // SICHER: Lesen und ECC prüfen/korrigieren
                wire [127:0] stored_data = key_memory[addr][127:0];
                wire [7:0] stored_ecc = key_memory[addr][135:128];
                wire [7:0] computed_ecc = compute_ecc(stored_data);
                wire [7:0] syndrome = stored_ecc ^ computed_ecc;

                if (syndrome == 8'h00) begin
                    // Kein Fehler
                    read_data <= stored_data;
                end
                else if (/* Einzelbitfehler */) begin
                    // SICHER: Einzelbitfehler korrigieren
                    read_data <= correct_single_bit(stored_data, syndrome);
                    ecc_error_corrected <= 1'b1;
                    // Auch Speicher bereinigen
                    key_memory[addr] <= {compute_ecc(read_data), read_data};
                end
                else begin
                    // SICHER: Nicht korrigierbarer Fehler
                    ecc_error_uncorrectable <= 1'b1;
                    read_data <= 128'h0;  // Null zurückgeben, nicht korrumpierte Daten
                end
            end
        end
    end

    // SICHER: Hintergrund-Scrubbing zur Verhinderung von Fehlerakkumulation
    reg [7:0] scrub_addr;
    always @(posedge clk) begin
        // Periodisch Speicher lesen und neu schreiben, um akkumulierte Fehler zu korrigieren
        scrub_addr <= scrub_addr + 1;
        // Scrubbing-Logik würde lesen, ECC prüfen, korrigieren, zurückschreiben
    end

endmodule
// SICHER: Software mit SEU-Schutz

#include <stdint.h>

// SICHER: Dreifach-redundante Privilegspeicherung
typedef struct {
    uint32_t value_a;
    uint32_t value_b;
    uint32_t value_c;
} tmr_uint32_t;

static tmr_uint32_t current_privilege = {
    .value_a = PRIVILEGE_USER,
    .value_b = PRIVILEGE_USER,
    .value_c = PRIVILEGE_USER
};

// SICHER: Mehrheitsabstimmungsfunktion
static uint32_t majority_vote(tmr_uint32_t* tmr) {
    // Bitweise Mehrheit
    return (tmr->value_a & tmr->value_b) |
           (tmr->value_b & tmr->value_c) |
           (tmr->value_a & tmr->value_c);
}

// SICHER: SEU-Fehler prüfen und korrigieren
static bool check_and_correct_tmr(tmr_uint32_t* tmr) {
    uint32_t voted = majority_vote(tmr);

    bool error = (tmr->value_a != tmr->value_b) ||
                 (tmr->value_b != tmr->value_c);

    if (error) {
        // Selbstkorrektur
        tmr->value_a = voted;
        tmr->value_b = voted;
        tmr->value_c = voted;
        log_seu_event("TMR-Korrektur angewendet");
    }

    return error;
}

// SICHER: Zugriffsprüfung mit Redundanz
int secure_check_access(uint32_t resource_id) {
    // Zuerst alle SEU-Fehler prüfen und korrigieren
    check_and_correct_tmr(&current_privilege);

    uint32_t privilege = majority_vote(&current_privilege);
    uint32_t required = get_required_privilege(resource_id);

    // SICHER: Prüfung dreimal durchführen
    int result_a = (privilege >= required);
    int result_b = (privilege >= required);
    int result_c = (privilege >= required);

    // Speicherbarrieren zur Verhinderung von Optimierung
    __asm__ volatile("" ::: "memory");

    // Mehrheitsabstimmung über Ergebnisse
    int voted_result = (result_a & result_b) | (result_b & result_c) | (result_a & result_c);

    // Auf Inkonsistenz prüfen
    if ((result_a != result_b) || (result_b != result_c)) {
        log_seu_event("Zugriffsprüfungs-Inkonsistenz erkannt");
        return ACCESS_DENIED;  // Sicher fehlschlagen
    }

    return voted_result ? ACCESS_GRANTED : ACCESS_DENIED;
}

// SICHER: ECC-geschützte Speicherung statt Parität
typedef struct {
    uint32_t data;
    uint32_t ecc;
} ecc_protected_t;

uint32_t secure_ecc_read(ecc_protected_t* value) {
    uint32_t computed_ecc = compute_hamming_ecc(value->data);
    uint32_t syndrome = computed_ecc ^ value->ecc;

    if (syndrome == 0) {
        // Kein Fehler
        return value->data;
    }
    else if (is_single_bit_error(syndrome)) {
        // SICHER: Einzelbitfehler korrigieren
        uint32_t corrected = value->data ^ get_error_mask(syndrome);
        value->data = corrected;  // Speicher bereinigen
        value->ecc = compute_hamming_ecc(corrected);
        log_seu_event("ECC-Korrektur angewendet");
        return corrected;
    }
    else {
        // Mehrbitfehler - kann nicht korrigieren
        log_seu_event("Nicht korrigierbarer ECC-Fehler");
        // Sicheren Wert zurückgeben oder Wiederherstellung auslösen
        return SAFE_DEFAULT_VALUE;
    }
}

CVE-Beispiele

  • Ein Herzschrittmacher-Vorfall 2016 betraf einen kosmische Strahlung-induzierten Bit-Flip in Flughöhe, der den sicheren Modus auslöste und Reverse Engineering ermöglichte, das hartcodierte kryptographische Schlüssel offenlegte.
  • Verschiedene Satelliten- und Luft- und Raumfahrtsystemausfälle, die auf SEU-induzierte Bit-Flips in ungeschütztem Speicher zurückgeführt werden.

Verwandte CWEs

  • CWE-1384: Unsachgemäße Behandlung physischer oder Umgebungsbedingungen (Eltern)
  • CWE-1254: Falsche Vergleichslogik-Granularität (Peer)
  • CWE-1247: Unsachgemäßer Schutz gegen Spannungs- und Taktglitches (verwandt)

Referenzen

  1. MITRE Corporation. "CWE-1261: Improper Handling of Single Event Upsets." https://cwe.mitre.org/data/definitions/1261.html
  2. Baumann, R. "Radiation-Induced Soft Errors in Advanced Semiconductor Technologies"
  3. NASA. "Single Event Effects Mitigation Techniques"