load_elf.c revision 60432
1/*- 2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3 * Copyright (c) 1998 Peter Wemm <peter@freebsd.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: head/sys/boot/common/load_elf.c 60432 2000-05-12 05:16:37Z bp $ 28 */ 29 30#include <sys/param.h> 31#include <sys/exec.h> 32#include <sys/reboot.h> 33#include <sys/linker.h> 34#include <sys/module.h> 35#include <string.h> 36#include <machine/bootinfo.h> 37#include <machine/elf.h> 38#include <stand.h> 39#define FREEBSD_ELF 40#include <link.h> 41 42#include "bootstrap.h" 43 44#define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l) 45 46 47typedef struct elf_file { 48 Elf_Phdr *ph; 49 Elf_Ehdr *ehdr; 50 Elf_Sym *symtab; 51 Elf_Off *hashtab; 52 Elf_Off nbuckets; 53 Elf_Off nchains; 54 Elf_Off* buckets; 55 Elf_Off* chains; 56 char *strtab; 57 size_t strsz; 58 int fd; 59 caddr_t firstpage; 60 int firstlen; 61 int kernel; 62 vm_offset_t off; 63} *elf_file_t; 64 65static int elf_loadimage(struct preloaded_file *mp, elf_file_t ef, vm_offset_t loadaddr); 66static int elf_lookup_symbol(struct preloaded_file *mp, elf_file_t ef, const char* name, Elf_Sym* sym); 67static int elf_parse_modmetadata(struct preloaded_file *mp, elf_file_t ef); 68 69char *elf_kerneltype = "elf kernel"; 70char *elf_moduletype = "elf module"; 71 72/* 73 * Attempt to load the file (file) as an ELF module. It will be stored at 74 * (dest), and a pointer to a module structure describing the loaded object 75 * will be saved in (result). 76 */ 77int 78elf_loadfile(char *filename, vm_offset_t dest, struct preloaded_file **result) 79{ 80 struct preloaded_file *fp, *kfp; 81 struct elf_file ef; 82 Elf_Ehdr *ehdr; 83 int err; 84 u_int pad; 85 char *s; 86 87 fp = NULL; 88 bzero(&ef, sizeof(struct elf_file)); 89 90 /* 91 * Open the image, read and validate the ELF header 92 */ 93 if (filename == NULL) /* can't handle nameless */ 94 return(EFTYPE); 95 if ((ef.fd = open(filename, O_RDONLY)) == -1) 96 return(errno); 97 ef.firstpage = malloc(PAGE_SIZE); 98 if (ef.firstpage == NULL) { 99 close(ef.fd); 100 return(ENOMEM); 101 } 102 ef.firstlen = read(ef.fd, ef.firstpage, PAGE_SIZE); 103 if (ef.firstlen <= sizeof(Elf_Ehdr)) { 104 err = EFTYPE; /* could be EIO, but may be small file */ 105 goto oerr; 106 } 107 ehdr = ef.ehdr = (Elf_Ehdr *)ef.firstpage; 108 109 /* Is it ELF? */ 110 if (!IS_ELF(*ehdr)) { 111 err = EFTYPE; 112 goto oerr; 113 } 114 if (ehdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || /* Layout ? */ 115 ehdr->e_ident[EI_DATA] != ELF_TARG_DATA || 116 ehdr->e_ident[EI_VERSION] != EV_CURRENT || /* Version ? */ 117 ehdr->e_version != EV_CURRENT || 118 ehdr->e_machine != ELF_TARG_MACH) { /* Machine ? */ 119 err = EFTYPE; 120 goto oerr; 121 } 122 123 124 /* 125 * Check to see what sort of module we are. 126 */ 127 kfp = file_findfile(NULL, NULL); 128 if (ehdr->e_type == ET_DYN) { 129 /* Looks like a kld module */ 130 if (kfp == NULL) { 131 printf("elf_loadfile: can't load module before kernel\n"); 132 err = EPERM; 133 goto oerr; 134 } 135 if (strcmp(elf_kerneltype, kfp->f_type)) { 136 printf("elf_loadfile: can't load module with kernel type '%s'\n", kfp->f_type); 137 err = EPERM; 138 goto oerr; 139 } 140 /* Looks OK, got ahead */ 141 ef.kernel = 0; 142 143 /* Page-align the load address */ 144 pad = (u_int)dest & PAGE_MASK; 145 if (pad != 0) { 146 pad = PAGE_SIZE - pad; 147 dest += pad; 148 } 149 } else if (ehdr->e_type == ET_EXEC) { 150 /* Looks like a kernel */ 151 if (kfp != NULL) { 152 printf("elf_loadfile: kernel already loaded\n"); 153 err = EPERM; 154 goto oerr; 155 } 156 /* 157 * Calculate destination address based on kernel entrypoint 158 */ 159 dest = (vm_offset_t) ehdr->e_entry; 160 if (dest == 0) { 161 printf("elf_loadfile: not a kernel (maybe static binary?)\n"); 162 err = EPERM; 163 goto oerr; 164 } 165 ef.kernel = 1; 166 167 } else { 168 err = EFTYPE; 169 goto oerr; 170 } 171 172 /* 173 * Ok, we think we should handle this. 174 */ 175 fp = file_alloc(); 176 if (fp == NULL) { 177 printf("elf_loadfile: cannot allocate module info\n"); 178 err = EPERM; 179 goto out; 180 } 181 if (ef.kernel) 182 setenv("kernelname", filename, 1); 183 s = strrchr(filename, '/'); 184 if (s) 185 fp->f_name = strdup(s + 1); 186 else 187 fp->f_name = strdup(filename); 188 fp->f_type = strdup(ef.kernel ? elf_kerneltype : elf_moduletype); 189 190#ifdef ELF_VERBOSE 191 if (ef.kernel) 192 printf("%s entry at %p\n", filename, (void *) dest); 193#else 194 printf("%s ", filename); 195#endif 196 197 fp->f_size = elf_loadimage(fp, &ef, dest); 198 if (fp->f_size == 0 || fp->f_addr == 0) 199 goto ioerr; 200 201 /* save exec header as metadata */ 202 file_addmetadata(fp, MODINFOMD_ELFHDR, sizeof(*ehdr), ehdr); 203 204 /* Load OK, return module pointer */ 205 *result = (struct preloaded_file *)fp; 206 err = 0; 207 goto out; 208 209 ioerr: 210 err = EIO; 211 oerr: 212 file_discard(fp); 213 out: 214 if (ef.firstpage) 215 free(ef.firstpage); 216 close(ef.fd); 217 return(err); 218} 219 220/* 221 * With the file (fd) open on the image, and (ehdr) containing 222 * the Elf header, load the image at (off) 223 */ 224static int 225elf_loadimage(struct preloaded_file *fp, elf_file_t ef, vm_offset_t off) 226{ 227 int i, j; 228 Elf_Ehdr *ehdr; 229 Elf_Phdr *phdr, *php; 230 Elf_Shdr *shdr; 231 int ret; 232 vm_offset_t firstaddr; 233 vm_offset_t lastaddr; 234 void *buf; 235 size_t resid, chunk; 236 vm_offset_t dest; 237 vm_offset_t ssym, esym; 238 Elf_Dyn *dp; 239 int ndp; 240 char *s; 241 int symstrindex; 242 int symtabindex; 243 long size; 244 int fpcopy; 245 246 dp = NULL; 247 shdr = NULL; 248 ret = 0; 249 firstaddr = lastaddr = 0; 250 ehdr = ef->ehdr; 251 if (ef->kernel) { 252#ifdef __i386__ 253 off = - (off & 0xff000000u); /* i386 relocates after locore */ 254#else 255 off = 0; /* alpha is direct mapped for kernels */ 256#endif 257 } 258 ef->off = off; 259 260 if ((ehdr->e_phoff + ehdr->e_phnum * sizeof(*phdr)) > ef->firstlen) { 261 printf("elf_loadimage: program header not within first page\n"); 262 goto out; 263 } 264 phdr = (Elf_Phdr *)(ef->firstpage + ehdr->e_phoff); 265 266 for (i = 0; i < ehdr->e_phnum; i++) { 267 /* We want to load PT_LOAD segments only.. */ 268 if (phdr[i].p_type != PT_LOAD) 269 continue; 270 271#ifdef ELF_VERBOSE 272 printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx", 273 (long)phdr[i].p_filesz, (long)phdr[i].p_offset, 274 (long)(phdr[i].p_vaddr + off), 275 (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1)); 276#else 277 if ((phdr[i].p_flags & PF_W) == 0) { 278 printf("text=0x%lx ", (long)phdr[i].p_filesz); 279 } else { 280 printf("data=0x%lx", (long)phdr[i].p_filesz); 281 if (phdr[i].p_filesz < phdr[i].p_memsz) 282 printf("+0x%lx", (long)(phdr[i].p_memsz -phdr[i].p_filesz)); 283 printf(" "); 284 } 285#endif 286 fpcopy = 0; 287 if (ef->firstlen > phdr[i].p_offset) { 288 fpcopy = ef->firstlen - phdr[i].p_offset; 289 archsw.arch_copyin(ef->firstpage + phdr[i].p_offset, 290 phdr[i].p_vaddr + off, fpcopy); 291 } 292 if (phdr[i].p_filesz > fpcopy) { 293 if (lseek(ef->fd, phdr[i].p_offset + fpcopy, SEEK_SET) == -1) { 294 printf("\nelf_loadexec: cannot seek\n"); 295 goto out; 296 } 297 if (archsw.arch_readin(ef->fd, phdr[i].p_vaddr + off + fpcopy, 298 phdr[i].p_filesz - fpcopy) != phdr[i].p_filesz - fpcopy) { 299 printf("\nelf_loadexec: archsw.readin failed\n"); 300 goto out; 301 } 302 } 303 /* clear space from oversized segments; eg: bss */ 304 if (phdr[i].p_filesz < phdr[i].p_memsz) { 305#ifdef ELF_VERBOSE 306 printf(" (bss: 0x%lx-0x%lx)", 307 (long)(phdr[i].p_vaddr + off + phdr[i].p_filesz), 308 (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1)); 309#endif 310 311 /* no archsw.arch_bzero */ 312 buf = malloc(PAGE_SIZE); 313 if (buf == NULL) { 314 printf("\nelf_loadimage: malloc() failed\n"); 315 goto out; 316 } 317 bzero(buf, PAGE_SIZE); 318 resid = phdr[i].p_memsz - phdr[i].p_filesz; 319 dest = phdr[i].p_vaddr + off + phdr[i].p_filesz; 320 while (resid > 0) { 321 chunk = min(PAGE_SIZE, resid); 322 archsw.arch_copyin(buf, dest, chunk); 323 resid -= chunk; 324 dest += chunk; 325 } 326 free(buf); 327 } 328#ifdef ELF_VERBOSE 329 printf("\n"); 330#endif 331 332 if (firstaddr == 0 || firstaddr > (phdr[i].p_vaddr + off)) 333 firstaddr = phdr[i].p_vaddr + off; 334 if (lastaddr == 0 || lastaddr < (phdr[i].p_vaddr + off + phdr[i].p_memsz)) 335 lastaddr = phdr[i].p_vaddr + off + phdr[i].p_memsz; 336 } 337 lastaddr = roundup(lastaddr, sizeof(long)); 338 339 /* 340 * Now grab the symbol tables. This isn't easy if we're reading a 341 * .gz file. I think the rule is going to have to be that you must 342 * strip a file to remove symbols before gzipping it so that we do not 343 * try to lseek() on it. 344 */ 345 chunk = ehdr->e_shnum * ehdr->e_shentsize; 346 if (chunk == 0 || ehdr->e_shoff == 0) 347 goto nosyms; 348 shdr = malloc(chunk); 349 if (shdr == NULL) 350 goto nosyms; 351 if (lseek(ef->fd, ehdr->e_shoff, SEEK_SET) == -1) { 352 printf("\nelf_loadimage: cannot lseek() to section headers"); 353 goto nosyms; 354 } 355 if (read(ef->fd, shdr, chunk) != chunk) { 356 printf("\nelf_loadimage: read section headers failed"); 357 goto nosyms; 358 } 359 symtabindex = -1; 360 symstrindex = -1; 361 for (i = 0; i < ehdr->e_shnum; i++) { 362 if (shdr[i].sh_type != SHT_SYMTAB) 363 continue; 364 for (j = 0; j < ehdr->e_phnum; j++) { 365 if (phdr[j].p_type != PT_LOAD) 366 continue; 367 if (shdr[i].sh_offset >= phdr[j].p_offset && 368 (shdr[i].sh_offset + shdr[i].sh_size <= 369 phdr[j].p_offset + phdr[j].p_filesz)) { 370 shdr[i].sh_offset = 0; 371 shdr[i].sh_size = 0; 372 break; 373 } 374 } 375 if (shdr[i].sh_offset == 0 || shdr[i].sh_size == 0) 376 continue; /* alread loaded in a PT_LOAD above */ 377 /* Save it for loading below */ 378 symtabindex = i; 379 symstrindex = shdr[i].sh_link; 380 } 381 if (symtabindex < 0 || symstrindex < 0) 382 goto nosyms; 383 384 /* Ok, committed to a load. */ 385#ifndef ELF_VERBOSE 386 printf("syms=["); 387#endif 388 ssym = lastaddr; 389 for (i = symtabindex; i >= 0; i = symstrindex) { 390#ifdef ELF_VERBOSE 391 char *secname; 392 393 switch(shdr[i].sh_type) { 394 case SHT_SYMTAB: /* Symbol table */ 395 secname = "symtab"; 396 break; 397 case SHT_STRTAB: /* String table */ 398 secname = "strtab"; 399 break; 400 default: 401 secname = "WHOA!!"; 402 break; 403 } 404#endif 405 406 size = shdr[i].sh_size; 407 archsw.arch_copyin(&size, lastaddr, sizeof(size)); 408 lastaddr += sizeof(long); 409 410#ifdef ELF_VERBOSE 411 printf("\n%s: 0x%lx@0x%lx -> 0x%lx-0x%lx", secname, 412 shdr[i].sh_size, shdr[i].sh_offset, 413 lastaddr, lastaddr + shdr[i].sh_size); 414#else 415 if (i == symstrindex) 416 printf("+"); 417 printf("0x%lx+0x%lx", (long)sizeof(size), size); 418#endif 419 420 if (lseek(ef->fd, shdr[i].sh_offset, SEEK_SET) == -1) { 421 printf("\nelf_loadimage: could not seek for symbols - skipped!"); 422 lastaddr = ssym; 423 ssym = 0; 424 goto nosyms; 425 } 426 if (archsw.arch_readin(ef->fd, lastaddr, shdr[i].sh_size) != 427 shdr[i].sh_size) { 428 printf("\nelf_loadimage: could not read symbols - skipped!"); 429 lastaddr = ssym; 430 ssym = 0; 431 goto nosyms; 432 } 433 /* Reset offsets relative to ssym */ 434 lastaddr += shdr[i].sh_size; 435 lastaddr = roundup(lastaddr, sizeof(long)); 436 if (i == symtabindex) 437 symtabindex = -1; 438 else if (i == symstrindex) 439 symstrindex = -1; 440 } 441 esym = lastaddr; 442#ifndef ELF_VERBOSE 443 printf("]"); 444#endif 445 446 file_addmetadata(fp, MODINFOMD_SSYM, sizeof(ssym), &ssym); 447 file_addmetadata(fp, MODINFOMD_ESYM, sizeof(esym), &esym); 448 449nosyms: 450 printf("\n"); 451 452 ret = lastaddr - firstaddr; 453 fp->f_addr = firstaddr; 454 455 php = NULL; 456 for (i = 0; i < ehdr->e_phnum; i++) { 457 if (phdr[i].p_type == PT_DYNAMIC) { 458 php = phdr + i; 459 dp = (Elf_Dyn *)(php->p_vaddr); 460 file_addmetadata(fp, MODINFOMD_DYNAMIC, sizeof(dp), &dp); 461 dp = NULL; 462 break; 463 } 464 } 465 466 if (php == NULL) /* this is bad, we cannot get to symbols or _DYNAMIC */ 467 goto out; 468 469 ndp = php->p_filesz / sizeof(Elf_Dyn); 470 if (ndp == 0) 471 goto out; 472 dp = malloc(php->p_filesz); 473 if (dp == NULL) 474 goto out; 475 archsw.arch_copyout(php->p_vaddr + off, dp, php->p_filesz); 476 477 ef->strsz = 0; 478 for (i = 0; i < ndp; i++) { 479 if (dp[i].d_tag == NULL) 480 break; 481 switch (dp[i].d_tag) { 482 case DT_HASH: 483 ef->hashtab = (Elf_Off*)(dp[i].d_un.d_ptr + off); 484 break; 485 case DT_STRTAB: 486 ef->strtab = (char *)(dp[i].d_un.d_ptr + off); 487 break; 488 case DT_STRSZ: 489 ef->strsz = dp[i].d_un.d_val; 490 break; 491 case DT_SYMTAB: 492 ef->symtab = (Elf_Sym*)(dp[i].d_un.d_ptr + off); 493 break; 494 default: 495 break; 496 } 497 } 498 if (ef->hashtab == NULL || ef->symtab == NULL || 499 ef->strtab == NULL || ef->strsz == 0) 500 goto out; 501 COPYOUT(ef->hashtab, &ef->nbuckets, sizeof(ef->nbuckets)); 502 COPYOUT(ef->hashtab + 1, &ef->nchains, sizeof(ef->nchains)); 503 ef->buckets = ef->hashtab + 2; 504 ef->chains = ef->buckets + ef->nbuckets; 505 if (elf_parse_modmetadata(fp, ef) == 0) 506 goto out; 507 508 if (ef->kernel) /* kernel must not depend on anything */ 509 goto out; 510 511 for (i = 0; i < ndp; i++) { 512 if (dp[i].d_tag == NULL) 513 break; 514 if (dp[i].d_tag != DT_NEEDED) 515 continue; 516 j = dp[i].d_un.d_ptr; 517 if (j < 1 || j > ef->strsz - 2) 518 continue; 519 s = strdupout((vm_offset_t)&ef->strtab[j]); 520 file_addmetadata(fp, MODINFOMD_DEPLIST, strlen(s) + 1, s); 521 free(s); 522 } 523 524out: 525 if (dp) 526 free(dp); 527 if (shdr) 528 free(shdr); 529 return ret; 530} 531 532static char invalid_name[] = "bad"; 533char * 534fake_modname(char *name) { 535 char *sp, *ep; 536 int len; 537 538 sp = strrchr(name, '/'); 539 if (sp) 540 sp++; 541 else 542 sp = name; 543 ep = strrchr(name, '.'); 544 if (ep) { 545 if (ep == name) { 546 sp = invalid_name; 547 ep = invalid_name + sizeof(invalid_name) - 1; 548 } 549 } else 550 ep = name + strlen(name); 551 len = ep - sp; 552 ep = malloc(len + 1); 553 if (ep == NULL) 554 return NULL; 555 memcpy(ep, sp, len); 556 ep[len] = '\0'; 557 return ep; 558} 559 560int 561elf_parse_modmetadata(struct preloaded_file *fp, elf_file_t ef) { 562 struct mod_metadata md; 563 Elf_Sym sym; 564 void **p, *v; 565 char *s; 566 long entries; 567 int modcnt; 568 569 if (elf_lookup_symbol(fp, ef, "modmetadata_set", &sym) != 0) 570 return ENOENT; 571 COPYOUT(sym.st_value + ef->off, &entries, sizeof(entries)); 572 573 modcnt = 0; 574 p = (void*)(sym.st_value + ef->off + sizeof(entries)); 575 while (entries--) { 576 COPYOUT(p++, &v, sizeof(v)); 577 COPYOUT(v + ef->off, &md, sizeof(md)); 578 switch(md.md_type) { 579 case MDT_DEPEND: 580 if (ef->kernel) /* kernel must not depend on anything */ 581 break; 582 s = strdupout((vm_offset_t)(md.md_cval + ef->off)); 583 file_addmetadata(fp, MODINFOMD_DEPLIST, strlen(s) + 1, s); 584 free(s); 585 break; 586 case MDT_VERSION: 587 s = strdupout((vm_offset_t)(md.md_cval + ef->off)); 588 file_addmodule(fp, s, NULL); 589 printf(" module: %s\n", s); 590 free(s); 591 modcnt++; 592 break; 593 } 594 } 595 if (modcnt == 0) { 596 s = fake_modname(fp->f_name); 597 file_addmodule(fp, s, NULL); 598 free(s); 599 } 600 return 0; 601} 602 603static unsigned long 604elf_hash(const char *name) 605{ 606 const unsigned char *p = (const unsigned char *) name; 607 unsigned long h = 0; 608 unsigned long g; 609 610 while (*p != '\0') { 611 h = (h << 4) + *p++; 612 if ((g = h & 0xf0000000) != 0) 613 h ^= g >> 24; 614 h &= ~g; 615 } 616 return h; 617} 618 619static const char elf_bad_symtable[] = "elf_lookup_symbol: corrupt symbol table\n"; 620int 621elf_lookup_symbol(struct preloaded_file *fp, elf_file_t ef, const char* name, 622 Elf_Sym *symp) 623{ 624 unsigned long symnum; 625 Elf_Sym sym; 626 char *strp; 627 unsigned long hash; 628 629 hash = elf_hash(name); 630 COPYOUT(&ef->buckets[hash % ef->nbuckets], &symnum, sizeof(symnum)); 631 632 while (symnum != STN_UNDEF) { 633 if (symnum >= ef->nchains) { 634 printf(elf_bad_symtable); 635 return ENOENT; 636 } 637 638 COPYOUT(ef->symtab + symnum, &sym, sizeof(sym)); 639 if (sym.st_name == 0) { 640 printf(elf_bad_symtable); 641 return ENOENT; 642 } 643 644 strp = strdupout((vm_offset_t)(ef->strtab + sym.st_name)); 645 if (strcmp(name, strp) == 0) { 646 free(strp); 647 if (sym.st_shndx != SHN_UNDEF || 648 (sym.st_value != 0 && 649 ELF_ST_TYPE(sym.st_info) == STT_FUNC)) { 650 *symp = sym; 651 return 0; 652 } 653 return ENOENT; 654 } 655 free(strp); 656 COPYOUT(&ef->chains[symnum], &symnum, sizeof(symnum)); 657 } 658 return ENOENT; 659} 660