Improper Management of Sensitive Trace Data

Description

Improper Management of Sensitive Trace Data occurs when trace data collected from System-on-Chip (SoC) sources is inadequately protected, being stored in unprotected locations or shared with untrusted agents. SoCs include specialized IP blocks that trace internal signals in real-time for verification and debugging purposes, aggregating data from security-critical sources like CPUs, crypto coprocessors, and on-chip fabrics. When traces from sensitive sources lack proper protection or tagging, untrusted software or hardware debuggers can access them to extract confidential information.

Risk

Improper trace data management has severe implications. Cryptographic keys extractable from traces. Private data leaked through debug infrastructure. Secure boot process observable. Authentication secrets exposed. Internal state revealed to attackers. Reverse engineering facilitated. Security boundaries violated. Privilege escalation through trace analysis. High likelihood when trace infrastructure lacks access control.

Solution

Tag traces to indicate ownership and required debugging privilege level (designer, OEM, or end-user) during implementation phase, ensuring privilege verification before access. Store sensitive traces in protected memory regions. Implement access control on trace buffers. Disable sensitive tracing in production. Use encryption for trace data in transit. Clear trace buffers during security-sensitive operations.

Common Consequences

ImpactDetails
ConfidentialityScope: Confidentiality

Adversaries can extract secret values captured in debug traces stored unsafely.

Example Code

Vulnerable Code

// Vulnerable: Trace controller without access protection

module vulnerable_trace_controller (
    input  wire        clk,
    input  wire        rst_n,

    // Trace sources
    input  wire [31:0] cpu_trace_data,
    input  wire        cpu_trace_valid,
    input  wire [31:0] crypto_trace_data,     // Contains key operations!
    input  wire        crypto_trace_valid,
    input  wire [31:0] fabric_trace_data,
    input  wire        fabric_trace_valid,

    // Trace configuration
    input  wire [2:0]  trace_enable,          // Per-source enable
    input  wire        trace_start,
    input  wire        trace_stop,

    // Trace buffer interface (VULNERABLE: unprotected)
    output reg  [31:0] trace_buffer_addr,
    output reg  [31:0] trace_buffer_data,
    output reg         trace_buffer_write,

    // Debug read interface (VULNERABLE: no access control)
    input  wire [31:0] debug_read_addr,
    input  wire        debug_read_en,
    output reg  [31:0] debug_read_data
);

    reg [31:0] trace_buffer [0:4095];  // 16KB trace buffer
    reg [11:0] write_ptr;
    reg        tracing_active;

    // VULNERABLE: No distinction between sensitive and non-sensitive traces
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            write_ptr <= 12'b0;
            tracing_active <= 1'b0;
        end else begin
            if (trace_start) begin
                tracing_active <= 1'b1;
            end else if (trace_stop) begin
                tracing_active <= 1'b0;
            end

            if (tracing_active) begin
                // VULNERABLE: Crypto trace data stored without protection
                if (crypto_trace_valid && trace_enable[1]) begin
                    trace_buffer[write_ptr] <= crypto_trace_data;
                    write_ptr <= write_ptr + 1;
                end

                // VULNERABLE: CPU trace (may contain secrets)
                if (cpu_trace_valid && trace_enable[0]) begin
                    trace_buffer[write_ptr] <= cpu_trace_data;
                    write_ptr <= write_ptr + 1;
                end

                if (fabric_trace_valid && trace_enable[2]) begin
                    trace_buffer[write_ptr] <= fabric_trace_data;
                    write_ptr <= write_ptr + 1;
                end
            end
        end
    end

    // VULNERABLE: Debug read without access control
    always @(posedge clk) begin
        if (debug_read_en) begin
            // VULNERABLE: Any debugger can read trace buffer
            // Including sensitive crypto operations!
            debug_read_data <= trace_buffer[debug_read_addr[11:0]];
        end
    end

    // Attack:
    // 1. Enable crypto tracing
    // 2. Trigger crypto operations
    // 3. Read trace buffer via debug interface
    // 4. Extract cryptographic keys from traces

endmodule

