diff -r 2a84f1cb4808 -r 99004fc8ada4 src/modules/elfextract.c --- 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 #include +#include #include #include #include @@ -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); +}