Improper Handling of Overlap Between Protected Memory Ranges
Description
Improper Handling of Overlap Between Protected Memory Ranges occurs when a product allows address regions to overlap, which can result in the bypassing of intended memory protection. This weakness occurs in hardware designs using isolated memory regions and access control policies to protect privileged software. When lower-privilege software can program overlapping memory address regions with higher-privilege regions, attackers may achieve privilege escalation. The memory protection unit (MPU) may incorrectly handle these overlaps, enabling unauthorized reads/writes or denial-of-service attacks.
Risk
Overlapping memory ranges create severe security implications. Memory protection can be bypassed. Privilege escalation becomes possible. Protected data may be read or modified. Kernel memory may be accessible to user code. Secure enclaves may be compromised. Denial of service through memory access blocking. System stability may be affected. Security isolation boundaries are violated.
Solution
Ensure memory regions remain properly isolated with enforced access control policies. Define a priority scheme for overlapping regions (e.g., lowest ID takes precedence). Block programming of regions with overlapping addresses via hardware logic. Apply policy filters to all overlapping ranges—access granted only if all policies permit it. Validate region configurations before applying them.
Common Consequences
| Impact | Details |
|---|---|
| Confidentiality | Scope: Confidentiality Read Memory - Protected memory contents can be read through overlapping region bypass. |
| Integrity | Scope: Integrity Modify Memory - Protected memory can be modified through overlapping regions. |
| Availability | Scope: Availability DoS: Instability - Overlapping regions can block legitimate access or cause system instability. |
Example Code
Vulnerable Code
// Vulnerable: MPU without overlap protection
module vulnerable_mpu (
input wire clk,
input wire reset_n,
// Region configuration
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,
// Memory access
input wire [31:0] access_addr,
input wire [1:0] access_privilege, // 0=user, 1=supervisor, 2=hypervisor, 3=secure
input wire access_read,
input wire access_write,
output reg access_allowed
);
// 8 configurable regions
reg [31:0] region_base [0:7];
reg [31:0] region_size [0:7];
reg [3:0] region_perms [0:7]; // [3:2]=write level, [1:0]=read level
reg region_enabled [0:7];
// VULNERABLE: Region configuration without overlap check
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
// VULNERABLE: No check if new region overlaps existing regions
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
// Access check
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
// VULNERABLE: First matching region wins
// Attacker can create overlapping region with higher ID
// and more permissive settings
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
// Attack:
// Region 0: base=0x8000_0000, size=0x1000, perms=0xF (secure only)
// Attacker programs Region 7: base=0x8000_0000, size=0x1000, perms=0x0 (all access)
// Both regions match, but attacker's permissive region allows access
endmodule
// Vulnerable: Memory map with overlap vulnerability
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
);
// Device regions
// VULNERABLE: UART region overlaps with AES region
parameter UART_BASE = 32'h1000_0000;
parameter UART_SIZE = 32'h0011_1000; // Too large!
// UART ends at 0x1011_1000
parameter AES_BASE = 32'h1010_0000; // Overlaps with UART!
parameter AES_SIZE = 32'h0001_0000;
// AES: 0x1010_0000 - 0x1010_FFFF
// This is INSIDE the UART range!
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: accessible to all (privilege >= 0)
// AES: requires secure access (privilege >= 3)
always @(*) begin
access_denied = 1'b0;
if (in_uart_range && in_aes_range) begin
// VULNERABLE: Both ranges match!
// Which policy applies? Implementation picks UART (permissive)
access_denied = 1'b0; // UART policy: allow all
end
else if (in_aes_range) begin
if (privilege_level < 2'd3) begin
access_denied = 1'b1;
end
end
// UART range: always allowed
end
// Attack: Access AES at 0x1010_0000 through UART region
// Address is in both ranges, but UART policy allows access
endmodule
// Vulnerable: Software MPU configuration with overlap
#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];
// VULNERABLE: No overlap checking
int vulnerable_configure_region(int region_id, uint32_t base, uint32_t size, uint32_t perms) {
if (region_id >= MPU_REGIONS) {
return -EINVAL;
}
// VULNERABLE: No check for overlap with existing regions
mpu_regions[region_id].base = base;
mpu_regions[region_id].size = size;
mpu_regions[region_id].permissions = perms;
mpu_regions[region_id].enabled = 1;
// Apply to hardware
MPU->RNR = region_id;
MPU->RBAR = base;
MPU->RASR = (size << 1) | perms | MPU_RASR_ENABLE_Msk;
return 0;
}
// Attack scenario
void exploit_overlap(void) {
// Kernel sets up protected region
// Region 0: 0x20000000-0x20001000, supervisor only
// Attacker (with privilege to configure MPU) creates overlap
// Region 7: 0x20000000-0x20001000, all access
// Now both regions cover same address
// Access check may use attacker's permissive region
}
Fixed Code
// Fixed: MPU with overlap protection
module secure_mpu (
input wire clk,
input wire reset_n,
// Region configuration
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, // Configuring agent's privilege
// Memory access
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 configurable regions
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]; // Privilege level that configured region
// FIXED: Check for overlap before allowing configuration
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];
// Check for any overlap
if (!(new_end <= region_base[i] || new_base >= existing_end)) begin
overlaps_existing = 1'b1;
end
end
end
end
endfunction
// FIXED: Detect overlaps and require higher privilege
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;
// FIXED: Check for overlap
if (proposed_overlaps) begin
overlap_detected <= 1'b1;
// FIXED: Only allow overlap if configuring agent has highest privilege
if (config_privilege < 2'd3) begin
config_denied <= 1'b1;
end
else begin
// Secure master can create overlaps
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
// No overlap - allow configuration
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
// FIXED: Access check with priority - most restrictive wins
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;
// FIXED: Take MOST restrictive permission from all matching regions
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
// FIXED: Access only if privilege meets ALL requirements
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
// Fixed: Memory map without overlap
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
);
// FIXED: Non-overlapping device regions
parameter UART_BASE = 32'h1000_0000;
parameter UART_SIZE = 32'h0000_1000; // Fixed: 4KB only
// UART: 0x1000_0000 - 0x1000_0FFF
parameter AES_BASE = 32'h1010_0000;
parameter AES_SIZE = 32'h0001_0000;
// AES: 0x1010_0000 - 0x1010_FFFF
// FIXED: Verify no overlap at compile time
// UART ends at 0x1000_1000, AES starts at 0x1010_0000 - no overlap
wire in_uart_range = (addr >= UART_BASE) && (addr < UART_BASE + UART_SIZE);
wire in_aes_range = (addr >= AES_BASE) && (addr < AES_BASE + AES_SIZE);
// FIXED: Detect if somehow both match (should not happen)
wire overlap_error = in_uart_range && in_aes_range;
always @(*) begin
access_denied = 1'b0;
if (overlap_error) begin
// FIXED: Fail-secure on overlap
access_denied = 1'b1;
end
else if (in_aes_range) begin
// AES requires secure access
if (privilege_level < 2'd3) begin
access_denied = 1'b1;
end
end
else if (in_uart_range) begin
// UART accessible to all
access_denied = 1'b0;
end
else begin
// Unknown region
access_denied = 1'b1;
end
end
endmodule
// Fixed: Software MPU configuration with overlap detection
#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];
// FIXED: Check for overlap with existing regions
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;
// Check for any overlap
if (!(new_end <= mpu_regions[i].base || base >= existing_end)) {
return true; // Overlap detected
}
}
}
return false;
}
// FIXED: Configure region with overlap protection
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;
}
// FIXED: Validate alignment (size must be power of 2)
if ((size & (size - 1)) != 0) {
return -EINVAL;
}
// FIXED: Base must be aligned to size
if ((base & (size - 1)) != 0) {
return -EINVAL;
}
// FIXED: Check for overlap
if (check_overlap(region_id, base, size)) {
// FIXED: Only secure master can create overlapping regions
if (caller_privilege < PRIVILEGE_SECURE) {
log_security_event("Overlap attempt denied: region %d", region_id);
return -EPERM;
}
// Secure master creating overlap - apply most restrictive policy
log_security_event("Secure overlap created: region %d", region_id);
}
// FIXED: Cannot configure region owned by higher privilege
if (mpu_regions[region_id].enabled &&
mpu_regions[region_id].owner_privilege > caller_privilege) {
return -EPERM;
}
// Configure region
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;
// Apply to hardware
__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;
}
// FIXED: Access check considering all matching regions
bool secure_check_access(uint32_t addr, uint32_t privilege, bool write) {
uint32_t required_privilege = 0;
bool any_match = false;
// FIXED: Find most restrictive requirement from all matching regions
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;
// Take most restrictive
if (region_req > required_privilege) {
required_privilege = region_req;
}
}
}
}
if (!any_match) {
return false; // No region covers this address
}
return privilege >= required_privilege;
}
CVE Examples
- CVE-2008-7096: Virtualization product bypass via remapping registers that overlapped with protected memory
- Processor design flaws allowing ring 0 code to access higher privilege rings through register window overlap
Related CWEs
- CWE-284: Improper Access Control (parent)
- CWE-119: Improper Restriction of Operations within Memory Buffer Bounds (can precede)
- CWE-1257: Improper Access Control Applied to Mirrored or Aliased Memory Regions (related)
References
- 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