/* * Checks to see if the /etc/path_to_inst file exists and whether or not * it has the magic string in it. * * Returns one of the following: * * PTI_FOUND - We have found the /etc/path_to_inst file * PTI_REBUILD - We have found the /etc/path_to_inst file and the * first line was PTI_MAGIC_STR. * PTI_NOT_FOUND - We did not find the /etc/path_to_inst file * */ static int in_get_infile(char *filename) { intptr_t file; int return_val; char buf[PTI_MAGIC_STR_LEN]; /* * Try to open the file. */ if ((file = kobj_open(filename)) == -1) { return (PTI_NOT_FOUND); } return_val = PTI_FOUND; /* * Read the first PTI_MAGIC_STR_LEN bytes from the file to see if * it contains the magic string. If there aren't that many bytes * in the file, then assume file is correct and no magic string * and move on. */ switch (kobj_read(file, buf, PTI_MAGIC_STR_LEN, 0)) { case PTI_MAGIC_STR_LEN: /* * If the first PTI_MAGIC_STR_LEN bytes are the magic string * then return PTI_REBUILD. */ if (strncmp(PTI_MAGIC_STR, buf, PTI_MAGIC_STR_LEN) == 0) return_val = PTI_REBUILD; break; case 0: /* * If the file is zero bytes in length, then consider the * file to not be found */ return_val = PTI_NOT_FOUND; default: /* Do nothing we have a good file */ break; } kobj_close(file); return (return_val); }
/* * kobj_load: * * Load an ELF object and prepare to link into the running kernel * image. */ static int kobj_load(kobj_t ko) { Elf_Ehdr *hdr; Elf_Shdr *shdr; Elf_Sym *es; vaddr_t mapbase; size_t mapsize; int error; int symtabindex; int symstrindex; int nsym; int pb, rl, ra; int alignmask; int i, j; void *addr; KASSERT(ko->ko_type != KT_UNSET); KASSERT(ko->ko_source != NULL); shdr = NULL; mapsize = 0; error = 0; hdr = NULL; /* * Read the elf header from the file. */ error = kobj_read(ko, (void **)&hdr, sizeof(*hdr), 0); if (error != 0) goto out; if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0) { kobj_error("not an ELF object"); error = ENOEXEC; goto out; } if (hdr->e_ident[EI_VERSION] != EV_CURRENT || hdr->e_version != EV_CURRENT) { kobj_error("unsupported file version"); error = ENOEXEC; goto out; } if (hdr->e_type != ET_REL) { kobj_error("unsupported file type"); error = ENOEXEC; goto out; } switch (hdr->e_machine) { #if ELFSIZE == 32 ELF32_MACHDEP_ID_CASES #else ELF64_MACHDEP_ID_CASES #endif default: kobj_error("unsupported machine"); error = ENOEXEC; goto out; } ko->ko_nprogtab = 0; ko->ko_shdr = 0; ko->ko_nrel = 0; ko->ko_nrela = 0; /* * Allocate and read in the section header. */ ko->ko_shdrsz = hdr->e_shnum * hdr->e_shentsize; if (ko->ko_shdrsz == 0 || hdr->e_shoff == 0 || hdr->e_shentsize != sizeof(Elf_Shdr)) { error = ENOEXEC; goto out; } error = kobj_read(ko, (void **)&shdr, ko->ko_shdrsz, hdr->e_shoff); if (error != 0) { goto out; } ko->ko_shdr = shdr; /* * Scan the section header for information and table sizing. */ nsym = 0; symtabindex = -1; symstrindex = -1; for (i = 0; i < hdr->e_shnum; i++) { switch (shdr[i].sh_type) { case SHT_PROGBITS: case SHT_NOBITS: ko->ko_nprogtab++; break; case SHT_SYMTAB: nsym++; symtabindex = i; symstrindex = shdr[i].sh_link; break; case SHT_REL: ko->ko_nrel++; break; case SHT_RELA: ko->ko_nrela++; break; case SHT_STRTAB: break; } } if (ko->ko_nprogtab == 0) { kobj_error("file has no contents"); error = ENOEXEC; goto out; } if (nsym != 1) { /* Only allow one symbol table for now */ kobj_error("file has no valid symbol table"); error = ENOEXEC; goto out; } if (symstrindex < 0 || symstrindex > hdr->e_shnum || shdr[symstrindex].sh_type != SHT_STRTAB) { kobj_error("file has invalid symbol strings"); error = ENOEXEC; goto out; } /* * Allocate space for tracking the load chunks. */ if (ko->ko_nprogtab != 0) { ko->ko_progtab = kmem_zalloc(ko->ko_nprogtab * sizeof(*ko->ko_progtab), KM_SLEEP); if (ko->ko_progtab == NULL) { error = ENOMEM; goto out; } } if (ko->ko_nrel != 0) { ko->ko_reltab = kmem_zalloc(ko->ko_nrel * sizeof(*ko->ko_reltab), KM_SLEEP); if (ko->ko_reltab == NULL) { error = ENOMEM; goto out; } } if (ko->ko_nrela != 0) { ko->ko_relatab = kmem_zalloc(ko->ko_nrela * sizeof(*ko->ko_relatab), KM_SLEEP); if (ko->ko_relatab == NULL) { error = ENOMEM; goto out; } } if (symtabindex == -1) { kobj_error("lost symbol table index"); goto out; } /* * Allocate space for and load the symbol table. */ ko->ko_symcnt = shdr[symtabindex].sh_size / sizeof(Elf_Sym); if (ko->ko_symcnt == 0) { kobj_error("no symbol table"); goto out; } error = kobj_read(ko, (void **)&ko->ko_symtab, ko->ko_symcnt * sizeof(Elf_Sym), shdr[symtabindex].sh_offset); if (error != 0) { goto out; } /* * Allocate space for and load the symbol strings. */ ko->ko_strtabsz = shdr[symstrindex].sh_size; if (ko->ko_strtabsz == 0) { kobj_error("no symbol strings"); goto out; } error = kobj_read(ko, (void *)&ko->ko_strtab, ko->ko_strtabsz, shdr[symstrindex].sh_offset); if (error != 0) { goto out; } /* * Do we have a string table for the section names? */ if (hdr->e_shstrndx != 0 && shdr[hdr->e_shstrndx].sh_size != 0 && shdr[hdr->e_shstrndx].sh_type == SHT_STRTAB) { ko->ko_shstrtabsz = shdr[hdr->e_shstrndx].sh_size; error = kobj_read(ko, (void *)&ko->ko_shstrtab, shdr[hdr->e_shstrndx].sh_size, shdr[hdr->e_shstrndx].sh_offset); if (error != 0) { goto out; } } /* * Size up code/data(progbits) and bss(nobits). */ alignmask = 0; mapbase = 0; for (i = 0; i < hdr->e_shnum; i++) { switch (shdr[i].sh_type) { case SHT_PROGBITS: case SHT_NOBITS: if (mapbase == 0) mapbase = shdr[i].sh_offset; alignmask = shdr[i].sh_addralign - 1; mapsize += alignmask; mapsize &= ~alignmask; mapsize += shdr[i].sh_size; break; } } /* * We know how much space we need for the text/data/bss/etc. * This stuff needs to be in a single chunk so that profiling etc * can get the bounds and gdb can associate offsets with modules. */ if (mapsize == 0) { kobj_error("no text/data/bss"); goto out; } if (ko->ko_type == KT_MEMORY) { mapbase += (vaddr_t)ko->ko_source; } else { mapbase = uvm_km_alloc(lkm_map, round_page(mapsize), 0, UVM_KMF_WIRED | UVM_KMF_EXEC); if (mapbase == 0) { error = ENOMEM; goto out; } } ko->ko_address = mapbase; ko->ko_size = mapsize; /* * Now load code/data(progbits), zero bss(nobits), allocate space * for and load relocs */ pb = 0; rl = 0; ra = 0; alignmask = 0; for (i = 0; i < hdr->e_shnum; i++) { switch (shdr[i].sh_type) { case SHT_PROGBITS: case SHT_NOBITS: alignmask = shdr[i].sh_addralign - 1; if (ko->ko_type == KT_MEMORY) { addr = (void *)(shdr[i].sh_offset + (vaddr_t)ko->ko_source); if (((vaddr_t)addr & alignmask) != 0) { kobj_error("section %d not aligned\n", i); goto out; } } else { mapbase += alignmask; mapbase &= ~alignmask; addr = (void *)mapbase; mapbase += shdr[i].sh_size; } ko->ko_progtab[pb].addr = addr; if (shdr[i].sh_type == SHT_PROGBITS) { ko->ko_progtab[pb].name = "<<PROGBITS>>"; error = kobj_read_bits(ko, addr, shdr[i].sh_size, shdr[i].sh_offset); if (error != 0) { goto out; } } else if (ko->ko_type == KT_MEMORY && shdr[i].sh_size != 0) { kobj_error("non-loadable BSS section in " "pre-loaded module"); error = EINVAL; goto out; } else { ko->ko_progtab[pb].name = "<<NOBITS>>"; memset(addr, 0, shdr[i].sh_size); } ko->ko_progtab[pb].size = shdr[i].sh_size; ko->ko_progtab[pb].sec = i; if (ko->ko_shstrtab != NULL && shdr[i].sh_name != 0) { ko->ko_progtab[pb].name = ko->ko_shstrtab + shdr[i].sh_name; } /* Update all symbol values with the offset. */ for (j = 0; j < ko->ko_symcnt; j++) { es = &ko->ko_symtab[j]; if (es->st_shndx != i) { continue; } es->st_value += (Elf_Addr)addr; } pb++; break; case SHT_REL: ko->ko_reltab[rl].size = shdr[i].sh_size; ko->ko_reltab[rl].size -= shdr[i].sh_size % sizeof(Elf_Rel); if (ko->ko_reltab[rl].size != 0) { ko->ko_reltab[rl].nrel = shdr[i].sh_size / sizeof(Elf_Rel); ko->ko_reltab[rl].sec = shdr[i].sh_info; error = kobj_read(ko, (void **)&ko->ko_reltab[rl].rel, ko->ko_reltab[rl].size, shdr[i].sh_offset); if (error != 0) { goto out; } } rl++; break; case SHT_RELA: ko->ko_relatab[ra].size = shdr[i].sh_size; ko->ko_relatab[ra].size -= shdr[i].sh_size % sizeof(Elf_Rela); if (ko->ko_relatab[ra].size != 0) { ko->ko_relatab[ra].nrela = shdr[i].sh_size / sizeof(Elf_Rela); ko->ko_relatab[ra].sec = shdr[i].sh_info; error = kobj_read(ko, (void **)&ko->ko_relatab[ra].rela, shdr[i].sh_size, shdr[i].sh_offset); if (error != 0) { goto out; } } ra++; break; default: break; } } if (pb != ko->ko_nprogtab) { panic("lost progbits"); } if (rl != ko->ko_nrel) { panic("lost rel"); } if (ra != ko->ko_nrela) { panic("lost rela"); } if (ko->ko_type != KT_MEMORY && mapbase != ko->ko_address + mapsize) { panic("mapbase 0x%lx != address %lx + mapsize %ld (0x%lx)\n", (long)mapbase, (long)ko->ko_address, (long)mapsize, (long)ko->ko_address + mapsize); } /* * Perform local relocations only. Relocations relating to global * symbols will be done by kobj_affix(). */ error = kobj_checkdup(ko); if (error == 0) { error = kobj_relocate(ko, true); } out: if (hdr != NULL) { kobj_free(ko, hdr, sizeof(*hdr)); } kobj_close(ko); if (error != 0) { kobj_unload(ko); } return error; }