Skip to content

Commit d9b5b65

Browse files
MJNowakowskiralfbaechle
authored andcommitted
MIPS: init: Ensure bootmem does not corrupt reserved memory
Current init code initialises bootmem allocator with all of the low memory that it assumes is available, but does not check for reserved memory block, which can lead to corruption of data that may be stored there. Move bootmem's allocation map to a location that does not cross any reserved regions Signed-off-by: Marcin Nowakowski <[email protected]> Cc: [email protected] Patchwork: https://patchwork.linux-mips.org/patch/14609/ Signed-off-by: Ralf Baechle <[email protected]>
1 parent e89ef66 commit d9b5b65

File tree

1 file changed

+71
-3
lines changed

1 file changed

+71
-3
lines changed

arch/mips/kernel/setup.c

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,35 @@ void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_add
153153
add_memory_region(start, size, BOOT_MEM_RAM);
154154
}
155155

156+
bool __init memory_region_available(phys_addr_t start, phys_addr_t size)
157+
{
158+
int i;
159+
bool in_ram = false, free = true;
160+
161+
for (i = 0; i < boot_mem_map.nr_map; i++) {
162+
phys_addr_t start_, end_;
163+
164+
start_ = boot_mem_map.map[i].addr;
165+
end_ = boot_mem_map.map[i].addr + boot_mem_map.map[i].size;
166+
167+
switch (boot_mem_map.map[i].type) {
168+
case BOOT_MEM_RAM:
169+
if (start >= start_ && start + size <= end_)
170+
in_ram = true;
171+
break;
172+
case BOOT_MEM_RESERVED:
173+
if ((start >= start_ && start < end_) ||
174+
(start < start_ && start + size >= start_))
175+
free = false;
176+
break;
177+
default:
178+
continue;
179+
}
180+
}
181+
182+
return in_ram && free;
183+
}
184+
156185
static void __init print_memory_map(void)
157186
{
158187
int i;
@@ -332,11 +361,19 @@ static void __init bootmem_init(void)
332361

333362
#else /* !CONFIG_SGI_IP27 */
334363

364+
static unsigned long __init bootmap_bytes(unsigned long pages)
365+
{
366+
unsigned long bytes = DIV_ROUND_UP(pages, 8);
367+
368+
return ALIGN(bytes, sizeof(long));
369+
}
370+
335371
static void __init bootmem_init(void)
336372
{
337373
unsigned long reserved_end;
338374
unsigned long mapstart = ~0UL;
339375
unsigned long bootmap_size;
376+
bool bootmap_valid = false;
340377
int i;
341378

342379
/*
@@ -430,11 +467,42 @@ static void __init bootmem_init(void)
430467
#endif
431468

432469
/*
433-
* Initialize the boot-time allocator with low memory only.
470+
* check that mapstart doesn't overlap with any of
471+
* memory regions that have been reserved through eg. DTB
434472
*/
435-
bootmap_size = init_bootmem_node(NODE_DATA(0), mapstart,
436-
min_low_pfn, max_low_pfn);
473+
bootmap_size = bootmap_bytes(max_low_pfn - min_low_pfn);
474+
475+
bootmap_valid = memory_region_available(PFN_PHYS(mapstart),
476+
bootmap_size);
477+
for (i = 0; i < boot_mem_map.nr_map && !bootmap_valid; i++) {
478+
unsigned long mapstart_addr;
479+
480+
switch (boot_mem_map.map[i].type) {
481+
case BOOT_MEM_RESERVED:
482+
mapstart_addr = PFN_ALIGN(boot_mem_map.map[i].addr +
483+
boot_mem_map.map[i].size);
484+
if (PHYS_PFN(mapstart_addr) < mapstart)
485+
break;
486+
487+
bootmap_valid = memory_region_available(mapstart_addr,
488+
bootmap_size);
489+
if (bootmap_valid)
490+
mapstart = PHYS_PFN(mapstart_addr);
491+
break;
492+
default:
493+
break;
494+
}
495+
}
437496

497+
if (!bootmap_valid)
498+
panic("No memory area to place a bootmap bitmap");
499+
500+
/*
501+
* Initialize the boot-time allocator with low memory only.
502+
*/
503+
if (bootmap_size != init_bootmem_node(NODE_DATA(0), mapstart,
504+
min_low_pfn, max_low_pfn))
505+
panic("Unexpected memory size required for bootmap");
438506

439507
for (i = 0; i < boot_mem_map.nr_map; i++) {
440508
unsigned long start, end;

0 commit comments

Comments
 (0)