Skip to content

Commit 48fb4b3

Browse files
committed
Merge tag 's390-6.11-4' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 fixes from Vasily Gorbik: - Fix KASLR base offset to account for symbol offsets in the vmlinux ELF file, preventing tool breakages like the drgn debugger - Fix potential memory corruption of physmem_info during kernel physical address randomization - Fix potential memory corruption due to overlap between the relocated lowcore and identity mapping by correctly reserving lowcore memory - Fix performance regression and avoid randomizing identity mapping base by default - Fix unnecessary delay of AP bus binding complete uevent to prevent startup lag in KVM guests using AP * tag 's390-6.11-4' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: s390/boot: Fix KASLR base offset off by __START_KERNEL bytes s390/boot: Avoid possible physmem_info segment corruption s390/ap: Refine AP bus bindings complete processing s390/mm: Pin identity mapping base to zero s390/mm: Prevent lowcore vs identity mapping overlap
2 parents 891e811 + 1642285 commit 48fb4b3

File tree

9 files changed

+91
-34
lines changed

9 files changed

+91
-34
lines changed

arch/s390/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,19 @@ config RANDOMIZE_BASE
604604
as a security feature that deters exploit attempts relying on
605605
knowledge of the location of kernel internals.
606606

607+
config RANDOMIZE_IDENTITY_BASE
608+
bool "Randomize the address of the identity mapping base"
609+
depends on RANDOMIZE_BASE
610+
default DEBUG_VM
611+
help
612+
The identity mapping base address is pinned to zero by default.
613+
Allow randomization of that base to expose otherwise missed
614+
notion of physical and virtual addresses of data structures.
615+
That does not have any impact on the base address at which the
616+
kernel image is loaded.
617+
618+
If unsure, say N
619+
607620
config KERNEL_IMAGE_BASE
608621
hex "Kernel image base address"
609622
range 0x100000 0x1FFFFFE0000000 if !KASAN

arch/s390/boot/startup.c

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ static void kaslr_adjust_relocs(unsigned long min_addr, unsigned long max_addr,
162162
loc = (long)*reloc + phys_offset;
163163
if (loc < min_addr || loc > max_addr)
164164
error("64-bit relocation outside of kernel!\n");
165-
*(u64 *)loc += offset - __START_KERNEL;
165+
*(u64 *)loc += offset;
166166
}
167167
}
168168

@@ -177,7 +177,7 @@ static void kaslr_adjust_got(unsigned long offset)
177177
*/
178178
for (entry = (u64 *)vmlinux.got_start; entry < (u64 *)vmlinux.got_end; entry++) {
179179
if (*entry)
180-
*entry += offset - __START_KERNEL;
180+
*entry += offset;
181181
}
182182
}
183183

@@ -252,7 +252,7 @@ static unsigned long setup_kernel_memory_layout(unsigned long kernel_size)
252252
vmemmap_size = SECTION_ALIGN_UP(pages) * sizeof(struct page);
253253

254254
/* choose kernel address space layout: 4 or 3 levels. */
255-
BUILD_BUG_ON(!IS_ALIGNED(__START_KERNEL, THREAD_SIZE));
255+
BUILD_BUG_ON(!IS_ALIGNED(TEXT_OFFSET, THREAD_SIZE));
256256
BUILD_BUG_ON(!IS_ALIGNED(__NO_KASLR_START_KERNEL, THREAD_SIZE));
257257
BUILD_BUG_ON(__NO_KASLR_END_KERNEL > _REGION1_SIZE);
258258
vsize = get_vmem_size(ident_map_size, vmemmap_size, vmalloc_size, _REGION3_SIZE);
@@ -341,7 +341,8 @@ static unsigned long setup_kernel_memory_layout(unsigned long kernel_size)
341341
BUILD_BUG_ON(MAX_DCSS_ADDR > (1UL << MAX_PHYSMEM_BITS));
342342
max_mappable = max(ident_map_size, MAX_DCSS_ADDR);
343343
max_mappable = min(max_mappable, vmemmap_start);
344-
__identity_base = round_down(vmemmap_start - max_mappable, rte_size);
344+
if (IS_ENABLED(CONFIG_RANDOMIZE_IDENTITY_BASE))
345+
__identity_base = round_down(vmemmap_start - max_mappable, rte_size);
345346

346347
return asce_limit;
347348
}
@@ -388,31 +389,25 @@ static void kaslr_adjust_vmlinux_info(long offset)
388389
#endif
389390
}
390391

