Skip to content

Commit 54f2ecc

Browse files
author
Alexander Gordeev
committed
s390: Map kernel at fixed location when KASLR is disabled
Since kernel virtual and physical address spaces are uncoupled the kernel is mapped at the top of the virtual address space in case KASLR is disabled. That does not pose any issue with regard to the kernel booting and operation, but makes it difficult to use a generated vmlinux with some debugging tools (e.g. gdb), because the exact location of the kernel image in virtual memory is unknown. Make that location known and introduce CONFIG_KERNEL_IMAGE_BASE configuration option. A custom CONFIG_KERNEL_IMAGE_BASE value that would break the virtual memory layout leads to a build error. The kernel image size is defined by KERNEL_IMAGE_SIZE macro and set to 512 MB, by analogy with x86. Suggested-by: Vasily Gorbik <gor@linux.ibm.com> Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
1 parent c98d2ec commit 54f2ecc

5 files changed

Lines changed: 51 additions & 11 deletions

File tree

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4780,7 +4780,9 @@
47804780

47814781
prot_virt= [S390] enable hosting protected virtual machines
47824782
isolated from the hypervisor (if hardware supports
4783-
that).
4783+
that). If enabled, the default kernel base address
4784+
might be overridden even when Kernel Address Space
4785+
Layout Randomization is disabled.
47844786
Format: <bool>
47854787

47864788
psi= [KNL] Enable or disable pressure stall information

arch/s390/Kconfig

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,25 @@ config RANDOMIZE_BASE
614614
as a security feature that deters exploit attempts relying on
615615
knowledge of the location of kernel internals.
616616

617+
config KERNEL_IMAGE_BASE
618+
hex "Kernel image base address"
619+
range 0x100000 0x1FFFFFE0000000 if !KASAN
620+
range 0x100000 0x1BFFFFE0000000 if KASAN
621+
default 0x3FFE0000000 if !KASAN
622+
default 0x7FFFE0000000 if KASAN
623+
help
624+
This is the address at which the kernel image is loaded in case
625+
Kernel Address Space Layout Randomization (KASLR) is disabled.
626+
627+
In case the Protected virtualization guest support is enabled the
628+
Ultravisor imposes a virtual address limit. If the value of this
629+
option leads to the kernel image exceeding the Ultravisor limit,
630+
this option is ignored and the image is loaded below the limit.
631+
632+
If the value of this option leads to the kernel image overlapping
633+
the virtual memory where other data structures are located, this
634+
option is ignored and the image is loaded above the structures.
635+
617636
endmenu
618637

619638
menu "Memory setup"

