hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
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,123 @@
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
+
189
+ ptr = (void *)ipl_cert_list_addr;
190
+ end = ptr + ipl_cert_list_size;
191
+ ncerts = 0;
192
+ while (ptr < end) {
193
+ ncerts++;
194
+ len = *(unsigned int *)ptr;
195
+ ptr += sizeof(len);
196
+ ptr += len;
197
+ }
198
+
199
+ addr = data->memsz + data->report->size;
200
+ addr += ncerts * sizeof(struct ipl_rb_certificate_entry);
201
+ ptr = (void *)ipl_cert_list_addr;
202
+ while (ptr < end) {
203
+ len = *(unsigned int *)ptr;
204
+ ptr += sizeof(len);
205
+ ipl_report_add_certificate(data->report, ptr, addr, len);
206
+ addr += len;
207
+ ptr += len;
208
+ }
209
+
210
+ ret = -ENOMEM;
211
+ buf.buffer = ipl_report_finish(data->report);
212
+ if (!buf.buffer)
213
+ goto out;
214
+ buf.bufsz = data->report->size;
215
+ buf.memsz = buf.bufsz;
216
+ image->arch.ipl_buf = buf.buffer;
217
+
218
+ data->memsz += buf.memsz;
219
+
220
+ lc_ipl_parmblock_ptr =
221
+ data->kernel_buf + offsetof(struct lowcore, ipl_parmblock_ptr);
222
+ *lc_ipl_parmblock_ptr = (__u32)buf.mem;
223
+
224
+ if (image->type == KEXEC_TYPE_CRASH)
225
+ buf.mem += crashk_res.start;
226
+
227
+ ret = kexec_add_buffer(&buf);
228
+out:
134229 return ret;
135230 }
136231
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 *))
232
+void *kexec_file_add_components(struct kimage *image,
233
+ int (*add_kernel)(struct kimage *image,
234
+ struct s390_load_data *data))
143235 {
144
- return 1;
236
+ struct s390_load_data data = {0};
237
+ int ret;
238
+
239
+ data.report = ipl_report_init(&ipl_block);
240
+ if (IS_ERR(data.report))
241
+ return data.report;
242
+
243
+ ret = add_kernel(image, &data);
244
+ if (ret)
245
+ goto out;
246
+
247
+ if (image->cmdline_buf_len >= ARCH_COMMAND_LINE_SIZE) {
248
+ ret = -EINVAL;
249
+ goto out;
250
+ }
251
+ memcpy(data.parm->command_line, image->cmdline_buf,
252
+ image->cmdline_buf_len);
253
+
254
+ if (image->type == KEXEC_TYPE_CRASH) {
255
+ data.parm->oldmem_base = crashk_res.start;
256
+ data.parm->oldmem_size = crashk_res.end - crashk_res.start + 1;
257
+ }
258
+
259
+ if (image->initrd_buf) {
260
+ ret = kexec_file_add_initrd(image, &data);
261
+ if (ret)
262
+ goto out;
263
+ }
264
+
265
+ ret = kexec_file_add_purgatory(image, &data);
266
+ if (ret)
267
+ goto out;
268
+
269
+ if (data.kernel_mem == 0) {
270
+ unsigned long restart_psw = 0x0008000080000000UL;
271
+ restart_psw += image->start;
272
+ memcpy(data.kernel_buf, &restart_psw, sizeof(restart_psw));
273
+ image->start = 0;
274
+ }
275
+
276
+ ret = kexec_file_add_ipl_report(image, &data);
277
+out:
278
+ ipl_report_free(data.report);
279
+ return ERR_PTR(ret);
145280 }
146281
147282 int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
....@@ -150,7 +285,8 @@
150285 const Elf_Shdr *symtab)
151286 {
152287 Elf_Rela *relas;
153
- int i;
288
+ int i, r_type;
289
+ int ret;
154290
155291 relas = (void *)pi->ehdr + relsec->sh_offset;
156292
....@@ -184,45 +320,11 @@
184320
185321 addr = section->sh_addr + relas[i].r_offset;
186322
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;
323
+ r_type = ELF64_R_TYPE(relas[i].r_info);
324
+ ret = arch_kexec_do_relocs(r_type, loc, val, addr);
325
+ if (ret) {
326
+ pr_err("Unknown rela relocation: %d\n", r_type);
327
+ return -ENOEXEC;
226328 }
227329 }
228330 return 0;
....@@ -235,11 +337,17 @@
235337 * load memory in head.S will be accessed, e.g. to register the next
236338 * command line. If the next kernel were smaller the current kernel
237339 * will panic at load.
238
- *
239
- * 0x11000 = sizeof(head.S)
240340 */
241
- if (buf_len < 0x11000)
341
+ if (buf_len < HEAD_END)
242342 return -ENOEXEC;
243343
244344 return kexec_image_probe_default(image, buf, buf_len);
245345 }
346
+
347
+int arch_kimage_file_post_load_cleanup(struct kimage *image)
348
+{
349
+ vfree(image->arch.ipl_buf);
350
+ image->arch.ipl_buf = NULL;
351
+
352
+ return kexec_image_post_load_cleanup_default(image);
353
+}