xref: /openbmc/linux/arch/s390/boot/kaslr.c (revision 6e259bc5)
1b2d24b97SGerald Schaefer // SPDX-License-Identifier: GPL-2.0
2b2d24b97SGerald Schaefer /*
3b2d24b97SGerald Schaefer  * Copyright IBM Corp. 2019
4b2d24b97SGerald Schaefer  */
5ca5999fdSMike Rapoport #include <linux/pgtable.h>
68c37cb7dSVasily Gorbik #include <asm/physmem_info.h>
7b2d24b97SGerald Schaefer #include <asm/cpacf.h>
8b2d24b97SGerald Schaefer #include <asm/timex.h>
9b2d24b97SGerald Schaefer #include <asm/sclp.h>
100c4ec024SVasily Gorbik #include <asm/kasan.h>
11edd4a866SHeiko Carstens #include "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 
check_prng(void)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 
get_random(unsigned long limit,unsigned long * value)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 
sort_reserved_ranges(struct reserved_range * res,unsigned long size)94*6e259bc5SVasily Gorbik static void sort_reserved_ranges(struct reserved_range *res, unsigned long size)
955c46f276SVasily Gorbik {
96*6e259bc5SVasily Gorbik 	struct reserved_range tmp;
97*6e259bc5SVasily Gorbik 	int i, j;
985c46f276SVasily Gorbik 
99*6e259bc5SVasily Gorbik 	for (i = 1; i < size; i++) {
100*6e259bc5SVasily Gorbik 		tmp = res[i];
101*6e259bc5SVasily Gorbik 		for (j = i - 1; j >= 0 && res[j].start > tmp.start; j--)
102*6e259bc5SVasily Gorbik 			res[j + 1] = res[j];
103*6e259bc5SVasily Gorbik 		res[j + 1] = tmp;
104*6e259bc5SVasily Gorbik 	}
105*6e259bc5SVasily Gorbik }
106*6e259bc5SVasily Gorbik 
iterate_valid_positions(unsigned long size,unsigned long align,unsigned long _min,unsigned long _max,struct reserved_range * res,size_t res_count,bool pos_count,unsigned long find_pos)107*6e259bc5SVasily Gorbik static unsigned long iterate_valid_positions(unsigned long size, unsigned long align,
108*6e259bc5SVasily Gorbik 					     unsigned long _min, unsigned long _max,
109*6e259bc5SVasily Gorbik 					     struct reserved_range *res, size_t res_count,
110*6e259bc5SVasily Gorbik 					     bool pos_count, unsigned long find_pos)
111*6e259bc5SVasily Gorbik {
112*6e259bc5SVasily Gorbik 	unsigned long start, end, tmp_end, range_pos, pos = 0;
113*6e259bc5SVasily Gorbik 	struct reserved_range *res_end = res + res_count;
114*6e259bc5SVasily Gorbik 	struct reserved_range *skip_res;
115*6e259bc5SVasily Gorbik 	int i;
116*6e259bc5SVasily Gorbik 
117*6e259bc5SVasily Gorbik 	align = max(align, 8UL);
118*6e259bc5SVasily Gorbik 	_min = round_up(_min, align);
119*6e259bc5SVasily Gorbik 	for_each_physmem_usable_range(i, &start, &end) {
120*6e259bc5SVasily Gorbik 		if (_min >= end)
121*6e259bc5SVasily Gorbik 			continue;
122*6e259bc5SVasily Gorbik 		start = round_up(start, align);
123*6e259bc5SVasily Gorbik 		if (start >= _max)
124*6e259bc5SVasily Gorbik 			break;
125*6e259bc5SVasily Gorbik 		start = max(_min, start);
126*6e259bc5SVasily Gorbik 		end = min(_max, end);
127*6e259bc5SVasily Gorbik 
128*6e259bc5SVasily Gorbik 		while (start + size <= end) {
129*6e259bc5SVasily Gorbik 			/* skip reserved ranges below the start */
130*6e259bc5SVasily Gorbik 			while (res && res->end <= start) {
131*6e259bc5SVasily Gorbik 				res++;
132*6e259bc5SVasily Gorbik 				if (res >= res_end)
133*6e259bc5SVasily Gorbik 					res = NULL;
134*6e259bc5SVasily Gorbik 			}
135*6e259bc5SVasily Gorbik 			skip_res = NULL;
136*6e259bc5SVasily Gorbik 			tmp_end = end;
137*6e259bc5SVasily Gorbik 			/* has intersecting reserved range */
138*6e259bc5SVasily Gorbik 			if (res && res->start < end) {
139*6e259bc5SVasily Gorbik 				skip_res = res;
140*6e259bc5SVasily Gorbik 				tmp_end = res->start;
141*6e259bc5SVasily Gorbik 			}
142*6e259bc5SVasily Gorbik 			if (start + size <= tmp_end) {
143*6e259bc5SVasily Gorbik 				range_pos = (tmp_end - start - size) / align + 1;
144*6e259bc5SVasily Gorbik 				if (pos_count) {
145*6e259bc5SVasily Gorbik 					pos += range_pos;
146*6e259bc5SVasily Gorbik 				} else {
147*6e259bc5SVasily Gorbik 					if (range_pos >= find_pos)
148*6e259bc5SVasily Gorbik 						return start + (find_pos - 1) * align;
149*6e259bc5SVasily Gorbik 					find_pos -= range_pos;
150*6e259bc5SVasily Gorbik 				}
151*6e259bc5SVasily Gorbik 			}
152*6e259bc5SVasily Gorbik 			if (!skip_res)
153*6e259bc5SVasily Gorbik 				break;
154*6e259bc5SVasily Gorbik 			start = round_up(skip_res->end, align);
155*6e259bc5SVasily Gorbik 		}
156*6e259bc5SVasily Gorbik 	}
157*6e259bc5SVasily Gorbik 
158*6e259bc5SVasily Gorbik 	return pos_count ? pos : 0;
159*6e259bc5SVasily Gorbik }
160*6e259bc5SVasily Gorbik 
161*6e259bc5SVasily Gorbik /*
162*6e259bc5SVasily Gorbik  * Two types of decompressor memory allocations/reserves are considered
163*6e259bc5SVasily Gorbik  * differently.
164*6e259bc5SVasily Gorbik  *
165*6e259bc5SVasily Gorbik  * "Static" or "single" allocations are done via physmem_alloc_range() and
166*6e259bc5SVasily Gorbik  * physmem_reserve(), and they are listed in physmem_info.reserved[]. Each
167*6e259bc5SVasily Gorbik  * type of "static" allocation can only have one allocation per type and
168*6e259bc5SVasily Gorbik  * cannot have chains.
169*6e259bc5SVasily Gorbik  *
170*6e259bc5SVasily Gorbik  * On the other hand, "dynamic" or "repetitive" allocations are done via
171*6e259bc5SVasily Gorbik  * physmem_alloc_top_down(). These allocations are tightly packed together
172*6e259bc5SVasily Gorbik  * top down from the end of online memory. physmem_alloc_pos represents
173*6e259bc5SVasily Gorbik  * current position where those allocations start.
174*6e259bc5SVasily Gorbik  *
175*6e259bc5SVasily Gorbik  * Functions randomize_within_range() and iterate_valid_positions()
176*6e259bc5SVasily Gorbik  * only consider "dynamic" allocations by never looking above
177*6e259bc5SVasily Gorbik  * physmem_alloc_pos. "Static" allocations, however, are explicitly
178*6e259bc5SVasily Gorbik  * considered by checking the "res" (reserves) array. The first
179*6e259bc5SVasily Gorbik  * reserved_range of a "dynamic" allocation may also be checked along the
180*6e259bc5SVasily Gorbik  * way, but it will always be above the maximum value anyway.
181*6e259bc5SVasily Gorbik  */
randomize_within_range(unsigned long size,unsigned long align,unsigned long min,unsigned long max)182*6e259bc5SVasily Gorbik unsigned long randomize_within_range(unsigned long size, unsigned long align,
183*6e259bc5SVasily Gorbik 				     unsigned long min, unsigned long max)
184*6e259bc5SVasily Gorbik {
185*6e259bc5SVasily Gorbik 	struct reserved_range res[RR_MAX];
186*6e259bc5SVasily Gorbik 	unsigned long max_pos, pos;
187*6e259bc5SVasily Gorbik 
188*6e259bc5SVasily Gorbik 	memcpy(res, physmem_info.reserved, sizeof(res));
189*6e259bc5SVasily Gorbik 	sort_reserved_ranges(res, ARRAY_SIZE(res));
190*6e259bc5SVasily Gorbik 	max = min(max, get_physmem_alloc_pos());
191*6e259bc5SVasily Gorbik 
192*6e259bc5SVasily Gorbik 	max_pos = iterate_valid_positions(size, align, min, max, res, ARRAY_SIZE(res), true, 0);
193*6e259bc5SVasily Gorbik 	if (!max_pos)
1945c46f276SVasily Gorbik 		return 0;
195*6e259bc5SVasily Gorbik 	if (get_random(max_pos, &pos))
196*6e259bc5SVasily Gorbik 		return 0;
197*6e259bc5SVasily Gorbik 	return iterate_valid_positions(size, align, min, max, res, ARRAY_SIZE(res), false, pos + 1);
198b2d24b97SGerald Schaefer }
199