Improper Finite State Machines (FSMs) in Hardware Logic
Description
Improper Finite State Machines (FSMs) in Hardware Logic occurs when faulty finite state machines in the hardware logic allow an attacker to put the system in an undefined state, to cause a denial of service (DoS) or gain privileges on the victim's system. The security and functionality of systems depend heavily on FSM implementation. These machines indicate system security states, and numerous secure data operations rely on their accuracy. Faulty FSM designs that omit certain states can allow attackers to drive systems into unstable, unrecoverable states.
Risk
Improper FSM implementation has severe security implications. Systems may enter undefined states. Denial of service may occur through state manipulation. Security state transitions may be bypassed. Privilege escalation may be possible. System crashes or restarts may occur. Deadlocks may render systems unresponsive. Authentication states may be bypassable. Access control decisions may be compromised.
Solution
Define all possible states and handle all unused states through default statements. Ensure that system defaults to a secure state. Use formal verification to check FSM completeness. Implement unreachable state detection and recovery. Add watchdog timers for FSM timeout. Log unexpected state transitions. Test all possible input combinations. Use encoding that detects invalid states.
Common Consequences
| Impact | Details |
|---|---|
| Availability | Scope: Availability DoS: Crash, Exit, or Restart - Faulty FSMs can cause unexpected system states leading to crashes or restarts. |
| Access Control | Scope: Access Control Gain Privileges or Assume Identity - FSM vulnerabilities may allow privilege escalation or bypassing security states. |
Example Code
Vulnerable Code
// Vulnerable: FSM with missing state handlers
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
);
// States
parameter IDLE = 2'b00;
parameter AUTHENTICATING = 2'b01;
parameter AUTHENTICATED = 2'b10;
// State 2'b11 undefined - VULNERABLE!
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
// VULNERABLE: No handler for state 2'b11
// If reached, FSM behavior is undefined!
endcase
end
end
endmodule
// Vulnerable: Input combinations not fully handled
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; // Safe state
3'h1: security_state <= 3'h1; // State 1
3'h2: security_state <= 3'h2; // State 2
3'h3: security_state <= 3'h3; // State 3
3'h4: security_state <= 3'h4; // State 4
3'h5: security_state <= 3'h5; // State 5
// VULNERABLE: Inputs 3'h6 and 3'h7 not handled!
// System goes to undefined state
endcase
end
end
endmodule
// Vulnerable: FSM can enter deadlock state
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
// VULNERABLE: No timeout handling - can deadlock here!
end
COMPLETE: begin
state <= IDLE;
transaction_complete <= 1'b0;
end
ERROR: begin
// VULNERABLE: No exit from ERROR state!
// System stuck in error forever
end
endcase
end
end
endmodule
// Vulnerable: Software FSM with missing cases
typedef enum {
STATE_INIT,
STATE_AUTHENTICATING,
STATE_AUTHENTICATED,
STATE_ADMIN,
STATE_COUNT // 4 states
} 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;
// VULNERABLE: STATE_ADMIN not handled!
// If reached, no state transitions possible
// VULNERABLE: No default case for invalid states
}
}
Fixed Code
// Fixed: FSM with all states handled
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
);
// States
parameter IDLE = 2'b00;
parameter AUTHENTICATING = 2'b01;
parameter AUTHENTICATED = 2'b10;
parameter ERROR = 2'b11; // Explicitly handle undefined state
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
// FIXED: Explicit handler for undefined/error state
default: begin
// Return to safe state
current_state <= IDLE;
authenticated <= 1'b0;
access_granted <= 1'b0;
fsm_error <= 1'b1; // Log error
end
endcase
end
end
endmodule
// Fixed: All input combinations handled
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;
// FIXED: Handle all remaining inputs
default: begin
security_state <= 3'h0; // Return to safe state
invalid_input <= 1'b1; // Flag invalid input
end
endcase
end
end
endmodule
// Fixed: FSM with timeout and recovery
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 counter for 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
// FIXED: Timeout handling for 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;
// FIXED: Exit from ERROR state with acknowledgment
if (error_ack) begin
state <= IDLE;
error_flag <= 1'b0;
end
end
// FIXED: Handle undefined states
default: begin
state <= IDLE;
error_flag <= 1'b1;
end
endcase
end
end
endmodule
// Fixed: Software FSM with all cases handled
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;
// FIXED: STATE_ADMIN handled
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:
// Error recovery
if (event == EVENT_RESET) {
current_state = STATE_INIT;
}
break;
// FIXED: Default case for invalid states
default:
log_error("Invalid FSM state: %d", current_state);
current_state = STATE_INIT; // Return to safe state
break;
}
}
// FSM validation function
bool validate_fsm_state(void) {
if (current_state >= STATE_COUNT) {
log_security_event("FSM in invalid state: %d", current_state);
current_state = STATE_INIT;
return false;
}
return true;
}
CVE Examples
FSM vulnerabilities have been found in various hardware designs where undefined states could be reached, leading to security bypasses or denial of service.
Related CWEs
- CWE-684: Incorrect Provision of Specified Functionality (parent)
- CWE-1199: General Circuit and Logic Design Concerns (category member)
References
- MITRE Corporation. "CWE-1245: Improper Finite State Machines (FSMs) in Hardware Logic." https://cwe.mitre.org/data/definitions/1245.html
- REF-1060: Farimah Farahmandi and Prabhat Mishra on FSM Anomaly Detection