// Vulnerable: Trace data stored in unprotected memory
module vulnerable_trace_memory (
    input  wire        clk,
    input  wire        rst_n,

    // Trace input
    input  wire [63:0] trace_data,
    input  wire [3:0]  trace_source,
    input  wire        trace_valid,

    // Memory interface (VULNERABLE: no protection)
    output reg  [31:0] mem_addr,
    output reg  [63:0] mem_data,
    output reg         mem_write
);

    // VULNERABLE: Trace stored in regular memory space
    // No memory protection for sensitive traces
    localparam TRACE_BASE = 32'h8000_0000;

    reg [15:0] trace_offset;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            trace_offset <= 16'b0;
            mem_write <= 1'b0;
        end else if (trace_valid) begin
            // VULNERABLE: All traces go to same unprotected region
            mem_addr <= TRACE_BASE + {trace_offset, 3'b000};
            mem_data <= trace_data;
            mem_write <= 1'b1;
            trace_offset <= trace_offset + 1;

            // VULNERABLE: No tagging of trace sensitivity
            // Crypto traces mixed with debug traces
            // Any software can read this memory region
        end else begin
            mem_write <= 1'b0;
        end
    end

endmodule

Fixed Code

// Fixed: Trace controller with access protection

module secure_trace_controller (
    input  wire        clk,
    input  wire        rst_n,

    // Trace sources with security levels
    input  wire [31:0] cpu_trace_data,
    input  wire        cpu_trace_valid,
    input  wire [1:0]  cpu_trace_security,    // FIXED: Security level

    input  wire [31:0] crypto_trace_data,
    input  wire        crypto_trace_valid,
    input  wire [1:0]  crypto_trace_security, // FIXED: Always high security

    input  wire [31:0] fabric_trace_data,
    input  wire        fabric_trace_valid,
    input  wire [1:0]  fabric_trace_security,

    // Trace configuration (protected)
    input  wire [2:0]  trace_enable,
    input  wire        trace_start,
    input  wire        trace_stop,
    input  wire        privileged_config,     // FIXED: Config protection

    // Trace buffer interface (protected)
    output reg  [31:0] trace_buffer_addr,
    output reg  [35:0] trace_buffer_data,     // FIXED: Includes security tag
    output reg         trace_buffer_write,

    // Debug read interface (protected)
    input  wire [31:0] debug_read_addr,
    input  wire        debug_read_en,
    input  wire [1:0]  debug_privilege,       // FIXED: Debugger privilege
    output reg  [31:0] debug_read_data,
    output reg         debug_access_denied,

    // Lifecycle
    input  wire        production_mode        // FIXED: Disable in production
);

    // FIXED: Separate buffers for different security levels
    reg [35:0] secure_trace_buffer [0:1023];   // High security traces
    reg [35:0] normal_trace_buffer [0:1023];   // Normal traces
    reg [9:0] secure_write_ptr;
    reg [9:0] normal_write_ptr;
    reg tracing_active;

    // FIXED: Security levels
    localparam SEC_LEVEL_PUBLIC  = 2'b00;
    localparam SEC_LEVEL_OEM     = 2'b01;
    localparam SEC_LEVEL_SILICON = 2'b10;
    localparam SEC_LEVEL_SECURE  = 2'b11;

    // FIXED: Configuration protection
    reg [2:0] trace_enable_reg;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            trace_enable_reg <= 3'b000;  // Disabled by default
        end else if (trace_start && privileged_config && !production_mode) begin
            // FIXED: Only privileged config can enable tracing
            // FIXED: Tracing disabled in production
            trace_enable_reg <= trace_enable;
            tracing_active <= 1'b1;
        end else if (trace_stop) begin
            tracing_active <= 1'b0;
        end
    end

    // FIXED: Separate trace storage by security level
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            secure_write_ptr <= 10'b0;
            normal_write_ptr <= 10'b0;
        end else if (tracing_active && !production_mode) begin
            // FIXED: Crypto traces always go to secure buffer
            if (crypto_trace_valid && trace_enable_reg[1]) begin
                // FIXED: Tag with security level
                secure_trace_buffer[secure_write_ptr] <=
                    {SEC_LEVEL_SECURE, 2'b01, crypto_trace_data};
                secure_write_ptr <= secure_write_ptr + 1;
            end

            // CPU traces sorted by security level
            if (cpu_trace_valid && trace_enable_reg[0]) begin
                if (cpu_trace_security >= SEC_LEVEL_OEM) begin
                    secure_trace_buffer[secure_write_ptr] <=
                        {cpu_trace_security, 2'b00, cpu_trace_data};
                    secure_write_ptr <= secure_write_ptr + 1;
                end else begin
                    normal_trace_buffer[normal_write_ptr] <=
                        {cpu_trace_security, 2'b00, cpu_trace_data};
                    normal_write_ptr <= normal_write_ptr + 1;
                end
            end

            if (fabric_trace_valid && trace_enable_reg[2]) begin
                if (fabric_trace_security >= SEC_LEVEL_OEM) begin
                    secure_trace_buffer[secure_write_ptr] <=
                        {fabric_trace_security, 2'b10, fabric_trace_data};
                    secure_write_ptr <= secure_write_ptr + 1;
                end else begin
                    normal_trace_buffer[normal_write_ptr] <=
                        {fabric_trace_security, 2'b10, fabric_trace_data};
                    normal_write_ptr <= normal_write_ptr + 1;
                end
            end
        end
    end

    // FIXED: Access-controlled debug read
    wire [1:0] accessed_security;
    wire [31:0] accessed_data;
    wire access_secure_buffer = debug_read_addr[12];

    assign accessed_security = access_secure_buffer ?
        secure_trace_buffer[debug_read_addr[9:0]][35:34] :
        normal_trace_buffer[debug_read_addr[9:0]][35:34];

    assign accessed_data = access_secure_buffer ?
        secure_trace_buffer[debug_read_addr[9:0]][31:0] :
        normal_trace_buffer[debug_read_addr[9:0]][31:0];

    always @(posedge clk) begin
        debug_access_denied <= 1'b0;

        if (debug_read_en) begin
            // FIXED: Check debugger privilege against trace security
            if (debug_privilege >= accessed_security) begin
                debug_read_data <= accessed_data;
            end else begin
                // FIXED: Deny access to higher security traces
                debug_read_data <= 32'hDEAD_BEEF;
                debug_access_denied <= 1'b1;
            end
        end
    end

    // FIXED: Clear sensitive traces on security transitions
    always @(posedge clk) begin
        if (production_mode) begin
            // FIXED: Clear all traces when entering production
            secure_write_ptr <= 10'b0;
            // Optionally zero out buffer contents
        end
    end

endmodule

// Fixed: Trace memory with protection
module secure_trace_memory (
    input  wire        clk,
    input  wire        rst_n,

    // Trace input with security tag
    input  wire [63:0] trace_data,
    input  wire [3:0]  trace_source,
    input  wire [1:0]  trace_security,
    input  wire        trace_valid,

    // Protected memory interfaces
    output reg  [31:0] secure_mem_addr,
    output reg  [63:0] secure_mem_data,
    output reg         secure_mem_write,

    output reg  [31:0] normal_mem_addr,
    output reg  [63:0] normal_mem_data,
    output reg         normal_mem_write,

    // Access control
    input  wire        production_mode
);

    // FIXED: Separate memory regions with different protection
    localparam SECURE_TRACE_BASE = 32'hA000_0000;  // Protected region
    localparam NORMAL_TRACE_BASE = 32'h8000_0000;  // Less protected

    reg [15:0] secure_offset;
    reg [15:0] normal_offset;

    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            secure_offset <= 16'b0;
            normal_offset <= 16'b0;
            secure_mem_write <= 1'b0;
            normal_mem_write <= 1'b0;
        end else if (trace_valid && !production_mode) begin
            secure_mem_write <= 1'b0;
            normal_mem_write <= 1'b0;

            // FIXED: Route traces to appropriate memory region
            if (trace_security >= 2'b10) begin
                // High security traces go to protected memory
                secure_mem_addr <= SECURE_TRACE_BASE + {secure_offset, 3'b000};
                secure_mem_data <= trace_data;
                secure_mem_write <= 1'b1;
                secure_offset <= secure_offset + 1;
            end else begin
                // Lower security traces to normal memory
                normal_mem_addr <= NORMAL_TRACE_BASE + {normal_offset, 3'b000};
                normal_mem_data <= trace_data;
                normal_mem_write <= 1'b1;
                normal_offset <= normal_offset + 1;
            end
        end else begin
            secure_mem_write <= 1'b0;
            normal_mem_write <= 1'b0;
        end
    end

endmodule

CVE Examples

  • CVE-2019-6260: Debug trace data accessible without proper authentication in BMC devices.
  • CVE-2020-8705: Sensitive trace information leaked through inadequately protected debug interfaces.

  • CWE-284: Improper Access Control (parent)
  • CWE-1207: Debug and Test Problems (category)
  • CWE-1243: Sensitive Non-Volatile Information Not Protected During Debug (related)
  • CWE-1244: Internal Asset Exposed to Unsafe Debug Access (related)

References

  1. MITRE Corporation. "CWE-1323: Improper Management of Sensitive Trace Data." https://cwe.mitre.org/data/definitions/1323.html
  2. Backer, Hely, & Karri. "Secure design-for-debug for Systems-on-Chip" (2015)
  3. Backer, Hely, & Karri. "Secure and Flexible Trace-Based Debugging" (2016)
  4. CAPEC-150: Collect Data from Common Resource Locations
  5. CAPEC-167: White Box Reverse Engineering
  6. CAPEC-545: Pull Data from System Resources