Unsachgemäße Zugriffskontrolle auf gespiegelte oder aliasierte Speicherbereiche
Beschreibung
Unsachgemäße Zugriffskontrolle auf gespiegelte oder aliasierte Speicherbereiche tritt auf, wenn ein Produkt inkonsistente Lese-/Schreibberechtigungen über aliasierte oder gespiegelte Speicherbereiche in Hardware-Designs aufweist. Hardware-Designs bilden oft dieselbe physische Speicherzelle auf mehrere Systemadressen ab, für Redundanz oder vereinfachte Dekodierungslogik. Wenn Zugriffskontrollen inkonsistent über diese Aliase angewendet werden, können Angreifer Schutzmaßnahmen umgehen, indem sie auf alternative Adressen zugreifen. Ein nicht vertrauenswürdiger Agent kann von einer Speicheradresse blockiert werden, aber über eine alternative Adresszuordnung auf dieselben Daten zugreifen.
Risiko
Inkonsistenter Alias-Schutz hat schwerwiegende Sicherheitsauswirkungen. Geschützte Daten können über alternative Adressen gelesen werden. Sicherheitskonfigurationen können über Aliase modifiziert werden. Speicherisolierung kann umgangen werden. Vertrauliche Informationen können offengelegt werden. Systemintegrität kann kompromittiert werden. Schutzmechanismen werden unwirksam. Angreifer können auf privilegierte Bereiche zugreifen. Sicherheitsrichtlinien werden undurchsetzbar.
Lösung
Wenden Sie konsistente Zugriffsrechte zwischen primären Speicherbereichen und allen gespiegelten oder aliasierten Speicherbereichen an. Beschränken Sie die Möglichkeit, Aliase zu erstellen oder zugeordnete Regionen zu vergrößern, auf vertrauenswürdige Software. Implementieren Sie einheitliche Zugriffskontrolle, die alle Adresszuordnungen auf denselben physischen Speicher abdeckt. Blockieren oder schützen Sie ungenutzte aliasierte Bereiche. Überprüfen Sie die Zugriffskontrollkonsistenz bei Sicherheitsaudits. Verwenden Sie Hardware-Adresskanonisierung.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Umfang: Vertraulichkeit Speicher lesen - Angreifer können geschützten Speicher über ungeschützte Aliase lesen. |
| Integrität | Umfang: Integrität Speicher modifizieren - Geschützter Speicher kann über ungeschützte Aliase modifiziert werden. |
| Verfügbarkeit | Umfang: Verfügbarkeit DoS: Instabilität - Speicherbeschädigung über Aliase kann Systeminstabilität verursachen. |
Beispielcode und Lösung
Verwundbarer Code
// VERWUNDBAR: Speicher mit inkonsistentem Alias-Schutz
module vulnerable_memory_alias (
input wire clk,
input wire reset_n,
input wire [15:0] addr,
input wire [31:0] write_data,
input wire write_enable,
input wire read_enable,
input wire [1:0] privilege_level,
output reg [31:0] read_data,
output reg access_denied
);
// 4KB Speicher, aber in 16KB Adressraum abgebildet
// Erzeugt 4 Aliase: 0x0000, 0x1000, 0x2000, 0x3000
reg [31:0] memory [0:1023];
// Adressdekoder - maskiert obere Bits und erzeugt Aliase
wire [9:0] physical_addr = addr[11:2]; // Nur Bits 11:2 verwenden
// Bits 15:12 werden ignoriert, erzeugen Aliase!
// Zugriffskontrolle nur auf primärem Bereich
wire is_protected_range = (addr >= 16'h0000) && (addr < 16'h0400);
// VERWUNDBAR: Prüft nur 0x0000-0x03FF
// Aliase 0x1000, 0x2000, 0x3000 sind NICHT geschützt!
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
read_data <= 32'h0;
access_denied <= 1'b0;
end
else begin
access_denied <= 1'b0;
if (write_enable) begin
// VERWUNDBAR: Prüfung gilt nur für einen Adressbereich
if (is_protected_range && privilege_level < 2'd2) begin
access_denied <= 1'b1;
end
else begin
// Schreiben erfolgreich - einschließlich über Aliase!
memory[physical_addr] <= write_data;
end
end
if (read_enable) begin
if (is_protected_range && privilege_level < 2'd1) begin
access_denied <= 1'b1;
read_data <= 32'h0;
end
else begin
// Lesen erfolgreich - einschließlich über Aliase!
read_data <= memory[physical_addr];
end
end
end
end
// Angriff: Geschützten Speicher bei 0x0100 über Alias 0x1100 zugreifen
// physical_addr = 0x1100[11:2] = 0x100[11:2] = gleicher Ort
// Aber 0x1100 ist nicht im "protected_range", daher Zugriff erlaubt!
endmodule
// VERWUNDBAR: Registerblock mit ungeschützten Aliasen
module vulnerable_register_alias (
input wire clk,
input wire reset_n,
input wire [7:0] addr,
input wire [31:0] write_data,
input wire write_enable,
input wire secure_access,
output reg [31:0] read_data,
output reg access_fault
);
// 16 Register, aber Adressraum ist 256 Bytes
// Erzeugt 16 Aliase für jedes Register
reg [31:0] registers [0:15];
// Sicherheitsrelevante Register
parameter SECURE_KEY_REG = 4'd0;
parameter SECURE_CONFIG_REG = 4'd1;
// Physische Adresse (nur untere 4 Bits relevant)
wire [3:0] reg_index = addr[5:2]; // Bits 5:2 wählen Register
// Bits 7:6 werden ignoriert - erzeugt Aliase!
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
access_fault <= 1'b0;
end
else begin
access_fault <= 1'b0;
if (write_enable) begin
// VERWUNDBAR: Prüft nur spezifische Adressen
if ((addr == 8'h00 || addr == 8'h04) && !secure_access) begin
// Schreiben auf 0x00 und 0x04 für Nicht-Sicher blockieren
access_fault <= 1'b1;
end
else begin
// VERWUNDBAR: Schreiben über Alias erfolgreich!
// addr = 0x40 bildet auf dasselbe Register wie 0x00 ab
registers[reg_index] <= write_data;
end
end
end
end
// Angriff: Sicheren Schlüssel über Alias schreiben
// Blockiert: Schreiben auf addr 0x00 (SECURE_KEY_REG)
// Erlaubt: Schreiben auf addr 0x40 (gleiches physisches Register!)
endmodule
// VERWUNDBAR: Software mit inkonsistenter Alias-Behandlung
#include <stdint.h>
// Speicherabbildung mit Aliasen
#define SECURE_MEM_PRIMARY 0x10000000
#define SECURE_MEM_ALIAS1 0x10001000 // Gleicher physischer Speicher
#define SECURE_MEM_ALIAS2 0x10002000 // Gleicher physischer Speicher
#define SECURE_MEM_SIZE 0x1000
// VERWUNDBAR: Prüft nur primäre Adresse
int vulnerable_memory_access(uint32_t addr, uint32_t* data, int write, int privilege) {
// VERWUNDBAR: Schützt nur primären Bereich
if (addr >= SECURE_MEM_PRIMARY &&
addr < SECURE_MEM_PRIMARY + SECURE_MEM_SIZE) {
if (privilege < PRIVILEGE_SECURE) {
return -EACCES; // Zugriff verweigert
}
}
// VERWUNDBAR: Aliase nicht geprüft!
// Zugriff auf SECURE_MEM_ALIAS1 oder ALIAS2 erfolgreich
// auch ohne Berechtigung
volatile uint32_t* ptr = (volatile uint32_t*)addr;
if (write) {
*ptr = *data;
} else {
*data = *ptr;
}
return 0;
}
// Angriffsausnutzung
void exploit_alias_access(void) {
uint32_t secret_data;
// Dies wird blockiert:
// vulnerable_memory_access(SECURE_MEM_PRIMARY, &secret_data, 0, PRIVILEGE_USER);
// Aber dies gelingt (gleicher physischer Speicher):
vulnerable_memory_access(SECURE_MEM_ALIAS1, &secret_data, 0, PRIVILEGE_USER);
// secret_data enthält jetzt geschützte Daten!
}
Sichere Lösung
// SICHER: Speicher mit konsistentem Alias-Schutz
module secure_memory_alias (
input wire clk,
input wire reset_n,
input wire [15:0] addr,
input wire [31:0] write_data,
input wire write_enable,
input wire read_enable,
input wire [1:0] privilege_level,
output reg [31:0] read_data,
output reg access_denied
);
// 4KB Speicher in 16KB Adressraum abgebildet
reg [31:0] memory [0:1023];
// SICHER: Adresse kanonisieren, um alle Aliase zu erkennen
wire [9:0] physical_addr = addr[11:2];
// SICHER: Schutz basierend auf PHYSISCHER Adresse prüfen, nicht logischer
// Dies erfasst automatisch alle Aliase
wire is_protected_physical = (physical_addr >= 10'h000) && (physical_addr < 10'h100);
// SICHER: Oder alternativ alle aliasierten Bereiche blockieren
wire is_valid_range = (addr[15:12] == 4'h0); // Nur 0x0XXX-Bereich erlauben
wire is_alias_access = !is_valid_range;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
read_data <= 32'h0;
access_denied <= 1'b0;
end
else begin
access_denied <= 1'b0;
// SICHER: Alle Alias-Zugriffe blockieren
if (is_alias_access) begin
access_denied <= 1'b1;
read_data <= 32'h0;
end
else if (write_enable) begin
// SICHER: Schutz basierend auf physischer Adresse
if (is_protected_physical && privilege_level < 2'd2) begin
access_denied <= 1'b1;
end
else begin
memory[physical_addr] <= write_data;
end
end
else if (read_enable) begin
if (is_protected_physical && privilege_level < 2'd1) begin
access_denied <= 1'b1;
read_data <= 32'h0;
end
else begin
read_data <= memory[physical_addr];
end
end
end
end
endmodule
// SICHER: Registerblock mit korrektem Alias-Schutz
module secure_register_alias (
input wire clk,
input wire reset_n,
input wire [7:0] addr,
input wire [31:0] write_data,
input wire write_enable,
input wire read_enable,
input wire secure_access,
output reg [31:0] read_data,
output reg access_fault
);
reg [31:0] registers [0:15];
// Sicherheitsrelevante Register
parameter SECURE_KEY_REG = 4'd0;
parameter SECURE_CONFIG_REG = 4'd1;
// SICHER: Auf physischen Registerindex kanonisieren
wire [3:0] reg_index = addr[5:2];
// SICHER: Schutz basierend auf physischem Register prüfen, nicht Adresse
wire is_secure_register = (reg_index == SECURE_KEY_REG) ||
(reg_index == SECURE_CONFIG_REG);
// SICHER: Alias-Zugriff erkennen und blockieren
wire is_valid_address = (addr[7:6] == 2'b00); // Nur 0x00-0x3F gültig
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
access_fault <= 1'b0;
read_data <= 32'h0;
end
else begin
access_fault <= 1'b0;
// SICHER: Alle Alias-Zugriffe blockieren
if (!is_valid_address) begin
access_fault <= 1'b1;
end
else if (write_enable) begin
// SICHER: Prüfung basierend auf physischem Registerindex
if (is_secure_register && !secure_access) begin
access_fault <= 1'b1;
end
else begin
registers[reg_index] <= write_data;
end
end
else if (read_enable) begin
if (is_secure_register && !secure_access) begin
access_fault <= 1'b1;
read_data <= 32'h0;
end
else begin
read_data <= registers[reg_index];
end
end
end
end
endmodule
// SICHER: Adressdekoder der Aliase blockiert
module secure_address_decoder (
input wire clk,
input wire reset_n,
input wire [31:0] addr,
input wire [1:0] privilege_level,
output reg valid_access,
output reg [31:0] canonical_addr,
output reg alias_detected
);
// Speicherregionen und ihre Größen
parameter REGION_A_BASE = 32'h1000_0000;
parameter REGION_A_SIZE = 32'h0000_1000; // 4KB
// SICHER: Kanonische Adresse berechnen
always @(*) begin
alias_detected = 1'b0;
valid_access = 1'b0;
canonical_addr = addr;
// Region A prüfen (4KB tatsächlich, 16KB Adressraum)
if (addr >= REGION_A_BASE && addr < REGION_A_BASE + 32'h4000) begin
// Adresse kanonisieren
canonical_addr = REGION_A_BASE + ((addr - REGION_A_BASE) & 32'h0FFF);
// SICHER: Erkennen, ob Alias verwendet wurde
if (addr != canonical_addr) begin
alias_detected = 1'b1;
valid_access = 1'b0; // Alias-Zugriff blockieren
end
else begin
valid_access = 1'b1;
end
end
end
endmodule
// SICHER: Software mit konsistenter Alias-Behandlung
#include <stdint.h>
#define SECURE_MEM_PRIMARY 0x10000000
#define SECURE_MEM_ALIAS1 0x10001000
#define SECURE_MEM_ALIAS2 0x10002000
#define SECURE_MEM_SIZE 0x1000
#define SECURE_MEM_MASK 0x00000FFF // 4KB-Maske
// SICHER: Adresse auf physische kanonisieren
static uint32_t canonicalize_address(uint32_t addr) {
// Prüfen, ob in einem aliasierten Bereich
if ((addr >= SECURE_MEM_PRIMARY && addr < SECURE_MEM_PRIMARY + 0x4000)) {
// Alle Aliase auf kanonische (primäre) Adresse abbilden
return SECURE_MEM_PRIMARY + ((addr - SECURE_MEM_PRIMARY) & SECURE_MEM_MASK);
}
return addr;
}
// SICHER: Prüfen, ob Adresse ein Alias ist
static bool is_alias_access(uint32_t addr) {
uint32_t canonical = canonicalize_address(addr);
return (canonical != addr);
}
int secure_memory_access(uint32_t addr, uint32_t* data, int write, int privilege) {
// SICHER: Alle Alias-Zugriffe blockieren
if (is_alias_access(addr)) {
log_security_event("Alias-Zugriff blockiert: 0x%08x", addr);
return -EACCES;
}
// SICHER: Kanonische Adresse für Schutzprüfung holen
uint32_t canonical_addr = canonicalize_address(addr);
// Schutz basierend auf kanonischer Adresse prüfen
if (canonical_addr >= SECURE_MEM_PRIMARY &&
canonical_addr < SECURE_MEM_PRIMARY + SECURE_MEM_SIZE) {
if (privilege < PRIVILEGE_SECURE) {
return -EACCES;
}
}
volatile uint32_t* ptr = (volatile uint32_t*)addr;
if (write) {
*ptr = *data;
} else {
*data = *ptr;
}
return 0;
}
// SICHER: MPU-Konfiguration mit Alias-Schutz
void configure_mpu_with_alias_protection(void) {
// Primäre Region konfigurieren
mpu_configure_region(0, SECURE_MEM_PRIMARY, SECURE_MEM_SIZE,
MPU_ATTR_SECURE_ONLY);
// SICHER: Alle Alias-Regionen explizit blockieren
mpu_configure_region(1, SECURE_MEM_ALIAS1, SECURE_MEM_SIZE,
MPU_ATTR_NO_ACCESS);
mpu_configure_region(2, SECURE_MEM_ALIAS2, SECURE_MEM_SIZE,
MPU_ATTR_NO_ACCESS);
// Oder den gesamten aliasierten Bereich mit konsistentem Schutz konfigurieren
mpu_configure_region(0, SECURE_MEM_PRIMARY, SECURE_MEM_SIZE * 4,
MPU_ATTR_SECURE_ONLY);
}
CVE-Beispiele
Speicher-Aliasing-Schwachstellen wurden in verschiedenen SoC-Designs gefunden, bei denen Angreifer Speicherschutz umgingen, indem sie über ungeschützte Alias-Adressen auf geschützte Bereiche zugriffen.
Verwandte CWEs
- CWE-284: Unsachgemäße Zugriffskontrolle (übergeordnet)
- CWE-119: Unsachgemäße Beschränkung von Operationen innerhalb eines Speicherpuffers (vorausgehend)
- CWE-1260: Unsachgemäße Behandlung von Überlappungen zwischen geschützten Speicherbereichen (verwandt)
- CAPEC-456: Infizierter Speicher (Angriffsmuster)
- CAPEC-679: Ausnutzung unsachgemäß konfigurierter Speicherschutzmaßnahmen (Angriffsmuster)
Referenzen
- MITRE Corporation. "CWE-1257: Improper Access Control Applied to Mirrored or Aliased Memory Regions." https://cwe.mitre.org/data/definitions/1257.html
- ARM. "Memory Protection Unit Configuration"
- Intel. "System Address Map and Memory Aliasing"