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

ImpactDetails
ConfidentialityScope: Confidentiality

Read Memory - Unpatched vulnerabilities allow data theft.
IntegrityScope: Integrity

Execute Unauthorized Code - Malware can be permanently installed.
AvailabilityScope: Availability

DoS - Devices may be rendered unusable.
Access ControlScope: Access Control

Gain Privileges - Attackers can gain full device control.
AuthenticationScope: 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.

  • 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

  1. MITRE Corporation. "CWE-1277: Firmware Not Updateable." https://cwe.mitre.org/data/definitions/1277.html
  2. NIST. "Guidelines for Firmware Update"
  3. IEC 62443. "Industrial Cybersecurity Standards"