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

AuswirkungDetails
VertraulichkeitBereich: Vertraulichkeit

Speicher lesen - Geschützte Speicherinhalte können durch Umgehung überlappender Regionen gelesen werden.
IntegritätBereich: Integrität

Speicher modifizieren - Geschützter Speicher kann durch überlappende Regionen modifiziert werden.
VerfügbarkeitBereich: 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

  1. MITRE Corporation. "CWE-1260: Improper Handling of Overlap Between Protected Memory Ranges." https://cwe.mitre.org/data/definitions/1260.html
  2. ARM. "Memory Protection Unit User Guide"
  3. Intel. "System Programming Guide" - Memory Protection