arch/s390/boot/startup.c

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,8 @@ static unsigned long get_vmem_size(unsigned long identity_size,
281281

282282
static unsigned long setup_kernel_memory_layout(unsigned long kernel_size)
283283
{
284-
unsigned long kernel_start, kernel_end;
285284
unsigned long vmemmap_start;
285+
unsigned long kernel_start;
286286
unsigned long asce_limit;
287287
unsigned long rte_size;
288288
unsigned long pages;
@@ -294,11 +294,18 @@ static unsigned long setup_kernel_memory_layout(unsigned long kernel_size)
294294
vmemmap_size = SECTION_ALIGN_UP(pages) * sizeof(struct page);
295295

296296
/* choose kernel address space layout: 4 or 3 levels. */
297+
BUILD_BUG_ON(!IS_ALIGNED(__NO_KASLR_START_KERNEL, THREAD_SIZE));
298+
BUILD_BUG_ON(__NO_KASLR_END_KERNEL > _REGION1_SIZE);
297299
vsize = get_vmem_size(ident_map_size, vmemmap_size, vmalloc_size, _REGION3_SIZE);
298-
if (IS_ENABLED(CONFIG_KASAN) || (vsize > _REGION2_SIZE)) {
300+
if (IS_ENABLED(CONFIG_KASAN) || __NO_KASLR_END_KERNEL > _REGION2_SIZE ||
301+
(vsize > _REGION2_SIZE && kaslr_enabled())) {
299302
asce_limit = _REGION1_SIZE;
300-
rte_size = _REGION2_SIZE;
301-
vsize = get_vmem_size(ident_map_size, vmemmap_size, vmalloc_size, _REGION2_SIZE);
303+
if (__NO_KASLR_END_KERNEL > _REGION2_SIZE) {
304+
rte_size = _REGION2_SIZE;
305+
vsize = get_vmem_size(ident_map_size, vmemmap_size, vmalloc_size, _REGION2_SIZE);
306+
} else {
307+
rte_size = _REGION3_SIZE;
308+
}
302309
} else {
303310
asce_limit = _REGION2_SIZE;
304311
rte_size = _REGION3_SIZE;
@@ -308,24 +315,32 @@ static unsigned long setup_kernel_memory_layout(unsigned long kernel_size)
308315
* Forcing modules and vmalloc area under the ultravisor
309316
* secure storage limit, so that any vmalloc allocation
310317
* we do could be used to back secure guest storage.
318+
*
319+
* Assume the secure storage limit always exceeds _REGION2_SIZE,
320+
* otherwise asce_limit and rte_size would have been adjusted.
311321
*/
312322
vmax = adjust_to_uv_max(asce_limit);
313323
#ifdef CONFIG_KASAN
324+
BUILD_BUG_ON(__NO_KASLR_END_KERNEL > KASAN_SHADOW_START);
314325
/* force vmalloc and modules below kasan shadow */
315326
vmax = min(vmax, KASAN_SHADOW_START);
316327
#endif
317-
kernel_end = vmax;
328+
vsize = min(vsize, vmax);
318329
if (kaslr_enabled()) {
319-
unsigned long kaslr_len, slots, pos;
330+
unsigned long kernel_end, kaslr_len, slots, pos;
320331

321-
vsize = min(vsize, vmax);
322332
kaslr_len = max(KASLR_LEN, vmax - vsize);
323333
slots = DIV_ROUND_UP(kaslr_len - kernel_size, THREAD_SIZE);
324334
if (get_random(slots, &pos))
325335
pos = 0;
326-
kernel_end -= pos * THREAD_SIZE;
336+
kernel_end = vmax - pos * THREAD_SIZE;
337+
kernel_start = round_down(kernel_end - kernel_size, THREAD_SIZE);
338+
} else if (vmax < __NO_KASLR_END_KERNEL || vsize > __NO_KASLR_END_KERNEL) {
339+
kernel_start = round_down(vmax - kernel_size, THREAD_SIZE);
340+
decompressor_printk("The kernel base address is forced to %lx\n", kernel_start);
341+
} else {
342+
kernel_start = __NO_KASLR_START_KERNEL;
327343
}
328-
kernel_start = round_down(kernel_end - kernel_size, THREAD_SIZE);
329344
__kaslr_offset = kernel_start;
330345

331346
MODULES_END = round_down(kernel_start, _SEGMENT_SIZE);

arch/s390/include/asm/page.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,4 +273,8 @@ static inline unsigned long virt_to_pfn(const void *kaddr)
273273
#include <asm-generic/memory_model.h>
274274
#include <asm-generic/getorder.h>
275275

276+
#define KERNEL_IMAGE_SIZE (512 * 1024 * 1024)
277+
#define __NO_KASLR_START_KERNEL CONFIG_KERNEL_IMAGE_BASE
278+
#define __NO_KASLR_END_KERNEL (__NO_KASLR_START_KERNEL + KERNEL_IMAGE_SIZE)
279+
276280
#endif /* _S390_PAGE_H */

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);
283+
add_reloc(&relocs64, offset - (ehdr.e_entry - 0x100000));
284284
break;
285285
default:
286286
die("Unsupported relocation type: %d\n", r_type);

0 commit comments

Comments
 (0)