1 /* $NetBSD: elf.c,v 1.22 2021/05/04 21:09:16 khorben Exp $ */ 2 3 /* 4 * Copyright (c) 2017-2020 The NetBSD Foundation, Inc. All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Maxime Villard. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #define ELFSIZE 64 32 33 #include "prekern.h" 34 #include <sys/exec_elf.h> 35 36 struct elfinfo { 37 Elf_Ehdr *ehdr; 38 Elf_Shdr *shdr; 39 char *shstrtab; 40 size_t shstrsz; 41 Elf_Sym *symtab; 42 size_t symcnt; 43 char *strtab; 44 size_t strsz; 45 }; 46 47 extern paddr_t kernpa_start, kernpa_end; 48 49 static struct elfinfo eif; 50 static const char entrypoint[] = "start_prekern"; 51 52 static int 53 elf_check_header(void) 54 { 55 if (memcmp((char *)eif.ehdr->e_ident, ELFMAG, SELFMAG) != 0 || 56 eif.ehdr->e_ident[EI_CLASS] != ELFCLASS || 57 eif.ehdr->e_type != ET_REL) { 58 return -1; 59 } 60 return 0; 61 } 62 63 static bool 64 elf_section_mappable(Elf_Shdr *shdr) 65 { 66 if (!(shdr->sh_flags & SHF_ALLOC)) { 67 return false; 68 } 69 if (shdr->sh_type != SHT_NOBITS && 70 shdr->sh_type != SHT_PROGBITS) { 71 return false; 72 } 73 return true; 74 } 75 76 static bool 77 elf_can_drop_unmappable(Elf_Shdr *shdr) 78 { 79 /* 80 * We found relocations from the section 'shdr' towards the rest of 81 * the binary, but 'shdr' is not mapped. Decide whether to skip the 82 * relocations from this section. 83 * 84 * We skip only if it is a note. It means that we allow notes to 85 * have relocations towards the rest of the binary, typically with 86 * the ".note.Xen" section. Notes do not play any role at run time. 87 * 88 * Any section other than a note is the sign there is a design 89 * mistake in the kernel (variables stored outside of rodata/data). 90 */ 91 if (shdr->sh_type == SHT_NOTE) { 92 return true; 93 } 94 return false; 95 } 96 97 static vaddr_t 98 elf_get_entrypoint(void) 99 { 100 Elf_Sym *sym; 101 size_t i; 102 char *buf; 103 104 for (i = 0; i < eif.symcnt; i++) { 105 sym = &eif.symtab[i]; 106 107 if (ELF_ST_TYPE(sym->st_info) != STT_FUNC) 108 continue; 109 if (sym->st_name == 0) 110 continue; 111 if (sym->st_shndx == SHN_UNDEF) 112 continue; /* Skip external references */ 113 buf = eif.strtab + sym->st_name; 114 115 if (!memcmp(buf, entrypoint, sizeof(entrypoint))) { 116 return (vaddr_t)sym->st_value; 117 } 118 } 119 120 return 0; 121 } 122 123 static Elf_Shdr * 124 elf_find_section(char *name) 125 { 126 char *buf; 127 size_t i; 128 129 for (i = 0; i < eif.ehdr->e_shnum; i++) { 130 if (eif.shdr[i].sh_name == 0) { 131 continue; 132 } 133 buf = eif.shstrtab + eif.shdr[i].sh_name; 134 if (!strcmp(name, buf)) { 135 return &eif.shdr[i]; 136 } 137 } 138 139 return NULL; 140 } 141 142 static uintptr_t 143 elf_sym_lookup(size_t symidx) 144 { 145 const Elf_Sym *sym; 146 char *buf, *secname; 147 Elf_Shdr *sec; 148 149 if (symidx == STN_UNDEF) { 150 return 0; 151 } 152 153 if (symidx >= eif.symcnt) { 154 fatal("elf_sym_lookup: symbol beyond table"); 155 } 156 sym = &eif.symtab[symidx]; 157 buf = eif.strtab + sym->st_name; 158 159 if (sym->st_shndx == SHN_UNDEF) { 160 if (!memcmp(buf, "__start_link_set", 16)) { 161 secname = buf + 8; 162 sec = elf_find_section(secname); 163 if (sec == NULL) { 164 fatal("elf_sym_lookup: unknown start link set"); 165 } 166 return (uintptr_t)((uint8_t *)eif.ehdr + 167 sec->sh_offset); 168 } 169 if (!memcmp(buf, "__stop_link_set", 15)) { 170 secname = buf + 7; 171 sec = elf_find_section(secname); 172 if (sec == NULL) { 173 fatal("elf_sym_lookup: unknown stop link set"); 174 } 175 return (uintptr_t)((uint8_t *)eif.ehdr + 176 sec->sh_offset + sec->sh_size); 177 } 178 179 fatal("elf_sym_lookup: external symbol"); 180 } 181 if (sym->st_shndx >= eif.ehdr->e_shnum) { 182 fatal("elf_sym_lookup: st_shndx is malformed"); 183 } 184 if (!elf_section_mappable(&eif.shdr[sym->st_shndx])) { 185 fatal("elf_sym_lookup: st_shndx not mappable"); 186 } 187 if (sym->st_value == 0) { 188 fatal("elf_sym_lookup: zero value"); 189 } 190 return (uintptr_t)sym->st_value; 191 } 192 193 static void 194 elf_apply_reloc(uintptr_t relocbase, const void *data, bool isrela) 195 { 196 Elf64_Addr *where, val; 197 Elf32_Addr *where32, val32; 198 Elf64_Addr addr; 199 Elf64_Addr addend; 200 uintptr_t rtype, symidx; 201 const Elf_Rel *rel; 202 const Elf_Rela *rela; 203 204 if (isrela) { 205 rela = (const Elf_Rela *)data; 206 where = (Elf64_Addr *)(relocbase + rela->r_offset); 207 addend = rela->r_addend; 208 rtype = ELF_R_TYPE(rela->r_info); 209 symidx = ELF_R_SYM(rela->r_info); 210 } else { 211 rel = (const Elf_Rel *)data; 212 where = (Elf64_Addr *)(relocbase + rel->r_offset); 213 rtype = ELF_R_TYPE(rel->r_info); 214 symidx = ELF_R_SYM(rel->r_info); 215 /* Addend is 32 bit on 32 bit relocs */ 216 switch (rtype) { 217 case R_X86_64_PC32: 218 case R_X86_64_32: 219 case R_X86_64_32S: 220 addend = *(Elf32_Addr *)where; 221 break; 222 default: 223 addend = *where; 224 break; 225 } 226 } 227 228 switch (rtype) { 229 case R_X86_64_NONE: /* none */ 230 break; 231 232 case R_X86_64_64: /* S + A */ 233 addr = elf_sym_lookup(symidx); 234 val = addr + addend; 235 *where = val; 236 break; 237 238 case R_X86_64_PC32: /* S + A - P */ 239 case R_X86_64_PLT32: 240 addr = elf_sym_lookup(symidx); 241 where32 = (Elf32_Addr *)where; 242 val32 = (Elf32_Addr)(addr + addend - (Elf64_Addr)where); 243 *where32 = val32; 244 break; 245 246 case R_X86_64_32: /* S + A */ 247 case R_X86_64_32S: /* S + A sign extend */ 248 addr = elf_sym_lookup(symidx); 249 val32 = (Elf32_Addr)(addr + addend); 250 where32 = (Elf32_Addr *)where; 251 *where32 = val32; 252 break; 253 254 case R_X86_64_GLOB_DAT: /* S */ 255 case R_X86_64_JUMP_SLOT:/* XXX need addend + offset */ 256 addr = elf_sym_lookup(symidx); 257 *where = addr; 258 break; 259 260 case R_X86_64_RELATIVE: /* B + A */ 261 addr = relocbase + addend; 262 val = addr; 263 *where = val; 264 break; 265 266 default: 267 fatal("elf_apply_reloc: unexpected relocation type"); 268 } 269 } 270 271 /* -------------------------------------------------------------------------- */ 272 273 size_t 274 elf_get_head_size(vaddr_t headva) 275 { 276 Elf_Ehdr *ehdr; 277 Elf_Shdr *shdr; 278 size_t size; 279 280 ehdr = (Elf_Ehdr *)headva; 281 shdr = (Elf_Shdr *)((uint8_t *)ehdr + ehdr->e_shoff); 282 283 size = (vaddr_t)shdr + (vaddr_t)(ehdr->e_shnum * sizeof(Elf_Shdr)) - 284 (vaddr_t)ehdr; 285 286 return roundup(size, PAGE_SIZE); 287 } 288 289 void 290 elf_build_head(vaddr_t headva) 291 { 292 memset(&eif, 0, sizeof(struct elfinfo)); 293 294 eif.ehdr = (Elf_Ehdr *)headva; 295 eif.shdr = (Elf_Shdr *)((uint8_t *)eif.ehdr + eif.ehdr->e_shoff); 296 297 if (elf_check_header() == -1) { 298 fatal("elf_build_head: wrong kernel ELF header"); 299 } 300 } 301 302 void 303 elf_fixup_boot(vaddr_t bootva, paddr_t bootpa) 304 { 305 const paddr_t basepa = kernpa_start; 306 const vaddr_t headva = (vaddr_t)eif.ehdr; 307 size_t i, offboot; 308 309 /* 310 * Fix up the 'sh_offset' field of the REL/RELA/SYM/STR sections, which 311 * are all in the "boot" region. 312 */ 313 for (i = 0; i < eif.ehdr->e_shnum; i++) { 314 if (eif.shdr[i].sh_type != SHT_STRTAB && 315 eif.shdr[i].sh_type != SHT_REL && 316 eif.shdr[i].sh_type != SHT_RELA && 317 eif.shdr[i].sh_type != SHT_SYMTAB) { 318 continue; 319 } 320 if (eif.shdr[i].sh_offset == 0) { 321 /* The bootloader dropped it. */ 322 continue; 323 } 324 325 /* Offset of the section within the boot region. */ 326 offboot = basepa + eif.shdr[i].sh_offset - bootpa; 327 328 /* We want (headva + sh_offset) to be the VA of the region. */ 329 eif.shdr[i].sh_offset = (bootva + offboot - headva); 330 } 331 } 332 333 void 334 elf_map_sections(void) 335 { 336 const paddr_t basepa = kernpa_start; 337 const vaddr_t headva = (vaddr_t)eif.ehdr; 338 Elf_Shdr *shdr; 339 int segtype; 340 vaddr_t secva; 341 paddr_t secpa; 342 size_t i, secsz, secalign; 343 344 for (i = 0; i < eif.ehdr->e_shnum; i++) { 345 shdr = &eif.shdr[i]; 346 347 if (!elf_section_mappable(shdr)) { 348 continue; 349 } 350 351 if (shdr->sh_flags & SHF_EXECINSTR) { 352 segtype = BTSEG_TEXT; 353 } else if (shdr->sh_flags & SHF_WRITE) { 354 segtype = BTSEG_DATA; 355 } else { 356 segtype = BTSEG_RODATA; 357 } 358 secpa = basepa + shdr->sh_offset; 359 secsz = shdr->sh_size; 360 secalign = shdr->sh_addralign; 361 ASSERT(shdr->sh_offset != 0); 362 ASSERT(secpa % PAGE_SIZE == 0); 363 ASSERT(secpa + secsz <= kernpa_end); 364 365 secva = mm_map_segment(segtype, secpa, secsz, secalign); 366 367 /* 368 * Fix up the 'sh_offset' field of the NOBITS/PROGBITS sections. 369 * We want (headva + sh_offset) to be the VA of the section. 370 */ 371 ASSERT(secva > headva); 372 shdr->sh_offset = secva - headva; 373 } 374 } 375 376 void 377 elf_build_info(void) 378 { 379 size_t i, j; 380 381 /* Locate the section names */ 382 j = eif.ehdr->e_shstrndx; 383 if (j == SHN_UNDEF) { 384 fatal("elf_build_info: shstrtab not found"); 385 } 386 if (j >= eif.ehdr->e_shnum) { 387 fatal("elf_build_info: wrong shstrtab index"); 388 } 389 eif.shstrtab = (char *)((uint8_t *)eif.ehdr + eif.shdr[j].sh_offset); 390 eif.shstrsz = eif.shdr[j].sh_size; 391 392 /* Locate the symbol table */ 393 for (i = 0; i < eif.ehdr->e_shnum; i++) { 394 if (eif.shdr[i].sh_type == SHT_SYMTAB) 395 break; 396 } 397 if (i == eif.ehdr->e_shnum) { 398 fatal("elf_build_info: symtab not found"); 399 } 400 if (eif.shdr[i].sh_offset == 0) { 401 fatal("elf_build_info: symtab not loaded"); 402 } 403 eif.symtab = (Elf_Sym *)((uint8_t *)eif.ehdr + eif.shdr[i].sh_offset); 404 eif.symcnt = eif.shdr[i].sh_size / sizeof(Elf_Sym); 405 406 /* Also locate the string table */ 407 j = eif.shdr[i].sh_link; 408 if (j == SHN_UNDEF || j >= eif.ehdr->e_shnum) { 409 fatal("elf_build_info: wrong strtab index"); 410 } 411 if (eif.shdr[j].sh_type != SHT_STRTAB) { 412 fatal("elf_build_info: wrong strtab type"); 413 } 414 if (eif.shdr[j].sh_offset == 0) { 415 fatal("elf_build_info: strtab not loaded"); 416 } 417 eif.strtab = (char *)((uint8_t *)eif.ehdr + eif.shdr[j].sh_offset); 418 eif.strsz = eif.shdr[j].sh_size; 419 } 420 421 vaddr_t 422 elf_kernel_reloc(void) 423 { 424 const vaddr_t baseva = (vaddr_t)eif.ehdr; 425 vaddr_t secva, ent; 426 Elf_Sym *sym; 427 size_t i, j; 428 429 print_state(STATE_NORMAL, "ELF info created"); 430 431 /* 432 * Update all symbol values with the appropriate offset. 433 */ 434 for (i = 0; i < eif.ehdr->e_shnum; i++) { 435 if (!elf_section_mappable(&eif.shdr[i])) { 436 continue; 437 } 438 439 ASSERT(eif.shdr[i].sh_offset != 0); 440 secva = baseva + eif.shdr[i].sh_offset; 441 for (j = 0; j < eif.symcnt; j++) { 442 sym = &eif.symtab[j]; 443 if (sym->st_shndx != i) { 444 continue; 445 } 446 sym->st_value += (Elf_Addr)secva; 447 } 448 } 449 450 print_state(STATE_NORMAL, "Symbol values updated"); 451 452 /* 453 * Perform relocations without addend if there are any. 454 */ 455 for (i = 0; i < eif.ehdr->e_shnum; i++) { 456 Elf_Rel *reltab, *rel; 457 size_t secidx, nrel; 458 uintptr_t base; 459 460 if (eif.shdr[i].sh_type != SHT_REL) { 461 continue; 462 } 463 ASSERT(eif.shdr[i].sh_offset != 0); 464 reltab = (Elf_Rel *)((uint8_t *)eif.ehdr + eif.shdr[i].sh_offset); 465 nrel = eif.shdr[i].sh_size / sizeof(Elf_Rel); 466 467 secidx = eif.shdr[i].sh_info; 468 if (secidx >= eif.ehdr->e_shnum) { 469 fatal("elf_kernel_reloc: REL sh_info is malformed"); 470 } 471 if (!elf_section_mappable(&eif.shdr[secidx])) { 472 if (elf_can_drop_unmappable(&eif.shdr[secidx])) { 473 continue; 474 } 475 fatal("elf_kernel_reloc: REL sh_info not mappable"); 476 } 477 base = (uintptr_t)eif.ehdr + eif.shdr[secidx].sh_offset; 478 479 for (j = 0; j < nrel; j++) { 480 rel = &reltab[j]; 481 elf_apply_reloc(base, rel, false); 482 } 483 } 484 485 print_state(STATE_NORMAL, "REL relocations applied"); 486 487 /* 488 * Perform relocations with addend if there are any. 489 */ 490 for (i = 0; i < eif.ehdr->e_shnum; i++) { 491 Elf_Rela *relatab, *rela; 492 size_t secidx, nrela; 493 uintptr_t base; 494 495 if (eif.shdr[i].sh_type != SHT_RELA) { 496 continue; 497 } 498 ASSERT(eif.shdr[i].sh_offset != 0); 499 relatab = (Elf_Rela *)((uint8_t *)eif.ehdr + eif.shdr[i].sh_offset); 500 nrela = eif.shdr[i].sh_size / sizeof(Elf_Rela); 501 502 secidx = eif.shdr[i].sh_info; 503 if (secidx >= eif.ehdr->e_shnum) { 504 fatal("elf_kernel_reloc: RELA sh_info is malformed"); 505 } 506 if (!elf_section_mappable(&eif.shdr[secidx])) { 507 if (elf_can_drop_unmappable(&eif.shdr[secidx])) { 508 continue; 509 } 510 fatal("elf_kernel_reloc: RELA sh_info not mappable"); 511 } 512 base = (uintptr_t)eif.ehdr + eif.shdr[secidx].sh_offset; 513 514 for (j = 0; j < nrela; j++) { 515 rela = &relatab[j]; 516 elf_apply_reloc(base, rela, true); 517 } 518 } 519 520 print_state(STATE_NORMAL, "RELA relocations applied"); 521 522 /* 523 * Get the entry point. 524 */ 525 ent = elf_get_entrypoint(); 526 if (ent == 0) { 527 fatal("elf_kernel_reloc: entry point not found"); 528 } 529 530 print_state(STATE_NORMAL, "Entry point found"); 531 532 return ent; 533 } 534