src/modules/elfextract.c
branchs11u3-sru
changeset 3483 99004fc8ada4
parent 2966 6a97d8a803d3
child 3485 3f207ee477ce
--- a/src/modules/elfextract.c	Thu Dec 08 03:40:53 2016 +0530
+++ b/src/modules/elfextract.c	Thu Dec 08 03:40:55 2016 +0530
@@ -20,12 +20,13 @@
  */
 
 /*
- *  Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ *  Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <libelf.h>
 #include <gelf.h>
 
+#include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/uio.h>
@@ -255,75 +256,32 @@
 	return (hi);
 }
 
-/*
- * For ELF nontriviality: Need to turn an ELF object into a unique hash.
- *
- * From Eric Saxe's investigations, we see that the following sections can
- * generally be ignored:
- *
- *    .SUNW_signature, .comment, .SUNW_dof, .debug, .plt, .rela.bss,
- *    .rela.plt, .line, .note
- *
- * Conversely, the following sections are generally significant:
- *
- *    .rodata.str1.8, .rodata.str1.1, .rodata, .data1, .data, .text
- *
- * Accordingly, we will hash on the latter group of sections to determine our
- * ELF hash.
- */
-static int
-hashsection(char *name)
-{
-	if (strcmp(name, ".SUNW_signature") == 0 ||
-	    strcmp(name, ".comment") == 0 ||
-	    strcmp(name, ".SUNW_dof") == 0 ||
-	    strcmp(name, ".debug") == 0 ||
-	    strcmp(name, ".plt") == 0 ||
-	    strcmp(name, ".rela.bss") == 0 ||
-	    strcmp(name, ".rela.plt") == 0 ||
-	    strcmp(name, ".line") == 0 ||
-	    strcmp(name, ".note") == 0 ||
-	    strcmp(name, ".compcom") == 0)
-		return (0);
-
-	return (1);
-}
+typedef struct hashcb_data {
+	char		*base;
+	SHA1_CTX	*s1c;
+	SHA256_CTX	*s2c;
+} hashcb_data_t;
 
 /*
- * Reads a section in 64k increments, adding it to the hash.
+ * Hashes a range from an mmap'd elf file
  */
