Fehlender Schutzmechanismus für alternative Hardware-Schnittstelle
Beschreibung
Ein fehlender Schutzmechanismus für alternative Hardware-Schnittstellen tritt auf, wenn Assets nicht über alle Zugriffspfade hinweg geschützt sind. Angreifer können primäre Schutzmechanismen umgehen, indem sie ungeschützte alternative Wege ausnutzen. Während ein Asset auf einer Schnittstelle Zugriffskontrollen haben kann, entstehen Schwachstellen, wenn alternative Pfade ungeschützt bleiben. Beispiele sind Shadow-/Mirror-Register, die Adressen abbilden, aber keine Zugriffskontrollen haben, mehrere externe Schnittstellen, von denen nur einige geschützt sind (z.B. PCIe geschützt, aber UART ungeschützt), und indirekte Zugriffswege wie Instruktionsbus versus Datenbus.
Risiko
Fehlender Schutz alternativer Schnittstellen hat schwerwiegende Auswirkungen. Speicheränderung über ungeschützte Pfade. Unautorisierte Lesezugriffe über alternative Schnittstellen. Denial of Service möglich. Schutzmechanismen vollständig umgangen. Privilege Escalation ermöglicht. Unautorisierte Codeausführung. Logikveränderung über ungeschützte Kanäle. Shadow-Register legen sensible Daten offen. Hohe Wahrscheinlichkeit der Ausnutzung.
Lösung
Schützen Sie Assets über alle potenziellen Schnittstellen und alternativen Pfade während der Anforderungsphase. Implementieren Sie systematisch Defense-in-Depth-Schutzmechanismen während der Architektur und des Entwurfs. Stellen Sie sicher, dass Zugriffskontrollen während der Implementierung alle Datenpfade umfassend abdecken. Prüfen Sie alle Pfade zu sensiblen Assets. Betrachten Sie Shadow-/Mirror-Register als separate Zugriffspunkte. Wenden Sie konsistenten Schutz über alle externen Schnittstellen hinweg an.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Bereich: Vertraulichkeit Unautorisierte Lesezugriffe über alternative Schnittstellen. |
| Integrität | Bereich: Integrität Speicheränderung über ungeschützte Pfade. |
| Verfügbarkeit | Bereich: Verfügbarkeit Denial of Service durch Ressourcenverbrauch. |
| Zugriffskontrolle | Bereich: Zugriffskontrolle Schutzumgehung durch alternative Kanäle. |
Beispielcode und Lösung
Verwundbarer Code
// VERWUNDBAR: Schutz nur auf primärer Adresse, nicht auf Shadow
module vulnerable_register_protection (
input wire clk,
input wire rst_n,
input wire [31:0] address,
input wire [31:0] write_data,
input wire write_enable,
input wire is_privileged,
output reg [31:0] read_data,
output reg access_denied
);
// Primäre Adresse für sicheres Register
localparam SECURE_REG_ADDR = 32'h0000_0F00;
// VERWUNDBAR: Shadow-Adresse existiert, ist aber nicht geschützt
// localparam SHADOW_REG_ADDR = 32'h0080_0F00;
// Shadow spiegelt die primäre Adresse, aber Hardware ignoriert Bit [23]
reg [31:0] secure_register;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
secure_register <= 32'b0;
access_denied <= 1'b0;
end else begin
access_denied <= 1'b0;
// VERWUNDBAR: Nur primäre Adresse wird geprüft
if (address == SECURE_REG_ADDR) begin
if (is_privileged) begin
if (write_enable) begin
secure_register <= write_data;
end
end else begin
access_denied <= 1'b1;
end
end
// VERWUNDBAR: Shadow-Adresse 0x800F00 wird nicht geprüft!
// Angreifer kann über Shadow-Adresse auf das Register zugreifen
// ohne Berechtigungsprüfung
end
end
// VERWUNDBAR: Lesezugriff schützt Shadow ebenfalls nicht
always @(*) begin
if (address == SECURE_REG_ADDR) begin
read_data = is_privileged ? secure_register : 32'b0;
end else if (address[22:0] == SECURE_REG_ADDR[22:0]) begin
// Shadow-Adresse stimmt überein - aber kein Schutz!
read_data = secure_register; // VERWUNDBAR: Keine Berechtigungsprüfung
end else begin
read_data = 32'b0;
end
end
endmodule
// VERWUNDBAR: Mehrere Schnittstellen mit inkonsistentem Schutz
module vulnerable_multi_interface (
input wire clk,
input wire rst_n,
// PCIe-Schnittstelle (geschützt)
input wire [31:0] pcie_addr,
input wire [31:0] pcie_data,
input wire pcie_write,
input wire pcie_privileged,
// UART-Schnittstelle (VERWUNDBAR: ungeschützt)
input wire [31:0] uart_addr,
input wire [31:0] uart_data,
input wire uart_write,
// SMBus-Schnittstelle (VERWUNDBAR: ungeschützt)
input wire [31:0] smbus_addr,
input wire [31:0] smbus_data,
input wire smbus_write,
output reg [31:0] config_register
);
localparam CONFIG_ADDR = 32'h0000_1000;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
config_register <= 32'b0;
end else begin
// PCIe-Schnittstelle - geschützt
if (pcie_write && pcie_addr == CONFIG_ADDR) begin
if (pcie_privileged) begin
config_register <= pcie_data;
end
end
// VERWUNDBAR: UART-Schnittstelle - kein Schutz!
if (uart_write && uart_addr == CONFIG_ADDR) begin
config_register <= uart_data; // Keine Berechtigungsprüfung!
end
// VERWUNDBAR: SMBus-Schnittstelle - kein Schutz!
if (smbus_write && smbus_addr == CONFIG_ADDR) begin
config_register <= smbus_data; // Keine Berechtigungsprüfung!
end
end
end
endmodule
// VERWUNDBAR: Instruktionsbus umgeht Datenbus-Schutz
module vulnerable_bus_bypass (
input wire clk,
input wire rst_n,
// Datenbus (geschützt)
input wire [31:0] data_addr,
input wire data_read,
input wire data_privileged,
output reg [31:0] data_out,
// Instruktionsbus (VERWUNDBAR: ungeschützt)
input wire [31:0] instr_addr,
input wire instr_fetch,
output reg [31:0] instr_out
);
// Sensibler Daten-/Codebereich
localparam SECRET_START = 32'h1000_0000;
localparam SECRET_END = 32'h1000_FFFF;
reg [31:0] secret_memory [0:4095];
// Datenbus - geschützt
always @(*) begin
data_out = 32'b0;
if (data_read) begin
if (data_addr >= SECRET_START && data_addr <= SECRET_END) begin
if (data_privileged) begin
data_out = secret_memory[data_addr[13:2]];
end
// Unprivilegierter Zugriff verweigert
end
end
end
// VERWUNDBAR: Instruktionsabruf umgeht den Schutz
always @(*) begin
instr_out = 32'b0;
if (instr_fetch) begin
if (instr_addr >= SECRET_START && instr_addr <= SECRET_END) begin
// VERWUNDBAR: Keine Berechtigungsprüfung auf dem Instruktionsbus!
instr_out = secret_memory[instr_addr[13:2]];
end
end
end
// Angriff: Geheime Daten über Instruktionsabruf lesen
// Code von angreiferkontrolliertem Speicherort ausführen, der "Instruktionen"
// aus dem geheimen Bereich abruft
endmodule
Sichere Lösung
// SICHER: Schutz auf allen Adressen einschließlich Shadow
module secure_register_protection (
input wire clk,
input wire rst_n,
input wire [31:0] address,
input wire [31:0] write_data,
input wire write_enable,
input wire is_privileged,
output reg [31:0] read_data,
output reg access_denied
);
// Primäre Adresse für sicheres Register
localparam SECURE_REG_ADDR = 32'h0000_0F00;
// SICHER: Auch Shadow-Adresse schützen
localparam SHADOW_REG_ADDR = 32'h0080_0F00;
reg [31:0] secure_register;
// SICHER: Funktion zur Prüfung, ob Adresse dem sicheren Register entspricht
function automatic is_secure_reg_address;
input [31:0] addr;
begin
// Primäre Adresse prüfen
if (addr == SECURE_REG_ADDR)
is_secure_reg_address = 1'b1;
// SICHER: Shadow-Adresse prüfen
else if (addr == SHADOW_REG_ADDR)
is_secure_reg_address = 1'b1;
// SICHER: Alle möglichen Aliase prüfen (Bit 23 wird von Hardware ignoriert)
else if (addr[22:0] == SECURE_REG_ADDR[22:0])
is_secure_reg_address = 1'b1;
else
is_secure_reg_address = 1'b0;
end
endfunction
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
secure_register <= 32'b0;
access_denied <= 1'b0;
end else begin
access_denied <= 1'b0;
// SICHER: Alle möglichen Adressen zum sicheren Register prüfen
if (is_secure_reg_address(address)) begin
if (is_privileged) begin
if (write_enable) begin
secure_register <= write_data;
end
end else begin
access_denied <= 1'b1; // SICHER: Bei jedem Alias verweigern
end
end
end
end
// SICHER: Leseschutz auf allen Aliasen
always @(*) begin
if (is_secure_reg_address(address)) begin
read_data = is_privileged ? secure_register : 32'b0;
end else begin
read_data = 32'b0;
end
end
endmodule
// SICHER: Konsistenter Schutz über alle Schnittstellen
module secure_multi_interface (
input wire clk,
input wire rst_n,
// PCIe-Schnittstelle
input wire [31:0] pcie_addr,
input wire [31:0] pcie_data,
input wire pcie_write,
input wire pcie_privileged,
// UART-Schnittstelle
input wire [31:0] uart_addr,
input wire [31:0] uart_data,
input wire uart_write,
input wire uart_privileged, // SICHER: Berechtigungssignal hinzugefügt
// SMBus-Schnittstelle
input wire [31:0] smbus_addr,
input wire [31:0] smbus_data,
input wire smbus_write,
input wire smbus_privileged, // SICHER: Berechtigungssignal hinzugefügt
output reg [31:0] config_register,
output reg access_fault
);
localparam CONFIG_ADDR = 32'h0000_1000;
// SICHER: Zentralisierte Zugriffskontrolle
function automatic access_allowed;
input [31:0] addr;
input privileged;
begin
if (addr == CONFIG_ADDR) begin
access_allowed = privileged;
end else begin
access_allowed = 1'b1; // Andere Adressen können öffentlich sein
end
end
endfunction
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
config_register <= 32'b0;
access_fault <= 1'b0;
end else begin
access_fault <= 1'b0;
// SICHER: PCIe-Schnittstelle - geschützt
if (pcie_write && pcie_addr == CONFIG_ADDR) begin
if (access_allowed(pcie_addr, pcie_privileged)) begin
config_register <= pcie_data;
end else begin
access_fault <= 1'b1;
end
end
// SICHER: UART-Schnittstelle - jetzt geschützt
if (uart_write && uart_addr == CONFIG_ADDR) begin
if (access_allowed(uart_addr, uart_privileged)) begin
config_register <= uart_data;
end else begin
access_fault <= 1'b1;
end
end
// SICHER: SMBus-Schnittstelle - jetzt geschützt
if (smbus_write && smbus_addr == CONFIG_ADDR) begin
if (access_allowed(smbus_addr, smbus_privileged)) begin
config_register <= smbus_data;
end else begin
access_fault <= 1'b1;
end
end
end
end
endmodule
// SICHER: Schutz auf Instruktions- und Datenbus
module secure_bus_protection (
input wire clk,
input wire rst_n,
// Datenbus
input wire [31:0] data_addr,
input wire data_read,
input wire data_privileged,
output reg [31:0] data_out,
output reg data_fault,
// Instruktionsbus
input wire [31:0] instr_addr,
input wire instr_fetch,
input wire instr_privileged, // SICHER: Berechtigung für Instruktionsabruf
output reg [31:0] instr_out,
output reg instr_fault
);
// Sensibler Bereich
localparam SECRET_START = 32'h1000_0000;
localparam SECRET_END = 32'h1000_FFFF;
reg [31:0] secret_memory [0:4095];
// SICHER: Zentralisierte Bereichsprüfung
function automatic is_secret_region;
input [31:0] addr;
begin
is_secret_region = (addr >= SECRET_START) && (addr <= SECRET_END);
end
endfunction
// Datenbus - geschützt
always @(*) begin
data_out = 32'b0;
data_fault = 1'b0;
if (data_read) begin
if (is_secret_region(data_addr)) begin
if (data_privileged) begin
data_out = secret_memory[data_addr[13:2]];
end else begin
data_fault = 1'b1; // Zugriff verweigert
end
end
end
end
// SICHER: Instruktionsbus - ebenfalls geschützt
always @(*) begin
instr_out = 32'b0;
instr_fault = 1'b0;
if (instr_fetch) begin
if (is_secret_region(instr_addr)) begin
// SICHER: Berechtigungsprüfung auch beim Instruktionsabruf
if (instr_privileged) begin
instr_out = secret_memory[instr_addr[13:2]];
end else begin
instr_fault = 1'b1; // Zugriff verweigert
end
end
end
end
endmodule
CVE-Beispiele
- CVE-2022-38399: Unauthentifizierter serieller Zugriff ermöglichte beliebige Befehlsausführung.
- CVE-2020-8004: Flash-Schutz über Instruktionsbus umgangen.
- CVE-2017-18293: GPIO-Schutz über gebankte Register umgangen.
Verwandte CWEs
- CWE-288: Authentifizierungsumgehung über einen alternativen Pfad oder Kanal (übergeordnet)
- CWE-420: Ungeschützter alternativer Kanal (übergeordnet)
- CWE-1191: On-Chip Debug- und Test-Schnittstelle mit unsachgemäßer Zugriffskontrolle (gleichrangig)
- CWE-1314: Fehlender Schreibschutz für parametrische Datenwerte (gleichrangig)
Referenzen
- MITRE Corporation. "CWE-1299: Missing Protection Mechanism for Alternate Hardware Interface." https://cwe.mitre.org/data/definitions/1299.html
- ARM. "AMBA AXI and ACE Protocol Specification"
- IEEE. "Secure Hardware Design Guidelines"