0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/errno.h>
0011 #include <linux/kernel.h>
0012 #include <linux/kexec.h>
0013 #include <asm/ipl.h>
0014 #include <asm/setup.h>
0015
0016 static int kexec_file_add_kernel_elf(struct kimage *image,
0017 struct s390_load_data *data)
0018 {
0019 struct kexec_buf buf;
0020 const Elf_Ehdr *ehdr;
0021 const Elf_Phdr *phdr;
0022 Elf_Addr entry;
0023 void *kernel;
0024 int i, ret;
0025
0026 kernel = image->kernel_buf;
0027 ehdr = (Elf_Ehdr *)kernel;
0028 buf.image = image;
0029 if (image->type == KEXEC_TYPE_CRASH)
0030 entry = STARTUP_KDUMP_OFFSET;
0031 else
0032 entry = ehdr->e_entry;
0033
0034 phdr = (void *)ehdr + ehdr->e_phoff;
0035 for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
0036 if (phdr->p_type != PT_LOAD)
0037 continue;
0038
0039 buf.buffer = kernel + phdr->p_offset;
0040 buf.bufsz = phdr->p_filesz;
0041
0042 buf.mem = ALIGN(phdr->p_paddr, phdr->p_align);
0043 if (image->type == KEXEC_TYPE_CRASH)
0044 buf.mem += crashk_res.start;
0045 buf.memsz = phdr->p_memsz;
0046 data->memsz = ALIGN(data->memsz, phdr->p_align) + buf.memsz;
0047
0048 if (entry - phdr->p_paddr < phdr->p_memsz) {
0049 data->kernel_buf = buf.buffer;
0050 data->kernel_mem = buf.mem;
0051 data->parm = buf.buffer + PARMAREA;
0052 }
0053
0054 ipl_report_add_component(data->report, &buf,
0055 IPL_RB_COMPONENT_FLAG_SIGNED |
0056 IPL_RB_COMPONENT_FLAG_VERIFIED,
0057 IPL_RB_CERT_UNKNOWN);
0058 ret = kexec_add_buffer(&buf);
0059 if (ret)
0060 return ret;
0061 }
0062
0063 return data->memsz ? 0 : -EINVAL;
0064 }
0065
0066 static void *s390_elf_load(struct kimage *image,
0067 char *kernel, unsigned long kernel_len,
0068 char *initrd, unsigned long initrd_len,
0069 char *cmdline, unsigned long cmdline_len)
0070 {
0071 const Elf_Ehdr *ehdr;
0072 const Elf_Phdr *phdr;
0073 size_t size;
0074 int i;
0075
0076
0077 ehdr = (Elf_Ehdr *)kernel;
0078
0079 if (ehdr->e_type != ET_EXEC ||
0080 ehdr->e_ident[EI_CLASS] != ELFCLASS64 ||
0081 !elf_check_arch(ehdr))
0082 return ERR_PTR(-EINVAL);
0083
0084 if (!ehdr->e_phnum || ehdr->e_phentsize != sizeof(Elf_Phdr))
0085 return ERR_PTR(-EINVAL);
0086
0087 size = ehdr->e_ehsize + ehdr->e_phoff;
0088 size += ehdr->e_phentsize * ehdr->e_phnum;
0089 if (size > kernel_len)
0090 return ERR_PTR(-EINVAL);
0091
0092 phdr = (void *)ehdr + ehdr->e_phoff;
0093 size = ALIGN(size, phdr->p_align);
0094 for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
0095 if (phdr->p_type == PT_INTERP)
0096 return ERR_PTR(-EINVAL);
0097
0098 if (phdr->p_offset > kernel_len)
0099 return ERR_PTR(-EINVAL);
0100
0101 size += ALIGN(phdr->p_filesz, phdr->p_align);
0102 }
0103
0104 if (size > kernel_len)
0105 return ERR_PTR(-EINVAL);
0106
0107 return kexec_file_add_components(image, kexec_file_add_kernel_elf);
0108 }
0109
0110 static int s390_elf_probe(const char *buf, unsigned long len)
0111 {
0112 const Elf_Ehdr *ehdr;
0113
0114 if (len < sizeof(Elf_Ehdr))
0115 return -ENOEXEC;
0116
0117 ehdr = (Elf_Ehdr *)buf;
0118
0119
0120
0121
0122
0123
0124 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0)
0125 return -ENOEXEC;
0126
0127 return 0;
0128 }
0129
0130 const struct kexec_file_ops s390_kexec_elf_ops = {
0131 .probe = s390_elf_probe,
0132 .load = s390_elf_load,
0133 #ifdef CONFIG_KEXEC_SIG
0134 .verify_sig = s390_verify_sig,
0135 #endif
0136 };