hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/arch/s390/kernel/machine_kexec_file.c
....@@ -8,7 +8,13 @@
88 */
99
1010 #include <linux/elf.h>
11
+#include <linux/errno.h>
1112 #include <linux/kexec.h>
13
+#include <linux/module_signature.h>
14
+#include <linux/verification.h>
15
+#include <linux/vmalloc.h>
16
+#include <asm/boot_data.h>
17
+#include <asm/ipl.h>
1218 #include <asm/setup.h>
1319
1420 const struct kexec_file_ops * const kexec_file_loaders[] = {
....@@ -17,38 +23,64 @@
1723 NULL,
1824 };
1925
20
-int *kexec_file_update_kernel(struct kimage *image,
21
- struct s390_load_data *data)
26
+#ifdef CONFIG_KEXEC_SIG
27
+int s390_verify_sig(const char *kernel, unsigned long kernel_len)
2228 {
23
- unsigned long *loc;
29
+ const unsigned long marker_len = sizeof(MODULE_SIG_STRING) - 1;
30
+ struct module_signature *ms;
31
+ unsigned long sig_len;
32
+ int ret;
2433
25
- if (image->cmdline_buf_len >= ARCH_COMMAND_LINE_SIZE)
26
- return ERR_PTR(-EINVAL);
34
+ /* Skip signature verification when not secure IPLed. */
35
+ if (!ipl_secure_flag)
36
+ return 0;
2737
28
- if (image->cmdline_buf_len)
29
- memcpy(data->kernel_buf + COMMAND_LINE_OFFSET,
30
- image->cmdline_buf, image->cmdline_buf_len);
38
+ if (marker_len > kernel_len)
39
+ return -EKEYREJECTED;
3140
32
- if (image->type == KEXEC_TYPE_CRASH) {
33
- loc = (unsigned long *)(data->kernel_buf + OLDMEM_BASE_OFFSET);
34
- *loc = crashk_res.start;
41
+ if (memcmp(kernel + kernel_len - marker_len, MODULE_SIG_STRING,
42
+ marker_len))
43
+ return -EKEYREJECTED;
44
+ kernel_len -= marker_len;
3545
36
- loc = (unsigned long *)(data->kernel_buf + OLDMEM_SIZE_OFFSET);
37
- *loc = crashk_res.end - crashk_res.start + 1;
46
+ ms = (void *)kernel + kernel_len - sizeof(*ms);
47
+ kernel_len -= sizeof(*ms);
48
+
49
+ sig_len = be32_to_cpu(ms->sig_len);
50
+ if (sig_len >= kernel_len)
51
+ return -EKEYREJECTED;
52
+ kernel_len -= sig_len;
53
+
54
+ if (ms->id_type != PKEY_ID_PKCS7)
55
+ return -EKEYREJECTED;
56
+
57
+ if (ms->algo != 0 ||
58
+ ms->hash != 0 ||
59
+ ms->signer_len != 0 ||
60
+ ms->key_id_len != 0 ||
61
+ ms->__pad[0] != 0 ||
62
+ ms->__pad[1] != 0 ||
63
+ ms->__pad[2] != 0) {
64
+ return -EBADMSG;
3865 }
3966
40
- if (image->initrd_buf) {
41
- loc = (unsigned long *)(data->kernel_buf + INITRD_START_OFFSET);
42
- *loc = data->initrd_load_addr;
43
-
44
- loc = (unsigned long *)(data->kernel_buf + INITRD_SIZE_OFFSET);
45
- *loc = image->initrd_buf_len;
46
- }
47
-
48
- return NULL;
67
+ ret = verify_pkcs7_signature(kernel, kernel_len,
68
+ kernel + kernel_len, sig_len,
69
+ VERIFY_USE_SECONDARY_KEYRING,
70
+ VERIFYING_MODULE_SIGNATURE,
71
+ NULL, NULL);
72
+ if (ret == -ENOKEY && IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING))
73
+ ret = verify_pkcs7_signature(kernel, kernel_len,
74
+ kernel + kernel_len, sig_len,
75
+ VERIFY_USE_PLATFORM_KEYRING,
76
+ VERIFYING_MODULE_SIGNATURE,
77
+ NULL, NULL);
78
+ return ret;
4979 }
80
+#endif /* CONFIG_KEXEC_SIG */
5081
51
-static int kexec_file_update_purgatory(struct kimage *image)
82
+static int kexec_file_update_purgatory(struct kimage *image,
83
+ struct s390_load_data *data)
5284 {
5385 u64 entry, type;
5486 int ret;
....@@ -90,7 +122,8 @@
90122 return ret;
91123 }
92124
93
-int kexec_file_add_purgatory(struct kimage *image, struct s390_load_data *data)
125
+static int kexec_file_add_purgatory(struct kimage *image,
126
+ struct s390_load_data *data)
94127 {
95128 struct kexec_buf buf;
96129 int ret;
....@@ -105,21 +138,21 @@
105138 ret = kexec_load_purgatory(image, &buf);
106139 if (ret)
107140 return ret;
141
+ data->memsz += buf.memsz;
108142
109
- ret = kexec_file_update_purgatory(image);
110
- return ret;
143
+ return kexec_file_update_purgatory(image, data);
111144 }
112145
113
-int kexec_file_add_initrd(struct kimage *image, struct s390_load_data *data,
114
- char *initrd, unsigned long initrd_len)
146
+static int kexec_file_add_initrd(struct kimage *image,
147
+ struct s390_load_data *data)
115148 {
116149 struct kexec_buf buf;
117150 int ret;
118151
119152 buf.image = image;
120153
121
- buf.buffer = initrd;
122
- buf.bufsz = initrd_len;
154
+ buf.buffer = image->initrd_buf;
155
+ buf.bufsz = image->initrd_buf_len;
123156
124157 data->memsz = ALIGN(data->memsz, PAGE_SIZE);
125158 buf.mem = data->memsz;
....@@ -127,21 +160,122 @@
127160 buf.mem += crashk_res.start;
128161 buf.memsz = buf.bufsz;
129162
130
- data->initrd_load_addr = buf.mem;
163
+ data->parm->initrd_start = data->memsz;
164
+ data->parm->initrd_size = buf.memsz;
131165 data->memsz += buf.memsz;
132166
133167 ret = kexec_add_buffer(&buf);
168
+ if (ret)
169
+ return ret;
170
+
171
+ return ipl_report_add_component(data->report, &buf, 0, 0);
172
+}
173
+
174
+static int kexec_file_add_ipl_report(struct kimage *image,
175
+ struct s390_load_data *data)
176
+{
177
+ __u32 *lc_ipl_parmblock_ptr;
178
+ unsigned int len, ncerts;
179
+ struct kexec_buf buf;
180
+ unsigned long addr;
181
+ void *ptr, *end;
182
+ int ret;
183
+
184
+ buf.image = image;
185
+
186
+ data->memsz = ALIGN(data->memsz, PAGE_SIZE);
187
+ buf.mem = data->memsz;
188
+ if (image->type == KEXEC_TYPE_CRASH)
189
+ buf.mem += crashk_res.start;
190
+
191
+ ptr = (void *)ipl_cert_list_addr;
192
+ end = ptr + ipl_cert_list_size;
193
+ ncerts = 0;
194
+ while (ptr < end) {
195
+ ncerts++;
196
+ len = *(unsigned int *)ptr;
197
+ ptr += sizeof(len);
198
+ ptr += len;
199
+ }
200
+
201
+ addr = data->memsz + data->report->size;
202
+ addr += ncerts * sizeof(struct ipl_rb_certificate_entry);
203
+ ptr = (void *)ipl_cert_list_addr;
204
+ while (ptr < end) {
205
+ len = *(unsigned int *)ptr;
206
+ ptr += sizeof(len);
207
+ ipl_report_add_certificate(data->report, ptr, addr, len);
208
+ addr += len;
209
+ ptr += len;
210
+ }
211
+
212
+ ret = -ENOMEM;
213
+ buf.buffer = ipl_report_finish(data->report);
214
+ if (!buf.buffer)
215
+ goto out;
216
+ buf.bufsz = data->report->size;
217
+ buf.memsz = buf.bufsz;
218
+ image->arch.ipl_buf = buf.buffer;
219
+
220
+ data->memsz += buf.memsz;
221
+
222
+ lc_ipl_parmblock_ptr =
223
+ data->kernel_buf + offsetof(struct lowcore, ipl_parmblock_ptr);
224
+ *lc_ipl_parmblock_ptr = (__u32)buf.mem;
225
+
226
+ ret = kexec_add_buffer(&buf);
227
+out:
134228 return ret;
135229 }
136230
137
-/*
138
- * The kernel is loaded to a fixed location. Turn off kexec_locate_mem_hole
139
- * and provide kbuf->mem by hand.
140
- */
141
-int arch_kexec_walk_mem(struct kexec_buf *kbuf,
142
- int (*func)(struct resource *, void *))
231
+void *kexec_file_add_components(struct kimage *image,
232
+ int (*add_kernel)(struct kimage *image,
233
+ struct s390_load_data *data))
143234 {
144
- return 1;
235
+ struct s390_load_data data = {0};
236
+ int ret;
237
+
238
+ data.report = ipl_report_init(&ipl_block);
239
+ if (IS_ERR(data.report))
240
+ return data.report;
241
+
242
+ ret = add_kernel(image, &data);
243
+ if (ret)
244
+ goto out;
245
+
246
+ if (image->cmdline_buf_len >= ARCH_COMMAND_LINE_SIZE) {
247
+ ret = -EINVAL;
248
+ goto out;
249
+ }
250
+ memcpy(data.parm->command_line, image->cmdline_buf,
251
+ image->cmdline_buf_len);
252
+
253
+ if (image->type == KEXEC_TYPE_CRASH) {
254
+ data.parm->oldmem_base = crashk_res.start;
255
+ data.parm->oldmem_size = crashk_res.end - crashk_res.start + 1;
256
+ }
257
+
258
+ if (image->initrd_buf) {
259
+ ret = kexec_file_add_initrd(image, &data);
260
+ if (ret)
261
+ goto out;
262
+ }
263
+
264
+ ret = kexec_file_add_purgatory(image, &data);
265
+ if (ret)
266
+ goto out;
267
+
268
+ if (data.kernel_mem == 0) {
269
+ unsigned long restart_psw = 0x0008000080000000UL;
270
+ restart_psw += image->start;
271
+ memcpy(data.kernel_buf, &restart_psw, sizeof(restart_psw));
272
+ image->start = 0;
273
+ }
274
+
275
+ ret = kexec_file_add_ipl_report(image, &data);
276
+out:
277
+ ipl_report_free(data.report);
278
+ return ERR_PTR(ret);
145279 }
146280
147281 int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
....@@ -150,7 +284,8 @@
150284 const Elf_Shdr *symtab)
151285 {
152286 Elf_Rela *relas;
153
- int i;
287
+ int i, r_type;
288
+ int ret;
154289
155290 relas = (void *)pi->ehdr + relsec->sh_offset;
156291
....@@ -184,45 +319,11 @@
184319
185320 addr = section->sh_addr + relas[i].r_offset;
186321
187
- switch (ELF64_R_TYPE(relas[i].r_info)) {
188
- case R_390_8: /* Direct 8 bit. */
189
- *(u8 *)loc = val;
190
- break;
191
- case R_390_12: /* Direct 12 bit. */
192
- *(u16 *)loc &= 0xf000;
193
- *(u16 *)loc |= val & 0xfff;
194
- break;
195
- case R_390_16: /* Direct 16 bit. */
196
- *(u16 *)loc = val;
197
- break;
198
- case R_390_20: /* Direct 20 bit. */
199
- *(u32 *)loc &= 0xf00000ff;
200
- *(u32 *)loc |= (val & 0xfff) << 16; /* DL */
201
- *(u32 *)loc |= (val & 0xff000) >> 4; /* DH */
202
- break;
203
- case R_390_32: /* Direct 32 bit. */
204
- *(u32 *)loc = val;
205
- break;
206
- case R_390_64: /* Direct 64 bit. */
207
- *(u64 *)loc = val;
208
- break;
209
- case R_390_PC16: /* PC relative 16 bit. */
210
- *(u16 *)loc = (val - addr);
211
- break;
212
- case R_390_PC16DBL: /* PC relative 16 bit shifted by 1. */
213
- *(u16 *)loc = (val - addr) >> 1;
214
- break;
215
- case R_390_PC32DBL: /* PC relative 32 bit shifted by 1. */
216
- *(u32 *)loc = (val - addr) >> 1;
217
- break;
218
- case R_390_PC32: /* PC relative 32 bit. */
219
- *(u32 *)loc = (val - addr);
220
- break;
221
- case R_390_PC64: /* PC relative 64 bit. */
222
- *(u64 *)loc = (val - addr);
223
- break;
224
- default:
225
- break;
322
+ r_type = ELF64_R_TYPE(relas[i].r_info);
323
+ ret = arch_kexec_do_relocs(r_type, loc, val, addr);
324
+ if (ret) {
325
+ pr_err("Unknown rela relocation: %d\n", r_type);
326
+ return -ENOEXEC;
226327 }
227328 }
228329 return 0;
....@@ -235,11 +336,17 @@
235336 * load memory in head.S will be accessed, e.g. to register the next
236337 * command line. If the next kernel were smaller the current kernel
237338 * will panic at load.
238
- *
239
- * 0x11000 = sizeof(head.S)
240339 */
241
- if (buf_len < 0x11000)
340
+ if (buf_len < HEAD_END)
242341 return -ENOEXEC;
243342
244343 return kexec_image_probe_default(image, buf, buf_len);
245344 }
345
+
346
+int arch_kimage_file_post_load_cleanup(struct kimage *image)
347
+{
348
+ vfree(image->arch.ipl_buf);
349
+ image->arch.ipl_buf = NULL;
350
+
351
+ return kexec_image_post_load_cleanup_default(image);
352
+}