Missing Write Protection for Parametric Data Values

Description

Missing Write Protection for Parametric Data Values occurs when the device does not write-protect the parametric data values for sensors that scale the sensor value, allowing untrusted software to manipulate the apparent result and potentially damage hardware or cause operational failure. Hardware devices employ sensors to monitor operational parameters like thermal, power, voltage, current, and frequency levels. While threshold limits are typically protected via hardware fuses or trusted BIOS, the sensor calibration data used for unit conversion may remain unprotected. Untrusted software can modify these parametric scaling values to bypass safety limits and falsify sensor readings.

Risk

Unprotected sensor parameters have severe implications. Physical hardware damage possible. Thermal limits bypassed causing overheating. Power limits bypassed causing component damage. False sensor readings mask dangerous conditions. Denial of service through induced failures. Safety mechanisms rendered ineffective. Hardware lifetime reduced. High availability impact.

Solution

Implement access controls restricting modification of threshold limits and sensor parametric data to trusted software only during architecture and design phase. Store calibration data in protected memory regions. Require privileged access for parameter modification. Consider hardware fuses for critical calibration values. Validate parameter changes against safe ranges even for trusted software.

Common Consequences

ImpactDetails
AvailabilityScope: Availability

Denial of service through hardware damage, false shutdowns, or induced instability.

Example Code

Vulnerable Code

// Vulnerable: Sensor with unprotected calibration parameters

