bin/174011: [patch] crunchide support non-custom elf object layout

Pete Chou petechou at gmail.com
Fri Nov 30 08:20:00 UTC 2012


>Number:         174011
>Category:       bin
>Synopsis:       [patch] crunchide support non-custom elf object layout
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Nov 30 08:20:00 UTC 2012
>Closed-Date:
>Last-Modified:
>Originator:     Pete Chou
>Release:        9.0
>Organization:
>Environment:
FreeBSD bsd 9.0-RELEASE FreeBSD 9.0-RELEASE #0: Tue Jan  3 07:15:25 UTC 2012     root at obrian.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  i386
>Description:
I find crunchide can't handle the object files generated from other linkers like gold linker and mclinker.

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). For example, both gold and mclinker put section headers in the end of file instead.

I also report this at
http://lists.freebsd.org/pipermail/freebsd-toolchain/2012-November/000604.html
>How-To-Repeat:
1. Use gold linker or mclinker to do partial linking on the attached x86 object files.
${LD} -dc -r -o cat.lo cat_stub.o cat.o

2. Let crunchide handle the output from previous partial linking
crunchide -k _crunched_cat_stub cat.lo

If using gold linker, we'll find a warning:
 cat.lo: weird executable (string table not last section)

As for mclinker, crunchide will break the object file.

>Fix:
Basically, crunchide will only increase the size of string table, so the patch is to move everyting behind string table to the correct position.

Patch attached with submission follows:

diff --git exec_elf32.c exec_elf32.c
index 0eae31a..770448c 100644
--- exec_elf32.c
+++ exec_elf32.c
@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD: release/9.0.0/usr.sbin/crunch/crunchide/exec_elf32.c 211222
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <limits.h>
 
 #include "extern.h"
 
@@ -235,17 +236,22 @@ int
 ELFNAMEEND(hide)(int fd, const char *fn)
 {
 	Elf_Ehdr ehdr;
-	Elf_Shdr *shdrp = NULL, *symtabshdr, *strtabshdr;
+	Elf_Shdr *shdrp = NULL, *symtabshdr, *strtabshdr, *shstrtabshdr;
+	Elf_Shdr shdrshdr;
 	Elf_Sym *symtabp = NULL;
-	char *strtabp = NULL;
+	char *strtabp = NULL, *shstrtabp = NULL;
 	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;
+	struct shlayout {
+		Elf_Shdr *shdr;
+		void * bufp;
+	};
+	struct shlayout *layoutp;
 
 	rv = 0;
 	if (xreadatoff(fd, &ehdr, 0, sizeof ehdr, fn) != sizeof ehdr)
@@ -260,62 +266,111 @@ ELFNAMEEND(hide)(int fd, const char *fn)
 	    shdrsize)
 		goto bad;
 
-	symtabshdr = strtabshdr = NULL;
+	symtabshdr = strtabshdr = shstrtabshdr = 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)];
-
-			/* 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;
+		case SHT_STRTAB:
+			if (i == xe16toh(ehdr.e_shstrndx))
+				shstrtabshdr = &shdrp[i];
 			break;
 		}
 	}
 	if (! weirdreason)
 		weirdreason = "unsupported";
-	if (symtabshdr == NULL)
-		goto out;
-	if (strtabshdr == NULL)
-		weird = 1;
-	if (!weird && stroff != maxoff) {
+	if (symtabshdr == NULL || strtabshdr == NULL || shstrtabshdr == NULL)
 		weird = 1;
-		weirdreason = "string table section not last in file";
-	}   
 	if (weird) {
 		fprintf(stderr, "%s: weird executable (%s)\n", fn, weirdreason);
 		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[0].shdr = &shdrshdr;
+
+	/* insert and sort normal section headers */
+	for (i = 0; i < xe16toh(ehdr.e_shnum); i++) {
+		int l = 0, r = i;
+		while (l <= r) {
+			int m = ( l + r) / 2;
+			if (xewtoh(shdrp[i].sh_offset) <
+				xewtoh(layoutp[m].shdr->sh_offset))
+				r = m - 1;
+			else
+				l = m + 1;
+		}
+
+		if (l != i + 1)
+			memmove(&layoutp[l + 1], &layoutp[l],
+				sizeof(struct shlayout) * (i - l + 1));
+
+		layoutp[l].shdr = &shdrp[i];
+		layoutp[l].bufp = NULL;
+	}
+
+	/*
 	 * load up everything we need
 	 */
 
-	/* symbol table */
-	if ((symtabp = xmalloc(xewtoh(symtabshdr->sh_size), fn, "symbol table"))
-	    == NULL)
+	/* load section string table for debug use */
+	if ((shstrtabp = xmalloc(xewtoh(shstrtabshdr->sh_size), fn,
+		"section string table")) == NULL)
 		goto bad;
