Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

kexec: derive purgatory entry from symbol

kexec_load_purgatory() derives image->start by locating e_entry inside an
SHF_EXECINSTR section. If the purgatory object contains multiple
executable sections with overlapping sh_addr, the entrypoint check can
match more than once and trigger a WARN.

Derive the entry section from the purgatory_start symbol when present and
compute image->start from its final placement. Keep the existing e_entry
fallback for purgatories that do not expose the symbol.

WARNING: kernel/kexec_file.c:1009 at kexec_load_purgatory+0x395/0x3c0, CPU#10: kexec/1784
Call Trace:
<TASK>
bzImage64_load+0x133/0xa00
__do_sys_kexec_file_load+0x2b3/0x5c0
do_syscall_64+0x81/0x610
entry_SYSCALL_64_after_hwframe+0x76/0x7e

[me@linux.beauty: move helper to avoid forward declaration, per Baoquan]
Link: https://lkml.kernel.org/r/20260128043511.316860-1-me@linux.beauty
Link: https://lkml.kernel.org/r/20260120124005.148381-1-me@linux.beauty
Fixes: 8652d44f466a ("kexec: support purgatories with .text.hot sections")
Signed-off-by: Li Chen <me@linux.beauty>
Acked-by: Baoquan He <bhe@redhat.com>
Cc: Alexander Graf <graf@amazon.com>
Cc: Eric Biggers <ebiggers@kernel.org>
Cc: Li Chen <me@linux.beauty>
Cc: Philipp Rudo <prudo@redhat.com>
Cc: Ricardo Ribalda Delgado <ribalda@chromium.org>
Cc: Ross Zwisler <zwisler@google.com>
Cc: Sourabh Jain <sourabhjain@linux.ibm.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Li Chen and committed by
Andrew Morton
480e1d5c 5138c936

