crunchide(1): support non-custom elf object layout

The crunchide utility presumes the last 3 chunks of an ELF object
layout are section headers, symbol table, and then string table.
However, this is  not specified in the ELF standards, and linkers
may generate different layouts when doing partial linking (-r).

This change is required to build FreeBSD with mclinker or the
gold linker.

PR:		bin/174011
Submitted by:	Pete Chou
Reviewed by:	Cristoph Mallon
MFC after:	2 weeks
This commit is contained in:
Pedro F. Giffuni 2013-02-03 20:35:37 +00:00
parent c7d346f269
commit b5782a4705
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=246296

View File

@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include <sys/stat.h> #include <sys/stat.h>
#include <errno.h> #include <errno.h>
#include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -82,11 +83,9 @@ __FBSDID("$FreeBSD$");
#define xe32toh(x) ((data == ELFDATA2MSB) ? be32toh(x) : le32toh(x)) #define xe32toh(x) ((data == ELFDATA2MSB) ? be32toh(x) : le32toh(x))
#define htoxe32(x) ((data == ELFDATA2MSB) ? htobe32(x) : htole32(x)) #define htoxe32(x) ((data == ELFDATA2MSB) ? htobe32(x) : htole32(x))
struct listelem { struct shlayout {
struct listelem *next; Elf_Shdr *shdr;
void *mem; void *bufp;
off_t file;
size_t size;
}; };
static ssize_t static ssize_t
@ -235,17 +234,20 @@ int
ELFNAMEEND(hide)(int fd, const char *fn) ELFNAMEEND(hide)(int fd, const char *fn)
{ {
Elf_Ehdr ehdr; Elf_Ehdr ehdr;
Elf_Shdr *shdrp = NULL, *symtabshdr, *strtabshdr; struct shlayout *layoutp = NULL;
Elf_Shdr *shdrp = NULL, *symtabshdr, *strtabshdr, *shstrtabshdr;
Elf_Shdr shdrshdr;
Elf_Sym *symtabp = NULL; Elf_Sym *symtabp = NULL;
char *strtabp = NULL; char *shstrtabp = NULL, *strtabp = NULL;
Elf_Size nsyms, ewi; Elf_Size nsyms, ewi;
Elf_Off off;
ssize_t shdrsize; ssize_t shdrsize;
int rv, i, weird; int rv, i, weird, l, m, r, strtabidx;
size_t nstrtab_size, nstrtab_nextoff, fn_size; size_t nstrtab_size, nstrtab_nextoff, fn_size, size;
char *nstrtabp = NULL; char *nstrtabp = NULL;
unsigned char data; unsigned char data;
Elf_Off maxoff, stroff;
const char *weirdreason = NULL; const char *weirdreason = NULL;
void *buf;
rv = 0; rv = 0;
if (xreadatoff(fd, &ehdr, 0, sizeof ehdr, fn) != sizeof ehdr) if (xreadatoff(fd, &ehdr, 0, sizeof ehdr, fn) != sizeof ehdr)
@ -260,62 +262,123 @@ ELFNAMEEND(hide)(int fd, const char *fn)
shdrsize) shdrsize)
goto bad; goto bad;
symtabshdr = strtabshdr = NULL; symtabshdr = strtabshdr = shstrtabshdr = NULL;
weird = 0; weird = 0;
maxoff = stroff = 0;
for (i = 0; i < xe16toh(ehdr.e_shnum); i++) { 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)) { switch (xe32toh(shdrp[i].sh_type)) {
case SHT_SYMTAB: case SHT_SYMTAB:
if (symtabshdr != NULL) if (symtabshdr != NULL) {
weird = 1; weird = 1;
weirdreason = "multiple symbol tables";
}
symtabshdr = &shdrp[i]; symtabshdr = &shdrp[i];
strtabshdr = &shdrp[xe32toh(shdrp[i].sh_link)]; strtabshdr = &shdrp[xe32toh(shdrp[i].sh_link)];
break;
/* Check whether the string table is the last section */ case SHT_STRTAB:
stroff = xewtoh(shdrp[xe32toh(shdrp[i].sh_link)].sh_offset); if (i == xe16toh(ehdr.e_shstrndx))
if (!weird && xe32toh(shdrp[i].sh_link) != (xe16toh(ehdr.e_shnum) - 1)) { shstrtabshdr = &shdrp[i];
weird = 1;
weirdreason = "string table not last section";
}
break; break;
} }
} }
if (! weirdreason)
weirdreason = "unsupported";
if (symtabshdr == NULL) if (symtabshdr == NULL)
goto out; goto out;
if (strtabshdr == NULL) if (strtabshdr == NULL) {
weird = 1; weird = 1;
if (!weird && stroff != maxoff) { weirdreason = "string table does not exist";
}
if (shstrtabshdr == NULL) {
weird = 1; weird = 1;
weirdreason = "string table section not last in file"; weirdreason = "section header string table does not exist";
} }
if (weirdreason == NULL)
weirdreason = "unsupported";
if (weird) { if (weird) {
fprintf(stderr, "%s: weird executable (%s)\n", fn, weirdreason); fprintf(stderr, "%s: weird executable (%s)\n", fn, weirdreason);
goto bad; goto bad;
} }
/*
* sort section layout table by offset
*/
layoutp = xmalloc(sizeof(struct shlayout) * (xe16toh(ehdr.e_shnum) + 1),
fn, "layout table");
if (layoutp == NULL)
goto bad;
/* add a pseudo entry to represent the section header table */
shdrshdr.sh_offset = ehdr.e_shoff;
shdrshdr.sh_size = htoxew(shdrsize);
shdrshdr.sh_addralign = htoxew(ELFSIZE / 8);
layoutp[xe16toh(ehdr.e_shnum)].shdr = &shdrshdr;
/* insert and sort normal section headers */
for (i = xe16toh(ehdr.e_shnum) - 1; i >= 0; i--) {
l = i + 1;
r = xe16toh(ehdr.e_shnum);
while (l <= r) {
m = ( l + r) / 2;
if (xewtoh(shdrp[i].sh_offset) >
xewtoh(layoutp[m].shdr->sh_offset))
l = m + 1;
else
r = m - 1;
}
if (r != i) {
memmove(&layoutp[i], &layoutp[i + 1],
sizeof(struct shlayout) * (r - i));
}
layoutp[r].shdr = &shdrp[i];
layoutp[r].bufp = NULL;
}
/* /*
* load up everything we need * load up everything we need
*/ */
/* symbol table */ /* load section string table for debug use */
if ((symtabp = xmalloc(xewtoh(symtabshdr->sh_size), fn, "symbol table")) if ((shstrtabp = xmalloc(xewtoh(shstrtabshdr->sh_size), fn,
== NULL) "section string table")) == NULL)
goto bad; goto bad;
if ((size_t)xreadatoff(fd, symtabp, xewtoh(symtabshdr->sh_offset), if ((size_t)xreadatoff(fd, shstrtabp, xewtoh(shstrtabshdr->sh_offset),
xewtoh(symtabshdr->sh_size), fn) != xewtoh(symtabshdr->sh_size)) xewtoh(shstrtabshdr->sh_size), fn) != xewtoh(shstrtabshdr->sh_size))
goto bad; goto bad;
/* string table */ /* we need symtab, strtab, and everything behind strtab */
if ((strtabp = xmalloc(xewtoh(strtabshdr->sh_size), fn, "string table")) strtabidx = INT_MAX;
== NULL) for (i = 0; i < xe16toh(ehdr.e_shnum) + 1; i++) {
goto bad; if (layoutp[i].shdr == &shdrshdr) {
if ((size_t)xreadatoff(fd, strtabp, xewtoh(strtabshdr->sh_offset), /* not load section header again */
xewtoh(strtabshdr->sh_size), fn) != xewtoh(strtabshdr->sh_size)) layoutp[i].bufp = shdrp;
goto bad; continue;
}
if (layoutp[i].shdr == shstrtabshdr) {
/* not load section string table again */
layoutp[i].bufp = shstrtabp;
continue;
}
if (layoutp[i].shdr == strtabshdr)
strtabidx = i;
if (layoutp[i].shdr == symtabshdr || i >= strtabidx) {
off = xewtoh(layoutp[i].shdr->sh_offset);
size = xewtoh(layoutp[i].shdr->sh_size);
layoutp[i].bufp = xmalloc(size, fn,
shstrtabp + xewtoh(layoutp[i].shdr->sh_name));
if (layoutp[i].bufp == NULL)
goto bad;
if ((size_t)xreadatoff(fd, layoutp[i].bufp, off, size, fn) !=
size)
goto bad;
/* set symbol table and string table */
if (layoutp[i].shdr == symtabshdr)
symtabp = layoutp[i].bufp;
else if (layoutp[i].shdr == strtabshdr)
strtabp = layoutp[i].bufp;
}
}
nstrtab_size = 256; nstrtab_size = 256;
nstrtabp = xmalloc(nstrtab_size, fn, "new string table"); nstrtabp = xmalloc(nstrtab_size, fn, "new string table");
@ -365,28 +428,62 @@ ELFNAMEEND(hide)(int fd, const char *fn)
strtabshdr->sh_size = htoxew(nstrtab_nextoff); strtabshdr->sh_size = htoxew(nstrtab_nextoff);
/* /*
* write new tables to the file * update section header table in ascending order of offset
*/ */
if (xwriteatoff(fd, shdrp, xewtoh(ehdr.e_shoff), shdrsize, fn) != for (i = strtabidx + 1; i < xe16toh(ehdr.e_shnum) + 1; i++) {
shdrsize) Elf_Off off, align;
goto bad; off = xewtoh(layoutp[i - 1].shdr->sh_offset) +
if ((size_t)xwriteatoff(fd, symtabp, xewtoh(symtabshdr->sh_offset), xewtoh(layoutp[i - 1].shdr->sh_size);
xewtoh(symtabshdr->sh_size), fn) != xewtoh(symtabshdr->sh_size)) align = xewtoh(layoutp[i].shdr->sh_addralign);
goto bad; off = (off + (align - 1)) & ~(align - 1);
/* write new symbol table strings */ layoutp[i].shdr->sh_offset = htoxew(off);
if ((size_t)xwriteatoff(fd, nstrtabp, xewtoh(strtabshdr->sh_offset), }
xewtoh(strtabshdr->sh_size), fn) != xewtoh(strtabshdr->sh_size))
goto bad; /*
* write data to the file in descending order of offset
*/
for (i = xe16toh(ehdr.e_shnum); i >= 0; i--) {
if (layoutp[i].shdr == strtabshdr) {
/* new string table */
buf = nstrtabp;
} else
buf = layoutp[i].bufp;
if (layoutp[i].shdr == &shdrshdr ||
layoutp[i].shdr == symtabshdr || i >= strtabidx) {
if (buf == NULL)
goto bad;
/*
* update the offset of section header table in elf
* header if needed.
*/
if (layoutp[i].shdr == &shdrshdr &&
ehdr.e_shoff != shdrshdr.sh_offset) {
ehdr.e_shoff = shdrshdr.sh_offset;
off = (ELFSIZE == 32) ? 32 : 44;
size = sizeof(Elf_Off);
if ((size_t)xwriteatoff(fd, &ehdr.e_shoff, off, size,
fn) != size)
goto bad;
}
off = xewtoh(layoutp[i].shdr->sh_offset);
size = xewtoh(layoutp[i].shdr->sh_size);
if ((size_t)xwriteatoff(fd, buf, off, size, fn) != size)
goto bad;
}
}
out: out:
if (shdrp != NULL) if (layoutp != NULL) {
free(shdrp); for (i = 0; i < xe16toh(ehdr.e_shnum) + 1; i++) {
if (symtabp != NULL) if (layoutp[i].bufp != NULL)
free(symtabp); free(layoutp[i].bufp);
if (strtabp != NULL) }
free(strtabp); free(layoutp);
if (nstrtabp != NULL) }
free(nstrtabp); free(nstrtabp);
return (rv); return (rv);
bad: bad: