svn commit: r211137 - head/usr.sbin/crunch/crunchide

Adrian Chadd adrian at FreeBSD.org
Tue Aug 10 09:24:20 UTC 2010


Author: adrian
Date: Tue Aug 10 09:24:19 2010
New Revision: 211137
URL: http://svn.freebsd.org/changeset/base/211137

Log:
  Port over changes to the crunch symbol hiding method from NetBSD.
  
  The older symbol hiding method breaks for MIPS. This implements
  symbol hiding through renaming to a symbol name which is highly
  unlikely to clash.
  
  The NetBSD code didn't use byte-swapping macros for endian-awareness;
  so it didn't work when cross-compiling a MIPS world on i386/amd64.
  This patch includes those (as best as I could figure what they
  should be) and has been tested to generate valid MIPS crunch
  binaries both cross- and native- compiled.

Modified:
  head/usr.sbin/crunch/crunchide/exec_elf32.c

Modified: head/usr.sbin/crunch/crunchide/exec_elf32.c
==============================================================================
--- head/usr.sbin/crunch/crunchide/exec_elf32.c	Tue Aug 10 07:56:56 2010	(r211136)
+++ head/usr.sbin/crunch/crunchide/exec_elf32.c	Tue Aug 10 09:24:19 2010	(r211137)
@@ -130,6 +130,20 @@ xmalloc(size_t size, const char *fn, con
 	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$$ <filename> <symbolname>".
+ * 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$$ <filename> <symname><NUL>" ->
+		 *    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;
-
-		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))
-			));
+		sp->st_name = htoxew(nstrtab_nextoff);
+
+		/* 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 @@ out:
 		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:


More information about the svn-src-all mailing list