Skip to content

Commit 034347a

Browse files
MJNowakowskigregkh
authored andcommitted
MIPS: init: Ensure bootmem does not corrupt reserved memory
[ Upstream commit d9b5b658210f28ed9f70c757d553e679d76e2986 ] 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 <marcin.nowakowski@imgtec.com> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14609/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org> Signed-off-by: Sasha Levin <alexander.levin@verizon.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent a904ebe commit 034347a

1 file changed

Lines changed: 71 additions & 3 deletions

File tree

arch/mips/kernel/setup.c

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

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

301330
#else /* !CONFIG_SGI_IP27 */
302331

332+
static unsigned long __init bootmap_bytes(unsigned long pages)
333+
{
334+
unsigned long bytes = DIV_ROUND_UP(pages, 8);
335+
336+
return ALIGN(bytes, sizeof(long));
337+
}
338+
303339
static void __init bootmem_init(void)
304340
{
305341
unsigned long reserved_end;
306342
unsigned long mapstart = ~0UL;
307343
unsigned long bootmap_size;
344+
bool bootmap_valid = false;
308345
int i;
309346

310347
/*
@@ -385,11 +422,42 @@ static void __init bootmem_init(void)
385422
#endif
386423

387424
/*
388-
* Initialize the boot-time allocator with low memory only.
425+
* check that mapstart doesn't overlap with any of
426+
* memory regions that have been reserved through eg. DTB
389427
*/
390-
bootmap_size = init_bootmem_node(NODE_DATA(0), mapstart,
391-
min_low_pfn, max_low_pfn);
428+
bootmap_size = bootmap_bytes(max_low_pfn - min_low_pfn);
429+
430+
bootmap_valid = memory_region_available(PFN_PHYS(mapstart),
431+
bootmap_size);
432+
for (i = 0; i < boot_mem_map.nr_map && !bootmap_valid; i++) {
433+
unsigned long mapstart_addr;
434+
435+
switch (boot_mem_map.map[i].type) {
436+
case BOOT_MEM_RESERVED:
437+
mapstart_addr = PFN_ALIGN(boot_mem_map.map[i].addr +
438+
boot_mem_map.map[i].size);
439+
if (PHYS_PFN(mapstart_addr) < mapstart)
440+
break;
441+
442+
bootmap_valid = memory_region_available(mapstart_addr,
443+
bootmap_size);
444+
if (bootmap_valid)
445+
mapstart = PHYS_PFN(mapstart_addr);
446+
break;
447+
default:
448+
break;
449+
}
450+
}
392451

452+
if (!bootmap_valid)
453+
panic("No memory area to place a bootmap bitmap");
454+
455+
/*
456+
* Initialize the boot-time allocator with low memory only.
457+
*/
458+
if (bootmap_size != init_bootmem_node(NODE_DATA(0), mapstart,
459+
min_low_pfn, max_low_pfn))
460+
panic("Unexpected memory size required for bootmap");
393461

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

0 commit comments

Comments
 (0)