Skip to content

Commit 693d41f

Browse files
Alexander GordeevVasily Gorbik
authored andcommitted
s390/mm: Restore mapping of kernel image using large pages
Since physical and virtual kernel address spaces are uncoupled the kernel image is not mapped using large segment pages anymore, which is a regression. Put the kernel image at the same large segment page offset in physical memory as in virtual memory. Such approach preserves the existing number of bits of entropy used for randomization of the kernel location in virtual memory when KASLR is on. As result, the kernel is mapped using large segment pages. Fixes: c98d2ec ("s390/mm: Uncouple physical vs virtual address spaces") Reported-by: Heiko Carstens <hca@linux.ibm.com> Reviewed-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
1 parent d8073dc commit 693d41f

File tree

3 files changed

+26
-4
lines changed

3 files changed

+26
-4
lines changed

arch/s390/boot/startup.c

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ static void fixup_vmlinux_info(void)
384384
void startup_kernel(void)
385385
{
386386
unsigned long kernel_size = vmlinux.image_size + vmlinux.bss_size;
387-
unsigned long nokaslr_offset_phys = mem_safe_offset();
387+
unsigned long nokaslr_offset_phys, kaslr_large_page_offset;
388388
unsigned long amode31_lma = 0;
389389
unsigned long max_physmem_end;
390390
unsigned long asce_limit;
@@ -393,6 +393,12 @@ void startup_kernel(void)
393393

394394
fixup_vmlinux_info();
395395
setup_lpp();
396+
397+
/*
398+
* Non-randomized kernel physical start address must be _SEGMENT_SIZE
399+
* aligned (see blow).
400+
*/
401+
nokaslr_offset_phys = ALIGN(mem_safe_offset(), _SEGMENT_SIZE);
396402
safe_addr = PAGE_ALIGN(nokaslr_offset_phys + kernel_size);
397403

398404
/*
@@ -425,10 +431,25 @@ void startup_kernel(void)
425431
save_ipl_cert_comp_list();
426432
rescue_initrd(safe_addr, ident_map_size);
427433

428-
if (kaslr_enabled())
429-
__kaslr_offset_phys = randomize_within_range(kernel_size, THREAD_SIZE, 0, ident_map_size);
434+
/*
435+
* __kaslr_offset_phys must be _SEGMENT_SIZE aligned, so the lower
436+
* 20 bits (the offset within a large page) are zero. Copy the last
437+
* 20 bits of __kaslr_offset, which is THREAD_SIZE aligned, to
438+
* __kaslr_offset_phys.
439+
*
440+
* With this the last 20 bits of __kaslr_offset_phys and __kaslr_offset
441+
* are identical, which is required to allow for large mappings of the
442+
* kernel image.
443+
*/
444+
kaslr_large_page_offset = __kaslr_offset & ~_SEGMENT_MASK;
445+
if (kaslr_enabled()) {
446+
unsigned long end = ident_map_size - kaslr_large_page_offset;
447+
448+
__kaslr_offset_phys = randomize_within_range(kernel_size, _SEGMENT_SIZE, 0, end);
449+
}
430450
if (!__kaslr_offset_phys)
431451
__kaslr_offset_phys = nokaslr_offset_phys;
452+
__kaslr_offset_phys |= kaslr_large_page_offset;
432453
kaslr_adjust_vmlinux_info(__kaslr_offset_phys);
433454
physmem_reserve(RR_VMLINUX, __kaslr_offset_phys, kernel_size);
434455
deploy_kernel((void *)__kaslr_offset_phys);

arch/s390/boot/vmem.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ static unsigned long _pa(unsigned long addr, unsigned long size, enum populate_m
261261

262262
static bool large_allowed(enum populate_mode mode)
263263
{
264-
return (mode == POPULATE_DIRECT) || (mode == POPULATE_IDENTITY);
264+
return (mode == POPULATE_DIRECT) || (mode == POPULATE_IDENTITY) || (mode == POPULATE_KERNEL);
265265
}
266266

267267
static bool can_large_pud(pud_t *pu_dir, unsigned long addr, unsigned long end,

arch/s390/boot/vmlinux.lds.S

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ SECTIONS
109109
#ifdef CONFIG_KERNEL_UNCOMPRESSED
110110
. = ALIGN(PAGE_SIZE);
111111
. += AMODE31_SIZE; /* .amode31 section */
112+
. = ALIGN(1 << 20); /* _SEGMENT_SIZE */
112113
#else
113114
. = ALIGN(8);
114115
#endif

0 commit comments

Comments
 (0)