Firmware Not Updateable
Description
Firmware Not Updateable occurs when a product lacks the ability to update or patch firmware to address vulnerabilities or weaknesses. This creates permanent risk throughout the device's lifetime, potentially spanning years or decades, as consumers remain vulnerable to exploitation of any known vulnerabilities, or any vulnerabilities that are discovered in the future. Without the ability to patch or update firmware, an exploitable vulnerability in one unpatched device may be weaponized against an entire device class.
Risk
Non-updateable firmware has severe security implications. Known vulnerabilities cannot be fixed. Future vulnerabilities cannot be addressed. Devices become permanently compromised. Attack tools can be developed for entire product lines. Botnets can recruit vulnerable devices. Compliance requirements may be violated. Product liability may increase. Consumer trust is eroded.
Solution
Specify firmware update capability with integrity checks and authentication to prevent untrusted installations during the requirements phase. Design devices allowing firmware updates and specify distribution, integrity, and authentication methods during architecture and design. Implement necessary functionality for firmware updates including secure boot chain verification. Test update capability thoroughly including rejection of invalid images.
Common Consequences
| Impact | Details |
|---|---|
| Confidentiality | Scope: Confidentiality Read Memory - Unpatched vulnerabilities allow data theft. |
| Integrity | Scope: Integrity Execute Unauthorized Code - Malware can be permanently installed. |
| Availability | Scope: Availability DoS - Devices may be rendered unusable. |
| Access Control | Scope: Access Control Gain Privileges - Attackers can gain full device control. |
| Authentication | Scope: Authentication Bypass Protection Mechanism - Security features cannot be improved. |
Example Code
Vulnerable Code
// Vulnerable: Device with ROM-only firmware
module vulnerable_rom_device (
input wire clk,
input wire reset_n,
input wire [15:0] addr,
output reg [31:0] data,
// No firmware update interface
output reg device_ready
);
// VULNERABLE: Firmware in ROM - cannot be updated
reg [31:0] firmware_rom [0:16383];
// ROM initialized at fabrication - never changes
initial begin
$readmemh("firmware.hex", firmware_rom);
end
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
device_ready <= 1'b0;
end
else begin
// VULNERABLE: Can only read from ROM
data <= firmware_rom[addr];
device_ready <= 1'b1;
// No mechanism to update firmware
// If vulnerability found, device is permanently at risk
end
end
// No update interface exists
// No flash programming capability
// No secure boot to verify new firmware
endmodule
// Vulnerable: Microcontroller with locked flash
module vulnerable_locked_mcu (
input wire clk,
input wire reset_n,
// Flash is permanently locked
input wire [15:0] flash_addr,
output reg [31:0] flash_data
);
// Flash memory
reg [31:0] flash_mem [0:32767];
// VULNERABLE: Lock fuse blown - flash cannot be reprogrammed
wire flash_locked = 1'b1; // Permanently locked
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
// Initialize from flash
end
else begin
// VULNERABLE: Write operations blocked
// flash_mem[flash_addr] <= write_data; // Not possible
// Read only
flash_data <= flash_mem[flash_addr];
end
end
// Device cannot receive security updates
// Known vulnerabilities cannot be patched
endmodule
// Vulnerable: IoT device without update capability
#include <stdint.h>
// VULNERABLE: No firmware update mechanism
void vulnerable_device_main(void) {
// Device initialization
init_hardware();
init_network();
// Main loop - runs same firmware forever
while (1) {
process_sensor_data();
send_to_cloud(); // May have vulnerabilities
receive_commands(); // May have vulnerabilities
// No way to update this code
// Vulnerabilities discovered later cannot be fixed
}
}
// VULNERABLE: Even if vulnerability is found, no fix possible
void vulnerable_network_handler(uint8_t* data, size_t len) {
// Buffer overflow vulnerability (CWE-120)
char buffer[64];
memcpy(buffer, data, len); // No bounds check
// This vulnerability cannot be patched
// All deployed devices remain vulnerable forever
process_data(buffer);
}
// VULNERABLE: No integrity checking even if update was possible
void no_update_mechanism(void) {
// No code to:
// - Receive firmware updates
// - Verify update signatures
// - Write to flash
// - Reboot into new firmware
}
Fixed Code
// Fixed: Device with secure firmware update capability
module secure_updateable_device (
input wire clk,
input wire reset_n,
input wire [15:0] addr,
output reg [31:0] data,
output reg device_ready,
// FIXED: Firmware update interface
input wire [31:0] update_data,
input wire [15:0] update_addr,
input wire update_write,
input wire update_start,
input wire update_complete,
// Signature verification
input wire [255:0] update_signature,
input wire verify_signature,
output reg signature_valid,
output reg update_success,
output reg update_error
);
// Firmware in flash - can be updated
reg [31:0] firmware_flash [0:16383];
// FIXED: Update staging area
reg [31:0] update_buffer [0:16383];
reg [15:0] update_counter;
// FIXED: Public key for signature verification (in ROM)
reg [255:0] signing_public_key;
initial begin
signing_public_key = 256'h...; // Manufacturer's public key
end
// State machine for update process
reg [2:0] update_state;
parameter IDLE = 3'd0;
parameter RECEIVING = 3'd1;
parameter VERIFYING = 3'd2;
parameter WRITING = 3'd3;
parameter COMPLETE = 3'd4;
parameter ERROR = 3'd5;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
update_state <= IDLE;
update_success <= 1'b0;
update_error <= 1'b0;
signature_valid <= 1'b0;
device_ready <= 1'b0;
end
else begin
case (update_state)
IDLE: begin
update_error <= 1'b0;
device_ready <= 1'b1;
// Normal operation - read from flash
data <= firmware_flash[addr];
if (update_start) begin
update_state <= RECEIVING;
update_counter <= 16'h0;
device_ready <= 1'b0;
end
end
RECEIVING: begin
// FIXED: Receive update into staging buffer
if (update_write) begin
update_buffer[update_addr] <= update_data;
update_counter <= update_counter + 1;
end
if (update_complete) begin
update_state <= VERIFYING;
end
end
VERIFYING: begin
// FIXED: Verify signature before applying update
if (verify_signature) begin
if (verify_ecdsa(update_buffer, update_counter,
update_signature, signing_public_key)) begin
signature_valid <= 1'b1;
update_state <= WRITING;
end
else begin
signature_valid <= 1'b0;
update_state <= ERROR;
end
end
end
WRITING: begin
// FIXED: Copy verified update to main flash
if (update_counter > 0) begin
firmware_flash[16383 - update_counter] <=
update_buffer[16383 - update_counter];
update_counter <= update_counter - 1;
end
else begin
update_state <= COMPLETE;
end
end
COMPLETE: begin
update_success <= 1'b1;
update_state <= IDLE;
// Device will reboot with new firmware
end
ERROR: begin
update_error <= 1'b1;
// Clear staging buffer
update_state <= IDLE;
end
endcase
end
end
endmodule
// Fixed: Secure boot with update support
module secure_boot_with_update (
input wire clk,
input wire reset_n,
input wire [31:0] flash_data,
output reg [15:0] flash_addr,
output reg boot_success,
output reg boot_error,
// Update bank selection
input wire use_backup_bank,
output reg active_bank
);
// FIXED: Dual-bank flash for safe updates
parameter BANK_A_START = 16'h0000;
parameter BANK_B_START = 16'h8000;
reg [2:0] boot_state;
parameter INIT = 3'd0;
parameter VERIFY_MAIN = 3'd1;
parameter VERIFY_BACKUP = 3'd2;
parameter BOOT = 3'd3;
parameter FALLBACK = 3'd4;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
boot_state <= INIT;
boot_success <= 1'b0;
boot_error <= 1'b0;
end
else begin
case (boot_state)
INIT: begin
// FIXED: Start verifying primary bank
flash_addr <= use_backup_bank ? BANK_B_START : BANK_A_START;
boot_state <= VERIFY_MAIN;
end
VERIFY_MAIN: begin
// FIXED: Verify primary firmware signature
if (verify_firmware_signature()) begin
active_bank <= use_backup_bank ? 1'b1 : 1'b0;
boot_state <= BOOT;
end
else begin
// Try backup bank
boot_state <= VERIFY_BACKUP;
end
end
VERIFY_BACKUP: begin
// FIXED: Verify backup firmware
flash_addr <= use_backup_bank ? BANK_A_START : BANK_B_START;
if (verify_firmware_signature()) begin
active_bank <= use_backup_bank ? 1'b0 : 1'b1;
boot_state <= FALLBACK;
end
else begin
// Both banks failed
boot_error <= 1'b1;
end
end
BOOT: begin
boot_success <= 1'b1;
// Execute verified firmware
end
FALLBACK: begin
// FIXED: Boot from backup after logging failure
log_boot_failure();
boot_success <= 1'b1;
end
endcase
end
end
endmodule
// Fixed: IoT device with secure update capability
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
// FIXED: Firmware update capability
#define FLASH_BANK_A 0x08000000
#define FLASH_BANK_B 0x08040000
#define FLASH_BANK_SIZE 0x40000
// Public key for firmware verification (in read-only memory)
static const uint8_t manufacturer_public_key[64] = { /* ... */ };
typedef struct {
uint32_t magic;
uint32_t version;
uint32_t size;
uint8_t signature[64];
uint8_t data[];
} firmware_image_t;
// FIXED: Verify firmware signature
static bool verify_firmware(const firmware_image_t* image) {
// Check magic number
if (image->magic != 0x46575550) { // "FWUP"
return false;
}
// Check size is valid
if (image->size > FLASH_BANK_SIZE - sizeof(firmware_image_t)) {
return false;
}
// FIXED: Verify ECDSA signature
if (!ecdsa_verify(
manufacturer_public_key,
image->data,
image->size,
image->signature)) {
log_error("Firmware signature verification failed");
return false;
}
return true;
}
// FIXED: Secure firmware update process
typedef enum {
UPDATE_SUCCESS,
UPDATE_INVALID_IMAGE,
UPDATE_VERIFICATION_FAILED,
UPDATE_FLASH_ERROR,
UPDATE_ROLLBACK_ATTEMPTED
} update_result_t;
update_result_t secure_firmware_update(const uint8_t* update_data, size_t len) {
const firmware_image_t* image = (const firmware_image_t*)update_data;
// FIXED: Verify before writing
if (!verify_firmware(image)) {
return UPDATE_VERIFICATION_FAILED;
}
// FIXED: Check version to prevent rollback
uint32_t current_version = get_current_firmware_version();
if (image->version < current_version) {
log_security_event("Firmware rollback attempt blocked");
return UPDATE_ROLLBACK_ATTEMPTED;
}
// FIXED: Determine inactive bank for update
uint32_t target_bank = get_inactive_bank();
uint32_t target_addr = (target_bank == 0) ? FLASH_BANK_A : FLASH_BANK_B;
// FIXED: Erase target bank
if (!flash_erase_bank(target_addr, FLASH_BANK_SIZE)) {
return UPDATE_FLASH_ERROR;
}
// FIXED: Write new firmware
if (!flash_write(target_addr, update_data, len)) {
return UPDATE_FLASH_ERROR;
}
// FIXED: Verify written data
if (memcmp((void*)target_addr, update_data, len) != 0) {
return UPDATE_FLASH_ERROR;
}
// FIXED: Update bank selection for next boot
set_active_bank(target_bank);
log_info("Firmware update successful, version %u -> %u",
current_version, image->version);
return UPDATE_SUCCESS;
}
// FIXED: Main loop with update capability
void secure_device_main(void) {
// Verify firmware integrity at boot
if (!verify_current_firmware()) {
// Boot from backup bank
boot_backup_firmware();
return;
}
init_hardware();
init_network();
while (1) {
process_sensor_data();
send_to_cloud();
receive_commands();
// FIXED: Check for and apply firmware updates
if (firmware_update_available()) {
uint8_t* update_data;
size_t update_size;
if (download_firmware_update(&update_data, &update_size)) {
update_result_t result = secure_firmware_update(
update_data, update_size);
if (result == UPDATE_SUCCESS) {
// Reboot to apply update
system_reboot();
}
else {
log_error("Firmware update failed: %d", result);
}
free(update_data);
}
}
}
}
// FIXED: Automatic update checking
void check_for_updates_periodically(void) {
static uint32_t last_check = 0;
uint32_t now = get_current_time();
// Check every 24 hours
if (now - last_check > 86400) {
last_check = now;
if (check_update_server()) {
schedule_firmware_update();
}
}
}
CVE Examples
- CVE-2020-9054: Network-attached storage devices with OS command injection vulnerabilities actively exploited for botnet recruitment, but end-of-support products cannot be patched.
- Smart lock with weak key generation vulnerability detectable via Bluetooth sniffing - firmware cannot be upgraded.
Related CWEs
- CWE-1329: Reliance on Component That is Not Updateable (parent)
- CWE-1208: Cross-Cutting Problems (category)
- CWE-912: Hidden Functionality (related)
- CAPEC-682: Exploitation of Firmware or ROM Code with Unpatchable Vulnerabilities (attack pattern)
References
- MITRE Corporation. "CWE-1277: Firmware Not Updateable." https://cwe.mitre.org/data/definitions/1277.html
- NIST. "Guidelines for Firmware Update"
- IEC 62443. "Industrial Cybersecurity Standards"