+74 -57
+74 -57
kernel/kexec_file.c
··· 883 883 884 884 #ifdef CONFIG_ARCH_SUPPORTS_KEXEC_PURGATORY 885 885 /* 886 + * kexec_purgatory_find_symbol - find a symbol in the purgatory 887 + * @pi: Purgatory to search in. 888 + * @name: Name of the symbol. 889 + * 890 + * Return: pointer to symbol in read-only symtab on success, NULL on error. 891 + */ 892 + static const Elf_Sym *kexec_purgatory_find_symbol(struct purgatory_info *pi, 893 + const char *name) 894 + { 895 + const Elf_Shdr *sechdrs; 896 + const Elf_Ehdr *ehdr; 897 + const Elf_Sym *syms; 898 + const char *strtab; 899 + int i, k; 900 + 901 + if (!pi->ehdr) 902 + return NULL; 903 + 904 + ehdr = pi->ehdr; 905 + sechdrs = (void *)ehdr + ehdr->e_shoff; 906 + 907 + for (i = 0; i < ehdr->e_shnum; i++) { 908 + if (sechdrs[i].sh_type != SHT_SYMTAB) 909 + continue; 910 + 911 + if (sechdrs[i].sh_link >= ehdr->e_shnum) 912 + /* Invalid strtab section number */ 913 + continue; 914 + strtab = (void *)ehdr + sechdrs[sechdrs[i].sh_link].sh_offset; 915 + syms = (void *)ehdr + sechdrs[i].sh_offset; 916 + 917 + /* Go through symbols for a match */ 918 + for (k = 0; k < sechdrs[i].sh_size/sizeof(Elf_Sym); k++) { 919 + if (ELF_ST_BIND(syms[k].st_info) != STB_GLOBAL) 920 + continue; 921 + 922 + if (strcmp(strtab + syms[k].st_name, name) != 0) 923 + continue; 924 + 925 + if (syms[k].st_shndx == SHN_UNDEF || 926 + syms[k].st_shndx >= ehdr->e_shnum) { 927 + pr_debug("Symbol: %s has bad section index %d.\n", 928 + name, syms[k].st_shndx); 929 + return NULL; 930 + } 931 + 932 + /* Found the symbol we are looking for */ 933 + return &syms[k]; 934 + } 935 + } 936 + 937 + return NULL; 938 + } 939 + /* 886 940 * kexec_purgatory_setup_kbuf - prepare buffer to load purgatory. 887 941 * @pi: Purgatory to be loaded. 888 942 * @kbuf: Buffer to setup. ··· 1014 960 unsigned long offset; 1015 961 size_t sechdrs_size; 1016 962 Elf_Shdr *sechdrs; 963 + const Elf_Sym *entry_sym; 964 + u16 entry_shndx = 0; 965 + unsigned long entry_off = 0; 966 + bool start_fixed = false; 1017 967 int i; 1018 968 1019 969 /* ··· 1034 976 offset = 0; 1035 977 bss_addr = kbuf->mem + kbuf->bufsz; 1036 978 kbuf->image->start = pi->ehdr->e_entry; 979 + 980 + entry_sym = kexec_purgatory_find_symbol(pi, "purgatory_start"); 981 + if (entry_sym) { 982 + entry_shndx = entry_sym->st_shndx; 983 + entry_off = entry_sym->st_value; 984 + } 1037 985 1038 986 for (i = 0; i < pi->ehdr->e_shnum; i++) { 1039 987 unsigned long align; ··· 1058 994 1059 995 offset = ALIGN(offset, align); 1060 996 997 + if (!start_fixed && entry_sym && i == entry_shndx && 998 + (sechdrs[i].sh_flags & SHF_EXECINSTR) && 999 + entry_off < sechdrs[i].sh_size) { 1000 + kbuf->image->start = kbuf->mem + offset + entry_off; 1001 + start_fixed = true; 1002 + } 1003 + 1061 1004 /* 1062 1005 * Check if the segment contains the entry point, if so, 1063 1006 * calculate the value of image->start based on it. ··· 1075 1004 * is not set to the initial value, and warn the user so they 1076 1005 * have a chance to fix their purgatory's linker script. 1077 1006 */ 1078 - if (sechdrs[i].sh_flags & SHF_EXECINSTR && 1007 + if (!start_fixed && sechdrs[i].sh_flags & SHF_EXECINSTR && 1079 1008 pi->ehdr->e_entry >= sechdrs[i].sh_addr && 1080 1009 pi->ehdr->e_entry < (sechdrs[i].sh_addr 1081 1010 + sechdrs[i].sh_size) && 1082 - !WARN_ON(kbuf->image->start != pi->ehdr->e_entry)) { 1011 + kbuf->image->start == pi->ehdr->e_entry) { 1083 1012 kbuf->image->start -= sechdrs[i].sh_addr; 1084 1013 kbuf->image->start += kbuf->mem + offset; 1014 + start_fixed = true; 1085 1015 } 1086 1016 1087 1017 src = (void *)pi->ehdr + sechdrs[i].sh_offset; ··· 1198 1126 vfree(pi->purgatory_buf); 1199 1127 pi->purgatory_buf = NULL; 1200 1128 return ret; 1201 - } 1202 - 1203 - /* 1204 - * kexec_purgatory_find_symbol - find a symbol in the purgatory 1205 - * @pi: Purgatory to search in. 1206 - * @name: Name of the symbol. 1207 - * 1208 - * Return: pointer to symbol in read-only symtab on success, NULL on error. 1209 - */ 1210 - static const Elf_Sym *kexec_purgatory_find_symbol(struct purgatory_info *pi, 1211 - const char *name) 1212 - { 1213 - const Elf_Shdr *sechdrs; 1214 - const Elf_Ehdr *ehdr; 1215 - const Elf_Sym *syms; 1216 - const char *strtab; 1217 - int i, k; 1218 - 1219 - if (!pi->ehdr) 1220 - return NULL; 1221 - 1222 - ehdr = pi->ehdr; 1223 - sechdrs = (void *)ehdr + ehdr->e_shoff; 1224 - 1225 - for (i = 0; i < ehdr->e_shnum; i++) { 1226 - if (sechdrs[i].sh_type != SHT_SYMTAB) 1227 - continue; 1228 - 1229 - if (sechdrs[i].sh_link >= ehdr->e_shnum) 1230 - /* Invalid strtab section number */ 1231 - continue; 1232 - strtab = (void *)ehdr + sechdrs[sechdrs[i].sh_link].sh_offset; 1233 - syms = (void *)ehdr + sechdrs[i].sh_offset; 1234 - 1235 - /* Go through symbols for a match */ 1236 - for (k = 0; k < sechdrs[i].sh_size/sizeof(Elf_Sym); k++) { 1237 - if (ELF_ST_BIND(syms[k].st_info) != STB_GLOBAL) 1238 - continue; 1239 - 1240 - if (strcmp(strtab + syms[k].st_name, name) != 0) 1241 - continue; 1242 - 1243 - if (syms[k].st_shndx == SHN_UNDEF || 1244 - syms[k].st_shndx >= ehdr->e_shnum) { 1245 - pr_debug("Symbol: %s has bad section index %d.\n", 1246 - name, syms[k].st_shndx); 1247 - return NULL; 1248 - } 1249 - 1250 - /* Found the symbol we are looking for */ 1251 - return &syms[k]; 1252 - } 1253 - } 1254 - 1255 - return NULL; 1256 1129 } 1257 1130 1258 1131 void *kexec_purgatory_get_symbol_addr(struct kimage *image, const char *name)