391-
static void fixup_vmlinux_info(void)
392-
{
393-
vmlinux.entry -= __START_KERNEL;
394-
kaslr_adjust_vmlinux_info(-__START_KERNEL);
395-
}
396-
397392
void startup_kernel(void)
398393
{
399-
unsigned long kernel_size = vmlinux.image_size + vmlinux.bss_size;
400-
unsigned long nokaslr_offset_phys, kaslr_large_page_offset;
401-
unsigned long amode31_lma = 0;
394+
unsigned long vmlinux_size = vmlinux.image_size + vmlinux.bss_size;
395+
unsigned long nokaslr_text_lma, text_lma = 0, amode31_lma = 0;
396+
unsigned long kernel_size = TEXT_OFFSET + vmlinux_size;
397+
unsigned long kaslr_large_page_offset;
402398
unsigned long max_physmem_end;
403399
unsigned long asce_limit;
404400
unsigned long safe_addr;
405401
psw_t psw;
406402

407-
fixup_vmlinux_info();
408403
setup_lpp();
409404

410405
/*
411406
* Non-randomized kernel physical start address must be _SEGMENT_SIZE
412407
* aligned (see blow).
413408
*/
414-
nokaslr_offset_phys = ALIGN(mem_safe_offset(), _SEGMENT_SIZE);
415-
safe_addr = PAGE_ALIGN(nokaslr_offset_phys + kernel_size);
409+
nokaslr_text_lma = ALIGN(mem_safe_offset(), _SEGMENT_SIZE);
410+
safe_addr = PAGE_ALIGN(nokaslr_text_lma + vmlinux_size);
416411

417412
/*
418413
* Reserve decompressor memory together with decompression heap,
@@ -456,16 +451,27 @@ void startup_kernel(void)
456451
*/
457452
kaslr_large_page_offset = __kaslr_offset & ~_SEGMENT_MASK;
458453
if (kaslr_enabled()) {
459-
unsigned long end = ident_map_size - kaslr_large_page_offset;
454+
unsigned long size = vmlinux_size + kaslr_large_page_offset;
460455

461-
__kaslr_offset_phys = randomize_within_range(kernel_size, _SEGMENT_SIZE, 0, end);
456+
text_lma = randomize_within_range(size, _SEGMENT_SIZE, TEXT_OFFSET, ident_map_size);
462457
}
463-
if (!__kaslr_offset_phys)
464-
__kaslr_offset_phys = nokaslr_offset_phys;
465-
__kaslr_offset_phys |= kaslr_large_page_offset;
458+
if (!text_lma)
459+
text_lma = nokaslr_text_lma;
460+
text_lma |= kaslr_large_page_offset;
461+
462+
/*
463+
* [__kaslr_offset_phys..__kaslr_offset_phys + TEXT_OFFSET] region is
464+
* never accessed via the kernel image mapping as per the linker script:
465+
*
466+
* . = TEXT_OFFSET;
467+
*
468+
* Therefore, this region could be used for something else and does
469+
* not need to be reserved. See how it is skipped in setup_vmem().
470+
*/
471+
__kaslr_offset_phys = text_lma - TEXT_OFFSET;
466472
kaslr_adjust_vmlinux_info(__kaslr_offset_phys);
467-
physmem_reserve(RR_VMLINUX, __kaslr_offset_phys, kernel_size);
468-
deploy_kernel((void *)__kaslr_offset_phys);
473+
physmem_reserve(RR_VMLINUX, text_lma, vmlinux_size);
474+
deploy_kernel((void *)text_lma);
469475

470476
/* vmlinux decompression is done, shrink reserved low memory */
471477
physmem_reserve(RR_DECOMPRESSOR, 0, (unsigned long)_decompressor_end);
@@ -488,7 +494,7 @@ void startup_kernel(void)
488494
amode31_lma = randomize_within_range(vmlinux.amode31_size, PAGE_SIZE, amode31_min, SZ_2G);
489495
}
490496
if (!amode31_lma)
491-
amode31_lma = __kaslr_offset_phys - vmlinux.amode31_size;
497+
amode31_lma = text_lma - vmlinux.amode31_size;
492498
physmem_reserve(RR_AMODE31, amode31_lma, vmlinux.amode31_size);
493499

494500
/*
@@ -504,8 +510,8 @@ void startup_kernel(void)
504510
* - copy_bootdata() must follow setup_vmem() to propagate changes
505511
* to bootdata made by setup_vmem()
506512
*/
507-
clear_bss_section(__kaslr_offset_phys);
508-
kaslr_adjust_relocs(__kaslr_offset_phys, __kaslr_offset_phys + vmlinux.image_size,
513+
clear_bss_section(text_lma);
514+
kaslr_adjust_relocs(text_lma, text_lma + vmlinux.image_size,
509515
__kaslr_offset, __kaslr_offset_phys);
510516
kaslr_adjust_got(__kaslr_offset);
511517
setup_vmem(__kaslr_offset, __kaslr_offset + kernel_size, asce_limit);

arch/s390/boot/vmem.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ static void kasan_populate_shadow(unsigned long kernel_start, unsigned long kern
9090
}
9191
memgap_start = end;
9292
}
93-
kasan_populate(kernel_start, kernel_end, POPULATE_KASAN_MAP_SHADOW);
93+
kasan_populate(kernel_start + TEXT_OFFSET, kernel_end, POPULATE_KASAN_MAP_SHADOW);
9494
kasan_populate(0, (unsigned long)__identity_va(0), POPULATE_KASAN_ZERO_SHADOW);
9595
kasan_populate(AMODE31_START, AMODE31_END, POPULATE_KASAN_ZERO_SHADOW);
9696
if (IS_ENABLED(CONFIG_KASAN_VMALLOC)) {
@@ -475,7 +475,17 @@ void setup_vmem(unsigned long kernel_start, unsigned long kernel_end, unsigned l
475475
(unsigned long)__identity_va(end),
476476
POPULATE_IDENTITY);
477477
}
478-
pgtable_populate(kernel_start, kernel_end, POPULATE_KERNEL);
478+
479+
/*
480+
* [kernel_start..kernel_start + TEXT_OFFSET] region is never
481+
* accessed as per the linker script:
482+
*
483+
* . = TEXT_OFFSET;
484+
*
485+
* Therefore, skip mapping TEXT_OFFSET bytes to prevent access to
486+
* [__kaslr_offset_phys..__kaslr_offset_phys + TEXT_OFFSET] region.
487+
*/
488+
pgtable_populate(kernel_start + TEXT_OFFSET, kernel_end, POPULATE_KERNEL);
479489
pgtable_populate(AMODE31_START, AMODE31_END, POPULATE_DIRECT);
480490
pgtable_populate(__abs_lowcore, __abs_lowcore + sizeof(struct lowcore),
481491
POPULATE_ABS_LOWCORE);

