1 // SPDX-License-Identifier: GPL-2.0
3 * s390 code for kexec_file_load system call
5 * Copyright IBM Corp. 2018
7 * Author(s): Philipp Rudo <prudo@linux.vnet.ibm.com>
10 #include <linux/elf.h>
11 #include <linux/errno.h>
12 #include <linux/kexec.h>
13 #include <linux/module.h>
14 #include <linux/verification.h>
15 #include <asm/boot_data.h>
17 #include <asm/setup.h>
19 const struct kexec_file_ops
* const kexec_file_loaders
[] = {
21 &s390_kexec_image_ops
,
25 #ifdef CONFIG_KEXEC_VERIFY_SIG
27 * Module signature information block.
29 * The constituents of the signature section are, in order:
36 struct module_signature
{
37 u8 algo
; /* Public-key crypto algorithm [0] */
38 u8 hash
; /* Digest algorithm [0] */
39 u8 id_type
; /* Key identifier type [PKEY_ID_PKCS7] */
40 u8 signer_len
; /* Length of signer's name [0] */
41 u8 key_id_len
; /* Length of key identifier [0] */
43 __be32 sig_len
; /* Length of signature data */
46 #define PKEY_ID_PKCS7 2
48 int s390_verify_sig(const char *kernel
, unsigned long kernel_len
)
50 const unsigned long marker_len
= sizeof(MODULE_SIG_STRING
) - 1;
51 struct module_signature
*ms
;
52 unsigned long sig_len
;
54 /* Skip signature verification when not secure IPLed. */
58 if (marker_len
> kernel_len
)
61 if (memcmp(kernel
+ kernel_len
- marker_len
, MODULE_SIG_STRING
,
64 kernel_len
-= marker_len
;
66 ms
= (void *)kernel
+ kernel_len
- sizeof(*ms
);
67 kernel_len
-= sizeof(*ms
);
69 sig_len
= be32_to_cpu(ms
->sig_len
);
70 if (sig_len
>= kernel_len
)
72 kernel_len
-= sig_len
;
74 if (ms
->id_type
!= PKEY_ID_PKCS7
)
79 ms
->signer_len
!= 0 ||
80 ms
->key_id_len
!= 0 ||
87 return verify_pkcs7_signature(kernel
, kernel_len
,
88 kernel
+ kernel_len
, sig_len
,
89 VERIFY_USE_PLATFORM_KEYRING
,
90 VERIFYING_MODULE_SIGNATURE
,
93 #endif /* CONFIG_KEXEC_VERIFY_SIG */
95 static int kexec_file_update_purgatory(struct kimage
*image
,
96 struct s390_load_data
*data
)
101 if (image
->type
== KEXEC_TYPE_CRASH
) {
102 entry
= STARTUP_KDUMP_OFFSET
;
103 type
= KEXEC_TYPE_CRASH
;
105 entry
= STARTUP_NORMAL_OFFSET
;
106 type
= KEXEC_TYPE_DEFAULT
;
109 ret
= kexec_purgatory_get_set_symbol(image
, "kernel_entry", &entry
,
110 sizeof(entry
), false);
114 ret
= kexec_purgatory_get_set_symbol(image
, "kernel_type", &type
,
115 sizeof(type
), false);
119 if (image
->type
== KEXEC_TYPE_CRASH
) {
122 ret
= kexec_purgatory_get_set_symbol(image
, "crash_start",
124 sizeof(crashk_res
.start
),
129 crash_size
= crashk_res
.end
- crashk_res
.start
+ 1;
130 ret
= kexec_purgatory_get_set_symbol(image
, "crash_size",
138 static int kexec_file_add_purgatory(struct kimage
*image
,
139 struct s390_load_data
*data
)
141 struct kexec_buf buf
;
146 data
->memsz
= ALIGN(data
->memsz
, PAGE_SIZE
);
147 buf
.mem
= data
->memsz
;
148 if (image
->type
== KEXEC_TYPE_CRASH
)
149 buf
.mem
+= crashk_res
.start
;
151 ret
= kexec_load_purgatory(image
, &buf
);
154 data
->memsz
+= buf
.memsz
;
156 return kexec_file_update_purgatory(image
, data
);
159 static int kexec_file_add_initrd(struct kimage
*image
,
160 struct s390_load_data
*data
)
162 struct kexec_buf buf
;
167 buf
.buffer
= image
->initrd_buf
;
168 buf
.bufsz
= image
->initrd_buf_len
;
170 data
->memsz
= ALIGN(data
->memsz
, PAGE_SIZE
);
171 buf
.mem
= data
->memsz
;
172 if (image
->type
== KEXEC_TYPE_CRASH
)
173 buf
.mem
+= crashk_res
.start
;
174 buf
.memsz
= buf
.bufsz
;
176 data
->parm
->initrd_start
= buf
.mem
;
177 data
->parm
->initrd_size
= buf
.memsz
;
178 data
->memsz
+= buf
.memsz
;
180 ret
= kexec_add_buffer(&buf
);
184 return ipl_report_add_component(data
->report
, &buf
, 0, 0);
187 static int kexec_file_add_ipl_report(struct kimage
*image
,
188 struct s390_load_data
*data
)
190 __u32
*lc_ipl_parmblock_ptr
;
191 unsigned int len
, ncerts
;
192 struct kexec_buf buf
;
198 data
->memsz
= ALIGN(data
->memsz
, PAGE_SIZE
);
199 buf
.mem
= data
->memsz
;
200 if (image
->type
== KEXEC_TYPE_CRASH
)
201 buf
.mem
+= crashk_res
.start
;
203 ptr
= (void *)ipl_cert_list_addr
;
204 end
= ptr
+ ipl_cert_list_size
;
208 len
= *(unsigned int *)ptr
;
213 addr
= data
->memsz
+ data
->report
->size
;
214 addr
+= ncerts
* sizeof(struct ipl_rb_certificate_entry
);
215 ptr
= (void *)ipl_cert_list_addr
;
217 len
= *(unsigned int *)ptr
;
219 ipl_report_add_certificate(data
->report
, ptr
, addr
, len
);
224 buf
.buffer
= ipl_report_finish(data
->report
);
225 buf
.bufsz
= data
->report
->size
;
226 buf
.memsz
= buf
.bufsz
;
228 data
->memsz
+= buf
.memsz
;
230 lc_ipl_parmblock_ptr
=
231 data
->kernel_buf
+ offsetof(struct lowcore
, ipl_parmblock_ptr
);
232 *lc_ipl_parmblock_ptr
= (__u32
)buf
.mem
;
234 return kexec_add_buffer(&buf
);
237 void *kexec_file_add_components(struct kimage
*image
,
238 int (*add_kernel
)(struct kimage
*image
,
239 struct s390_load_data
*data
))
241 struct s390_load_data data
= {0};
244 data
.report
= ipl_report_init(&ipl_block
);
245 if (IS_ERR(data
.report
))
248 ret
= add_kernel(image
, &data
);
252 if (image
->cmdline_buf_len
>= ARCH_COMMAND_LINE_SIZE
) {
256 memcpy(data
.parm
->command_line
, image
->cmdline_buf
,
257 image
->cmdline_buf_len
);
259 if (image
->type
== KEXEC_TYPE_CRASH
) {
260 data
.parm
->oldmem_base
= crashk_res
.start
;
261 data
.parm
->oldmem_size
= crashk_res
.end
- crashk_res
.start
+ 1;
264 if (image
->initrd_buf
) {
265 ret
= kexec_file_add_initrd(image
, &data
);
270 ret
= kexec_file_add_purgatory(image
, &data
);
274 if (data
.kernel_mem
== 0) {
275 unsigned long restart_psw
= 0x0008000080000000UL
;
276 restart_psw
+= image
->start
;
277 memcpy(data
.kernel_buf
, &restart_psw
, sizeof(restart_psw
));
281 ret
= kexec_file_add_ipl_report(image
, &data
);
283 ipl_report_free(data
.report
);
287 int arch_kexec_apply_relocations_add(struct purgatory_info
*pi
,
289 const Elf_Shdr
*relsec
,
290 const Elf_Shdr
*symtab
)
295 relas
= (void *)pi
->ehdr
+ relsec
->sh_offset
;
297 for (i
= 0; i
< relsec
->sh_size
/ sizeof(*relas
); i
++) {
298 const Elf_Sym
*sym
; /* symbol to relocate */
299 unsigned long addr
; /* final location after relocation */
300 unsigned long val
; /* relocated symbol value */
301 void *loc
; /* tmp location to modify */
303 sym
= (void *)pi
->ehdr
+ symtab
->sh_offset
;
304 sym
+= ELF64_R_SYM(relas
[i
].r_info
);
306 if (sym
->st_shndx
== SHN_UNDEF
)
309 if (sym
->st_shndx
== SHN_COMMON
)
312 if (sym
->st_shndx
>= pi
->ehdr
->e_shnum
&&
313 sym
->st_shndx
!= SHN_ABS
)
316 loc
= pi
->purgatory_buf
;
317 loc
+= section
->sh_offset
;
318 loc
+= relas
[i
].r_offset
;
321 if (sym
->st_shndx
!= SHN_ABS
)
322 val
+= pi
->sechdrs
[sym
->st_shndx
].sh_addr
;
323 val
+= relas
[i
].r_addend
;
325 addr
= section
->sh_addr
+ relas
[i
].r_offset
;
327 r_type
= ELF64_R_TYPE(relas
[i
].r_info
);
328 arch_kexec_do_relocs(r_type
, loc
, val
, addr
);
333 int arch_kexec_kernel_image_probe(struct kimage
*image
, void *buf
,
334 unsigned long buf_len
)
336 /* A kernel must be at least large enough to contain head.S. During
337 * load memory in head.S will be accessed, e.g. to register the next
338 * command line. If the next kernel were smaller the current kernel
339 * will panic at load.
341 if (buf_len
< HEAD_END
)
344 return kexec_image_probe_default(image
, buf
, buf_len
);