Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/s390/boot/kaslr.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Copyright IBM Corp. 2019
4
*/
5
#include <linux/pgtable.h>
6
#include <asm/physmem_info.h>
7
#include <asm/cpacf.h>
8
#include <asm/timex.h>
9
#include <asm/sclp.h>
10
#include <asm/kasan.h>
11
#include "decompressor.h"
12
#include "boot.h"
13
14
#define PRNG_MODE_TDES 1
15
#define PRNG_MODE_SHA512 2
16
#define PRNG_MODE_TRNG 3
17
18
struct prno_parm {
19
u32 res;
20
u32 reseed_counter;
21
u64 stream_bytes;
22
u8 V[112];
23
u8 C[112];
24
};
25
26
struct prng_parm {
27
u8 parm_block[32];
28
u32 reseed_counter;
29
u64 byte_counter;
30
};
31
32
static int check_prng(void)
33
{
34
if (!cpacf_query_func(CPACF_KMC, CPACF_KMC_PRNG)) {
35
boot_warn("KASLR disabled: CPU has no PRNG\n");
36
return 0;
37
}
38
if (cpacf_query_func(CPACF_PRNO, CPACF_PRNO_TRNG))
39
return PRNG_MODE_TRNG;
40
if (cpacf_query_func(CPACF_PRNO, CPACF_PRNO_SHA512_DRNG_GEN))
41
return PRNG_MODE_SHA512;
42
else
43
return PRNG_MODE_TDES;
44
}
45
46
int get_random(unsigned long limit, unsigned long *value)
47
{
48
struct prng_parm prng = {
49
/* initial parameter block for tdes mode, copied from libica */
50
.parm_block = {
51
0x0F, 0x2B, 0x8E, 0x63, 0x8C, 0x8E, 0xD2, 0x52,
52
0x64, 0xB7, 0xA0, 0x7B, 0x75, 0x28, 0xB8, 0xF4,
53
0x75, 0x5F, 0xD2, 0xA6, 0x8D, 0x97, 0x11, 0xFF,
54
0x49, 0xD8, 0x23, 0xF3, 0x7E, 0x21, 0xEC, 0xA0
55
},
56
};
57
unsigned long seed, random;
58
struct prno_parm prno;
59
__u64 entropy[4];
60
int mode, i;
61
62
mode = check_prng();
63
seed = get_tod_clock_fast();
64
switch (mode) {
65
case PRNG_MODE_TRNG:
66
cpacf_trng(NULL, 0, (u8 *) &random, sizeof(random));
67
break;
68
case PRNG_MODE_SHA512:
69
cpacf_prno(CPACF_PRNO_SHA512_DRNG_SEED, &prno, NULL, 0,
70
(u8 *) &seed, sizeof(seed));
71
cpacf_prno(CPACF_PRNO_SHA512_DRNG_GEN, &prno, (u8 *) &random,
72
sizeof(random), NULL, 0);
73
break;
74
case PRNG_MODE_TDES:
75
/* add entropy */
76
*(unsigned long *) prng.parm_block ^= seed;
77
for (i = 0; i < 16; i++) {
78
cpacf_kmc(CPACF_KMC_PRNG, prng.parm_block,
79
(u8 *) entropy, (u8 *) entropy,
80
sizeof(entropy));
81
memcpy(prng.parm_block, entropy, sizeof(entropy));
82
}
83
random = seed;
84
cpacf_kmc(CPACF_KMC_PRNG, prng.parm_block, (u8 *) &random,
85
(u8 *) &random, sizeof(random));
86
break;
87
default:
88
return -1;
89
}
90
*value = random % limit;
91
return 0;
92
}
93
94
static void sort_reserved_ranges(struct reserved_range *res, unsigned long size)
95
{
96
struct reserved_range tmp;
97
int i, j;
98
99
for (i = 1; i < size; i++) {
100
tmp = res[i];
101
for (j = i - 1; j >= 0 && res[j].start > tmp.start; j--)
102
res[j + 1] = res[j];
103
res[j + 1] = tmp;
104
}
105
}
106
107
static unsigned long iterate_valid_positions(unsigned long size, unsigned long align,
108
unsigned long _min, unsigned long _max,
109
struct reserved_range *res, size_t res_count,
110
bool pos_count, unsigned long find_pos)
111
{
112
unsigned long start, end, tmp_end, range_pos, pos = 0;
113
struct reserved_range *res_end = res + res_count;
114
struct reserved_range *skip_res;
115
int i;
116
117
align = max(align, 8UL);
118
_min = round_up(_min, align);
119
for_each_physmem_usable_range(i, &start, &end) {
120
if (_min >= end)
121
continue;
122
start = round_up(start, align);
123
if (start >= _max)
124
break;
125
start = max(_min, start);
126
end = min(_max, end);
127
128
while (start + size <= end) {
129
/* skip reserved ranges below the start */
130
while (res && res->end <= start) {
131
res++;
132
if (res >= res_end)
133
res = NULL;
134
}
135
skip_res = NULL;
136
tmp_end = end;
137
/* has intersecting reserved range */
138
if (res && res->start < end) {
139
skip_res = res;
140
tmp_end = res->start;
141
}
142
if (start + size <= tmp_end) {
143
range_pos = (tmp_end - start - size) / align + 1;
144
if (pos_count) {
145
pos += range_pos;
146
} else {
147
if (range_pos >= find_pos)
148
return start + (find_pos - 1) * align;
149
find_pos -= range_pos;
150
}
151
}
152
if (!skip_res)
153
break;
154
start = round_up(skip_res->end, align);
155
}
156
}
157
158
return pos_count ? pos : 0;
159
}
160
161
/*
162
* Two types of decompressor memory allocations/reserves are considered
163
* differently.
164
*
165
* "Static" or "single" allocations are done via physmem_alloc_range() and
166
* physmem_reserve(), and they are listed in physmem_info.reserved[]. Each
167
* type of "static" allocation can only have one allocation per type and
168
* cannot have chains.
169
*
170
* On the other hand, "dynamic" or "repetitive" allocations are done via
171
* physmem_alloc_or_die(). These allocations are tightly packed together
172
* top down from the end of online memory. physmem_alloc_pos represents
173
* current position where those allocations start.
174
*
175
* Functions randomize_within_range() and iterate_valid_positions()
176
* only consider "dynamic" allocations by never looking above
177
* physmem_alloc_pos. "Static" allocations, however, are explicitly
178
* considered by checking the "res" (reserves) array. The first
179
* reserved_range of a "dynamic" allocation may also be checked along the
180
* way, but it will always be above the maximum value anyway.
181
*/
182
unsigned long randomize_within_range(unsigned long size, unsigned long align,
183
unsigned long min, unsigned long max)
184
{
185
struct reserved_range res[RR_MAX];
186
unsigned long max_pos, pos;
187
188
memcpy(res, physmem_info.reserved, sizeof(res));
189
sort_reserved_ranges(res, ARRAY_SIZE(res));
190
max = min(max, get_physmem_alloc_pos());
191
192
max_pos = iterate_valid_positions(size, align, min, max, res, ARRAY_SIZE(res), true, 0);
193
if (!max_pos)
194
return 0;
195
if (get_random(max_pos, &pos))
196
return 0;
197
return iterate_valid_positions(size, align, min, max, res, ARRAY_SIZE(res), false, pos + 1);
198
}
199
200