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
| Impact | Details |
|---|---|
| Confidentiality | Scope: 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.
Related CWEs
- 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
- MITRE Corporation. "CWE-1323: Improper Management of Sensitive Trace Data." https://cwe.mitre.org/data/definitions/1323.html
- Backer, Hely, & Karri. "Secure design-for-debug for Systems-on-Chip" (2015)
- Backer, Hely, & Karri. "Secure and Flexible Trace-Based Debugging" (2016)
- CAPEC-150: Collect Data from Common Resource Locations
- CAPEC-167: White Box Reverse Engineering
- CAPEC-545: Pull Data from System Resources