1 // SPDX-License-Identifier: GPL-2.0
3 * ELF loader for kexec_file_load system call.
5 * Copyright IBM Corp. 2018
7 * Author(s): Philipp Rudo <prudo@linux.vnet.ibm.com>
10 #include <linux/errno.h>
11 #include <linux/kernel.h>
12 #include <linux/kexec.h>
13 #include <asm/setup.h>
15 static int kexec_file_add_elf_kernel(struct kimage
*image
,
16 struct s390_load_data
*data
,
17 char *kernel
, unsigned long kernel_len
)
24 ehdr
= (Elf_Ehdr
*)kernel
;
27 phdr
= (void *)ehdr
+ ehdr
->e_phoff
;
28 for (i
= 0; i
< ehdr
->e_phnum
; i
++, phdr
++) {
29 if (phdr
->p_type
!= PT_LOAD
)
32 buf
.buffer
= kernel
+ phdr
->p_offset
;
33 buf
.bufsz
= phdr
->p_filesz
;
35 buf
.mem
= ALIGN(phdr
->p_paddr
, phdr
->p_align
);
36 buf
.memsz
= phdr
->p_memsz
;
38 if (phdr
->p_paddr
== 0) {
39 data
->kernel_buf
= buf
.buffer
;
40 data
->memsz
+= STARTUP_NORMAL_OFFSET
;
42 buf
.buffer
+= STARTUP_NORMAL_OFFSET
;
43 buf
.bufsz
-= STARTUP_NORMAL_OFFSET
;
45 buf
.mem
+= STARTUP_NORMAL_OFFSET
;
46 buf
.memsz
-= STARTUP_NORMAL_OFFSET
;
49 if (image
->type
== KEXEC_TYPE_CRASH
)
50 buf
.mem
+= crashk_res
.start
;
52 ret
= kexec_add_buffer(&buf
);
56 data
->memsz
+= buf
.memsz
;
62 static void *s390_elf_load(struct kimage
*image
,
63 char *kernel
, unsigned long kernel_len
,
64 char *initrd
, unsigned long initrd_len
,
65 char *cmdline
, unsigned long cmdline_len
)
67 struct s390_load_data data
= {0};
73 /* image->fobs->probe already checked for valid ELF magic number. */
74 ehdr
= (Elf_Ehdr
*)kernel
;
76 if (ehdr
->e_type
!= ET_EXEC
||
77 ehdr
->e_ident
[EI_CLASS
] != ELFCLASS64
||
78 !elf_check_arch(ehdr
))
79 return ERR_PTR(-EINVAL
);
81 if (!ehdr
->e_phnum
|| ehdr
->e_phentsize
!= sizeof(Elf_Phdr
))
82 return ERR_PTR(-EINVAL
);
84 size
= ehdr
->e_ehsize
+ ehdr
->e_phoff
;
85 size
+= ehdr
->e_phentsize
* ehdr
->e_phnum
;
86 if (size
> kernel_len
)
87 return ERR_PTR(-EINVAL
);
89 phdr
= (void *)ehdr
+ ehdr
->e_phoff
;
90 size
= ALIGN(size
, phdr
->p_align
);
91 for (i
= 0; i
< ehdr
->e_phnum
; i
++, phdr
++) {
92 if (phdr
->p_type
== PT_INTERP
)
93 return ERR_PTR(-EINVAL
);
95 if (phdr
->p_offset
> kernel_len
)
96 return ERR_PTR(-EINVAL
);
98 size
+= ALIGN(phdr
->p_filesz
, phdr
->p_align
);
101 if (size
> kernel_len
)
102 return ERR_PTR(-EINVAL
);
104 ret
= kexec_file_add_elf_kernel(image
, &data
, kernel
, kernel_len
);
109 return ERR_PTR(-EINVAL
);
112 ret
= kexec_file_add_initrd(image
, &data
, initrd
, initrd_len
);
117 ret
= kexec_file_add_purgatory(image
, &data
);
121 return kexec_file_update_kernel(image
, &data
);
124 static int s390_elf_probe(const char *buf
, unsigned long len
)
126 const Elf_Ehdr
*ehdr
;
128 if (len
< sizeof(Elf_Ehdr
))
131 ehdr
= (Elf_Ehdr
*)buf
;
133 /* Only check the ELF magic number here and do proper validity check
134 * in the loader. Any check here that fails would send the erroneous
135 * ELF file to the image loader that does not care what it gets.
136 * (Most likely) causing behavior not intended by the user.
138 if (memcmp(ehdr
->e_ident
, ELFMAG
, SELFMAG
) != 0)
144 const struct kexec_file_ops s390_kexec_elf_ops
= {
145 .probe
= s390_elf_probe
,
146 .load
= s390_elf_load
,