diff options
-rw-r--r-- | arch/x86/kernel/machine_kexec_64.c | 56 | ||||
-rw-r--r-- | include/linux/kexec.h | 13 | ||||
-rw-r--r-- | kernel/kexec_file.c | 63 |
3 files changed, 71 insertions, 61 deletions
diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c index c51d2cf27d93..63dea30c8e02 100644 --- a/arch/x86/kernel/machine_kexec_64.c +++ b/arch/x86/kernel/machine_kexec_64.c | |||
@@ -382,52 +382,36 @@ void *arch_kexec_kernel_image_load(struct kimage *image) | |||
382 | /* | 382 | /* |
383 | * Apply purgatory relocations. | 383 | * Apply purgatory relocations. |
384 | * | 384 | * |
385 | * ehdr: Pointer to elf headers | 385 | * @pi: Purgatory to be relocated. |
386 | * sechdrs: Pointer to section headers. | 386 | * @section: Section relocations applying to. |
387 | * relsec: section index of SHT_RELA section. | 387 | * @relsec: Section containing RELAs. |
388 | * @symtabsec: Corresponding symtab. | ||
388 | * | 389 | * |
389 | * TODO: Some of the code belongs to generic code. Move that in kexec.c. | 390 | * TODO: Some of the code belongs to generic code. Move that in kexec.c. |
390 | */ | 391 | */ |
391 | int arch_kexec_apply_relocations_add(const Elf64_Ehdr *ehdr, | 392 | int arch_kexec_apply_relocations_add(struct purgatory_info *pi, |
392 | Elf64_Shdr *sechdrs, unsigned int relsec) | 393 | Elf_Shdr *section, const Elf_Shdr *relsec, |
394 | const Elf_Shdr *symtabsec) | ||
393 | { | 395 | { |
394 | unsigned int i; | 396 | unsigned int i; |
395 | Elf64_Rela *rel; | 397 | Elf64_Rela *rel; |
396 | Elf64_Sym *sym; | 398 | Elf64_Sym *sym; |
397 | void *location; | 399 | void *location; |
398 | Elf64_Shdr *section, *symtabsec; | ||
399 | unsigned long address, sec_base, value; | 400 | unsigned long address, sec_base, value; |
400 | const char *strtab, *name, *shstrtab; | 401 | const char *strtab, *name, *shstrtab; |
402 | const Elf_Shdr *sechdrs; | ||
401 | 403 | ||
402 | /* | 404 | /* String & section header string table */ |
403 | * ->sh_offset has been modified to keep the pointer to section | 405 | sechdrs = (void *)pi->ehdr + pi->ehdr->e_shoff; |
404 | * contents in memory | 406 | strtab = (char *)pi->ehdr + sechdrs[symtabsec->sh_link].sh_offset; |
405 | */ | 407 | shstrtab = (char *)pi->ehdr + sechdrs[pi->ehdr->e_shstrndx].sh_offset; |
406 | rel = (void *)sechdrs[relsec].sh_offset; | ||
407 | |||
408 | /* Section to which relocations apply */ | ||
409 | section = &sechdrs[sechdrs[relsec].sh_info]; | ||
410 | |||
411 | pr_debug("Applying relocate section %u to %u\n", relsec, | ||
412 | sechdrs[relsec].sh_info); | ||
413 | |||
414 | /* Associated symbol table */ | ||
415 | symtabsec = &sechdrs[sechdrs[relsec].sh_link]; | ||
416 | |||
417 | /* String table */ | ||
418 | if (symtabsec->sh_link >= ehdr->e_shnum) { | ||
419 | /* Invalid strtab section number */ | ||
420 | pr_err("Invalid string table section index %d\n", | ||
421 | symtabsec->sh_link); | ||
422 | return -ENOEXEC; | ||
423 | } | ||
424 | 408 | ||
425 | strtab = (char *)sechdrs[symtabsec->sh_link].sh_offset; | 409 | rel = (void *)pi->ehdr + relsec->sh_offset; |
426 | 410 | ||
427 | /* section header string table */ | 411 | pr_debug("Applying relocate section %s to %u\n", |
428 | shstrtab = (char *)sechdrs[ehdr->e_shstrndx].sh_offset; | 412 | shstrtab + relsec->sh_name, relsec->sh_info); |
429 | 413 | ||
430 | for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { | 414 | for (i = 0; i < relsec->sh_size / sizeof(*rel); i++) { |
431 | 415 | ||
432 | /* | 416 | /* |
433 | * rel[i].r_offset contains byte offset from beginning | 417 | * rel[i].r_offset contains byte offset from beginning |
@@ -450,8 +434,8 @@ int arch_kexec_apply_relocations_add(const Elf64_Ehdr *ehdr, | |||
450 | * to apply. ELF64_R_SYM() and ELF64_R_TYPE() macros get | 434 | * to apply. ELF64_R_SYM() and ELF64_R_TYPE() macros get |
451 | * these respectively. | 435 | * these respectively. |
452 | */ | 436 | */ |
453 | sym = (Elf64_Sym *)symtabsec->sh_offset + | 437 | sym = (void *)pi->ehdr + symtabsec->sh_offset; |
454 | ELF64_R_SYM(rel[i].r_info); | 438 | sym += ELF64_R_SYM(rel[i].r_info); |
455 | 439 | ||
456 | if (sym->st_name) | 440 | if (sym->st_name) |
457 | name = strtab + sym->st_name; | 441 | name = strtab + sym->st_name; |
@@ -474,12 +458,12 @@ int arch_kexec_apply_relocations_add(const Elf64_Ehdr *ehdr, | |||
474 | 458 | ||
475 | if (sym->st_shndx == SHN_ABS) | 459 | if (sym->st_shndx == SHN_ABS) |
476 | sec_base = 0; | 460 | sec_base = 0; |
477 | else if (sym->st_shndx >= ehdr->e_shnum) { | 461 | else if (sym->st_shndx >= pi->ehdr->e_shnum) { |
478 | pr_err("Invalid section %d for symbol %s\n", | 462 | pr_err("Invalid section %d for symbol %s\n", |
479 | sym->st_shndx, name); | 463 | sym->st_shndx, name); |
480 | return -ENOEXEC; | 464 | return -ENOEXEC; |
481 | } else | 465 | } else |
482 | sec_base = sechdrs[sym->st_shndx].sh_addr; | 466 | sec_base = pi->sechdrs[sym->st_shndx].sh_addr; |
483 | 467 | ||
484 | value = sym->st_value; | 468 | value = sym->st_value; |
485 | value += sec_base; | 469 | value += sec_base; |
diff --git a/include/linux/kexec.h b/include/linux/kexec.h index 8c5819d1a808..0e389b9b7722 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h | |||
@@ -171,6 +171,15 @@ struct kexec_buf { | |||
171 | bool top_down; | 171 | bool top_down; |
172 | }; | 172 | }; |
173 | 173 | ||
174 | int __weak arch_kexec_apply_relocations_add(struct purgatory_info *pi, | ||
175 | Elf_Shdr *section, | ||
176 | const Elf_Shdr *relsec, | ||
177 | const Elf_Shdr *symtab); | ||
178 | int __weak arch_kexec_apply_relocations(struct purgatory_info *pi, | ||
179 | Elf_Shdr *section, | ||
180 | const Elf_Shdr *relsec, | ||
181 | const Elf_Shdr *symtab); | ||
182 | |||
174 | int __weak arch_kexec_walk_mem(struct kexec_buf *kbuf, | 183 | int __weak arch_kexec_walk_mem(struct kexec_buf *kbuf, |
175 | int (*func)(struct resource *, void *)); | 184 | int (*func)(struct resource *, void *)); |
176 | extern int kexec_add_buffer(struct kexec_buf *kbuf); | 185 | extern int kexec_add_buffer(struct kexec_buf *kbuf); |
@@ -304,10 +313,6 @@ int crash_shrink_memory(unsigned long new_size); | |||
304 | size_t crash_get_memory_size(void); | 313 | size_t crash_get_memory_size(void); |
305 | void crash_free_reserved_phys_range(unsigned long begin, unsigned long end); | 314 | void crash_free_reserved_phys_range(unsigned long begin, unsigned long end); |
306 | 315 | ||
307 | int __weak arch_kexec_apply_relocations_add(const Elf_Ehdr *ehdr, | ||
308 | Elf_Shdr *sechdrs, unsigned int relsec); | ||
309 | int __weak arch_kexec_apply_relocations(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, | ||
310 | unsigned int relsec); | ||
311 | void arch_kexec_protect_crashkres(void); | 316 | void arch_kexec_protect_crashkres(void); |
312 | void arch_kexec_unprotect_crashkres(void); | 317 | void arch_kexec_unprotect_crashkres(void); |
313 | 318 | ||
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index 9bd1ec1dd875..5c70f7f2bae3 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c | |||
@@ -110,19 +110,35 @@ int __weak arch_kexec_kernel_verify_sig(struct kimage *image, void *buf, | |||
110 | } | 110 | } |
111 | #endif | 111 | #endif |
112 | 112 | ||
113 | /* Apply relocations of type RELA */ | 113 | /* |
114 | * arch_kexec_apply_relocations_add - apply relocations of type RELA | ||
115 | * @pi: Purgatory to be relocated. | ||
116 | * @section: Section relocations applying to. | ||
117 | * @relsec: Section containing RELAs. | ||
118 | * @symtab: Corresponding symtab. | ||
119 | * | ||
120 | * Return: 0 on success, negative errno on error. | ||
121 | */ | ||
114 | int __weak | 122 | int __weak |
115 | arch_kexec_apply_relocations_add(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, | 123 | arch_kexec_apply_relocations_add(struct purgatory_info *pi, Elf_Shdr *section, |
116 | unsigned int relsec) | 124 | const Elf_Shdr *relsec, const Elf_Shdr *symtab) |
117 | { | 125 | { |
118 | pr_err("RELA relocation unsupported.\n"); | 126 | pr_err("RELA relocation unsupported.\n"); |
119 | return -ENOEXEC; | 127 | return -ENOEXEC; |
120 | } | 128 | } |
121 | 129 | ||
122 | /* Apply relocations of type REL */ | 130 | /* |
131 | * arch_kexec_apply_relocations - apply relocations of type REL | ||
132 | * @pi: Purgatory to be relocated. | ||
133 | * @section: Section relocations applying to. | ||
134 | * @relsec: Section containing RELs. | ||
135 | * @symtab: Corresponding symtab. | ||
136 | * | ||
137 | * Return: 0 on success, negative errno on error. | ||
138 | */ | ||
123 | int __weak | 139 | int __weak |
124 | arch_kexec_apply_relocations(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, | 140 | arch_kexec_apply_relocations(struct purgatory_info *pi, Elf_Shdr *section, |
125 | unsigned int relsec) | 141 | const Elf_Shdr *relsec, const Elf_Shdr *symtab) |
126 | { | 142 | { |
127 | pr_err("REL relocation unsupported.\n"); | 143 | pr_err("REL relocation unsupported.\n"); |
128 | return -ENOEXEC; | 144 | return -ENOEXEC; |
@@ -879,14 +895,19 @@ static int kexec_apply_relocations(struct kimage *image) | |||
879 | { | 895 | { |
880 | int i, ret; | 896 | int i, ret; |
881 | struct purgatory_info *pi = &image->purgatory_info; | 897 | struct purgatory_info *pi = &image->purgatory_info; |
882 | Elf_Shdr *sechdrs = pi->sechdrs; | 898 | const Elf_Shdr *sechdrs; |
899 | |||
900 | sechdrs = (void *)pi->ehdr + pi->ehdr->e_shoff; | ||
883 | 901 | ||
884 | /* Apply relocations */ | ||
885 | for (i = 0; i < pi->ehdr->e_shnum; i++) { | 902 | for (i = 0; i < pi->ehdr->e_shnum; i++) { |
886 | Elf_Shdr *section, *symtab; | 903 | const Elf_Shdr *relsec; |
904 | const Elf_Shdr *symtab; | ||
905 | Elf_Shdr *section; | ||
906 | |||
907 | relsec = sechdrs + i; | ||
887 | 908 | ||
888 | if (sechdrs[i].sh_type != SHT_RELA && | 909 | if (relsec->sh_type != SHT_RELA && |
889 | sechdrs[i].sh_type != SHT_REL) | 910 | relsec->sh_type != SHT_REL) |
890 | continue; | 911 | continue; |
891 | 912 | ||
892 | /* | 913 | /* |
@@ -895,12 +916,12 @@ static int kexec_apply_relocations(struct kimage *image) | |||
895 | * symbol table. And ->sh_info contains section header | 916 | * symbol table. And ->sh_info contains section header |
896 | * index of section to which relocations apply. | 917 | * index of section to which relocations apply. |
897 | */ | 918 | */ |
898 | if (sechdrs[i].sh_info >= pi->ehdr->e_shnum || | 919 | if (relsec->sh_info >= pi->ehdr->e_shnum || |
899 | sechdrs[i].sh_link >= pi->ehdr->e_shnum) | 920 | relsec->sh_link >= pi->ehdr->e_shnum) |
900 | return -ENOEXEC; | 921 | return -ENOEXEC; |
901 | 922 | ||
902 | section = &sechdrs[sechdrs[i].sh_info]; | 923 | section = pi->sechdrs + relsec->sh_info; |
903 | symtab = &sechdrs[sechdrs[i].sh_link]; | 924 | symtab = sechdrs + relsec->sh_link; |
904 | 925 | ||
905 | if (!(section->sh_flags & SHF_ALLOC)) | 926 | if (!(section->sh_flags & SHF_ALLOC)) |
906 | continue; | 927 | continue; |
@@ -917,12 +938,12 @@ static int kexec_apply_relocations(struct kimage *image) | |||
917 | * Respective architecture needs to provide support for applying | 938 | * Respective architecture needs to provide support for applying |
918 | * relocations of type SHT_RELA/SHT_REL. | 939 | * relocations of type SHT_RELA/SHT_REL. |
919 | */ | 940 | */ |
920 | if (sechdrs[i].sh_type == SHT_RELA) | 941 | if (relsec->sh_type == SHT_RELA) |
921 | ret = arch_kexec_apply_relocations_add(pi->ehdr, | 942 | ret = arch_kexec_apply_relocations_add(pi, section, |
922 | sechdrs, i); | 943 | relsec, symtab); |
923 | else if (sechdrs[i].sh_type == SHT_REL) | 944 | else if (relsec->sh_type == SHT_REL) |
924 | ret = arch_kexec_apply_relocations(pi->ehdr, | 945 | ret = arch_kexec_apply_relocations(pi, section, |
925 | sechdrs, i); | 946 | relsec, symtab); |
926 | if (ret) | 947 | if (ret) |
927 | return ret; | 948 | return ret; |
928 | } | 949 | } |