Unsachgemäße endliche Zustandsautomaten (FSMs) in Hardware-Logik
Beschreibung
Unsachgemäße endliche Zustandsautomaten (FSMs) in Hardware-Logik tritt auf, wenn fehlerhafte endliche Zustandsautomaten in der Hardware-Logik einem Angreifer ermöglichen, das System in einen undefinierten Zustand zu versetzen, um einen Denial of Service (DoS) zu verursachen oder Berechtigungen auf dem System des Opfers zu erlangen. Die Sicherheit und Funktionalität von Systemen hängen stark von der FSM-Implementierung ab. Diese Automaten zeigen Systemsicherheitszustände an, und zahlreiche sichere Datenoperationen beruhen auf ihrer Genauigkeit. Fehlerhafte FSM-Designs, die bestimmte Zustände auslassen, können es Angreifern ermöglichen, Systeme in instabile, nicht wiederherstellbare Zustände zu treiben.
Risiko
Unsachgemäße FSM-Implementierung hat schwerwiegende Sicherheitsauswirkungen. Systeme können in undefinierte Zustände eintreten. Denial of Service kann durch Zustandsmanipulation auftreten. Sicherheitszustandsübergänge können umgangen werden. Privilege Escalation kann möglich sein. Systemabstürze oder -neustarts können auftreten. Deadlocks können Systeme unresponsiv machen. Authentifizierungszustände können umgehbar sein. Zugriffskontrollentscheidungen können kompromittiert werden.
Lösung
Definieren Sie alle möglichen Zustände und behandeln Sie alle unbenutzten Zustände durch Default-Anweisungen. Stellen Sie sicher, dass das System standardmäßig in einen sicheren Zustand wechselt. Verwenden Sie formale Verifikation zur Überprüfung der FSM-Vollständigkeit. Implementieren Sie Erkennung und Wiederherstellung nicht erreichbarer Zustände. Fügen Sie Watchdog-Timer für FSM-Timeouts hinzu. Protokollieren Sie unerwartete Zustandsübergänge. Testen Sie alle möglichen Eingabekombinationen. Verwenden Sie Kodierungen, die ungültige Zustände erkennen.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Verfügbarkeit | Umfang: Verfügbarkeit DoS: Absturz, Beendigung oder Neustart - Fehlerhafte FSMs können zu unerwarteten Systemzuständen führen, die Abstürze oder Neustarts verursachen. |
| Zugriffskontrolle | Umfang: Zugriffskontrolle Berechtigungen erlangen oder Identität annehmen - FSM-Schwachstellen können Privilege Escalation oder das Umgehen von Sicherheitszustanden ermöglichen. |
Beispielcode und Lösung
Verwundbarer Code
// VERWUNDBAR: FSM mit fehlenden Zustandsbehandlern
module vulnerable_auth_fsm (
input wire clk,
input wire reset_n,
input wire [2:0] input_event,
output reg [1:0] current_state,
output reg authenticated,
output reg access_granted
);
// Zustände
parameter IDLE = 2'b00;
parameter AUTHENTICATING = 2'b01;
parameter AUTHENTICATED = 2'b10;
// Zustand 2'b11 undefiniert - VERWUNDBAR!
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
current_state <= IDLE;
authenticated <= 1'b0;
access_granted <= 1'b0;
end
else begin
case (current_state)
IDLE: begin
if (input_event == 3'h1) begin
current_state <= AUTHENTICATING;
end
end
AUTHENTICATING: begin
if (input_event == 3'h2) begin
current_state <= AUTHENTICATED;
authenticated <= 1'b1;
end
else if (input_event == 3'h3) begin
current_state <= IDLE;
end
end
AUTHENTICATED: begin
access_granted <= 1'b1;
if (input_event == 3'h4) begin
current_state <= IDLE;
authenticated <= 1'b0;
access_granted <= 1'b0;
end
end
// VERWUNDBAR: Kein Handler für Zustand 2'b11
// Wenn erreicht, ist das FSM-Verhalten undefiniert!
endcase
end
end
endmodule
// VERWUNDBAR: Eingabekombinationen nicht vollständig behandelt
module vulnerable_security_fsm (
input wire clk,
input wire reset_n,
input wire [2:0] security_input,
output reg [2:0] security_state
);
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
security_state <= 3'h0;
end
else begin
case (security_input)
3'h0: security_state <= 3'h0; // Sicherer Zustand
3'h1: security_state <= 3'h1; // Zustand 1
3'h2: security_state <= 3'h2; // Zustand 2
3'h3: security_state <= 3'h3; // Zustand 3
3'h4: security_state <= 3'h4; // Zustand 4
3'h5: security_state <= 3'h5; // Zustand 5
// VERWUNDBAR: Eingaben 3'h6 und 3'h7 nicht behandelt!
// System geht in undefinierten Zustand
endcase
end
end
endmodule
// VERWUNDBAR: FSM kann in Deadlock-Zustand eintreten
module vulnerable_protocol_fsm (
input wire clk,
input wire reset_n,
input wire request,
input wire response,
input wire timeout,
output reg [2:0] state,
output reg transaction_complete
);
parameter IDLE = 3'h0;
parameter WAIT_ACK = 3'h1;
parameter PROCESSING = 3'h2;
parameter WAIT_RESPONSE = 3'h3;
parameter COMPLETE = 3'h4;
parameter ERROR = 3'h5;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
state <= IDLE;
transaction_complete <= 1'b0;
end
else begin
case (state)
IDLE: begin
if (request) state <= WAIT_ACK;
end
WAIT_ACK: begin
if (response) state <= PROCESSING;
else if (timeout) state <= ERROR;
end
PROCESSING: begin
state <= WAIT_RESPONSE;
end
WAIT_RESPONSE: begin
if (response) begin
state <= COMPLETE;
transaction_complete <= 1'b1;
end
// VERWUNDBAR: Keine Timeout-Behandlung - kann hier blockieren!
end
COMPLETE: begin
state <= IDLE;
transaction_complete <= 1'b0;
end
ERROR: begin
// VERWUNDBAR: Kein Ausgang aus dem ERROR-Zustand!
// System dauerhaft im Fehlerzustand
end
endcase
end
end
endmodule
// VERWUNDBAR: Software-FSM mit fehlenden Fällen
typedef enum {
STATE_INIT,
STATE_AUTHENTICATING,
STATE_AUTHENTICATED,
STATE_ADMIN,
STATE_COUNT // 4 Zustände
} system_state_t;
system_state_t current_state = STATE_INIT;
void vulnerable_state_machine(int event) {
switch (current_state) {
case STATE_INIT:
if (event == EVENT_LOGIN) {
current_state = STATE_AUTHENTICATING;
}
break;
case STATE_AUTHENTICATING:
if (event == EVENT_AUTH_SUCCESS) {
current_state = STATE_AUTHENTICATED;
} else if (event == EVENT_AUTH_FAIL) {
current_state = STATE_INIT;
}
break;
case STATE_AUTHENTICATED:
if (event == EVENT_LOGOUT) {
current_state = STATE_INIT;
} else if (event == EVENT_ADMIN_REQUEST) {
current_state = STATE_ADMIN;
}
break;
// VERWUNDBAR: STATE_ADMIN nicht behandelt!
// Wenn erreicht, keine Zustandsübergänge möglich
// VERWUNDBAR: Kein Default-Fall für ungültige Zustände
}
}
Sichere Lösung
// SICHER: FSM mit allen Zuständen behandelt
module secure_auth_fsm (
input wire clk,
input wire reset_n,
input wire [2:0] input_event,
output reg [1:0] current_state,
output reg authenticated,
output reg access_granted,
output reg fsm_error
);
// Zustände
parameter IDLE = 2'b00;
parameter AUTHENTICATING = 2'b01;
parameter AUTHENTICATED = 2'b10;
parameter ERROR = 2'b11; // Undefinierten Zustand explizit behandeln
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
current_state <= IDLE;
authenticated <= 1'b0;
access_granted <= 1'b0;
fsm_error <= 1'b0;
end
else begin
case (current_state)
IDLE: begin
authenticated <= 1'b0;
access_granted <= 1'b0;
if (input_event == 3'h1) begin
current_state <= AUTHENTICATING;
end
end
AUTHENTICATING: begin
if (input_event == 3'h2) begin
current_state <= AUTHENTICATED;
authenticated <= 1'b1;
end
else if (input_event == 3'h3) begin
current_state <= IDLE;
end
end
AUTHENTICATED: begin
access_granted <= 1'b1;
if (input_event == 3'h4) begin
current_state <= IDLE;
authenticated <= 1'b0;
access_granted <= 1'b0;
end
end
// SICHER: Expliziter Handler für undefinierten/Fehlerzustand
default: begin
// In sicheren Zustand zurückkehren
current_state <= IDLE;
authenticated <= 1'b0;
access_granted <= 1'b0;
fsm_error <= 1'b1; // Fehler protokollieren
end
endcase
end
end
endmodule
// SICHER: Alle Eingabekombinationen behandelt
module secure_security_fsm (
input wire clk,
input wire reset_n,
input wire [2:0] security_input,
output reg [2:0] security_state,
output reg invalid_input
);
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
security_state <= 3'h0;
invalid_input <= 1'b0;
end
else begin
invalid_input <= 1'b0;
case (security_input)
3'h0: security_state <= 3'h0;
3'h1: security_state <= 3'h1;
3'h2: security_state <= 3'h2;
3'h3: security_state <= 3'h3;
3'h4: security_state <= 3'h4;
3'h5: security_state <= 3'h5;
// SICHER: Alle verbleibenden Eingaben behandeln
default: begin
security_state <= 3'h0; // In sicheren Zustand zurückkehren
invalid_input <= 1'b1; // Ungültige Eingabe markieren
end
endcase
end
end
endmodule
// SICHER: FSM mit Timeout und Wiederherstellung
module secure_protocol_fsm (
input wire clk,
input wire reset_n,
input wire request,
input wire response,
input wire timeout,
input wire error_ack,
output reg [2:0] state,
output reg transaction_complete,
output reg error_flag
);
parameter IDLE = 3'h0;
parameter WAIT_ACK = 3'h1;
parameter PROCESSING = 3'h2;
parameter WAIT_RESPONSE = 3'h3;
parameter COMPLETE = 3'h4;
parameter ERROR = 3'h5;
// Timeout-Zähler für WAIT_RESPONSE
reg [15:0] wait_counter;
parameter WAIT_TIMEOUT = 16'hFFFF;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
state <= IDLE;
transaction_complete <= 1'b0;
error_flag <= 1'b0;
wait_counter <= 16'h0;
end
else begin
case (state)
IDLE: begin
error_flag <= 1'b0;
wait_counter <= 16'h0;
if (request) state <= WAIT_ACK;
end
WAIT_ACK: begin
if (response) state <= PROCESSING;
else if (timeout) state <= ERROR;
end
PROCESSING: begin
state <= WAIT_RESPONSE;
wait_counter <= 16'h0;
end
WAIT_RESPONSE: begin
wait_counter <= wait_counter + 1;
if (response) begin
state <= COMPLETE;
transaction_complete <= 1'b1;
end
// SICHER: Timeout-Behandlung für WAIT_RESPONSE
else if (wait_counter >= WAIT_TIMEOUT) begin
state <= ERROR;
error_flag <= 1'b1;
end
end
COMPLETE: begin
state <= IDLE;
transaction_complete <= 1'b0;
end
ERROR: begin
error_flag <= 1'b1;
// SICHER: Ausgang aus ERROR-Zustand mit Bestätigung
if (error_ack) begin
state <= IDLE;
error_flag <= 1'b0;
end
end
// SICHER: Undefinierte Zustände behandeln
default: begin
state <= IDLE;
error_flag <= 1'b1;
end
endcase
end
end
endmodule
// SICHER: Software-FSM mit allen Fällen behandelt
typedef enum {
STATE_INIT,
STATE_AUTHENTICATING,
STATE_AUTHENTICATED,
STATE_ADMIN,
STATE_ERROR,
STATE_COUNT
} system_state_t;
system_state_t current_state = STATE_INIT;
void secure_state_machine(int event) {
switch (current_state) {
case STATE_INIT:
if (event == EVENT_LOGIN) {
current_state = STATE_AUTHENTICATING;
}
break;
case STATE_AUTHENTICATING:
if (event == EVENT_AUTH_SUCCESS) {
current_state = STATE_AUTHENTICATED;
} else if (event == EVENT_AUTH_FAIL) {
current_state = STATE_INIT;
}
break;
case STATE_AUTHENTICATED:
if (event == EVENT_LOGOUT) {
current_state = STATE_INIT;
} else if (event == EVENT_ADMIN_REQUEST) {
current_state = STATE_ADMIN;
}
break;
// SICHER: STATE_ADMIN behandelt
case STATE_ADMIN:
if (event == EVENT_LOGOUT) {
current_state = STATE_INIT;
} else if (event == EVENT_ADMIN_DONE) {
current_state = STATE_AUTHENTICATED;
}
break;
case STATE_ERROR:
// Fehlerwiederherstellung
if (event == EVENT_RESET) {
current_state = STATE_INIT;
}
break;
// SICHER: Default-Fall für ungültige Zustände
default:
log_error("Ungültiger FSM-Zustand: %d", current_state);
current_state = STATE_INIT; // In sicheren Zustand zurückkehren
break;
}
}
// FSM-Validierungsfunktion
bool validate_fsm_state(void) {
if (current_state >= STATE_COUNT) {
log_security_event("FSM in ungültigem Zustand: %d", current_state);
current_state = STATE_INIT;
return false;
}
return true;
}
CVE-Beispiele
FSM-Schwachstellen wurden in verschiedenen Hardware-Designs gefunden, bei denen undefinierte Zustände erreicht werden könnten, was zu Sicherheitsumgehungen oder Denial of Service führte.
Verwandte CWEs
- CWE-684: Fehlerhafte Bereitstellung spezifizierter Funktionalität (übergeordnet)
- CWE-1199: Allgemeine Schaltungs- und Logik-Design-Probleme (Kategoriemitglied)
Referenzen
- MITRE Corporation. "CWE-1245: Improper Finite State Machines (FSMs) in Hardware Logic." https://cwe.mitre.org/data/definitions/1245.html
- REF-1060: Farimah Farahmandi und Prabhat Mishra zur FSM-Anomalieerkennung