-static int
-readhash(int fd, SHA1_CTX *shc, SHA256_CTX *shc2, off_t offset, off_t size,
-    int sha1, int sha256)
+static void
+elfhash_cb(size_t offset, size_t size, void *udata)
 {
-	off_t n;
-	char hashbuf[64 * 1024];
-	ssize_t rbytes;
+	hashcb_data_t *h = (hashcb_data_t *)udata;
 
 	if (!size)
-		return (0);
+		return;
 
-	if (lseek(fd, offset, SEEK_SET) == -1) {
-		PyErr_SetFromErrno(PyExc_IOError);
-		return (-1);
+	if (h->s1c != NULL) {
+		SHA1Update(h->s1c, h->base + offset, size);
 	}
 
-	do {
-		n = MIN(size, sizeof (hashbuf));
-		if ((rbytes = read(fd, hashbuf, n)) == -1) {
-			PyErr_SetFromErrno(PyExc_IOError);
-			return (-1);
-		}
-                if (sha1 > 0) {
-		        SHA1Update(shc, hashbuf, rbytes);
-                }
-                if (sha256 > 0) {
-                        SHA256Update(shc2, hashbuf, rbytes);
-                }
-		size -= rbytes;
-	} while (size != 0);
+	if (h->s2c != NULL) {
+		SHA256Update(h->s2c, h->base + offset, size);
+	}
 
-	return (0);
+	return;
 }
 
 /*
@@ -331,11 +289,9 @@
  * information we want from an ELF file.  Returns NULL
  * if it can't find everything (eg. not ELF file, wrong
  * class of ELF file).
- * If sha1 is > 0, we produce an SHA1 hash as part of the returned dictionary.
- * If sha256 is > 0, we include an SHA2 256 hash in the returned dictionary.
  */
 dyninfo_t *
-getdynamic(int fd, int sha1, int sha256)
+getdynamic(int fd)
 {
 	Elf		*elf = NULL;
 	Elf_Scn		*scn = NULL;
@@ -383,12 +339,6 @@
 	}
 
 	/* get useful sections */
-        if (sha1 > 0) {
-                SHA1Init(&shc);
-        }
-        if (sha256 > 0) {
-                SHA256Init(&shc2);
-        }
 	while ((scn = elf_nextscn(elf, scn))) {
 		if (gelf_getshdr(scn, &shdr) != &shdr) {
 			PyErr_SetString(ElfError, elf_errmsg(-1));
@@ -400,36 +350,6 @@
 			goto bad;
 		}
 
-		if (hashsection(name) && (sha1 > 0 || sha256 > 0)) {
-			if (shdr.sh_type == SHT_NOBITS) {
-				/*
-				 * We can't just push shdr.sh_size into
-				 * SHA1Update(), as its raw bytes will be
-				 * different on x86 than they are on sparc.
-				 * Convert to network byte-order first.
-				 */
-				uint64_t n = shdr.sh_size;
-				uint64_t mask = 0xffffffff00000000ULL;
-				uint32_t top = htonl((uint32_t)((n & mask) >> 32));
-				uint32_t bot = htonl((uint32_t)n);
-                                if (sha1 > 0) {
-				        SHA1Update(&shc, &top, sizeof (top));
-                                        SHA1Update(&shc, &bot, sizeof (bot));
-                                }
-                                if (sha256 > 0) {
-                                        SHA256Update(&shc2, &top, sizeof (top));
-                                        SHA256Update(&shc2, &bot, sizeof (bot));
-                                }
-			} else {
-				int hash;
-                                hash = readhash(fd, &shc, &shc2, shdr.sh_offset,
-				    shdr.sh_size, sha1, sha256);
-
-				if (hash == -1)
-					goto bad;
-			}
-		}
-
 		switch (shdr.sh_type) {
 		case SHT_DYNAMIC:
 			if (!(data_dyn = elf_getdata(scn, NULL))) {
@@ -604,12 +524,6 @@
 	dyn->deps = deps;
 	dyn->def = def;
 	dyn->vers = verdef;
-        if (sha1 > 0) {
-	        SHA1Final(dyn->hash, &shc);
-        }
-        if (sha256 > 0) {
-                SHA256Final(dyn->hash256, &shc2);
-        }
 	return (dyn);
 
 bad:
@@ -632,3 +546,80 @@
 	(void) elf_end(dyn->elf);
 	free(dyn);
 }
+
+/*
+ * gethashes - returns a struct filled with the hashes computed from an ELF
+ * file.  Returns NULL if it encounters a problem (eg. not ELF file, offset out
+ * of range).
+ */
+hashinfo_t *
+gethashes(int fd, int dosha1, int dosha2)
+{
+	hashinfo_t	*hashes = NULL;
+	hashcb_data_t	hdata = { NULL, NULL, NULL };
+	Elf		*elf;
+	struct stat	status;
+
+	if ((elf_version(EV_CURRENT) == EV_NONE) ||
+	    ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)) {
+		PyErr_SetString(ElfError, elf_errmsg(-1));
+		return (NULL);
+	}
+
+	if ((fstat(fd, &status) == -1) ||
+	    ((hdata.base = mmap(NULL, status.st_size, PROT_READ, MAP_PRIVATE,
+	    fd, 0)) == MAP_FAILED)) {
+		PyErr_SetString(ElfError, strerror(errno));
+		goto hash_out;
+	}
+	    
+	if (dosha1 > 0) {
+		hdata.s1c = (SHA1_CTX *)malloc(sizeof (SHA1_CTX));
+		if (hdata.s1c == NULL) {
+			(void) PyErr_NoMemory();
+		        goto hash_out;
+		}
+		SHA1Init(hdata.s1c);
+	}
+
+	if (dosha2 > 0) {
+		hdata.s2c = (SHA256_CTX *)malloc(sizeof (SHA256_CTX));
+		if (hdata.s2c == NULL) {
+			(void) PyErr_NoMemory();
+			goto hash_out;
+		}
+		SHA256Init(hdata.s2c);
+	}
+
+	if (!gelf_sign_range(elf, elfhash_cb, ELF_SR_INTERPRET, &hdata)) {
+		PyErr_SetString(ElfError, elf_errmsg(-1));
+		goto hash_out;
+	}
+
+	if ((hashes = malloc(sizeof (hashinfo_t))) == NULL) {
+		(void) PyErr_NoMemory();
+		goto hash_out;
+	}
+
+	if (dosha1 > 0) {
+		SHA1Final(hashes->hash, hdata.s1c);
+	}
+
+	if (dosha2 > 0) {
+		SHA256Final(hashes->hash256, hdata.s2c);
+	}
+
+hash_out:
+	(void) elf_end(elf);
+
+	if (hdata.base)
+		munmap(hdata.base, status.st_size);
+
+	if (hdata.s1c)
+		free(hdata.s1c);
+
+	if (hdata.s2c)
+		free(hdata.s2c);
+
+	return (hashes);
+}