arch/s390/boot/vmlinux.lds.S

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,12 @@ SECTIONS
109109
#ifdef CONFIG_KERNEL_UNCOMPRESSED
110110
. = ALIGN(PAGE_SIZE);
111111
. += AMODE31_SIZE; /* .amode31 section */
112-
. = ALIGN(1 << 20); /* _SEGMENT_SIZE */
112+
113+
/*
114+
* Make sure the location counter is not less than TEXT_OFFSET.
115+
* _SEGMENT_SIZE is not available, use ALIGN(1 << 20) instead.
116+
*/
117+
. = MAX(TEXT_OFFSET, ALIGN(1 << 20));
113118
#else
114119
. = ALIGN(8);
115120
#endif

arch/s390/include/asm/page.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,9 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
279279
#define AMODE31_SIZE (3 * PAGE_SIZE)
280280

281281
#define KERNEL_IMAGE_SIZE (512 * 1024 * 1024)
282-
#define __START_KERNEL 0x100000
283282
#define __NO_KASLR_START_KERNEL CONFIG_KERNEL_IMAGE_BASE
284283
#define __NO_KASLR_END_KERNEL (__NO_KASLR_START_KERNEL + KERNEL_IMAGE_SIZE)
285284

285+
#define TEXT_OFFSET 0x100000
286+
286287
#endif /* _S390_PAGE_H */

arch/s390/kernel/setup.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,23 @@ static void __init memblock_add_physmem_info(void)
734734
}
735735

736736
/*
737-
* Reserve memory used for lowcore/command line/kernel image.
737+
* Reserve memory used for lowcore.
738+
*/
739+
static void __init reserve_lowcore(void)
740+
{
741+
void *lowcore_start = get_lowcore();
742+
void *lowcore_end = lowcore_start + sizeof(struct lowcore);
743+
void *start, *end;
744+
745+
if ((void *)__identity_base < lowcore_end) {
746+
start = max(lowcore_start, (void *)__identity_base);
747+
end = min(lowcore_end, (void *)(__identity_base + ident_map_size));
748+
memblock_reserve(__pa(start), __pa(end));
749+
}
750+
}
751+
752+
/*
753+
* Reserve memory used for absolute lowcore/command line/kernel image.
738754
*/
739755
static void __init reserve_kernel(void)
740756
{
@@ -918,6 +934,7 @@ void __init setup_arch(char **cmdline_p)
918934

919935
/* Do some memory reservations *before* memory is added to memblock */
920936
reserve_pgtables();
937+
reserve_lowcore();
921938
reserve_kernel();
922939
reserve_initrd();
923940
reserve_certificate_list();

arch/s390/kernel/vmlinux.lds.S

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ PHDRS {
3939

4040
SECTIONS
4141
{
42-
. = __START_KERNEL;
42+
. = TEXT_OFFSET;
4343
.text : {
4444
_stext = .; /* Start of text section */
4545
_text = .; /* Text and read-only data */

arch/s390/tools/relocs.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ static int do_reloc(struct section *sec, Elf_Rel *rel)
280280
case R_390_GOTOFF64:
281281
break;
282282
case R_390_64:
283-
add_reloc(&relocs64, offset - ehdr.e_entry);
283+
add_reloc(&relocs64, offset);
284284
break;
285285
default:
286286
die("Unsupported relocation type: %d\n", r_type);

drivers/s390/crypto/ap_bus.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -971,11 +971,16 @@ int ap_driver_register(struct ap_driver *ap_drv, struct module *owner,
971971
char *name)
972972
{
973973
struct device_driver *drv = &ap_drv->driver;
974+
int rc;
974975

975976
drv->bus = &ap_bus_type;
976977
drv->owner = owner;
977978
drv->name = name;
978-
return driver_register(drv);
979+
rc = driver_register(drv);
980+
981+
ap_check_bindings_complete();
982+
983+
return rc;
979984
}
980985
EXPORT_SYMBOL(ap_driver_register);
981986

0 commit comments

Comments
 (0)