Unautorisierte Fehlerinjektion kann Hardware-Redundanz beeinträchtigen
Beschreibung
Unautorisierte Fehlerinjektion kann Hardware-Redundanz beeinträchtigen tritt auf, wenn ein unautorisierter Agent Fehler in einen redundanten Block injizieren kann, um dem System die Redundanz zu entziehen oder es in einen degradierten Betriebsmodus zu versetzen. Hardware-Designer implementieren redundante Blöcke, um Leistung und Zuverlässigkeit bei Ausfall primärer Komponenten aufrechtzuerhalten. Wenn das Design jedoch unautorisierten Parteien erlaubt, Fehler in diese redundanten Systeme zu injizieren, können sie Backup-Pfade deaktivieren, das System in degradierte Betriebszustände zwingen und potenziell nachfolgende Angriffe ermöglichen.
Risiko
Unautorisierte Fehlerinjektion hat schwerwiegende Auswirkungen. Redundanz wird eliminiert und ermöglicht Einzelpunktausfälle. Sicherheitsmargen werden entfernt. Fehlertoleranz wird umgangen. Systemzuverlässigkeit wird beeintrachtigt. Nachfolgende Angriffe werden ermöglicht. Denial of Service durch induzierte Ausfalle. Qualitätsverschlechterung. Leistungsbeeinträchtigung. Erhöhter Ressourcenverbrauch. Hohe Wahrscheinlichkeit, wenn Fehlerinjektionsschnittstellen keine Zugangskontrolle haben.
Lösung
Fehlerinjektion während der normalen Laufzeit in der Architektur- und Designphase verhindern. Zugangskontrollen für Fehlerinjektionsschnittstellen implementieren. Fehlerinjektion in Standard-Betriebsmodi während der Implementierungsphase verbieten. Zugangskontrollen für Fehlerinjektionsmechanismen hinzufügen. Zugangskontrollen über ungeschützte Schnittstellen während der Integrationsphase schichten.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Verfügbarkeit | Bereich: Verfügbarkeit Denial of Service durch Systemabsturze, Neustarts und Instabilität. |
| Integritat | Bereich: Integritat Qualitätsverschlechterung und reduzierte Leistung durch deaktivierte Redundanz. |
Beispielcode
Verwundbarer Code
// VERWUNDBAR: Redundantes System ohne Fehlerinjektionsschutz
module vulnerable_redundant_system (
input wire clk,
input wire rst_n,
// Primäre und redundante Berechnungspfade
input wire [31:0] data_in,
input wire compute_start,
// Fehlerinjektionsschnittstelle (VERWUNDBAR: kein Schutz)
input wire inject_error_primary,
input wire inject_error_redundant,
input wire [7:0] error_pattern,
output reg [31:0] result,
output reg result_valid,
output reg redundancy_mismatch
);
reg [31:0] primary_result;
reg [31:0] redundant_result;
// Primärer Berechnungspfad
always @(posedge clk) begin
if (compute_start) begin
primary_result <= compute_function(data_in);
// VERWUNDBAR: Fehler kann ohne Autorisierung injiziert werden
if (inject_error_primary) begin
primary_result <= primary_result ^ {24'b0, error_pattern};
end
end
end
// Redundanter Berechnungspfad
always @(posedge clk) begin
if (compute_start) begin
redundant_result <= compute_function(data_in);
// VERWUNDBAR: Fehlerinjektion in redundanten Pfad
if (inject_error_redundant) begin
redundant_result <= redundant_result ^ {24'b0, error_pattern};
end
end
end
// Vergleichslogik
always @(posedge clk) begin
redundancy_mismatch <= (primary_result != redundant_result);
if (!redundancy_mismatch) begin
result <= primary_result;
result_valid <= 1'b1;
end else begin
// System wechselt in degradierten Modus
result_valid <= 1'b0;
end
end
// Angriff:
// 1. Kontinuierliche Fehler in redundanten Pfad injizieren
// 2. System erkennt ständig Abweichungen
// 3. Redundanz erscheint ausgefallen
// 4. System arbeitet im degradierten Modus
// 5. Ein einzelner Fehler führt nun zum vollständigen Ausfall
endmodule
// VERWUNDBAR: ECC-Speicher ohne Fehlerinjektionsschutz
module vulnerable_ecc_memory (
input wire clk,
input wire rst_n,
input wire [15:0] addr,
input wire [31:0] data_in,
input wire write_en,
input wire read_en,
// VERWUNDBAR: Fehlerinjektion für Tests
input wire inject_single_bit_error,
input wire inject_multi_bit_error,
input wire [4:0] error_bit_position,
output reg [31:0] data_out,
output reg single_bit_corrected,
output reg multi_bit_detected
);
reg [38:0] memory [0:65535]; // 32 Daten + 7 ECC-Bits
always @(posedge clk) begin
if (write_en) begin
memory[addr] <= {compute_ecc(data_in), data_in};
end
if (read_en) begin
reg [38:0] raw_data = memory[addr];
// VERWUNDBAR: Fehlerinjektion ohne Zugangskontrolle
if (inject_single_bit_error) begin
raw_data[error_bit_position] <= ~raw_data[error_bit_position];
end
if (inject_multi_bit_error) begin
raw_data[error_bit_position] <= ~raw_data[error_bit_position];
raw_data[error_bit_position + 1] <= ~raw_data[error_bit_position + 1];
end
// ECC-Dekodierung
{single_bit_corrected, multi_bit_detected, data_out} <= ecc_decode(raw_data);
end
end
// Angriff: Kontinuierlich Multi-Bit-Fehler injizieren
// System protokolliert Ausfalle, kann ECC-Schutz deaktivieren
// Speicher ist nun anfällig für tatsachliche Fehler
endmodule
Sichere Lösung
// SICHER: Redundantes System mit geschützter Fehlerinjektion
module secure_redundant_system (
input wire clk,
input wire rst_n,
// Primäre und redundante Berechnungspfade
input wire [31:0] data_in,
input wire compute_start,
// Fehlerinjektionsschnittstelle (SICHER: geschützt)
input wire inject_error_primary,
input wire inject_error_redundant,
input wire [7:0] error_pattern,
input wire test_mode_enabled, // SICHER: Lebenszyklus-Signal
input wire privileged_access, // SICHER: Zugangskontrolle
input wire boot_complete, // SICHER: Laufzeitindikator
output reg [31:0] result,
output reg result_valid,
output reg redundancy_mismatch,
output reg injection_denied
);
reg [31:0] primary_result;
reg [31:0] redundant_result;
// SICHER: Fehlerinjektionskontrolle
wire error_injection_allowed = test_mode_enabled &&
privileged_access &&
!boot_complete;
// Primärer Berechnungspfad
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
primary_result <= 32'b0;
injection_denied <= 1'b0;
end else if (compute_start) begin
primary_result <= compute_function(data_in);
injection_denied <= 1'b0;
// SICHER: Fehlerinjektion nur in erlaubten Modi
if (inject_error_primary) begin
if (error_injection_allowed) begin
primary_result <= primary_result ^ {24'b0, error_pattern};
end else begin
// SICHER: Unautorisierte Injektion ablehnen
injection_denied <= 1'b1;
end
end
end
end
// Redundanter Berechnungspfad (ähnlicher Schutz)
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
redundant_result <= 32'b0;
end else if (compute_start) begin
redundant_result <= compute_function(data_in);
if (inject_error_redundant && error_injection_allowed) begin
redundant_result <= redundant_result ^ {24'b0, error_pattern};
end
end
end
// SICHER: Vergleich mit Protokollierung von Injektionsversuchen
always @(posedge clk) begin
redundancy_mismatch <= (primary_result != redundant_result);
if (!redundancy_mismatch) begin
result <= primary_result;
result_valid <= 1'b1;
end else begin
result_valid <= 1'b0;
end
end
// SICHER: Testmodus nach dem Booten sperren
always @(posedge boot_complete) begin
// Testmodus wird nach dem Booten automatisch deaktiviert
// Fehlerinjektion ist nicht mehr möglich
end
endmodule
// SICHER: ECC-Speicher mit geschützter Fehlerinjektion
module secure_ecc_memory (
input wire clk,
input wire rst_n,
input wire [15:0] addr,
input wire [31:0] data_in,
input wire write_en,
input wire read_en,
// SICHER: Geschutzte Fehlerinjektion
input wire inject_single_bit_error,
input wire inject_multi_bit_error,
input wire [4:0] error_bit_position,
input wire test_mode,
input wire secure_debug_enabled, // SICHER: Debug-Authentifizierung
input wire manufacturing_mode, // SICHER: Lebenszyklus
output reg [31:0] data_out,
output reg single_bit_corrected,
output reg multi_bit_detected,
output reg injection_blocked
);
reg [38:0] memory [0:65535];
// SICHER: Fehlerinjektion nur während Fertigungstest
wire injection_allowed = manufacturing_mode &&
(test_mode || secure_debug_enabled);
// SICHER: Ratenbegrenzung für Fehlerinjektion
reg [7:0] injection_count;
localparam MAX_INJECTIONS = 100;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
injection_count <= 8'b0;
injection_blocked <= 1'b0;
end else begin
injection_blocked <= 1'b0;
if (write_en) begin
memory[addr] <= {compute_ecc(data_in), data_in};
end
if (read_en) begin
reg [38:0] raw_data;
raw_data = memory[addr];
// SICHER: Geschutzte Fehlerinjektion
if (inject_single_bit_error || inject_multi_bit_error) begin
if (injection_allowed && injection_count < MAX_INJECTIONS) begin
if (inject_single_bit_error) begin
raw_data[error_bit_position] = ~raw_data[error_bit_position];
end
if (inject_multi_bit_error) begin
raw_data[error_bit_position] = ~raw_data[error_bit_position];
raw_data[error_bit_position + 1] = ~raw_data[error_bit_position + 1];
end
injection_count <= injection_count + 1;
end else begin
// SICHER: Unautorisierte oder übermäßige Injektion blockieren
injection_blocked <= 1'b1;
end
end
// ECC-Dekodierung
{single_bit_corrected, multi_bit_detected, data_out} <= ecc_decode(raw_data);
end
end
end
// SICHER: Injektionsfahigkeit in Produktion sperren
always @(posedge clk) begin
if (!manufacturing_mode) begin
injection_count <= MAX_INJECTIONS; // Effektiv deaktivieren
end
end
endmodule
// SICHER: Redundanzmanager mit Angriffserkennung
module secure_redundancy_manager (
input wire clk,
input wire rst_n,
// Redundante Eingange
input wire [31:0] input_a,
input wire [31:0] input_b,
input wire [31:0] input_c, // Dreifach modulare Redundanz
input wire inputs_valid,
// Status
output reg [31:0] voted_output,
output reg output_valid,
output reg single_failure,
output reg double_failure,
output reg attack_detected
);
// SICHER: Ausfallmuster verfolgen, um Angriffe zu erkennen
reg [15:0] failure_history;
reg [7:0] failure_count_a;
reg [7:0] failure_count_b;
reg [7:0] failure_count_c;
localparam ATTACK_THRESHOLD = 10; // Ausfalle im Zeitfenster
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
failure_history <= 16'b0;
failure_count_a <= 8'b0;
failure_count_b <= 8'b0;
failure_count_c <= 8'b0;
attack_detected <= 1'b0;
end else if (inputs_valid) begin
// Dreifach modulare Redundanz-Abstimmung
reg match_ab = (input_a == input_b);
reg match_bc = (input_b == input_c);
reg match_ac = (input_a == input_c);
// SICHER: Verfolgen, welche Kanäle ausfallen
if (!match_ab && !match_ac) failure_count_a <= failure_count_a + 1;
if (!match_ab && !match_bc) failure_count_b <= failure_count_b + 1;
if (!match_ac && !match_bc) failure_count_c <= failure_count_c + 1;
// SICHER: Angriffsmuster erkennen (konsistente Ausfalle auf einem Kanal)
if (failure_count_a > ATTACK_THRESHOLD ||
failure_count_b > ATTACK_THRESHOLD ||
failure_count_c > ATTACK_THRESHOLD) begin
attack_detected <= 1'b1;
end
// Abstimmungslogik
if (match_ab || match_ac) begin
voted_output <= input_a;
output_valid <= 1'b1;
single_failure <= !(match_ab && match_ac && match_bc);
double_failure <= 1'b0;
end else if (match_bc) begin
voted_output <= input_b;
output_valid <= 1'b1;
single_failure <= 1'b1;
double_failure <= 1'b0;
end else begin
// Alle drei stimmen nicht überein
output_valid <= 1'b0;
double_failure <= 1'b1;
end
end
end
// SICHER: Periodisches Zurücksetzen der Ausfallzahler (gleitendes Fenster)
reg [15:0] window_counter;
localparam WINDOW_SIZE = 10000;
always @(posedge clk) begin
window_counter <= window_counter + 1;
if (window_counter >= WINDOW_SIZE) begin
window_counter <= 16'b0;
failure_count_a <= failure_count_a >> 1; // Abklingen
failure_count_b <= failure_count_b >> 1;
failure_count_c <= failure_count_c >> 1;
end
end
endmodule
CVE-Beispiele
- CVE-2019-11135: TSX Asynchronous Abort (TAA) ermöglichte Fehlerinjektion, die CPU-Redundanzmechanismen beeintrachtigt.
- CVE-2020-0549: L1D Eviction Sampling-Schwachstelle, die durch Fehlerinjektion ausnutzbar ist.
Verwandte CWEs
- CWE-284: Improper Access Control (ubergeordnet)
- CWE-1198: Privilege Separation and Access Control Issues (Kategorie)
- CAPEC-624: Hardware Fault Injection
- CAPEC-625: Mobile Device Fault Injection
Referenzen
- MITRE Corporation. "CWE-1334: Unauthorized Error Injection Can Degrade Hardware Redundancy." https://cwe.mitre.org/data/definitions/1334.html
- IEEE. "Fault Tolerance in Digital Systems"
- NASA. "Fault Tolerant Design Handbook"