-	if (xreadatoff(fd, symtabp, xewtoh(symtabshdr->sh_offset),
-	    xewtoh(symtabshdr->sh_size), fn) != xewtoh(symtabshdr->sh_size))
+	if (xreadatoff(fd, shstrtabp, xewtoh(shstrtabshdr->sh_offset),
+		xewtoh(shstrtabshdr->sh_size), fn) != xewtoh(shstrtabshdr->sh_size))
 		goto bad;
 
-	/* string table */
-	if ((strtabp = xmalloc(xewtoh(strtabshdr->sh_size), fn, "string table"))
-	    == NULL)
-		goto bad;
-	if (xreadatoff(fd, strtabp, xewtoh(strtabshdr->sh_offset),
-	    xewtoh(strtabshdr->sh_size), fn) != xewtoh(strtabshdr->sh_size))
-		goto bad;
+	/* we need symtab, strtab, and everything behind strtab */
+	for (i = 0; i < xe16toh(ehdr.e_shnum) + 1; i++) {
+		static int strtabidx = INT_MAX;
+		size_t size;
+		if (layoutp[i].shdr == &shdrshdr) {
+			/* not load section header again */
+			layoutp[i].bufp = shdrp;
+			continue;
+		}
+		else 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) {
+			size = xewtoh(layoutp[i].shdr->sh_size);
+			if ((layoutp[i].bufp = xmalloc(size, fn,
+				shstrtabp + xewtoh(layoutp[i].shdr->sh_name))) == NULL)
+				goto bad;
+			if (xreadatoff(fd, layoutp[i].bufp,
+				xewtoh(layoutp[i].shdr->sh_offset), size, fn) != size)
+				goto bad;
+
+			/* set symbol table */
+			if (layoutp[i].shdr == symtabshdr)
+				symtabp = layoutp[i].bufp;
+			/* set string table */
+			else if (layoutp[i].shdr == strtabshdr)
+				strtabp = layoutp[i].bufp;
+		}
+	}
 
 	nstrtab_size = 256;
 	nstrtabp = xmalloc(nstrtab_size, fn, "new string table");
@@ -366,26 +421,68 @@ ELFNAMEEND(hide)(int fd, const char *fn)
 	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) !=
-	    shdrsize)
-		goto bad;
-	if (xwriteatoff(fd, symtabp, xewtoh(symtabshdr->sh_offset),
-	    xewtoh(symtabshdr->sh_size), fn) != xewtoh(symtabshdr->sh_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;
+	for (i = 0; layoutp[i].shdr != strtabshdr; i++)
+		;
+	for (; i < xe16toh(ehdr.e_shnum) + 1; i++) {
+		Elf_Off off, align;
+		off = xewtoh(layoutp[i - 1].shdr->sh_offset) +
+			xewtoh(layoutp[i - 1].shdr->sh_size);
+		align = xewtoh(layoutp[i].shdr->sh_addralign);
+		off = (off + (align - 1)) & ~(Elf_Off)(align - 1);
+		layoutp[i].shdr->sh_offset = htoxew(off);
+	}
+
+	/*
+	 * write data to the file in descending order of offset
+	 */
+	for (i = xe16toh(ehdr.e_shnum); i >= 0; i--) {
+		static int strtabidx = INT_MIN;
+		void *buf;
+		size_t size;
+
+		if (layoutp[i].shdr == strtabshdr) {
+			strtabidx = i;
+			/* 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;
+
+			if (layoutp[i].shdr == &shdrshdr) {
+				/* 
+				 * update elf header if the offset of section header
+				 * table is changed.
+				 */
+				if (ehdr.e_shoff != shdrshdr.sh_offset) {
+					ehdr.e_shoff = shdrshdr.sh_offset;
+					if (xwriteatoff(fd, &ehdr, 0, sizeof ehdr, fn)
+						!= sizeof ehdr)
+						goto bad;
+				}
+			}
+
+			size = xewtoh(layoutp[i].shdr->sh_size);
+			if (xwriteatoff(fd, buf, xewtoh(layoutp[i].shdr->sh_offset),
+				size, fn) != size)
+				goto bad;
+		}
+	}
 
 out:
-	if (shdrp != NULL)
-		free(shdrp);
-	if (symtabp != NULL)
-		free(symtabp);
-	if (strtabp != NULL)
-		free(strtabp);
+	if (layoutp != NULL) {
+		for (i = 0; i < xe16toh(ehdr.e_shnum) + 1; i++)
+			if (layoutp[i].bufp != NULL)
+				free(layoutp[i].bufp);
+		free(layoutp);
+	}
+	if (nstrtabp != NULL)
+		free(nstrtabp);
 	return (rv);
 
 bad:


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list