diff --git a/usr.sbin/crunch/crunchide/exec_elf32.c b/usr.sbin/crunch/crunchide/exec_elf32.c index ed84fc421e86..61d02419c9c7 100644 --- a/usr.sbin/crunch/crunchide/exec_elf32.c +++ b/usr.sbin/crunch/crunchide/exec_elf32.c @@ -130,6 +130,20 @@ xmalloc(size_t size, const char *fn, const char *use) return (rv); } +static void * +xrealloc(void *ptr, size_t size, const char *fn, const char *use) +{ + void *rv; + + rv = realloc(ptr, size); + if (rv == NULL) { + free(ptr); + fprintf(stderr, "%s: out of memory (reallocating for %s)\n", + fn, use); + } + return (rv); +} + int ELFNAMEEND(check)(int fd, const char *fn) { @@ -197,6 +211,21 @@ ELFNAMEEND(check)(int fd, const char *fn) return 1; } +/* + * This function 'hides' (some of) ELF executable file's symbols. + * It hides them by renaming them to "_$$hide$$ ". + * Symbols in the global keep list, or which are marked as being undefined, + * are left alone. + * + * An old version of this code shuffled various tables around, turning + * global symbols to be hidden into local symbols. That lost on the + * mips, because CALL16 relocs must reference global symbols, and, if + * those symbols were being hidden, they were no longer global. + * + * The new renaming behaviour doesn't take global symbols out of the + * namespace. However, it's ... unlikely that there will ever be + * any collisions in practice because of the new method. + */ int ELFNAMEEND(hide)(int fd, const char *fn) { @@ -204,11 +233,14 @@ ELFNAMEEND(hide)(int fd, const char *fn) Elf_Shdr *shdrp = NULL, *symtabshdr, *strtabshdr; Elf_Sym *symtabp = NULL; char *strtabp = NULL; - Elf_Size *symfwmap = NULL, *symrvmap = NULL, nsyms, nlocalsyms, ewi; - struct listelem *relalist = NULL, *rellist = NULL, *tmpl; + Elf_Size nsyms, nlocalsyms, ewi; ssize_t shdrsize; int rv, i, weird; + size_t nstrtab_size, nstrtab_nextoff, fn_size; + char *nstrtabp = NULL; unsigned char data; + Elf_Off maxoff, stroff; + const char *weirdreason = NULL; rv = 0; if (xreadatoff(fd, &ehdr, 0, sizeof ehdr, fn) != sizeof ehdr) @@ -225,42 +257,38 @@ ELFNAMEEND(hide)(int fd, const char *fn) symtabshdr = strtabshdr = NULL; weird = 0; + maxoff = stroff = 0; for (i = 0; i < xe16toh(ehdr.e_shnum); i++) { + if (xewtoh(shdrp[i].sh_offset) > maxoff) + maxoff = xewtoh(shdrp[i].sh_offset); switch (xe32toh(shdrp[i].sh_type)) { case SHT_SYMTAB: if (symtabshdr != NULL) weird = 1; symtabshdr = &shdrp[i]; strtabshdr = &shdrp[xe32toh(shdrp[i].sh_link)]; - break; - case SHT_RELA: - tmpl = xmalloc(sizeof *tmpl, fn, "rela list element"); - if (tmpl == NULL) - goto bad; - tmpl->mem = NULL; - tmpl->file = xewtoh(shdrp[i].sh_offset); - tmpl->size = xewtoh(shdrp[i].sh_size); - tmpl->next = relalist; - relalist = tmpl; - break; - case SHT_REL: - tmpl = xmalloc(sizeof *tmpl, fn, "rel list element"); - if (tmpl == NULL) - goto bad; - tmpl->mem = NULL; - tmpl->file = xewtoh(shdrp[i].sh_offset); - tmpl->size = xewtoh(shdrp[i].sh_size); - tmpl->next = rellist; - rellist = tmpl; + + /* Check whether the string table is the last section */ + stroff = xewtoh(shdrp[xe32toh(shdrp[i].sh_link)].sh_offset); + if (!weird && xe32toh(shdrp[i].sh_link) != (xe16toh(ehdr.e_shnum) - 1)) { + weird = 1; + weirdreason = "string table not last section"; + } break; } } + if (! weirdreason) + weirdreason = "unsupported"; if (symtabshdr == NULL) goto out; if (strtabshdr == NULL) weird = 1; + if (!weird && stroff != maxoff) { + weird = 1; + weirdreason = "string table section not last in file"; + } if (weird) { - fprintf(stderr, "%s: weird executable (unsupported)\n", fn); + fprintf(stderr, "%s: weird executable (%s)\n", fn, weirdreason); goto bad; } @@ -284,105 +312,53 @@ ELFNAMEEND(hide)(int fd, const char *fn) xewtoh(strtabshdr->sh_size), fn) != xewtoh(strtabshdr->sh_size)) goto bad; - /* any rela tables */ - for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) { - if ((tmpl->mem = xmalloc(tmpl->size, fn, "rela table")) - == NULL) - goto bad; - if (xreadatoff(fd, tmpl->mem, tmpl->file, - tmpl->size, fn) != tmpl->size) - goto bad; - } + nstrtab_size = 256; + nstrtabp = xmalloc(nstrtab_size, fn, "new string table"); + if (nstrtabp == NULL) + goto bad; + nstrtab_nextoff = 0; - /* any rel tables */ - for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) { - if ((tmpl->mem = xmalloc(tmpl->size, fn, "rel table")) - == NULL) - goto bad; - if (xreadatoff(fd, tmpl->mem, tmpl->file, - tmpl->size, fn) != tmpl->size) - goto bad; - } + fn_size = strlen(fn); /* Prepare data structures for symbol movement. */ nsyms = xewtoh(symtabshdr->sh_size) / xewtoh(symtabshdr->sh_entsize); nlocalsyms = xe32toh(symtabshdr->sh_info); - if ((symfwmap = xmalloc(nsyms * sizeof (Elf_Size), fn, - "symbol forward mapping table")) == NULL) - goto bad; - if ((symrvmap = xmalloc(nsyms * sizeof (Elf_Size), fn, - "symbol reverse mapping table")) == NULL) - goto bad; - - /* init location -> symbol # table */ - for (ewi = 0; ewi < nsyms; ewi++) - symrvmap[ewi] = ewi; /* move symbols, making them local */ - for (ewi = nlocalsyms; ewi < nsyms; ewi++) { - Elf_Sym *sp, symswap; - Elf_Size mapswap; - - sp = &symtabp[ewi]; - - /* if it's on our keep list, don't move it */ - if (in_keep_list(strtabp + xe32toh(sp->st_name))) - continue; - - /* if it's an undefined symbol, keep it */ - if (xe16toh(sp->st_shndx) == SHN_UNDEF) - continue; - - /* adjust the symbol so that it's local */ - sp->st_info = - ELF_ST_INFO(STB_LOCAL, sp->st_info); -/* (STB_LOCAL << 4) | ELF_SYM_TYPE(sp->st_info); *//* XXX */ - + for (ewi = 0; ewi < nsyms; ewi++) { + Elf_Sym *sp = &symtabp[ewi]; + const char *symname = strtabp + xe32toh(sp->st_name); + size_t newent_len; /* - * move the symbol to its new location + * make sure there's size for the next entry, even if it's + * as large as it can be. + * + * "_$$hide$$ " -> + * 9 + 3 + sizes of fn and sym name */ - - /* note that symbols in those locations have been swapped */ - mapswap = symrvmap[ewi]; - symrvmap[ewi] = symrvmap[nlocalsyms]; - symrvmap[nlocalsyms] = mapswap; - - /* and swap the symbols */ - symswap = *sp; - *sp = symtabp[nlocalsyms]; - symtabp[nlocalsyms] = symswap; - - nlocalsyms++; /* note new local sym */ - } - symtabshdr->sh_info = htoxe32(nlocalsyms); - - /* set up symbol # -> location mapping table */ - for (ewi = 0; ewi < nsyms; ewi++) - symfwmap[symrvmap[ewi]] = ewi; - - /* any rela tables */ - for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) { - Elf_Rela *relap = tmpl->mem; - - for (ewi = 0; ewi < tmpl->size / sizeof(*relap); ewi++) { - relap[ewi].r_info = htoxew(ELF_R_INFO( - symfwmap[ELF_R_SYM(xewtoh(relap[ewi].r_info))], - ELF_R_TYPE(xewtoh(relap[ewi].r_info)) - )); + while ((nstrtab_size - nstrtab_nextoff) < + strlen(symname) + fn_size + 12) { + nstrtab_size *= 2; + nstrtabp = xrealloc(nstrtabp, nstrtab_size, fn, + "new string table"); + if (nstrtabp == NULL) + goto bad; } - } - /* any rel tables */ - for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) { - Elf_Rel *relp = tmpl->mem; + sp->st_name = htoxew(nstrtab_nextoff); - for (ewi = 0; ewi < tmpl->size / sizeof *relp; ewi++) { - relp[ewi].r_info = htoxew(ELF_R_INFO( - symfwmap[ELF_R_SYM(xewtoh(relp[ewi].r_info))], - ELF_R_TYPE(xewtoh(relp[ewi].r_info)) - )); + /* if it's a keeper or is undefined, don't rename it. */ + if (in_keep_list(symname) || + (xe16toh(sp->st_shndx) == SHN_UNDEF)) { + newent_len = sprintf(nstrtabp + nstrtab_nextoff, + "%s", symname) + 1; + } else { + newent_len = sprintf(nstrtabp + nstrtab_nextoff, + "_$$hide$$ %s %s", fn, symname) + 1; } + nstrtab_nextoff += newent_len; } + strtabshdr->sh_size = htoxew(nstrtab_nextoff); /* * write new tables to the file @@ -393,16 +369,10 @@ ELFNAMEEND(hide)(int fd, const char *fn) if (xwriteatoff(fd, symtabp, xewtoh(symtabshdr->sh_offset), xewtoh(symtabshdr->sh_size), fn) != xewtoh(symtabshdr->sh_size)) goto bad; - for (tmpl = relalist; tmpl != NULL; tmpl = tmpl->next) { - if (xwriteatoff(fd, tmpl->mem, tmpl->file, - tmpl->size, fn) != tmpl->size) - goto bad; - } - for (tmpl = rellist; tmpl != NULL; tmpl = tmpl->next) { - if (xwriteatoff(fd, tmpl->mem, tmpl->file, - tmpl->size, fn) != tmpl->size) - goto bad; - } + /* write new symbol table strings */ + if ((size_t)xwriteatoff(fd, nstrtabp, xewtoh(strtabshdr->sh_offset), + xewtoh(strtabshdr->sh_size), fn) != xewtoh(strtabshdr->sh_size)) + goto bad; out: if (shdrp != NULL) @@ -411,22 +381,6 @@ ELFNAMEEND(hide)(int fd, const char *fn) free(symtabp); if (strtabp != NULL) free(strtabp); - if (symfwmap != NULL) - free(symfwmap); - if (symrvmap != NULL) - free(symrvmap); - while ((tmpl = relalist) != NULL) { - relalist = tmpl->next; - if (tmpl->mem != NULL) - free(tmpl->mem); - free(tmpl); - } - while ((tmpl = rellist) != NULL) { - rellist = tmpl->next; - if (tmpl->mem != NULL) - free(tmpl->mem); - free(tmpl); - } return (rv); bad: