s390/kexec_file: fix error handling when applying relocations
[linux-2.6-microblaze.git] / arch / s390 / kernel / machine_kexec_file.c
index 9975ad2..876cdd3 100644 (file)
@@ -7,6 +7,8 @@
  * Author(s): Philipp Rudo <prudo@linux.vnet.ibm.com>
  */
 
+#define pr_fmt(fmt)    "kexec: " fmt
+
 #include <linux/elf.h>
 #include <linux/errno.h>
 #include <linux/kexec.h>
@@ -290,8 +292,16 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
                                     const Elf_Shdr *relsec,
                                     const Elf_Shdr *symtab)
 {
+       const char *strtab, *name, *shstrtab;
+       const Elf_Shdr *sechdrs;
        Elf_Rela *relas;
        int i, r_type;
+       int ret;
+
+       /* String & section header string table */
+       sechdrs = (void *)pi->ehdr + pi->ehdr->e_shoff;
+       strtab = (char *)pi->ehdr + sechdrs[symtab->sh_link].sh_offset;
+       shstrtab = (char *)pi->ehdr + sechdrs[pi->ehdr->e_shstrndx].sh_offset;
 
        relas = (void *)pi->ehdr + relsec->sh_offset;
 
@@ -304,15 +314,27 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
                sym = (void *)pi->ehdr + symtab->sh_offset;
                sym += ELF64_R_SYM(relas[i].r_info);
 
-               if (sym->st_shndx == SHN_UNDEF)
+               if (sym->st_name)
+                       name = strtab + sym->st_name;
+               else
+                       name = shstrtab + sechdrs[sym->st_shndx].sh_name;
+
+               if (sym->st_shndx == SHN_UNDEF) {
+                       pr_err("Undefined symbol: %s\n", name);
                        return -ENOEXEC;
+               }
 
-               if (sym->st_shndx == SHN_COMMON)
+               if (sym->st_shndx == SHN_COMMON) {
+                       pr_err("symbol '%s' in common section\n", name);
                        return -ENOEXEC;
+               }
 
                if (sym->st_shndx >= pi->ehdr->e_shnum &&
-                   sym->st_shndx != SHN_ABS)
+                   sym->st_shndx != SHN_ABS) {
+                       pr_err("Invalid section %d for symbol %s\n",
+                              sym->st_shndx, name);
                        return -ENOEXEC;
+               }
 
                loc = pi->purgatory_buf;
                loc += section->sh_offset;
@@ -326,7 +348,11 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
                addr = section->sh_addr + relas[i].r_offset;
 
                r_type = ELF64_R_TYPE(relas[i].r_info);
-               arch_kexec_do_relocs(r_type, loc, val, addr);
+               ret = arch_kexec_do_relocs(r_type, loc, val, addr);
+               if (ret) {
+                       pr_err("Unknown rela relocation: %d\n", r_type);
+                       return -ENOEXEC;
+               }
        }
        return 0;
 }