module vulnerable_temperature_sensor (
    input  wire        clk,
    input  wire        rst_n,

    // Raw sensor input (oscillator frequency)
    input  wire [15:0] oscillator_freq,

    // Calibration parameters (VULNERABLE: writable by anyone)
    input  wire        param_write_enable,
    input  wire [31:0] param_write_data,
    input  wire [3:0]  param_write_addr,

    // Temperature output
    output reg  [15:0] temperature_celsius,
    output reg         over_temp_alarm,
    output reg         shutdown_required
);

    // Calibration parameters for temperature calculation
    // Temperature = a * freq + b (linear approximation)
    reg signed [15:0] param_a;  // Slope coefficient
    reg signed [15:0] param_b;  // Offset coefficient

    // Threshold (typically protected by fuse)
    localparam SHUTDOWN_THRESHOLD = 16'd100;  // 100°C

    // VULNERABLE: Calibration parameters writable without restriction
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            // Default calibration values
            param_a <= 16'h0010;  // Default slope
            param_b <= 16'hFF00;  // Default offset
        end else if (param_write_enable) begin
            // VULNERABLE: Any software can modify parameters
            case (param_write_addr)
                4'h0: param_a <= param_write_data[15:0];
                4'h1: param_b <= param_write_data[15:0];
            endcase
        end
    end

    // Calculate temperature from oscillator frequency
    reg signed [31:0] temp_calc;

    always @(posedge clk) begin
        // Temperature = a * freq + b
        temp_calc <= param_a * $signed({1'b0, oscillator_freq}) + param_b;
        temperature_celsius <= temp_calc[15:0];

        // Check against threshold
        if (temperature_celsius >= SHUTDOWN_THRESHOLD) begin
            over_temp_alarm <= 1'b1;
            shutdown_required <= 1'b1;
        end else begin
            over_temp_alarm <= 1'b0;
            shutdown_required <= 1'b0;
        end
    end

    // Attack:
    // 1. Attacker sets param_a = 0, param_b = 0
    // 2. Temperature always reads as 0°C
    // 3. Hardware overheats to dangerous levels
    // 4. Shutdown threshold never triggered
    // 5. Physical damage to hardware

endmodule

// Vulnerable: Power sensor with unprotected scaling
module vulnerable_power_sensor (
    input  wire        clk,
    input  wire        rst_n,

    // Raw ADC reading
    input  wire [11:0] adc_reading,

    // Scaling parameters (VULNERABLE: unprotected)
    input  wire        scale_write_en,
    input  wire [15:0] scale_multiplier,
    input  wire [15:0] scale_divisor,

    // Power output
    output reg  [15:0] power_watts,
    output reg         power_limit_exceeded
);

    // VULNERABLE: Scaling factors writable without authentication
    reg [15:0] multiplier;
    reg [15:0] divisor;

    localparam POWER_LIMIT = 16'd150;  // 150W limit

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            multiplier <= 16'd100;  // Default calibration
            divisor <= 16'd1024;
        end else if (scale_write_en) begin
            // VULNERABLE: No access control
            multiplier <= scale_multiplier;
            divisor <= scale_divisor;
        end
    end

    // Calculate power
    always @(posedge clk) begin
        if (divisor != 0) begin
            power_watts <= (adc_reading * multiplier) / divisor;
        end else begin
            // VULNERABLE: Division by zero if attacker sets divisor=0
            power_watts <= 16'hFFFF;  // Overflow!
        end

        power_limit_exceeded <= (power_watts > POWER_LIMIT);
    end

    // Attack:
    // Set multiplier=0 -> power always reads 0W
    // Or set divisor=0 -> causes undefined behavior
    // Power limits never triggered, component damage possible

endmodule
// Vulnerable: Software sensor driver without parameter protection

#include <stdint.h>
#include <stdbool.h>

// VULNERABLE: Calibration structure accessible to all software
typedef struct {
    int16_t slope;
    int16_t offset;
    uint16_t threshold;
} sensor_calibration_t;

// VULNERABLE: Global, unprotected calibration data
static sensor_calibration_t thermal_calibration = {
    .slope = 16,
    .offset = -256,
    .threshold = 100
};

// VULNERABLE: Any code can modify calibration
void vulnerable_set_calibration(int16_t slope, int16_t offset) {
    // No privilege check!
    thermal_calibration.slope = slope;
    thermal_calibration.offset = offset;
}

int16_t vulnerable_read_temperature(uint16_t raw_reading) {
    // Uses potentially compromised calibration
    int32_t temp = (thermal_calibration.slope * raw_reading) +
                   thermal_calibration.offset;
    return (int16_t)temp;
}

bool vulnerable_check_thermal_limit(uint16_t raw_reading) {
    int16_t temp = vulnerable_read_temperature(raw_reading);

    // VULNERABLE: Returns false if calibration corrupted to show low temp
    return temp >= thermal_calibration.threshold;
}

// Attack:
// malicious_code() {
//     vulnerable_set_calibration(0, 0);  // Set slope=0, offset=0
//     // Now all temperature readings return 0
//     // System won't trigger thermal protection
// }

Fixed Code

// Fixed: Sensor with protected calibration parameters

module secure_temperature_sensor (
    input  wire        clk,
    input  wire        rst_n,

    // Raw sensor input
    input  wire [15:0] oscillator_freq,

    // Calibration write interface (restricted)
    input  wire        param_write_enable,
    input  wire [31:0] param_write_data,
    input  wire [3:0]  param_write_addr,
    input  wire        privileged_access,     // FIXED: Privilege signal
    input  wire        boot_complete,         // FIXED: Lifecycle signal

    // Temperature output
    output reg  [15:0] temperature_celsius,
    output reg         over_temp_alarm,
    output reg         shutdown_required,
    output reg         param_write_denied
);

    // Calibration parameters
    reg signed [15:0] param_a;
    reg signed [15:0] param_b;

    // FIXED: Write lock after boot
    reg calibration_locked;

    // FIXED: Valid parameter ranges
    localparam MIN_SLOPE = 16'sh0001;
    localparam MAX_SLOPE = 16'sh00FF;
    localparam MIN_OFFSET = 16'shFC00;
    localparam MAX_OFFSET = 16'sh0400;

    localparam SHUTDOWN_THRESHOLD = 16'd100;

    // FIXED: Lock calibration after boot
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            calibration_locked <= 1'b0;
        end else if (boot_complete) begin
            // FIXED: Once boot completes, lock calibration
            calibration_locked <= 1'b1;
        end
    end

    // FIXED: Protected calibration parameter writes
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            // Load default calibration from OTP/fuse
            param_a <= 16'h0010;
            param_b <= 16'hFF00;
            param_write_denied <= 1'b0;
        end else if (param_write_enable) begin
            param_write_denied <= 1'b0;

            // FIXED: Check privileges and lifecycle
            if (!privileged_access || calibration_locked) begin
                // FIXED: Deny write from unprivileged or after lock
                param_write_denied <= 1'b1;
            end else begin
                // FIXED: Validate parameter ranges
                case (param_write_addr)
                    4'h0: begin
                        if ($signed(param_write_data[15:0]) >= MIN_SLOPE &&
                            $signed(param_write_data[15:0]) <= MAX_SLOPE) begin
                            param_a <= param_write_data[15:0];
                        end else begin
                            param_write_denied <= 1'b1;  // Out of range
                        end
                    end
                    4'h1: begin
                        if ($signed(param_write_data[15:0]) >= MIN_OFFSET &&
                            $signed(param_write_data[15:0]) <= MAX_OFFSET) begin
                            param_b <= param_write_data[15:0];
                        end else begin
                            param_write_denied <= 1'b1;  // Out of range
                        end
                    end
                    default: begin
                        param_write_denied <= 1'b1;
                    end
                endcase
            end
        end
    end

    // Calculate temperature
    reg signed [31:0] temp_calc;

    always @(posedge clk) begin
        temp_calc <= param_a * $signed({1'b0, oscillator_freq}) + param_b;
        temperature_celsius <= temp_calc[15:0];

        if (temperature_celsius >= SHUTDOWN_THRESHOLD) begin
            over_temp_alarm <= 1'b1;
            shutdown_required <= 1'b1;
        end else begin
            over_temp_alarm <= 1'b0;
            shutdown_required <= 1'b0;
        end
    end

endmodule

// Fixed: Power sensor with protected and validated parameters
module secure_power_sensor (
    input  wire        clk,
    input  wire        rst_n,

    // Raw ADC reading
    input  wire [11:0] adc_reading,

    // Protected scaling parameter interface
    input  wire        scale_write_en,
    input  wire [15:0] scale_multiplier,
    input  wire [15:0] scale_divisor,
    input  wire        privileged_access,
    input  wire        boot_complete,

    // Power output
    output reg  [15:0] power_watts,
    output reg         power_limit_exceeded,
    output reg         param_error
);

    reg [15:0] multiplier;
    reg [15:0] divisor;
    reg params_locked;

    // FIXED: Safe parameter ranges
    localparam MIN_DIVISOR = 16'd100;  // Prevent division issues
    localparam MAX_MULTIPLIER = 16'd1000;

    localparam POWER_LIMIT = 16'd150;

    // FIXED: Lock after boot
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            params_locked <= 1'b0;
        end else if (boot_complete) begin
            params_locked <= 1'b1;
        end
    end

    // FIXED: Protected parameter writes
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            multiplier <= 16'd100;
            divisor <= 16'd1024;
            param_error <= 1'b0;
        end else if (scale_write_en) begin
            param_error <= 1'b0;

            if (!privileged_access || params_locked) begin
                // FIXED: Deny unprivileged or locked writes
                param_error <= 1'b1;
            end else begin
                // FIXED: Validate divisor to prevent divide-by-zero
                if (scale_divisor >= MIN_DIVISOR &&
                    scale_multiplier <= MAX_MULTIPLIER) begin
                    multiplier <= scale_multiplier;
                    divisor <= scale_divisor;
                end else begin
                    param_error <= 1'b1;
                end
            end
        end
    end

    // Calculate power (safe with validated divisor)
    always @(posedge clk) begin
        power_watts <= (adc_reading * multiplier) / divisor;
        power_limit_exceeded <= (power_watts > POWER_LIMIT);
    end

endmodule
// Fixed: Software sensor driver with protected parameters

#include <stdint.h>
#include <stdbool.h>

typedef struct {
    int16_t slope;
    int16_t offset;
    uint16_t threshold;
    bool locked;  // FIXED: Lock flag
} sensor_calibration_t;

// FIXED: Static calibration, not directly accessible
static sensor_calibration_t thermal_calibration = {
    .slope = 16,
    .offset = -256,
    .threshold = 100,
    .locked = false
};

// FIXED: Valid parameter ranges
#define MIN_SLOPE 1
#define MAX_SLOPE 255
#define MIN_OFFSET -1024
#define MAX_OFFSET 1024

// FIXED: Privileged-only calibration setting
bool secure_set_calibration(int16_t slope, int16_t offset, bool privileged) {
    // FIXED: Require privilege
    if (!privileged) {
        return false;
    }

    // FIXED: Prevent modification after lock
    if (thermal_calibration.locked) {
        return false;
    }

    // FIXED: Validate parameter ranges
    if (slope < MIN_SLOPE || slope > MAX_SLOPE) {
        return false;
    }

    if (offset < MIN_OFFSET || offset > MAX_OFFSET) {
        return false;
    }

    thermal_calibration.slope = slope;
    thermal_calibration.offset = offset;

    return true;
}

// FIXED: Lock calibration after initialization
void secure_lock_calibration(void) {
    thermal_calibration.locked = true;
}

int16_t secure_read_temperature(uint16_t raw_reading) {
    int32_t temp = (thermal_calibration.slope * raw_reading) +
                   thermal_calibration.offset;
    return (int16_t)temp;
}

bool secure_check_thermal_limit(uint16_t raw_reading) {
    int16_t temp = secure_read_temperature(raw_reading);
    return temp >= thermal_calibration.threshold;
}

// FIXED: Initialization sequence
void secure_sensor_init(int16_t cal_slope, int16_t cal_offset) {
    // Only during boot, from trusted code
    if (secure_set_calibration(cal_slope, cal_offset, true)) {
        secure_lock_calibration();
    } else {
        // Use safe defaults if calibration fails
        // Don't lock - allows recovery with valid params
    }
}

CVE Examples

  • CVE-2020-8703: Improper input validation in thermal subsystem allowed manipulation of temperature readings.
  • CVE-2019-0151: Insufficient access control on power sensor parameters in certain Intel processors.

  • CWE-862: Missing Authorization (parent)
  • CWE-1299: Missing Protection Mechanism for Alternate Hardware Interface (peer)
  • CWE-1198: Privilege Separation and Access Control Issues (category)
  • CWE-1206: Power, Clock, Thermal, and Reset Concerns (category)

References

  1. MITRE Corporation. "CWE-1314: Missing Write Protection for Parametric Data Values." https://cwe.mitre.org/data/definitions/1314.html
  2. Intel. "Thermal Management Specifications"
  3. JEDEC. "Power Management Standards"