Unsachgemäß erhaltene Integrität des Hardware-Konfigurationszustands während einer Energiespar-/Wiederherstellungsoperation
Beschreibung
Die unsachgemäß erhaltene Integrität des Hardware-Konfigurationszustands während einer Energiespar-/Wiederherstellungsoperation tritt auf, wenn ein Produkt eine Energiespar-/Wiederherstellungsoperation durchführt, aber nicht sicherstellt, dass die Integrität des Konfigurationszustands zwischen Beginn und Ende der Operation aufrechterhalten und/oder verifiziert wird. Während des Herunterfahrens speichert Hardware-IP ihren Zustand in persistentem Speicher wie Flash-Speicher. Die Schwachstelle tritt auf, wenn Angreifer mit Speicherzugriff diese gespeicherte Konfiguration ändern, um Privilegien zu kompromittieren, Schutzmaßnahmen zu deaktivieren oder Hardware zu beschädigen. Ohne Validierung bei der Wiederherstellung aktiviert das System potenziell schädliche Konfigurationen.
Risiko
Unsachgemäße Zustandserhaltung hat schwerwiegende Auswirkungen. Denial of Service durch beschädigten Zustand. Privilegienerweiterung durch modifizierte Konfiguration. Schutzmechanismen deaktiviert. Ausführungslogik verändert. Hardwareschäden möglich. Systeminstabilität und Abstürze. Unerwartete Zustände aktiviert. Leistung und Zuverlässigkeit beeinträchtigt. Hohe Ausnutzungswahrscheinlichkeit, wenn der Zustand in zugänglichem Speicher abgelegt wird.
Lösung
Implementieren Sie kryptografische Hash-Integritätsprüfungen innerhalb der IP während der Architektur- und Entwurfsphase. Speichern Sie Hashes in stromgeschützten internen Registern, vergleichen Sie sie während der Wiederherstellung und halten Sie an, wenn Abweichungen auftreten. Verwenden Sie einen vertrauenswürdigen externen Agenten zum Hashen und Validieren der Konfiguration vor dem Herunterfahren und nach der Wiederherstellung. Speichern Sie die Konfiguration in einer geschützten Umgebung, die nur für vertrauenswürdige Agenten zugänglich ist.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Bereich: Vertraulichkeit Sensible Konfigurationsdaten können im Speicher offengelegt werden. |
| Integrität | Bereich: Integrität Konfiguration kann während der Speicherung modifiziert werden, was zu einem kompromittierten Systemzustand führt. |
| Verfügbarkeit | Bereich: Verfügbarkeit Beschädigte Konfiguration verursacht Systeminstabilität, Abstürze oder Denial of Service. |
Beispielcode und Lösung
Verwundbarer Code
// VERWUNDBAR: Energiespar-/Wiederherstellung ohne Integritätsprüfung
module vulnerable_power_manager (
input wire clk,
input wire rst_n,
input wire power_save_request,
input wire power_restore_request,
// Konfigurationsregister
input wire [31:0] config_reg_0,
input wire [31:0] config_reg_1,
input wire [31:0] config_reg_2,
input wire [31:0] config_reg_3,
input wire [7:0] security_level,
input wire protection_enable,
// Externe Speicherschnittstelle (z.B. Flash)
output reg [31:0] storage_addr,
output reg [31:0] storage_wdata,
input wire [31:0] storage_rdata,
output reg storage_write,
output reg storage_read,
// Wiederhergestellte Konfigurationsausgänge
output reg [31:0] restored_config_0,
output reg [31:0] restored_config_1,
output reg [31:0] restored_config_2,
output reg [31:0] restored_config_3,
output reg [7:0] restored_security_level,
output reg restored_protection_enable
);
localparam IDLE = 3'b000;
localparam SAVE_STATE = 3'b001;
localparam RESTORE_STATE = 3'b010;
localparam DONE = 3'b011;
reg [2:0] state;
reg [2:0] save_counter;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= IDLE;
storage_write <= 1'b0;
storage_read <= 1'b0;
end else begin
case (state)
IDLE: begin
if (power_save_request) begin
state <= SAVE_STATE;
save_counter <= 3'b0;
end else if (power_restore_request) begin
state <= RESTORE_STATE;
save_counter <= 3'b0;
end
end
SAVE_STATE: begin
// VERWUNDBAR: Konfiguration einfach ohne Schutz speichern
case (save_counter)
3'd0: begin
storage_addr <= 32'h0000;
storage_wdata <= config_reg_0;
storage_write <= 1'b1;
end
3'd1: begin
storage_addr <= 32'h0004;
storage_wdata <= config_reg_1;
end
3'd2: begin
storage_addr <= 32'h0008;
storage_wdata <= config_reg_2;
end
3'd3: begin
storage_addr <= 32'h000C;
storage_wdata <= config_reg_3;
end
3'd4: begin
storage_addr <= 32'h0010;
storage_wdata <= {protection_enable, 23'b0, security_level};
// VERWUNDBAR: Kein Integritäts-Hash berechnet oder gespeichert
end
3'd5: begin
storage_write <= 1'b0;
state <= DONE;
end
endcase
save_counter <= save_counter + 1;
end
RESTORE_STATE: begin
// VERWUNDBAR: Wiederherstellung ohne Verifizierung
storage_read <= 1'b1;
case (save_counter)
3'd0: begin
storage_addr <= 32'h0000;
end
3'd1: begin
// VERWUNDBAR: Keine Validierung der wiederhergestellten Daten
restored_config_0 <= storage_rdata;
storage_addr <= 32'h0004;
end
3'd2: begin
restored_config_1 <= storage_rdata;
storage_addr <= 32'h0008;
end
3'd3: begin
restored_config_2 <= storage_rdata;
storage_addr <= 32'h000C;
end
3'd4: begin
restored_config_3 <= storage_rdata;
storage_addr <= 32'h0010;
end
3'd5: begin
// VERWUNDBAR: Blind gespeicherten Sicherheitseinstellungen vertrauen
restored_security_level <= storage_rdata[7:0];
restored_protection_enable <= storage_rdata[24];
// Angreifer hätte den Speicher ändern können um:
// - security_level zu erhöhen für Privilegien
// - protection_enable zu deaktivieren
storage_read <= 1'b0;
state <= DONE;
end
endcase
save_counter <= save_counter + 1;
end
DONE: begin
state <= IDLE;
end
endcase
end
end
endmodule
// VERWUNDBAR: Software-Energieverwaltung ohne Integrität
#include <stdint.h>
#include <string.h>
typedef struct {
uint32_t config_reg_0;
uint32_t config_reg_1;
uint32_t config_reg_2;
uint32_t config_reg_3;
uint8_t security_level;
uint8_t protection_enabled;
// VERWUNDBAR: Kein Integritätsfeld
} device_state_t;
// VERWUNDBAR: Zustand ohne Integritätsschutz speichern
void vulnerable_save_state(const device_state_t* state, void* storage) {
// VERWUNDBAR: Zustand einfach in Speicher kopieren
memcpy(storage, state, sizeof(device_state_t));
// Kein Hash oder Signatur berechnet
// Angreifer mit Speicherzugriff kann Zustand ändern
}
// VERWUNDBAR: Zustand ohne Verifizierung wiederherstellen
void vulnerable_restore_state(device_state_t* state, const void* storage) {
// VERWUNDBAR: Blind aus Speicher wiederherstellen
memcpy(state, storage, sizeof(device_state_t));
// Keine Verifizierung, ob Zustand manipuliert wurde
// Modifizierter Zustand jetzt aktiv
// Wiederhergestellte (potenziell bösartige) Konfiguration anwenden
apply_security_level(state->security_level);
set_protection(state->protection_enabled);
}
Sichere Lösung
// SICHER: Energiespar-/Wiederherstellung mit Integritätsprüfung
module secure_power_manager (
input wire clk,
input wire rst_n,
input wire power_save_request,
input wire power_restore_request,
// Konfigurationsregister
input wire [31:0] config_reg_0,
input wire [31:0] config_reg_1,
input wire [31:0] config_reg_2,
input wire [31:0] config_reg_3,
input wire [7:0] security_level,
input wire protection_enable,
// Externe Speicherschnittstelle
output reg [31:0] storage_addr,
output reg [31:0] storage_wdata,
input wire [31:0] storage_rdata,
output reg storage_write,
output reg storage_read,
// Wiederhergestellte Konfigurationsausgänge
output reg [31:0] restored_config_0,
output reg [31:0] restored_config_1,
output reg [31:0] restored_config_2,
output reg [31:0] restored_config_3,
output reg [7:0] restored_security_level,
output reg restored_protection_enable,
// Statusausgänge
output reg restore_valid,
output reg integrity_error
);
// SICHER: Stromgeschütztes Register zum Halten des Integritäts-Hashes
// Dieses Register behält seinen Wert während des Schlafmodus (batteriegepuffert oder Always-On-Domäne)
reg [255:0] saved_hash; // SHA-256 Hash
// SICHER: Temporärer Speicher für wiederhergestellte Daten vor Validierung
reg [31:0] temp_config [0:4];
reg [255:0] computed_hash;
reg [255:0] stored_hash;
localparam IDLE = 4'b0000;
localparam SAVE_CONFIG = 4'b0001;
localparam COMPUTE_SAVE_HASH = 4'b0010;
localparam SAVE_HASH = 4'b0011;
localparam RESTORE_CONFIG = 4'b0100;
localparam RESTORE_HASH = 4'b0101;
localparam COMPUTE_VERIFY_HASH = 4'b0110;
localparam VERIFY_HASH = 4'b0111;
localparam APPLY_CONFIG = 4'b1000;
localparam ERROR_STATE = 4'b1001;
localparam DONE = 4'b1010;
reg [3:0] state;
reg [2:0] counter;
// SICHER: Hash-Berechnungsmodul
wire [255:0] hash_result;
wire hash_done;
reg hash_start;
reg [159:0] hash_input;
sha256_core u_sha256 (
.clk(clk),
.rst_n(rst_n),
.start(hash_start),
.data(hash_input),
.hash(hash_result),
.done(hash_done)
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= IDLE;
restore_valid <= 1'b0;
integrity_error <= 1'b0;
storage_write <= 1'b0;
storage_read <= 1'b0;
hash_start <= 1'b0;
end else begin
case (state)
IDLE: begin
restore_valid <= 1'b0;
integrity_error <= 1'b0;
if (power_save_request) begin
state <= SAVE_CONFIG;
counter <= 3'b0;
end else if (power_restore_request) begin
state <= RESTORE_CONFIG;
counter <= 3'b0;
end
end
SAVE_CONFIG: begin
// Konfiguration im Speicher sichern
storage_write <= 1'b1;
case (counter)
3'd0: begin storage_addr <= 32'h0000; storage_wdata <= config_reg_0; end
3'd1: begin storage_addr <= 32'h0004; storage_wdata <= config_reg_1; end
3'd2: begin storage_addr <= 32'h0008; storage_wdata <= config_reg_2; end
3'd3: begin storage_addr <= 32'h000C; storage_wdata <= config_reg_3; end
3'd4: begin
storage_addr <= 32'h0010;
storage_wdata <= {protection_enable, 23'b0, security_level};
end
3'd5: begin
storage_write <= 1'b0;
state <= COMPUTE_SAVE_HASH;
end
endcase
counter <= counter + 1;
end
COMPUTE_SAVE_HASH: begin
// SICHER: Hash der Konfiguration berechnen
hash_input <= {config_reg_0, config_reg_1, config_reg_2,
config_reg_3, protection_enable, security_level};
hash_start <= 1'b1;
if (hash_done) begin
hash_start <= 1'b0;
saved_hash <= hash_result; // SICHER: In geschütztem Register speichern
state <= SAVE_HASH;
counter <= 3'b0;
end
end
SAVE_HASH: begin
// SICHER: Hash auch im Speicher sichern (Defense in Depth)
storage_write <= 1'b1;
case (counter)
3'd0: begin storage_addr <= 32'h0020; storage_wdata <= saved_hash[31:0]; end
3'd1: begin storage_addr <= 32'h0024; storage_wdata <= saved_hash[63:32]; end
// ... für vollständigen Hash fortsetzen
3'd7: begin
storage_write <= 1'b0;
state <= DONE;
end
endcase
counter <= counter + 1;
end
RESTORE_CONFIG: begin
// SICHER: Zuerst in temporären Puffer wiederherstellen
storage_read <= 1'b1;
case (counter)
3'd0: storage_addr <= 32'h0000;
3'd1: begin temp_config[0] <= storage_rdata; storage_addr <= 32'h0004; end
3'd2: begin temp_config[1] <= storage_rdata; storage_addr <= 32'h0008; end
3'd3: begin temp_config[2] <= storage_rdata; storage_addr <= 32'h000C; end
3'd4: begin temp_config[3] <= storage_rdata; storage_addr <= 32'h0010; end
3'd5: begin
temp_config[4] <= storage_rdata;
storage_read <= 1'b0;
state <= COMPUTE_VERIFY_HASH;
end
endcase
counter <= counter + 1;
end
COMPUTE_VERIFY_HASH: begin
// SICHER: Hash der wiederhergestellten Daten berechnen
hash_input <= {temp_config[0], temp_config[1], temp_config[2],
temp_config[3], temp_config[4][24], temp_config[4][7:0]};
hash_start <= 1'b1;
if (hash_done) begin
hash_start <= 1'b0;
computed_hash <= hash_result;
state <= VERIFY_HASH;
end
end
VERIFY_HASH: begin
// SICHER: Berechneten Hash mit gespeichertem Hash vergleichen
if (computed_hash == saved_hash) begin
// Integrität verifiziert
state <= APPLY_CONFIG;
end else begin
// SICHER: Integritätsfehler - anhalten
state <= ERROR_STATE;
integrity_error <= 1'b1;
end
end
APPLY_CONFIG: begin
// SICHER: Nur nach Verifizierung anwenden
restored_config_0 <= temp_config[0];
restored_config_1 <= temp_config[1];
restored_config_2 <= temp_config[2];
restored_config_3 <= temp_config[3];
restored_security_level <= temp_config[4][7:0];
restored_protection_enable <= temp_config[4][24];
restore_valid <= 1'b1;
state <= DONE;
end
ERROR_STATE: begin
// SICHER: Bei Integritätsfehler anhalten
// Konfiguration nicht anwenden
// System muss zurückgesetzt oder manuell wiederhergestellt werden
end
DONE: begin
state <= IDLE;
end
endcase
end
end
endmodule
// SICHER: Software-Energieverwaltung mit Integritätsprüfung
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
typedef struct {
uint32_t config_reg_0;
uint32_t config_reg_1;
uint32_t config_reg_2;
uint32_t config_reg_3;
uint8_t security_level;
uint8_t protection_enabled;
uint8_t reserved[2];
uint8_t hash[32]; // SICHER: SHA-256 Hash für Integrität
} protected_device_state_t;
// SICHER: Integritäts-Hash berechnen
void compute_state_hash(const protected_device_state_t* state, uint8_t* hash) {
// Alles ausser dem Hash-Feld selbst hashen
sha256_context ctx;
sha256_init(&ctx);
sha256_update(&ctx, &state->config_reg_0, sizeof(state->config_reg_0));
sha256_update(&ctx, &state->config_reg_1, sizeof(state->config_reg_1));
sha256_update(&ctx, &state->config_reg_2, sizeof(state->config_reg_2));
sha256_update(&ctx, &state->config_reg_3, sizeof(state->config_reg_3));
sha256_update(&ctx, &state->security_level, sizeof(state->security_level));
sha256_update(&ctx, &state->protection_enabled, sizeof(state->protection_enabled));
sha256_final(&ctx, hash);
}
// SICHER: Zustand mit Integritätsschutz speichern
bool secure_save_state(protected_device_state_t* state, void* storage) {
// SICHER: Integritäts-Hash vor dem Speichern berechnen
compute_state_hash(state, state->hash);
// Zustand einschließlich Hash im Speicher sichern
memcpy(storage, state, sizeof(protected_device_state_t));
// SICHER: Hash auch in geschütztem (batteriegepuffertem) Register speichern
store_hash_in_protected_register(state->hash);
return true;
}
// SICHER: Zustand mit Verifizierung wiederherstellen
bool secure_restore_state(protected_device_state_t* state, const void* storage) {
protected_device_state_t temp_state;
uint8_t computed_hash[32];
uint8_t protected_hash[32];
// SICHER: In temporären Puffer wiederherstellen
memcpy(&temp_state, storage, sizeof(protected_device_state_t));
// SICHER: Hash der wiederhergestellten Konfiguration berechnen
compute_state_hash(&temp_state, computed_hash);
// SICHER: Erwarteten Hash aus geschütztem Register holen
get_hash_from_protected_register(protected_hash);
// SICHER: Integrität verifizieren
if (secure_memcmp(computed_hash, protected_hash, 32) != 0) {
// Integritätsfehler
log_security_event("Zustandsintegritätsprüfung fehlgeschlagen");
return false;
}
// SICHER: Auch gegen gespeicherten Hash verifizieren
if (secure_memcmp(computed_hash, temp_state.hash, 32) != 0) {
log_security_event("Gespeicherte Hash-Abweichung");
return false;
}
// SICHER: Integrität verifiziert - Konfiguration anwenden
memcpy(state, &temp_state, sizeof(protected_device_state_t));
// Verifizierte Konfiguration anwenden
apply_security_level(state->security_level);
set_protection(state->protection_enabled);
return true;
}
CVE-Beispiele
- CVE-2020-8705: Energiezustandswiederherstellung in bestimmten Intel-Prozessoren prüfte die Konfigurationsintegrität nicht ordnungsgemäß.
- CVE-2019-11139: Spannungs-Glitching während Energieübergängen beeinflusste den sicheren Zustand.
Verwandte CWEs
- CWE-284: Improper Access Control (Eltern)
- CWE-345: Insufficient Verification of Data Authenticity (Peer)
- CWE-1271: Uninitialized Value on Reset for Registers Holding Security Settings (Peer)
- CWE-1206: Power, Clock, Thermal, and Reset Concerns (Kategorie)
Referenzen
- MITRE Corporation. "CWE-1304: Improperly Preserved Integrity of Hardware Configuration State During a Power Save/Restore Operation." https://cwe.mitre.org/data/definitions/1304.html
- NIST. "Guidelines for Power Management Security"
- ARM. "TrustZone Power State Management"