Fehlender Schutz für gespiegelte Bereiche in On-Chip Fabric Firewall
Beschreibung
Der fehlende Schutz für gespiegelte Bereiche in der On-Chip Fabric Firewall tritt auf, wenn die Firewall in einem On-Chip Fabric den adressierten Hauptbereich schützt, aber keine gespiegelten Speicher- oder Memory-Mapped-IO (MMIO)-Bereiche schützt. Systeme setzen manchmal gespiegelten Speicher und Adressbereiche mit Datenkopien zur Fehlertoleranz ein. Wenn Fabric-Firewalls Originalbereiche schützen, aber gespiegelte Bereiche vernachlässigen, können Angreifer Zugriffskontrollen umgehen, indem sie die ungeschützten Spiegel ansteuern. Dies ermöglicht die Umgehung von Lese-/Schreibschutz, um zugrunde liegende Daten zu leaken oder zu beschädigen.
Risiko
Fehlender Spiegelschutz hat schwerwiegende Auswirkungen. Zugriffskontrolle vollständig über Spiegel umgehbar. Geschützter Speicher über ungeschützten Alias lesbar. Speicherbeschädigung durch gespiegelte Schreibzugriffe. Firewall-Sicherheit unwirksam gemacht. Vertrauliche Daten offengelegt. Systemintegrität kompromittiert. Hohe Wahrscheinlichkeit wenn Spiegel existieren und nicht geschützt sind.
Lösung
Die Fabric-Firewall sollte während der Architektur- und Entwurfsphase dieselben Schutzmaßnahmen wie für den Originalbereich auch auf die gespiegelten Bereiche anwenden. Wenden Sie während der Implementierung identischen Schutz auf gespiegelte Bereiche an wie auf Originalbereiche. Erfassen Sie alle Adress-Aliase und Spiegel während des Entwurfs. Konfigurieren Sie Firewall-Regeln, um alle Adressbereiche abzudecken, die auf geschützte Daten abbilden. Verifizieren Sie den Schutz durch Tests mit Spiegel-Adressen.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Bereich: Vertraulichkeit Geschützte Daten über ungeschützte Spiegel-Adressen lesbar. |
| Integrität | Bereich: Integrität Geschützter Speicher über Spiegel-Schreibzugriffe modifizierbar. |
| Zugriffskontrolle | Bereich: Zugriffskontrolle Firewall-Schutzmechanismus vollständig umgehbar. |
Beispielcode und Lösung
Verwundbarer Code
// VERWUNDBAR: Fabric-Firewall ohne Spiegelschutz
module vulnerable_fabric_firewall (
input wire clk,
input wire rst_n,
input wire [31:0] addr,
input wire [31:0] wdata,
input wire write_en,
input wire read_en,
input wire [1:0] security_level,
output reg [31:0] rdata,
output reg access_granted,
output reg access_denied
);
// Speicher-Controller erstellt Spiegel über obere Adressbits
// Originalbereich: 0x0000_0000 - 0x0000_FFFF (Bits [31:16] = 00)
// Spiegel 1: 0x0001_0000 - 0x0001_FFFF (Bits [31:16] = 01)
// Spiegel 2: 0x0002_0000 - 0x0002_FFFF (Bits [31:16] = 02)
// Spiegel 3: 0x0003_0000 - 0x0003_FFFF (Bits [31:16] = 03)
// Alle Spiegel bilden auf denselben physischen Speicher ab
// Geschützter Bereich innerhalb des Originalbereichs
localparam PROTECTED_START = 32'h0000_8000;
localparam PROTECTED_END = 32'h0000_8FFF;
localparam REQUIRED_LEVEL = 2'b10; // Privilegierter Zugriff erforderlich
// VERWUNDBAR: Prüft nur den Originaladressbereich
wire in_protected_region = (addr >= PROTECTED_START) &&
(addr <= PROTECTED_END);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
access_granted <= 1'b0;
access_denied <= 1'b0;
end else begin
access_granted <= 1'b0;
access_denied <= 1'b0;
if (read_en || write_en) begin
if (in_protected_region) begin
// VERWUNDBAR: Schutz nur auf Originalbereich
if (security_level >= REQUIRED_LEVEL) begin
access_granted <= 1'b1;
end else begin
access_denied <= 1'b1;
end
end else begin
// Nicht-geschützter Bereich - Zugriff erlauben
access_granted <= 1'b1;
end
end
end
end
// Angriff:
// Geschützte Adresse: 0x0000_8000 - erfordert Stufe 2
// Angreifer nutzt Spiegel: 0x0001_8000 - kein Schutz!
// Zugriff gewährt, weil 0x0001_8000 NICHT im geschützten Bereich liegt
// Aber Speicher-Controller bildet es auf dieselbe physische Stelle ab!
endmodule
// VERWUNDBAR: Speicher-Controller mit ungeschützten Aliassen
module vulnerable_memory_controller (
input wire clk,
input wire rst_n,
input wire [31:0] addr,
input wire [31:0] wdata,
input wire write_en,
input wire read_en,
output reg [31:0] rdata
);
// Physischer Speicher
reg [31:0] memory [0:65535];
// Adress-Aliasing - Bits [31:16] ignoriert
wire [15:0] physical_addr = addr[15:0];
// VERWUNDBAR: Alle Adressbereiche greifen auf denselben physischen Speicher zu
// Keine Unterscheidung zwischen Original und Spiegeln
// Wenn Firewall Spiegel nicht schützt, Sicherheit umgangen
always @(posedge clk) begin
if (write_en) begin
memory[physical_addr] <= wdata;
end
if (read_en) begin
rdata <= memory[physical_addr];
end
end
// Speicher-Map:
// 0x0000_XXXX -> memory[XXXX] (Original)
// 0x0001_XXXX -> memory[XXXX] (Spiegel 1)
// 0x0002_XXXX -> memory[XXXX] (Spiegel 2)
// 0x0003_XXXX -> memory[XXXX] (Spiegel 3)
//
// Alle bilden auf dieselbe physische Stelle ab!
endmodule
// VERWUNDBAR: Software-Firewall-Konfiguration ohne Spiegel
#include <stdint.h>
#include <stdbool.h>
typedef struct {
uint32_t start_addr;
uint32_t end_addr;
uint8_t required_level;
} firewall_rule_t;
// VERWUNDBAR: Schützt nur Originalbereich
static firewall_rule_t firewall_rules[] = {
{0x00008000, 0x00008FFF, 2}, // Geschützter Bereich
// VERWUNDBAR: Keine Regeln für Spiegelbereiche
// 0x00018000-0x00018FFF (Spiegel 1) - ungeschützt!
// 0x00028000-0x00028FFF (Spiegel 2) - ungeschützt!
// 0x00038000-0x00038FFF (Spiegel 3) - ungeschützt!
};
bool vulnerable_check_access(uint32_t addr, uint8_t security_level) {
for (int i = 0; i < sizeof(firewall_rules)/sizeof(firewall_rules[0]); i++) {
if (addr >= firewall_rules[i].start_addr &&
addr <= firewall_rules[i].end_addr) {
// VERWUNDBAR: Prüft nur exakte Adressübereinstimmung
return security_level >= firewall_rules[i].required_level;
}
}
// Keine passende Regel - Zugriff erlauben
// VERWUNDBAR: Spiegel-Adressen fallen hier durch
return true;
}
Sichere Lösung
// SICHER: Fabric-Firewall mit Spiegelschutz
module secure_fabric_firewall (
input wire clk,
input wire rst_n,
input wire [31:0] addr,
input wire [31:0] wdata,
input wire write_en,
input wire read_en,
input wire [1:0] security_level,
output reg [31:0] rdata,
output reg access_granted,
output reg access_denied
);
// Speicherlayout mit Spiegeln
// Originalbereich: 0x0000_0000 - 0x0000_FFFF (Bits [31:16] = 00)
// Spiegel 1: 0x0001_0000 - 0x0001_FFFF (Bits [31:16] = 01)
// Spiegel 2: 0x0002_0000 - 0x0002_FFFF (Bits [31:16] = 02)
// Spiegel 3: 0x0003_0000 - 0x0003_FFFF (Bits [31:16] = 03)
// Geschützter Bereich (gilt für alle Spiegel)
localparam PROTECTED_OFFSET_START = 16'h8000;
localparam PROTECTED_OFFSET_END = 16'h8FFF;
localparam REQUIRED_LEVEL = 2'b10;
// SICHER: Physische Adresse extrahieren (Spiegel-Bits ignorieren)
wire [15:0] physical_offset = addr[15:0];
// SICHER: Prüfen ob physischer Offset im geschützten Bereich liegt
// Dies erkennt Zugriffe über jede Spiegel-Adresse
wire in_protected_region = (physical_offset >= PROTECTED_OFFSET_START) &&
(physical_offset <= PROTECTED_OFFSET_END);
// SICHER: Verifizieren, dass Adresse im gültigen Speicherbereich liegt (jeder Spiegel)
wire in_memory_space = (addr[31:18] == 14'b0); // Erste 4 Bereiche
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
access_granted <= 1'b0;
access_denied <= 1'b0;
end else begin
access_granted <= 1'b0;
access_denied <= 1'b0;
if ((read_en || write_en) && in_memory_space) begin
if (in_protected_region) begin
// SICHER: Schutz gilt für alle Spiegel
if (security_level >= REQUIRED_LEVEL) begin
access_granted <= 1'b1;
end else begin
access_denied <= 1'b1;
end
end else begin
access_granted <= 1'b1;
end
end else if (read_en || write_en) begin
// Ausserhalb des gültigen Speicherbereichs
access_denied <= 1'b1;
end
end
end
endmodule
// SICHER: Umfassende Firewall mit Alias-Erkennung
module secure_alias_aware_firewall #(
parameter NUM_MIRRORS = 4,
parameter MIRROR_BITS = 2 // Anzahl der Bits für Spiegelauswahl
) (
input wire clk,
input wire rst_n,
input wire [31:0] addr,
input wire [31:0] wdata,
input wire write_en,
input wire read_en,
input wire [1:0] security_level,
output reg access_granted,
output reg access_denied
);
// SICHER: Firewall-Regeln in physischen Adressen definiert
// Schutz gilt unabhängig davon, welcher Spiegel zugegriffen wird
// Regelformat: {start_offset, end_offset, required_level}
reg [47:0] firewall_rules [0:7];
reg [2:0] num_rules;
initial begin
// Geschützter Bereich 1: 0x8000-0x8FFF, Stufe 2
firewall_rules[0] = {16'h8000, 16'h8FFF, 16'h0002};
// Geschützter Bereich 2: 0xF000-0xFFFF, Stufe 3
firewall_rules[1] = {16'hF000, 16'hFFFF, 16'h0003};
num_rules = 2;
end
// SICHER: Jede Adresse in kanonischen physischen Offset umwandeln
wire [15:0] canonical_offset = addr[15:0];
// SICHER: Adresse gegen alle Regeln mit kanonischem Offset prüfen
reg rule_match;
reg [1:0] required_level;
integer i;
always @(*) begin
rule_match = 1'b0;
required_level = 2'b00;
for (i = 0; i < num_rules; i = i + 1) begin
if (canonical_offset >= firewall_rules[i][47:32] &&
canonical_offset <= firewall_rules[i][31:16]) begin
rule_match = 1'b1;
required_level = firewall_rules[i][1:0];
end
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
access_granted <= 1'b0;
access_denied <= 1'b0;
end else begin
access_granted <= 1'b0;
access_denied <= 1'b0;
if (read_en || write_en) begin
if (rule_match) begin
// SICHER: Für alle Spiegel durchgesetzt
if (security_level >= required_level) begin
access_granted <= 1'b1;
end else begin
access_denied <= 1'b1;
end
end else begin
access_granted <= 1'b1;
end
end
end
end
endmodule
// SICHER: Software-Firewall mit Spiegel-Erkennung
#include <stdint.h>
#include <stdbool.h>
typedef struct {
uint16_t start_offset; // Physischer Offset (nicht vollständige Adresse)
uint16_t end_offset;
uint8_t required_level;
} secure_firewall_rule_t;
// SICHER: Regeln in physischen Offsets definiert
static secure_firewall_rule_t firewall_rules[] = {
{0x8000, 0x8FFF, 2}, // Geschützter Bereich 1
{0xF000, 0xFFFF, 3}, // Geschützter Bereich 2
};
// SICHER: Adresse in kanonischen physischen Offset umwandeln
static uint16_t get_physical_offset(uint32_t addr) {
// Bits [15:0] sind der physische Offset
// Bits [17:16] wählen den Spiegel (für Schutz ignoriert)
return addr & 0xFFFF;
}
// SICHER: Adresse auf Speicherbereich validieren
static bool is_valid_memory_address(uint32_t addr) {
// Speicherbereich ist 0x00000000 - 0x0003FFFF (4 Spiegel von 64KB)
return addr < 0x00040000;
}
bool secure_check_access(uint32_t addr, uint8_t security_level) {
// SICHER: Zuerst Adresse validieren
if (!is_valid_memory_address(addr)) {
return false;
}
// SICHER: Kanonischen physischen Offset ermitteln
uint16_t offset = get_physical_offset(addr);
// SICHER: Alle Regeln mit physischem Offset prüfen
for (size_t i = 0; i < sizeof(firewall_rules)/sizeof(firewall_rules[0]); i++) {
if (offset >= firewall_rules[i].start_offset &&
offset <= firewall_rules[i].end_offset) {
// SICHER: Schutz gilt für alle Spiegel
return security_level >= firewall_rules[i].required_level;
}
}
// Keine Regel passt - Zugriff erlauben
return true;
}
// SICHER: Verifizierungsfunktion zum Testen des Spiegelschutzes
bool verify_mirror_protection(void) {
// Testen, dass Schutz für alle Spiegel funktioniert
uint32_t protected_offset = 0x8000;
for (int mirror = 0; mirror < 4; mirror++) {
uint32_t addr = (mirror << 16) | protected_offset;
// Stufe 1 sollte für alle Spiegel abgelehnt werden
if (secure_check_access(addr, 1)) {
return false; // Spiegelschutz fehlgeschlagen!
}
// Stufe 2 sollte für alle Spiegel erlaubt werden
if (!secure_check_access(addr, 2)) {
return false; // Schutz inkonsistent!
}
}
return true; // Alle Spiegel gleichmäßig geschützt
}
CVE-Beispiele
- CVE-2019-0090: Intel-CSME-Speicherbereich über ungeschützte Spiegel-Adressen zugänglich.
- CVE-2020-0551: Load Value Injection durch ungeschützte Speicher-Aliase.
Verwandte CWEs
- CWE-284: Improper Access Control (Eltern)
- CWE-1251: Mirrored Regions with Different Values (Peer)
- CWE-1203: Peripherals, On-chip Fabric, and Interface/IO Problems (Kategorie)
- CWE-1299: Missing Protection Mechanism for Alternate Hardware Interface (verwandt)
Referenzen
- MITRE Corporation. "CWE-1312: Missing Protection for Mirrored Regions in On-Chip Fabric Firewall." https://cwe.mitre.org/data/definitions/1312.html
- ARM. "TrustZone Address Space Controller Technical Reference Manual"
- Intel. "System Address Map Configuration"