mirror of
https://github.com/torvalds/linux.git
synced 2026-09-28 03:52:02 +02:00
arm64: mm: fix accidental linear mapping of no-map reserved memory
When reserved-memory regions with the "no-map" property are not
page-aligned, the kernel may accidentally map them into the linear
mapping, contradicting the no-map semantics.
The root cause is a mismatch between /proc/iomem's address boundaries
and the actual page table mapping boundaries:
1. /proc/iomem derives its ranges from memblock via
memblock_region_reserved_base_pfn/memblock_region_reserved_end_pfn,
which perform PFN rounding so the displayed boundaries are
page-aligned. This gives the impression that the no-map region
occupies whole pages.
2. However, memblock_mark_nomap() splits memblock.memory regions at
exact byte boundaries (memblock_isolate_range preserves raw DT
base/size with no alignment). When for_each_mem_range iterates the
non-NOMAP regions adjacent to a no-map region, it returns start/end
values that are NOT page-aligned — they are the precise byte
boundaries from the memblock split.
3. These sub-page-aligned values are passed to
__create_pgd_mapping_locked(), which does:
phys &= PAGE_MASK;
addr = virt & PAGE_MASK;
end = PAGE_ALIGN(virt + size);
The downward rounding of phys via PAGE_MASK extends the mapped
range backward into the adjacent no-map region, effectively
including no-map memory in the linear mapping.
For example, with 64K pages, reserved_region@A2000000 (base=0xA2000000,
size=0x8000, no-map) causes for_each_mem_range to return
start=0xA2008000 for the next mappable region. After phys &= PAGE_MASK,
the actual mapping starts at 0xA2000000 — the entire no-map region is
incorrectly mapped.
Fix this by rounding the mappable range inward to PAGE_SIZE boundaries
before passing it to __map_memblock: start is rounded UP and end is
rounded DOWN. This ensures the mapped area never overlaps with adjacent
no-map regions. The cost is at most one page of unmapped gap at each
boundary, which is preferable to violating no-map semantics.
Signed-off-by: liulhong617 <liulhong617@gmail.com>
Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
parent
3b56ebafec
commit
7ace06a01e
|
|
@ -1190,6 +1190,20 @@ static void __init map_mem(void)
|
|||
|
||||
/* map all the memory banks */
|
||||
for_each_mem_range(i, &start, &end) {
|
||||
/*
|
||||
* for_each_mem_range may return sub-page-aligned boundaries
|
||||
* after memblock_mark_nomap() splits regions at byte precision.
|
||||
* __create_pgd_mapping_locked aligns phys down to PAGE_MASK,
|
||||
* which could accidentally map no-map memory on the boundary.
|
||||
* Round the mappable range inward: start UP, end DOWN, so
|
||||
* that the mapped area never overlaps with adjacent no-map
|
||||
* regions. The cost is at most one page of unmapped gap at
|
||||
* each boundary.
|
||||
*/
|
||||
start = PAGE_ALIGN(start);
|
||||
end = end & PAGE_MASK;
|
||||
if (start >= end)
|
||||
continue;
|
||||
/*
|
||||
* The linear map must allow allocation tags reading/writing
|
||||
* if MTE is present. Otherwise, it has the same attributes as
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user