xref: /openbmc/linux/arch/s390/boot/kaslr.c (revision 0c4ec024)
1b2d24b97SGerald Schaefer // SPDX-License-Identifier: GPL-2.0
2b2d24b97SGerald Schaefer /*
3b2d24b97SGerald Schaefer  * Copyright IBM Corp. 2019
4b2d24b97SGerald Schaefer  */
5ca5999fdSMike Rapoport #include <linux/pgtable.h>
665fddcfcSMike Rapoport #include <asm/mem_detect.h>
7b2d24b97SGerald Schaefer #include <asm/cpacf.h>
8b2d24b97SGerald Schaefer #include <asm/timex.h>
9b2d24b97SGerald Schaefer #include <asm/sclp.h>
10*0c4ec024SVasily Gorbik #include <asm/kasan.h>
11b2d24b97SGerald Schaefer #include "compressed/decompressor.h"
12868202ceSVasily Gorbik #include "boot.h"
13b2d24b97SGerald Schaefer 
14b2d24b97SGerald Schaefer #define PRNG_MODE_TDES	 1
15b2d24b97SGerald Schaefer #define PRNG_MODE_SHA512 2
16b2d24b97SGerald Schaefer #define PRNG_MODE_TRNG	 3
17b2d24b97SGerald Schaefer 
18b2d24b97SGerald Schaefer struct prno_parm {
19b2d24b97SGerald Schaefer 	u32 res;
20b2d24b97SGerald Schaefer 	u32 reseed_counter;
21b2d24b97SGerald Schaefer 	u64 stream_bytes;
22b2d24b97SGerald Schaefer 	u8  V[112];
23b2d24b97SGerald Schaefer 	u8  C[112];
24b2d24b97SGerald Schaefer };
25b2d24b97SGerald Schaefer 
26b2d24b97SGerald Schaefer struct prng_parm {
27b2d24b97SGerald Schaefer 	u8  parm_block[32];
28b2d24b97SGerald Schaefer 	u32 reseed_counter;
29b2d24b97SGerald Schaefer 	u64 byte_counter;
30b2d24b97SGerald Schaefer };
31b2d24b97SGerald Schaefer 
32b2d24b97SGerald Schaefer static int check_prng(void)
33b2d24b97SGerald Schaefer {
34b2d24b97SGerald Schaefer 	if (!cpacf_query_func(CPACF_KMC, CPACF_KMC_PRNG)) {
35b2d24b97SGerald Schaefer 		sclp_early_printk("KASLR disabled: CPU has no PRNG\n");
36b2d24b97SGerald Schaefer 		return 0;
37b2d24b97SGerald Schaefer 	}
38b2d24b97SGerald Schaefer 	if (cpacf_query_func(CPACF_PRNO, CPACF_PRNO_TRNG))
39b2d24b97SGerald Schaefer 		return PRNG_MODE_TRNG;
40b2d24b97SGerald Schaefer 	if (cpacf_query_func(CPACF_PRNO, CPACF_PRNO_SHA512_DRNG_GEN))
41b2d24b97SGerald Schaefer 		return PRNG_MODE_SHA512;
42b2d24b97SGerald Schaefer 	else
43b2d24b97SGerald Schaefer 		return PRNG_MODE_TDES;
44b2d24b97SGerald Schaefer }
45b2d24b97SGerald Schaefer 
4607a699bcSVasily Gorbik static int get_random(unsigned long limit, unsigned long *value)
47b2d24b97SGerald Schaefer {
48b2d24b97SGerald Schaefer 	struct prng_parm prng = {
49b2d24b97SGerald Schaefer 		/* initial parameter block for tdes mode, copied from libica */
50b2d24b97SGerald Schaefer 		.parm_block = {
51b2d24b97SGerald Schaefer 			0x0F, 0x2B, 0x8E, 0x63, 0x8C, 0x8E, 0xD2, 0x52,
52b2d24b97SGerald Schaefer 			0x64, 0xB7, 0xA0, 0x7B, 0x75, 0x28, 0xB8, 0xF4,
53b2d24b97SGerald Schaefer 			0x75, 0x5F, 0xD2, 0xA6, 0x8D, 0x97, 0x11, 0xFF,
54b2d24b97SGerald Schaefer 			0x49, 0xD8, 0x23, 0xF3, 0x7E, 0x21, 0xEC, 0xA0
55b2d24b97SGerald Schaefer 		},
56b2d24b97SGerald Schaefer 	};
57b2d24b97SGerald Schaefer 	unsigned long seed, random;
58b2d24b97SGerald Schaefer 	struct prno_parm prno;
59b2d24b97SGerald Schaefer 	__u64 entropy[4];
60b2d24b97SGerald Schaefer 	int mode, i;
61b2d24b97SGerald Schaefer 
62b2d24b97SGerald Schaefer 	mode = check_prng();
63b2d24b97SGerald Schaefer 	seed = get_tod_clock_fast();
64b2d24b97SGerald Schaefer 	switch (mode) {
65b2d24b97SGerald Schaefer 	case PRNG_MODE_TRNG:
66b2d24b97SGerald Schaefer 		cpacf_trng(NULL, 0, (u8 *) &random, sizeof(random));
67b2d24b97SGerald Schaefer 		break;
68b2d24b97SGerald Schaefer 	case PRNG_MODE_SHA512:
69b2d24b97SGerald Schaefer 		cpacf_prno(CPACF_PRNO_SHA512_DRNG_SEED, &prno, NULL, 0,
70b2d24b97SGerald Schaefer 			   (u8 *) &seed, sizeof(seed));
71b2d24b97SGerald Schaefer 		cpacf_prno(CPACF_PRNO_SHA512_DRNG_GEN, &prno, (u8 *) &random,
72b2d24b97SGerald Schaefer 			   sizeof(random), NULL, 0);
73b2d24b97SGerald Schaefer 		break;
74b2d24b97SGerald Schaefer 	case PRNG_MODE_TDES:
75b2d24b97SGerald Schaefer 		/* add entropy */
76b2d24b97SGerald Schaefer 		*(unsigned long *) prng.parm_block ^= seed;
77b2d24b97SGerald Schaefer 		for (i = 0; i < 16; i++) {
78b2d24b97SGerald Schaefer 			cpacf_kmc(CPACF_KMC_PRNG, prng.parm_block,
79788d6715SNathan Chancellor 				  (u8 *) entropy, (u8 *) entropy,
80b2d24b97SGerald Schaefer 				  sizeof(entropy));
81b2d24b97SGerald Schaefer 			memcpy(prng.parm_block, entropy, sizeof(entropy));
82b2d24b97SGerald Schaefer 		}
83b2d24b97SGerald Schaefer 		random = seed;
84b2d24b97SGerald Schaefer 		cpacf_kmc(CPACF_KMC_PRNG, prng.parm_block, (u8 *) &random,
85b2d24b97SGerald Schaefer 			  (u8 *) &random, sizeof(random));
86b2d24b97SGerald Schaefer 		break;
87b2d24b97SGerald Schaefer 	default:
8807a699bcSVasily Gorbik 		return -1;
89b2d24b97SGerald Schaefer 	}
9007a699bcSVasily Gorbik 	*value = random % limit;
9107a699bcSVasily Gorbik 	return 0;
92b2d24b97SGerald Schaefer }
93b2d24b97SGerald Schaefer 
945c46f276SVasily Gorbik /*
955c46f276SVasily Gorbik  * To randomize kernel base address we have to consider several facts:
965c46f276SVasily Gorbik  * 1. physical online memory might not be continuous and have holes. mem_detect
975c46f276SVasily Gorbik  *    info contains list of online memory ranges we should consider.
985c46f276SVasily Gorbik  * 2. we have several memory regions which are occupied and we should not
995c46f276SVasily Gorbik  *    overlap and destroy them. Currently safe_addr tells us the border below
1005c46f276SVasily Gorbik  *    which all those occupied regions are. We are safe to use anything above
1015c46f276SVasily Gorbik  *    safe_addr.
1025c46f276SVasily Gorbik  * 3. the upper limit might apply as well, even if memory above that limit is
1035c46f276SVasily Gorbik  *    online. Currently those limitations are:
1045c46f276SVasily Gorbik  *    3.1. Limit set by "mem=" kernel command line option
1055c46f276SVasily Gorbik  *    3.2. memory reserved at the end for kasan initialization.
1065c46f276SVasily Gorbik  * 4. kernel base address must be aligned to THREAD_SIZE (kernel stack size).
1075c46f276SVasily Gorbik  *    Which is required for CONFIG_CHECK_STACK. Currently THREAD_SIZE is 4 pages
1085c46f276SVasily Gorbik  *    (16 pages when the kernel is built with kasan enabled)
1095c46f276SVasily Gorbik  * Assumptions:
1105c46f276SVasily Gorbik  * 1. kernel size (including .bss size) and upper memory limit are page aligned.
1115c46f276SVasily Gorbik  * 2. mem_detect memory region start is THREAD_SIZE aligned / end is PAGE_SIZE
1125c46f276SVasily Gorbik  *    aligned (in practice memory configurations granularity on z/VM and LPAR
1135c46f276SVasily Gorbik  *    is 1mb).
1145c46f276SVasily Gorbik  *
1155c46f276SVasily Gorbik  * To guarantee uniform distribution of kernel base address among all suitable
1165c46f276SVasily Gorbik  * addresses we generate random value just once. For that we need to build a
1175c46f276SVasily Gorbik  * continuous range in which every value would be suitable. We can build this
1185c46f276SVasily Gorbik  * range by simply counting all suitable addresses (let's call them positions)
1195c46f276SVasily Gorbik  * which would be valid as kernel base address. To count positions we iterate
1205c46f276SVasily Gorbik  * over online memory ranges. For each range which is big enough for the
1215c46f276SVasily Gorbik  * kernel image we count all suitable addresses we can put the kernel image at
1225c46f276SVasily Gorbik  * that is
1235c46f276SVasily Gorbik  * (end - start - kernel_size) / THREAD_SIZE + 1
1245c46f276SVasily Gorbik  * Two functions count_valid_kernel_positions and position_to_address help
1255c46f276SVasily Gorbik  * to count positions in memory range given and then convert position back
1265c46f276SVasily Gorbik  * to address.
1275c46f276SVasily Gorbik  */
1285c46f276SVasily Gorbik static unsigned long count_valid_kernel_positions(unsigned long kernel_size,
1295c46f276SVasily Gorbik 						  unsigned long _min,
1305c46f276SVasily Gorbik 						  unsigned long _max)
1315c46f276SVasily Gorbik {
1325c46f276SVasily Gorbik 	unsigned long start, end, pos = 0;
1335c46f276SVasily Gorbik 	int i;
1345c46f276SVasily Gorbik 
1355c46f276SVasily Gorbik 	for_each_mem_detect_block(i, &start, &end) {
1365c46f276SVasily Gorbik 		if (_min >= end)
1375c46f276SVasily Gorbik 			continue;
1385c46f276SVasily Gorbik 		if (start >= _max)
1395c46f276SVasily Gorbik 			break;
1405c46f276SVasily Gorbik 		start = max(_min, start);
1415c46f276SVasily Gorbik 		end = min(_max, end);
1425c46f276SVasily Gorbik 		if (end - start < kernel_size)
1435c46f276SVasily Gorbik 			continue;
1445c46f276SVasily Gorbik 		pos += (end - start - kernel_size) / THREAD_SIZE + 1;
1455c46f276SVasily Gorbik 	}
1465c46f276SVasily Gorbik 
1475c46f276SVasily Gorbik 	return pos;
1485c46f276SVasily Gorbik }
1495c46f276SVasily Gorbik 
1505c46f276SVasily Gorbik static unsigned long position_to_address(unsigned long pos, unsigned long kernel_size,
1515c46f276SVasily Gorbik 				 unsigned long _min, unsigned long _max)
1525c46f276SVasily Gorbik {
1535c46f276SVasily Gorbik 	unsigned long start, end;
1545c46f276SVasily Gorbik 	int i;
1555c46f276SVasily Gorbik 
1565c46f276SVasily Gorbik 	for_each_mem_detect_block(i, &start, &end) {
1575c46f276SVasily Gorbik 		if (_min >= end)
1585c46f276SVasily Gorbik 			continue;
1595c46f276SVasily Gorbik 		if (start >= _max)
1605c46f276SVasily Gorbik 			break;
1615c46f276SVasily Gorbik 		start = max(_min, start);
1625c46f276SVasily Gorbik 		end = min(_max, end);
1635c46f276SVasily Gorbik 		if (end - start < kernel_size)
1645c46f276SVasily Gorbik 			continue;
1655c46f276SVasily Gorbik 		if ((end - start - kernel_size) / THREAD_SIZE + 1 >= pos)
1665c46f276SVasily Gorbik 			return start + (pos - 1) * THREAD_SIZE;
1675c46f276SVasily Gorbik 		pos -= (end - start - kernel_size) / THREAD_SIZE + 1;
1685c46f276SVasily Gorbik 	}
1695c46f276SVasily Gorbik 
1705c46f276SVasily Gorbik 	return 0;
1715c46f276SVasily Gorbik }
1725c46f276SVasily Gorbik 
173b2d24b97SGerald Schaefer unsigned long get_random_base(unsigned long safe_addr)
174b2d24b97SGerald Schaefer {
1755c46f276SVasily Gorbik 	unsigned long memory_limit = get_mem_detect_end();
1765c46f276SVasily Gorbik 	unsigned long base_pos, max_pos, kernel_size;
177759d4899SVasily Gorbik 	unsigned long kasan_needs;
178b2d24b97SGerald Schaefer 	int i;
179b2d24b97SGerald Schaefer 
1805c46f276SVasily Gorbik 	if (memory_end_set)
1815c46f276SVasily Gorbik 		memory_limit = min(memory_limit, memory_end);
1825c46f276SVasily Gorbik 
183*0c4ec024SVasily Gorbik 	/*
184*0c4ec024SVasily Gorbik 	 * Avoid putting kernel in the end of physical memory
185*0c4ec024SVasily Gorbik 	 * which kasan will use for shadow memory and early pgtable
186*0c4ec024SVasily Gorbik 	 * mapping allocations.
187*0c4ec024SVasily Gorbik 	 */
188*0c4ec024SVasily Gorbik 	memory_limit -= kasan_estimate_memory_needs(memory_limit);
189*0c4ec024SVasily Gorbik 
190b2d24b97SGerald Schaefer 	if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && INITRD_START && INITRD_SIZE) {
191b2d24b97SGerald Schaefer 		if (safe_addr < INITRD_START + INITRD_SIZE)
192b2d24b97SGerald Schaefer 			safe_addr = INITRD_START + INITRD_SIZE;
193b2d24b97SGerald Schaefer 	}
194b2d24b97SGerald Schaefer 	safe_addr = ALIGN(safe_addr, THREAD_SIZE);
195b2d24b97SGerald Schaefer 
196b2d24b97SGerald Schaefer 	kernel_size = vmlinux.image_size + vmlinux.bss_size;
1975c46f276SVasily Gorbik 	if (safe_addr + kernel_size > memory_limit)
1985c46f276SVasily Gorbik 		return 0;
1995c46f276SVasily Gorbik 
2005c46f276SVasily Gorbik 	max_pos = count_valid_kernel_positions(kernel_size, safe_addr, memory_limit);
2015c46f276SVasily Gorbik 	if (!max_pos) {
202b2d24b97SGerald Schaefer 		sclp_early_printk("KASLR disabled: not enough memory\n");
203b2d24b97SGerald Schaefer 		return 0;
204b2d24b97SGerald Schaefer 	}
205b2d24b97SGerald Schaefer 
2065c46f276SVasily Gorbik 	/* we need a value in the range [1, base_pos] inclusive */
2075c46f276SVasily Gorbik 	if (get_random(max_pos, &base_pos))
208b2d24b97SGerald Schaefer 		return 0;
2095c46f276SVasily Gorbik 	return position_to_address(base_pos + 1, kernel_size, safe_addr, memory_limit);
210b2d24b97SGerald Schaefer }
211