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
| Auswirkung | Details |
|---|---|
| Integrität, Autorisierung | Bereich: 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. |
| Zugriffskontrolle | Bereich: 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
- MITRE Corporation. "CWE-1223: Race Condition for Write-Once Attributes." https://cwe.mitre.org/data/definitions/1223.html
- Abwehr von Hardware-Race-Conditions
- Richtlinien zur Secure-Boot-Implementierung