Unsachgemäße Behandlung von Überlappungen zwischen geschützten Speicherbereichen
Beschreibung
Unsachgemäße Behandlung von Überlappungen zwischen geschützten Speicherbereichen tritt auf, wenn ein Produkt die Überlappung von Adressbereichen zulässt, was zur Umgehung des beabsichtigten Speicherschutzes führen kann. Diese Schwachstelle tritt in Hardware-Designs auf, die isolierte Speicherregionen und Zugriffskontrollrichtlinien zum Schutz privilegierter Software verwenden. Wenn Software mit niedrigeren Privilegien überlappende Speicheradressbereiche mit Bereichen höherer Privilegien programmieren kann, können Angreifer eine Privilegieneskalation erreichen. Die Memory Protection Unit (MPU) kann diese Überlappungen falsch behandeln und so unautorisierte Lese-/Schreibzugriffe oder Denial-of-Service-Angriffe ermöglichen.
Risiko
Überlappende Speicherbereiche haben schwerwiegende Sicherheitsauswirkungen. Speicherschutz kann umgangen werden. Privilegieneskalation wird möglich. Geschützte Daten können gelesen oder modifiziert werden. Kernel-Speicher kann für Benutzercode zugänglich sein. Sichere Enklaven können kompromittiert werden. Denial of Service durch Blockierung des Speicherzugriffs. Systemstabilität kann beeinträchtigt werden. Sicherheitsisolationsgrenzen werden verletzt.
Lösung
Stellen Sie sicher, dass Speicherbereiche mit erzwungenen Zugriffskontrollrichtlinien ordnungsgemäß isoliert bleiben. Definieren Sie ein Prioritätsschema für überlappende Regionen (z.B. niedrigste ID hat Vorrang). Blockieren Sie die Programmierung von Regionen mit überlappenden Adressen über Hardware-Logik. Wenden Sie Richtlinienfilter auf alle überlappenden Bereiche an – Zugriff wird nur gewährt, wenn alle Richtlinien es erlauben. Validieren Sie Regionskonfigurationen vor der Anwendung.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Bereich: Vertraulichkeit Speicher lesen - Geschützte Speicherinhalte können durch Umgehung überlappender Regionen gelesen werden. |
| Integrität | Bereich: Integrität Speicher modifizieren - Geschützter Speicher kann durch überlappende Regionen modifiziert werden. |
| Verfügbarkeit | Bereich: Verfügbarkeit DoS: Instabilität - Überlappende Regionen können legitimen Zugriff blockieren oder Systeminstabilität verursachen. |
Beispielcode und Lösung
Verwundbarer Code
// VERWUNDBAR: MPU ohne Überlappungsschutz
module vulnerable_mpu (
input wire clk,
input wire reset_n,
// Regionskonfiguration
input wire [2:0] config_region_id,
input wire [31:0] config_base_addr,
input wire [31:0] config_size,
input wire [3:0] config_permissions,
input wire config_enable,
input wire config_write,
// Speicherzugriff
input wire [31:0] access_addr,
input wire [1:0] access_privilege, // 0=Benutzer, 1=Supervisor, 2=Hypervisor, 3=sicher
input wire access_read,
input wire access_write,
output reg access_allowed
);
// 8 konfigurierbare Regionen
reg [31:0] region_base [0:7];
reg [31:0] region_size [0:7];
reg [3:0] region_perms [0:7]; // [3:2]=Schreibstufe, [1:0]=Lesestufe
reg region_enabled [0:7];
// VERWUNDBAR: Regionskonfiguration ohne Überlappungsprüfung
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
integer i;
for (i = 0; i < 8; i = i + 1) begin
region_enabled[i] <= 1'b0;
end
end
else if (config_write && config_enable) begin
// VERWUNDBAR: Keine Prüfung, ob neue Region bestehende Regionen überlappt
region_base[config_region_id] <= config_base_addr;
region_size[config_region_id] <= config_size;
region_perms[config_region_id] <= config_permissions;
region_enabled[config_region_id] <= 1'b1;
end
end
// Zugriffsprüfung
reg [7:0] region_match;
reg access_result;
always @(*) begin
integer i;
access_allowed = 1'b0;
for (i = 0; i < 8; i = i + 1) begin
if (region_enabled[i] &&
access_addr >= region_base[i] &&
access_addr < (region_base[i] + region_size[i])) begin
// VERWUNDBAR: Erste übereinstimmende Region gewinnt
// Angreifer kann überlappende Region mit höherer ID
// und freizügigeren Einstellungen erstellen
if (access_read && access_privilege >= region_perms[i][1:0]) begin
access_allowed = 1'b1;
end
if (access_write && access_privilege >= region_perms[i][3:2]) begin
access_allowed = 1'b1;
end
end
end
end
// Angriff:
// Region 0: base=0x8000_0000, size=0x1000, perms=0xF (nur sicher)
// Angreifer programmiert Region 7: base=0x8000_0000, size=0x1000, perms=0x0 (alle Zugriffe)
// Beide Regionen stimmen überein, aber die freizügige Region des Angreifers erlaubt Zugriff
endmodule
// VERWUNDBAR: Speicherkarte mit Überlappungsschwachstelle
module vulnerable_memory_map (
input wire clk,
input wire reset_n,
input wire [31:0] addr,
input wire read_enable,
input wire write_enable,
input wire [1:0] privilege_level,
output reg [31:0] read_data,
output reg access_denied
);
// Geräteregionen
// VERWUNDBAR: UART-Region überlappt mit AES-Region
parameter UART_BASE = 32'h1000_0000;
parameter UART_SIZE = 32'h0011_1000; // Zu groß!
// UART endet bei 0x1011_1000
parameter AES_BASE = 32'h1010_0000; // Überlappt mit UART!
parameter AES_SIZE = 32'h0001_0000;
// AES: 0x1010_0000 - 0x1010_FFFF
// Das liegt INNERHALB des UART-Bereichs!
wire in_uart_range = (addr >= UART_BASE) && (addr < UART_BASE + UART_SIZE);
wire in_aes_range = (addr >= AES_BASE) && (addr < AES_BASE + AES_SIZE);
// UART: für alle zugänglich (Privileg >= 0)
// AES: erfordert sicheren Zugriff (Privileg >= 3)
always @(*) begin
access_denied = 1'b0;
if (in_uart_range && in_aes_range) begin
// VERWUNDBAR: Beide Bereiche stimmen überein!
// Welche Richtlinie gilt? Implementierung wählt UART (freizügig)
access_denied = 1'b0; // UART-Richtlinie: alle erlauben
end
else if (in_aes_range) begin
if (privilege_level < 2'd3) begin
access_denied = 1'b1;
end
end
// UART-Bereich: immer erlaubt
end
// Angriff: Zugriff auf AES bei 0x1010_0000 durch UART-Region
// Adresse liegt in beiden Bereichen, aber UART-Richtlinie erlaubt Zugriff
endmodule
// VERWUNDBAR: Software-MPU-Konfiguration mit Überlappung
#include <stdint.h>
#define MPU_REGIONS 8
typedef struct {
uint32_t base;
uint32_t size;
uint32_t permissions;
uint32_t enabled;
} mpu_region_t;
mpu_region_t mpu_regions[MPU_REGIONS];
// VERWUNDBAR: Keine Überlappungsprüfung
int vulnerable_configure_region(int region_id, uint32_t base, uint32_t size, uint32_t perms) {
if (region_id >= MPU_REGIONS) {
return -EINVAL;
}
// VERWUNDBAR: Keine Prüfung auf Überlappung mit bestehenden Regionen
mpu_regions[region_id].base = base;
mpu_regions[region_id].size = size;
mpu_regions[region_id].permissions = perms;
mpu_regions[region_id].enabled = 1;
// Auf Hardware anwenden
MPU->RNR = region_id;
MPU->RBAR = base;
MPU->RASR = (size << 1) | perms | MPU_RASR_ENABLE_Msk;
return 0;
}
// Angriffsszenario
void exploit_overlap(void) {
// Kernel richtet geschützte Region ein
// Region 0: 0x20000000-0x20001000, nur Supervisor
// Angreifer (mit Privileg zur MPU-Konfiguration) erstellt Überlappung
// Region 7: 0x20000000-0x20001000, alle Zugriffe
// Jetzt decken beide Regionen dieselbe Adresse ab
// Zugriffsprüfung kann die freizügige Region des Angreifers verwenden
}
Sichere Lösung
// SICHER: MPU mit Überlappungsschutz
module secure_mpu (
input wire clk,
input wire reset_n,
// Regionskonfiguration
input wire [2:0] config_region_id,
input wire [31:0] config_base_addr,
input wire [31:0] config_size,
input wire [3:0] config_permissions,
input wire config_enable,
input wire config_write,
input wire [1:0] config_privilege, // Privileg des konfigurierenden Agenten
// Speicherzugriff
input wire [31:0] access_addr,
input wire [1:0] access_privilege,
input wire access_read,
input wire access_write,
output reg access_allowed,
output reg config_denied,
output reg overlap_detected
);
// 8 konfigurierbare Regionen
reg [31:0] region_base [0:7];
reg [31:0] region_size [0:7];
reg [3:0] region_perms [0:7];
reg region_enabled [0:7];
reg [1:0] region_owner [0:7]; // Privilegstufe, die Region konfiguriert hat
// SICHER: Auf Überlappung prüfen, bevor Konfiguration erlaubt wird
function automatic overlaps_existing;
input [31:0] new_base;
input [31:0] new_size;
input [2:0] new_id;
integer i;
reg [31:0] new_end;
reg [31:0] existing_end;
begin
overlaps_existing = 1'b0;
new_end = new_base + new_size;
for (i = 0; i < 8; i = i + 1) begin
if (i != new_id && region_enabled[i]) begin
existing_end = region_base[i] + region_size[i];
// Auf Überlappung prüfen
if (!(new_end <= region_base[i] || new_base >= existing_end)) begin
overlaps_existing = 1'b1;
end
end
end
end
endfunction
// SICHER: Überlappungen erkennen und höhere Privilegien erfordern
wire proposed_overlaps = overlaps_existing(config_base_addr, config_size, config_region_id);
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
integer i;
for (i = 0; i < 8; i = i + 1) begin
region_enabled[i] <= 1'b0;
end
config_denied <= 1'b0;
overlap_detected <= 1'b0;
end
else if (config_write && config_enable) begin
config_denied <= 1'b0;
overlap_detected <= 1'b0;
// SICHER: Auf Überlappung prüfen
if (proposed_overlaps) begin
overlap_detected <= 1'b1;
// SICHER: Überlappung nur erlauben, wenn konfigurierender Agent höchstes Privileg hat
if (config_privilege < 2'd3) begin
config_denied <= 1'b1;
end
else begin
// Sicherer Master kann Überlappungen erstellen
region_base[config_region_id] <= config_base_addr;
region_size[config_region_id] <= config_size;
region_perms[config_region_id] <= config_permissions;
region_enabled[config_region_id] <= 1'b1;
region_owner[config_region_id] <= config_privilege;
end
end
else begin
// Keine Überlappung - Konfiguration erlauben
region_base[config_region_id] <= config_base_addr;
region_size[config_region_id] <= config_size;
region_perms[config_region_id] <= config_permissions;
region_enabled[config_region_id] <= 1'b1;
region_owner[config_region_id] <= config_privilege;
end
end
end
// SICHER: Zugriffsprüfung mit Priorität - restriktivste gewinnt
always @(*) begin
integer i;
reg [3:0] required_read_level;
reg [3:0] required_write_level;
reg any_match;
access_allowed = 1'b0;
required_read_level = 4'd0;
required_write_level = 4'd0;
any_match = 1'b0;
for (i = 0; i < 8; i = i + 1) begin
if (region_enabled[i] &&
access_addr >= region_base[i] &&
access_addr < (region_base[i] + region_size[i])) begin
any_match = 1'b1;
// SICHER: RESTRIKTIVSTE Berechtigung aus allen übereinstimmenden Regionen nehmen
if (region_perms[i][1:0] > required_read_level) begin
required_read_level = region_perms[i][1:0];
end
if (region_perms[i][3:2] > required_write_level) begin
required_write_level = region_perms[i][3:2];
end
end
end
// SICHER: Zugriff nur, wenn Privileg ALLE Anforderungen erfüllt
if (any_match) begin
if (access_read && access_privilege >= required_read_level) begin
access_allowed = 1'b1;
end
else if (access_write && access_privilege >= required_write_level) begin
access_allowed = 1'b1;
end
else begin
access_allowed = 1'b0;
end
end
end
endmodule
// SICHER: Speicherkarte ohne Überlappung
module secure_memory_map (
input wire clk,
input wire reset_n,
input wire [31:0] addr,
input wire read_enable,
input wire write_enable,
input wire [1:0] privilege_level,
output reg [31:0] read_data,
output reg access_denied
);
// SICHER: Nicht überlappende Geräteregionen
parameter UART_BASE = 32'h1000_0000;
parameter UART_SIZE = 32'h0000_1000; // Korrigiert: nur 4KB
// UART: 0x1000_0000 - 0x1000_0FFF
parameter AES_BASE = 32'h1010_0000;
parameter AES_SIZE = 32'h0001_0000;
// AES: 0x1010_0000 - 0x1010_FFFF
// SICHER: Keine Überlappung zur Kompilierzeit verifizieren
// UART endet bei 0x1000_1000, AES beginnt bei 0x1010_0000 - keine Überlappung
wire in_uart_range = (addr >= UART_BASE) && (addr < UART_BASE + UART_SIZE);
wire in_aes_range = (addr >= AES_BASE) && (addr < AES_BASE + AES_SIZE);
// SICHER: Erkennen, wenn irgendwie beide übereinstimmen (sollte nicht passieren)
wire overlap_error = in_uart_range && in_aes_range;
always @(*) begin
access_denied = 1'b0;
if (overlap_error) begin
// SICHER: Bei Überlappung sicher fehlschlagen
access_denied = 1'b1;
end
else if (in_aes_range) begin
// AES erfordert sicheren Zugriff
if (privilege_level < 2'd3) begin
access_denied = 1'b1;
end
end
else if (in_uart_range) begin
// UART für alle zugänglich
access_denied = 1'b0;
end
else begin
// Unbekannte Region
access_denied = 1'b1;
end
end
endmodule
// SICHER: Software-MPU-Konfiguration mit Überlappungserkennung
#include <stdint.h>
#define MPU_REGIONS 8
typedef struct {
uint32_t base;
uint32_t size;
uint32_t permissions;
uint32_t enabled;
uint32_t owner_privilege;
} mpu_region_t;
static mpu_region_t mpu_regions[MPU_REGIONS];
// SICHER: Auf Überlappung mit bestehenden Regionen prüfen
static bool check_overlap(int region_id, uint32_t base, uint32_t size) {
uint32_t new_end = base + size;
for (int i = 0; i < MPU_REGIONS; i++) {
if (i != region_id && mpu_regions[i].enabled) {
uint32_t existing_end = mpu_regions[i].base + mpu_regions[i].size;
// Auf Überlappung prüfen
if (!(new_end <= mpu_regions[i].base || base >= existing_end)) {
return true; // Überlappung erkannt
}
}
}
return false;
}
// SICHER: Region mit Überlappungsschutz konfigurieren
int secure_configure_region(int region_id, uint32_t base, uint32_t size,
uint32_t perms, uint32_t caller_privilege) {
if (region_id >= MPU_REGIONS) {
return -EINVAL;
}
// SICHER: Ausrichtung validieren (Größe muss Zweierpotenz sein)
if ((size & (size - 1)) != 0) {
return -EINVAL;
}
// SICHER: Basis muss an Größe ausgerichtet sein
if ((base & (size - 1)) != 0) {
return -EINVAL;
}
// SICHER: Auf Überlappung prüfen
if (check_overlap(region_id, base, size)) {
// SICHER: Nur sicherer Master kann überlappende Regionen erstellen
if (caller_privilege < PRIVILEGE_SECURE) {
log_security_event("Überlappungsversuch abgelehnt: Region %d", region_id);
return -EPERM;
}
// Sicherer Master erstellt Überlappung - restriktivste Richtlinie anwenden
log_security_event("Sichere Überlappung erstellt: Region %d", region_id);
}
// SICHER: Kann keine Region konfigurieren, die einem höheren Privileg gehört
if (mpu_regions[region_id].enabled &&
mpu_regions[region_id].owner_privilege > caller_privilege) {
return -EPERM;
}
// Region konfigurieren
mpu_regions[region_id].base = base;
mpu_regions[region_id].size = size;
mpu_regions[region_id].permissions = perms;
mpu_regions[region_id].enabled = 1;
mpu_regions[region_id].owner_privilege = caller_privilege;
// Auf Hardware anwenden
__disable_irq();
MPU->RNR = region_id;
MPU->RBAR = base;
MPU->RASR = encode_size(size) | perms | MPU_RASR_ENABLE_Msk;
__DSB();
__ISB();
__enable_irq();
return 0;
}
// SICHER: Zugriffsprüfung unter Berücksichtigung aller übereinstimmenden Regionen
bool secure_check_access(uint32_t addr, uint32_t privilege, bool write) {
uint32_t required_privilege = 0;
bool any_match = false;
// SICHER: Restriktivste Anforderung aus allen übereinstimmenden Regionen finden
for (int i = 0; i < MPU_REGIONS; i++) {
if (mpu_regions[i].enabled) {
uint32_t region_end = mpu_regions[i].base + mpu_regions[i].size;
if (addr >= mpu_regions[i].base && addr < region_end) {
any_match = true;
uint32_t region_req = write ?
(mpu_regions[i].permissions >> 4) & 0xF :
mpu_regions[i].permissions & 0xF;
// Restriktivste nehmen
if (region_req > required_privilege) {
required_privilege = region_req;
}
}
}
}
if (!any_match) {
return false; // Keine Region deckt diese Adresse ab
}
return privilege >= required_privilege;
}
CVE-Beispiele
- CVE-2008-7096: Virtualisierungsprodukt-Bypass durch Neuzuordnung von Registern, die mit geschütztem Speicher überlappten
- Prozessor-Designfehler, die Ring-0-Code den Zugriff auf höher privilegierte Ringe durch Register-Fenster-Überlappung ermöglichten
Verwandte CWEs
- CWE-284: Unsachgemäße Zugriffskontrolle (Eltern)
- CWE-119: Unsachgemäße Einschränkung von Operationen innerhalb von Speicherpuffergrenzen (kann vorangehen)
- CWE-1257: Unsachgemäße Zugriffskontrolle auf gespiegelte oder aliasierte Speicherbereiche (verwandt)
Referenzen
- MITRE Corporation. "CWE-1260: Improper Handling of Overlap Between Protected Memory Ranges." https://cwe.mitre.org/data/definitions/1260.html
- ARM. "Memory Protection Unit User Guide"
- Intel. "System Programming Guide" - Memory Protection