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

AuswirkungDetails
VertraulichkeitUmfang: Vertraulichkeit

Speicher lesen - Angreifer können geschützten Speicher über ungeschützte Aliase lesen.
IntegritätUmfang: Integrität

Speicher modifizieren - Geschützter Speicher kann über ungeschützte Aliase modifiziert werden.
VerfügbarkeitUmfang: 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

  1. MITRE Corporation. "CWE-1257: Improper Access Control Applied to Mirrored or Aliased Memory Regions." https://cwe.mitre.org/data/definitions/1257.html
  2. ARM. "Memory Protection Unit Configuration"
  3. Intel. "System Address Map and Memory Aliasing"