Improper Access Control Applied to Mirrored or Aliased Memory Regions
Description
Improper Access Control Applied to Mirrored or Aliased Memory Regions occurs when a product has inconsistent read/write permissions across aliased or mirrored memory regions in hardware designs. Hardware designs often map the same physical memory cell to multiple system addresses for redundancy or simplified decoding logic. When access controls are applied inconsistently across these aliases, attackers can bypass protections by accessing alternate addresses. An untrusted agent may be blocked from one memory address but can access the same data through an alternate address mapping.
Risk
Inconsistent alias protection has severe security implications. Protected data can be read through alternate addresses. Security configurations can be modified via aliases. Memory isolation can be bypassed. Confidential information may be exposed. System integrity may be compromised. Protection mechanisms become ineffective. Attackers can access privileged regions. Security policies become unenforceable.
Solution
Apply consistent access rights between primary memory regions and any mirrored or aliased memory regions. Restrict the ability to create aliases or resize mapped regions to trusted software only. Implement unified access control that covers all address mappings to the same physical memory. Block or protect unused aliased ranges. Verify access control consistency during security audits. Use hardware address canonicalization.
Common Consequences
| Impact | Details |
|---|---|
| Confidentiality | Scope: Confidentiality Read Memory - Attackers can read protected memory through unprotected aliases. |
| Integrity | Scope: Integrity Modify Memory - Protected memory can be modified through unprotected aliases. |
| Availability | Scope: Availability DoS: Instability - Memory corruption through aliases can cause system instability. |
Example Code
Vulnerable Code
// Vulnerable: Memory with inconsistent alias protection
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 memory, but mapped into 16KB address space
// Creates 4 aliases: 0x0000, 0x1000, 0x2000, 0x3000
reg [31:0] memory [0:1023];
// Address decoder - masks upper bits creating aliases
wire [9:0] physical_addr = addr[11:2]; // Only use bits 11:2
// Bits 15:12 are ignored, creating aliases!
// Access control only on primary range
wire is_protected_range = (addr >= 16'h0000) && (addr < 16'h0400);
// VULNERABLE: Only checks 0x0000-0x03FF
// Aliases 0x1000, 0x2000, 0x3000 are NOT protected!
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
// VULNERABLE: Check only applies to one address range
if (is_protected_range && privilege_level < 2'd2) begin
access_denied <= 1'b1;
end
else begin
// Write succeeds - including via aliases!
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
// Read succeeds - including via aliases!
read_data <= memory[physical_addr];
end
end
end
end
// Attack: Access protected memory at 0x0100 via alias 0x1100
// physical_addr = 0x1100[11:2] = 0x100[11:2] = same location
// But 0x1100 is not in "protected_range", so access allowed!
endmodule
// Vulnerable: Register block with unprotected aliases
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 registers, but address space is 256 bytes
// Creates 16 aliases for each register
reg [31:0] registers [0:15];
// Security-sensitive registers
parameter SECURE_KEY_REG = 4'd0;
parameter SECURE_CONFIG_REG = 4'd1;
// Physical address (only lower 4 bits matter)
wire [3:0] reg_index = addr[5:2]; // Bits 5:2 select register
// Bits 7:6 are ignored - creates aliases!
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
// VULNERABLE: Only checks specific addresses
if ((addr == 8'h00 || addr == 8'h04) && !secure_access) begin
// Block write to 0x00 and 0x04 for non-secure
access_fault <= 1'b1;
end
else begin
// VULNERABLE: Write via alias succeeds!
// addr = 0x40 maps to same register as 0x00
registers[reg_index] <= write_data;
end
end
end
end
// Attack: Write secure key via alias
// Blocked: write to addr 0x00 (SECURE_KEY_REG)
// Allowed: write to addr 0x40 (same physical register!)
endmodule
// Vulnerable: Software with inconsistent alias handling
#include <stdint.h>
// Memory map with aliases
#define SECURE_MEM_PRIMARY 0x10000000
#define SECURE_MEM_ALIAS1 0x10001000 // Same physical memory
#define SECURE_MEM_ALIAS2 0x10002000 // Same physical memory
#define SECURE_MEM_SIZE 0x1000
// Vulnerable: Only checks primary address
int vulnerable_memory_access(uint32_t addr, uint32_t* data, int write, int privilege) {
// VULNERABLE: Only protects primary range
if (addr >= SECURE_MEM_PRIMARY &&
addr < SECURE_MEM_PRIMARY + SECURE_MEM_SIZE) {
if (privilege < PRIVILEGE_SECURE) {
return -EACCES; // Access denied
}
}
// VULNERABLE: Aliases not checked!
// Access to SECURE_MEM_ALIAS1 or ALIAS2 succeeds
// even without privilege
volatile uint32_t* ptr = (volatile uint32_t*)addr;
if (write) {
*ptr = *data;
} else {
*data = *ptr;
}
return 0;
}
// Attack exploitation
void exploit_alias_access(void) {
uint32_t secret_data;
// This is blocked:
// vulnerable_memory_access(SECURE_MEM_PRIMARY, &secret_data, 0, PRIVILEGE_USER);
// But this succeeds (same physical memory):
vulnerable_memory_access(SECURE_MEM_ALIAS1, &secret_data, 0, PRIVILEGE_USER);
// secret_data now contains protected data!
}
Fixed Code
// Fixed: Memory with consistent alias protection
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 memory mapped into 16KB address space
reg [31:0] memory [0:1023];
// FIXED: Canonicalize address to detect all aliases
wire [9:0] physical_addr = addr[11:2];
// FIXED: Check protection based on PHYSICAL address, not logical
// This catches all aliases automatically
wire is_protected_physical = (physical_addr >= 10'h000) && (physical_addr < 10'h100);
// FIXED: Or alternatively, block all aliased ranges
wire is_valid_range = (addr[15:12] == 4'h0); // Only allow 0x0XXX range
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;
// FIXED: Block all alias accesses
if (is_alias_access) begin
access_denied <= 1'b1;
read_data <= 32'h0;
end
else if (write_enable) begin
// FIXED: Protection based on physical address
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
// Fixed: Register block with proper alias protection
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];
// Security-sensitive registers
parameter SECURE_KEY_REG = 4'd0;
parameter SECURE_CONFIG_REG = 4'd1;
// FIXED: Canonicalize to physical register index
wire [3:0] reg_index = addr[5:2];
// FIXED: Check protection based on physical register, not address
wire is_secure_register = (reg_index == SECURE_KEY_REG) ||
(reg_index == SECURE_CONFIG_REG);
// FIXED: Detect and block alias access
wire is_valid_address = (addr[7:6] == 2'b00); // Only 0x00-0x3F valid
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;
// FIXED: Block all alias accesses
if (!is_valid_address) begin
access_fault <= 1'b1;
end
else if (write_enable) begin
// FIXED: Check based on physical register index
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
// Fixed: Address decoder that blocks aliases
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
);
// Memory regions and their sizes
parameter REGION_A_BASE = 32'h1000_0000;
parameter REGION_A_SIZE = 32'h0000_1000; // 4KB
// FIXED: Calculate canonical address
always @(*) begin
alias_detected = 1'b0;
valid_access = 1'b0;
canonical_addr = addr;
// Check Region A (4KB actual, 16KB address space)
if (addr >= REGION_A_BASE && addr < REGION_A_BASE + 32'h4000) begin
// Canonicalize address
canonical_addr = REGION_A_BASE + ((addr - REGION_A_BASE) & 32'h0FFF);
// FIXED: Detect if alias was used
if (addr != canonical_addr) begin
alias_detected = 1'b1;
valid_access = 1'b0; // Block alias access
end
else begin
valid_access = 1'b1;
end
end
end
endmodule
// Fixed: Software with consistent alias handling
#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 mask
// FIXED: Canonicalize address to physical
static uint32_t canonicalize_address(uint32_t addr) {
// Check if in any aliased region
if ((addr >= SECURE_MEM_PRIMARY && addr < SECURE_MEM_PRIMARY + 0x4000)) {
// Map all aliases to canonical (primary) address
return SECURE_MEM_PRIMARY + ((addr - SECURE_MEM_PRIMARY) & SECURE_MEM_MASK);
}
return addr;
}
// FIXED: Check if address is an alias
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) {
// FIXED: Block all alias accesses
if (is_alias_access(addr)) {
log_security_event("Alias access blocked: 0x%08x", addr);
return -EACCES;
}
// FIXED: Get canonical address for protection check
uint32_t canonical_addr = canonicalize_address(addr);
// Check protection based on canonical address
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;
}
// FIXED: Memory protection unit configuration
void configure_mpu_with_alias_protection(void) {
// Configure primary region
mpu_configure_region(0, SECURE_MEM_PRIMARY, SECURE_MEM_SIZE,
MPU_ATTR_SECURE_ONLY);
// FIXED: Explicitly block all alias regions
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);
// Or configure the entire aliased range with consistent protection
mpu_configure_region(0, SECURE_MEM_PRIMARY, SECURE_MEM_SIZE * 4,
MPU_ATTR_SECURE_ONLY);
}
CVE Examples
Memory aliasing vulnerabilities have been found in various SoC designs where attackers bypassed memory protection by accessing protected regions through unprotected alias addresses.
Related CWEs
- CWE-284: Improper Access Control (parent)
- CWE-119: Improper Restriction of Operations within Memory Buffer (preceding)
- CWE-1260: Improper Handling of Overlap Between Protected Memory Ranges (related)
- CAPEC-456: Infected Memory (attack pattern)
- CAPEC-679: Exploitation of Improperly Configured Memory Protections (attack pattern)
References
- 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"