diff options
Diffstat (limited to 'contrib/file/readelf.c')
| -rw-r--r-- | contrib/file/readelf.c | 1022 |
1 files changed, 295 insertions, 727 deletions
diff --git a/contrib/file/readelf.c b/contrib/file/readelf.c index 878a7636b3a98..52dcec3b72a95 100644 --- a/contrib/file/readelf.c +++ b/contrib/file/readelf.c @@ -1,63 +1,36 @@ -/* - * Copyright (c) Christos Zoulas 2003. - * All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice immediately at the beginning of the file, without modification, - * this list of conditions, and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ #include "file.h" #ifdef BUILTIN_ELF +#include <sys/types.h> #include <string.h> +#include <stdio.h> #include <ctype.h> #include <stdlib.h> #ifdef HAVE_UNISTD_H #include <unistd.h> #endif +#include <errno.h> #include "readelf.h" #ifndef lint -FILE_RCSID("@(#)$Id: readelf.c,v 1.54 2006/01/13 00:45:21 christos Exp $") +FILE_RCSID("@(#)$Id: readelf.c,v 1.16 2000/08/05 18:18:50 christos Exp $") #endif #ifdef ELFCORE -private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t); +static void dophn_core __P((int, int, int, off_t, int, size_t)); #endif -private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t); -private int doshn(struct magic_set *, int, int, int, off_t, int, size_t); -private size_t donote(struct magic_set *, unsigned char *, size_t, size_t, int, - int, size_t, int *); - -#define ELF_ALIGN(a) ((((a) + align - 1) / align) * align) - -#define isquote(c) (strchr("'\"`", (c)) != NULL) +static void dophn_exec __P((int, int, int, off_t, int, size_t)); +static void doshn __P((int, int, int, off_t, int, size_t)); -private uint16_t getu16(int, uint16_t); -private uint32_t getu32(int, uint32_t); -private uint64_t getu64(int, uint64_t); +static uint16_t getu16 __P((int, int)); +static uint32_t getu32 __P((int, uint32_t)); +static uint64_t getu64 __P((int, uint64_t)); -private uint16_t -getu16(int swap, uint16_t value) +static uint16_t +getu16(swap, value) + int swap; + uint16_t value; { union { uint16_t ui; @@ -75,8 +48,10 @@ getu16(int swap, uint16_t value) return value; } -private uint32_t -getu32(int swap, uint32_t value) +static uint32_t +getu32(swap, value) + int swap; + uint32_t value; { union { uint32_t ui; @@ -96,8 +71,10 @@ getu32(int swap, uint32_t value) return value; } -private uint64_t -getu64(int swap, uint64_t value) +static uint64_t +getu64(swap, value) + int swap; + uint64_t value; { union { uint64_t ui; @@ -121,71 +98,101 @@ getu64(int swap, uint64_t value) return value; } -#ifdef USE_ARRAY_FOR_64BIT_TYPES -# define elf_getu64(swap, array) \ - ((swap ? ((uint64_t)getu32(swap, array[0])) << 32 : getu32(swap, array[0])) + \ - (swap ? getu32(swap, array[1]) : ((uint64_t)getu32(swap, array[1]) << 32))) -#else -# define elf_getu64(swap, value) getu64(swap, value) -#endif - -#define xsh_addr (class == ELFCLASS32 \ +#define sh_addr (class == ELFCLASS32 \ ? (void *) &sh32 \ : (void *) &sh64) -#define xsh_sizeof (class == ELFCLASS32 \ - ? sizeof sh32 \ - : sizeof sh64) -#define xsh_size (class == ELFCLASS32 \ - ? getu32(swap, sh32.sh_size) \ - : getu64(swap, sh64.sh_size)) -#define xsh_offset (class == ELFCLASS32 \ - ? getu32(swap, sh32.sh_offset) \ - : getu64(swap, sh64.sh_offset)) -#define xsh_type (class == ELFCLASS32 \ +#define shs_type (class == ELFCLASS32 \ ? getu32(swap, sh32.sh_type) \ : getu32(swap, sh64.sh_type)) -#define xph_addr (class == ELFCLASS32 \ +#define ph_addr (class == ELFCLASS32 \ ? (void *) &ph32 \ : (void *) &ph64) -#define xph_sizeof (class == ELFCLASS32 \ - ? sizeof ph32 \ - : sizeof ph64) -#define xph_type (class == ELFCLASS32 \ +#define ph_type (class == ELFCLASS32 \ ? getu32(swap, ph32.p_type) \ : getu32(swap, ph64.p_type)) -#define xph_offset (class == ELFCLASS32 \ +#define ph_offset (class == ELFCLASS32 \ ? getu32(swap, ph32.p_offset) \ : getu64(swap, ph64.p_offset)) -#define xph_align (size_t)((class == ELFCLASS32 \ - ? (off_t) (ph32.p_align ? \ - getu32(swap, ph32.p_align) : 4) \ - : (off_t) (ph64.p_align ? \ - getu64(swap, ph64.p_align) : 4))) -#define xph_filesz (size_t)((class == ELFCLASS32 \ - ? getu32(swap, ph32.p_filesz) \ - : getu64(swap, ph64.p_filesz))) -#define xnh_addr (class == ELFCLASS32 \ - ? (void *) &nh32 \ - : (void *) &nh64) -#define xph_memsz (size_t)((class == ELFCLASS32 \ - ? getu32(swap, ph32.p_memsz) \ - : getu64(swap, ph64.p_memsz))) -#define xnh_sizeof (class == ELFCLASS32 \ - ? sizeof nh32 \ - : sizeof nh64) -#define xnh_type (class == ELFCLASS32 \ - ? getu32(swap, nh32.n_type) \ - : getu32(swap, nh64.n_type)) -#define xnh_namesz (class == ELFCLASS32 \ - ? getu32(swap, nh32.n_namesz) \ - : getu32(swap, nh64.n_namesz)) -#define xnh_descsz (class == ELFCLASS32 \ - ? getu32(swap, nh32.n_descsz) \ - : getu32(swap, nh64.n_descsz)) +#define nh_size (class == ELFCLASS32 \ + ? sizeof *nh32 \ + : sizeof *nh64) +#define nh_type (class == ELFCLASS32 \ + ? getu32(swap, nh32->n_type) \ + : getu32(swap, nh64->n_type)) +#define nh_namesz (class == ELFCLASS32 \ + ? getu32(swap, nh32->n_namesz) \ + : getu32(swap, nh64->n_namesz)) +#define nh_descsz (class == ELFCLASS32 \ + ? getu32(swap, nh32->n_descsz) \ + : getu32(swap, nh64->n_descsz)) #define prpsoffsets(i) (class == ELFCLASS32 \ ? prpsoffsets32[i] \ : prpsoffsets64[i]) +static void +doshn(class, swap, fd, off, num, size) + int class; + int swap; + int fd; + off_t off; + int num; + size_t size; +{ + Elf32_Shdr sh32; + Elf64_Shdr sh64; + + if (lseek(fd, off, SEEK_SET) == -1) + error("lseek failed (%s).\n", strerror(errno)); + + for ( ; num; num--) { + if (read(fd, sh_addr, size) == -1) + error("read failed (%s).\n", strerror(errno)); + if (shs_type == SHT_SYMTAB /* || shs_type == SHT_DYNSYM */) { + (void) printf (", not stripped"); + return; + } + } + (void) printf (", stripped"); +} + +/* + * Look through the program headers of an executable image, searching + * for a PT_INTERP section; if one is found, it's dynamically linked, + * otherwise it's statically linked. + */ +static void +dophn_exec(class, swap, fd, off, num, size) + int class; + int swap; + int fd; + off_t off; + int num; + size_t size; +{ + Elf32_Phdr ph32; + Elf64_Phdr ph64; + char *linking_style = "statically"; + char *shared_libraries = ""; + + if (lseek(fd, off, SEEK_SET) == -1) + error("lseek failed (%s).\n", strerror(errno)); + + for ( ; num; num--) { + if (read(fd, ph_addr, size) == -1) + error("read failed (%s).\n", strerror(errno)); + + switch (ph_type) { + case PT_DYNAMIC: + linking_style = "dynamically"; + break; + case PT_INTERP: + shared_libraries = " (uses shared libs)"; + break; + } + } + printf(", %s linked%s", linking_style, shared_libraries); +} + #ifdef ELFCORE size_t prpsoffsets32[] = { 8, /* FreeBSD */ @@ -195,8 +202,6 @@ size_t prpsoffsets32[] = { }; size_t prpsoffsets64[] = { - 16, /* FreeBSD, 64-bit */ - 40, /* Linux (tested on core from 2.4.x) */ 120, /* SunOS 5.x, 64-bit */ }; @@ -225,637 +230,190 @@ size_t prpsoffsets64[] = { * *do* have that binary, the debugger will probably tell you what * signal it was.) */ - -#define OS_STYLE_SVR4 0 -#define OS_STYLE_FREEBSD 1 -#define OS_STYLE_NETBSD 2 - -private const char *os_style_names[] = { - "SVR4", - "FreeBSD", - "NetBSD", -}; - -#define FLAGS_DID_CORE 1 - -private int -dophn_core(struct magic_set *ms, int class, int swap, int fd, off_t off, - int num, size_t size) +static void +dophn_core(class, swap, fd, off, num, size) + int class; + int swap; + int fd; + off_t off; + int num; + size_t size; { Elf32_Phdr ph32; + Elf32_Nhdr *nh32; Elf64_Phdr ph64; - size_t offset; - unsigned char nbuf[BUFSIZ]; - ssize_t bufsize; - int flags = 0; - - if (size != xph_sizeof) { - if (file_printf(ms, ", corrupted program header size") == -1) - return -1; - return 0; - } + Elf64_Nhdr *nh64; + size_t offset, nameoffset, noffset, reloffset; + unsigned char c; + int i, j; + char nbuf[BUFSIZ]; + int bufsize; + int is_freebsd; /* * Loop through all the program headers. */ for ( ; num; num--) { - if (lseek(fd, off, SEEK_SET) == (off_t)-1) { - file_badseek(ms); - return -1; - } - if (read(fd, xph_addr, xph_sizeof) == -1) { - file_badread(ms); - return -1; - } + if (lseek(fd, off, SEEK_SET) == -1) + error("lseek failed (%s).\n", strerror(errno)); + if (read(fd, ph_addr, size) == -1) + error("read failed (%s).\n", strerror(errno)); off += size; - if (xph_type != PT_NOTE) + if (ph_type != PT_NOTE) continue; /* * This is a PT_NOTE section; loop through all the notes * in the section. */ - if (lseek(fd, (off_t)xph_offset, SEEK_SET) == (off_t)-1) { - file_badseek(ms); - return -1; - } - bufsize = read(fd, nbuf, - ((xph_filesz < sizeof(nbuf)) ? xph_filesz : sizeof(nbuf))); - if (bufsize == -1) { - file_badread(ms); - return -1; - } + if (lseek(fd, (off_t) ph_offset, SEEK_SET) == -1) + error("lseek failed (%s).\n", strerror(errno)); + bufsize = read(fd, nbuf, BUFSIZ); + if (bufsize == -1) + error(": " "read failed (%s).\n", strerror(errno)); offset = 0; for (;;) { - if (offset >= (size_t)bufsize) + if (offset >= bufsize) break; - offset = donote(ms, nbuf, offset, (size_t)bufsize, - class, swap, 4, &flags); - if (offset == 0) - break; - - } - } - return 0; -} -#endif - -private size_t -donote(struct magic_set *ms, unsigned char *nbuf, size_t offset, size_t size, - int class, int swap, size_t align, int *flags) -{ - Elf32_Nhdr nh32; - Elf64_Nhdr nh64; - size_t noff, doff; -#ifdef ELFCORE - int os_style = -1; -#endif - uint32_t namesz, descsz; - - (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof); - offset += xnh_sizeof; - - namesz = xnh_namesz; - descsz = xnh_descsz; - if ((namesz == 0) && (descsz == 0)) { - /* - * We're out of note headers. - */ - return offset; - } - - if (namesz & 0x80000000) { - (void)file_printf(ms, ", bad note name size 0x%lx", - (unsigned long)namesz); - return offset; - } - - if (descsz & 0x80000000) { - (void)file_printf(ms, ", bad note description size 0x%lx", - (unsigned long)descsz); - return offset; - } - - - noff = offset; - doff = ELF_ALIGN(offset + namesz); - - if (offset + namesz > size) { - /* - * We're past the end of the buffer. - */ - return doff; - } - - offset = ELF_ALIGN(doff + descsz); - if (doff + descsz > size) { - return offset; - } - - if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && - xnh_type == NT_GNU_VERSION && descsz == 16) { - uint32_t desc[4]; - (void)memcpy(desc, &nbuf[doff], sizeof(desc)); - - if (file_printf(ms, ", for GNU/") == -1) - return size; - switch (getu32(swap, desc[0])) { - case GNU_OS_LINUX: - if (file_printf(ms, "Linux") == -1) - return size; - break; - case GNU_OS_HURD: - if (file_printf(ms, "Hurd") == -1) - return size; - break; - case GNU_OS_SOLARIS: - if (file_printf(ms, "Solaris") == -1) - return size; - break; - default: - if (file_printf(ms, "<unknown>") == -1) - return size; - } - if (file_printf(ms, " %d.%d.%d", getu32(swap, desc[1]), - getu32(swap, desc[2]), getu32(swap, desc[3])) == -1) - return size; - return size; - } - - if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0 && - xnh_type == NT_NETBSD_VERSION && descsz == 4) { - uint32_t desc; - (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); - desc = getu32(swap, desc); - - if (file_printf(ms, ", for NetBSD") == -1) - return size; - /* - * The version number used to be stuck as 199905, and was thus - * basically content-free. Newer versions of NetBSD have fixed - * this and now use the encoding of __NetBSD_Version__: - * - * MMmmrrpp00 - * - * M = major version - * m = minor version - * r = release ["",A-Z,Z[A-Z] but numeric] - * p = patchlevel - */ - if (desc > 100000000U) { - u_int ver_patch = (desc / 100) % 100; - u_int ver_rel = (desc / 10000) % 100; - u_int ver_min = (desc / 1000000) % 100; - u_int ver_maj = desc / 100000000; - - if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1) - return size; - if (ver_rel == 0 && ver_patch != 0) { - if (file_printf(ms, ".%u", ver_patch) == -1) - return size; - } else if (ver_rel != 0) { - while (ver_rel > 26) { - file_printf(ms, "Z"); - ver_rel -= 26; - } - file_printf(ms, "%c", 'A' + ver_rel - 1); - } - } - return size; - } - - if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0 && - xnh_type == NT_FREEBSD_VERSION && descsz == 4) { - uint32_t desc; - (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); - desc = getu32(swap, desc); - if (file_printf(ms, ", for FreeBSD") == -1) - return size; - - /* - * Contents is __FreeBSD_version, whose relation to OS - * versions is defined by a huge table in the Porter's - * Handbook. This is the general scheme: - * - * Releases: - * Mmp000 (before 4.10) - * Mmi0p0 (before 5.0) - * Mmm0p0 - * - * Development branches: - * Mmpxxx (before 4.6) - * Mmp1xx (before 4.10) - * Mmi1xx (before 5.0) - * M000xx (pre-M.0) - * Mmm1xx - * - * M = major version - * m = minor version - * i = minor version increment (491000 -> 4.10) - * p = patchlevel - * x = revision - * - * The first release of FreeBSD to use ELF by default - * was version 3.0. - */ - if (desc == 460002) { - if (file_printf(ms, " 4.6.2") == -1) - return size; - } else if (desc < 460100) { - if (file_printf(ms, " %d.%d", desc / 100000, - desc / 10000 % 10) == -1) - return size; - if (desc / 1000 % 10 > 0) - if (file_printf(ms, ".%d", desc / 1000 % 10) - == -1) - return size; - if ((desc % 1000 > 0) || (desc % 100000 == 0)) - if (file_printf(ms, " (%d)", desc) == -1) - return size; - } else if (desc < 500000) { - if (file_printf(ms, " %d.%d", desc / 100000, - desc / 10000 % 10 + desc / 1000 % 10) == -1) - return size; - if (desc / 100 % 10 > 0) { - if (file_printf(ms, " (%d)", desc) == -1) - return size; - } else if (desc / 10 % 10 > 0) { - if (file_printf(ms, ".%d", desc / 10 % 10) - == -1) - return size; - } - } else { - if (file_printf(ms, " %d.%d", desc / 100000, - desc / 1000 % 100) == -1) - return size; - if ((desc / 100 % 10 > 0) || - (desc % 100000 / 100 == 0)) { - if (file_printf(ms, " (%d)", desc) == -1) - return size; - } else if (desc / 10 % 10 > 0) { - if (file_printf(ms, ".%d", desc / 10 % 10) - == -1) - return size; - } - } - return size; - } + if (class == ELFCLASS32) + nh32 = (Elf32_Nhdr *)&nbuf[offset]; + else + nh64 = (Elf64_Nhdr *)&nbuf[offset]; + offset += nh_size; - if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 && - xnh_type == NT_OPENBSD_VERSION && descsz == 4) { - if (file_printf(ms, ", for OpenBSD") == -1) - return size; - /* Content of note is always 0 */ - return size; - } - - if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 && - xnh_type == NT_DRAGONFLY_VERSION && descsz == 4) { - uint32_t desc; - if (file_printf(ms, ", for DragonFly") == -1) - return size; - (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); - desc = getu32(swap, desc); - if (file_printf(ms, " %d.%d.%d", desc / 100000, - desc / 10000 % 10, desc % 10000) == -1) - return size; - return size; - } - - /* - * Sigh. The 2.0.36 kernel in Debian 2.1, at - * least, doesn't correctly implement name - * sections, in core dumps, as specified by - * the "Program Linking" section of "UNIX(R) System - * V Release 4 Programmer's Guide: ANSI C and - * Programming Support Tools", because my copy - * clearly says "The first 'namesz' bytes in 'name' - * contain a *null-terminated* [emphasis mine] - * character representation of the entry's owner - * or originator", but the 2.0.36 kernel code - * doesn't include the terminating null in the - * name.... - */ - if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) || - (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) { - os_style = OS_STYLE_SVR4; - } - - if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) { - os_style = OS_STYLE_FREEBSD; - } - - if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11) - == 0)) { - os_style = OS_STYLE_NETBSD; - } - -#ifdef ELFCORE - if (os_style != -1) { - if ((*flags & FLAGS_DID_CORE) == 0) { - if (file_printf(ms, ", %s-style", - os_style_names[os_style]) == -1) - return size; - *flags |= FLAGS_DID_CORE; - } - } - - switch (os_style) { - case OS_STYLE_NETBSD: - if (xnh_type == NT_NETBSD_CORE_PROCINFO) { - uint32_t signo; - /* - * Extract the program name. It is at - * offset 0x7c, and is up to 32-bytes, - * including the terminating NUL. - */ - if (file_printf(ms, ", from '%.31s'", - &nbuf[doff + 0x7c]) == -1) - return size; - /* - * Extract the signal number. It is at - * offset 0x08. + * Check whether this note has the name "CORE" or + * "FreeBSD". */ - (void)memcpy(&signo, &nbuf[doff + 0x08], - sizeof(signo)); - if (file_printf(ms, " (signal %u)", - getu32(swap, signo)) == -1) - return size; - return size; - } - break; + if (offset + nh_namesz >= bufsize) { + /* + * We're past the end of the buffer. + */ + break; + } + + nameoffset = offset; + offset += nh_namesz; + offset = ((offset + 3)/4)*4; - default: - if (xnh_type == NT_PRPSINFO) { - size_t i, j; - unsigned char c; /* - * Extract the program name. We assume - * it to be 16 characters (that's what it - * is in SunOS 5.x and Linux). - * - * Unfortunately, it's at a different offset - * in varous OSes, so try multiple offsets. - * If the characters aren't all printable, - * reject it. + * Sigh. The 2.0.36 kernel in Debian 2.1, at + * least, doesn't correctly implement name + * sections, in core dumps, as specified by + * the "Program Linking" section of "UNIX(R) System + * V Release 4 Programmer's Guide: ANSI C and + * Programming Support Tools", because my copy + * clearly says "The first 'namesz' bytes in 'name' + * contain a *null-terminated* [emphasis mine] + * character representation of the entry's owner + * or originator", but the 2.0.36 kernel code + * doesn't include the terminating null in the + * name.... */ - for (i = 0; i < NOFFSETS; i++) { - size_t reloffset = prpsoffsets(i); - size_t noffset = doff + reloffset; - for (j = 0; j < 16; j++, noffset++, - reloffset++) { - /* - * Make sure we're not past - * the end of the buffer; if - * we are, just give up. - */ - if (noffset >= size) - goto tryanother; - - /* - * Make sure we're not past - * the end of the contents; - * if we are, this obviously - * isn't the right offset. - */ - if (reloffset >= descsz) - goto tryanother; - - c = nbuf[noffset]; - if (c == '\0') { + if ((nh_namesz == 4 && + strncmp(&nbuf[nameoffset], "CORE", 4) == 0) || + (nh_namesz == 5 && + strcmp(&nbuf[nameoffset], "CORE") == 0)) + is_freebsd = 0; + else if ((nh_namesz == 8 && + strcmp(&nbuf[nameoffset], "FreeBSD") == 0)) + is_freebsd = 1; + else + continue; + if (nh_type == NT_PRPSINFO) { + /* + * Extract the program name. We assume + * it to be 16 characters (that's what it + * is in SunOS 5.x and Linux). + * + * Unfortunately, it's at a different offset + * in varous OSes, so try multiple offsets. + * If the characters aren't all printable, + * reject it. + */ + for (i = 0; i < NOFFSETS; i++) { + reloffset = prpsoffsets(i); + noffset = offset + reloffset; + for (j = 0; j < 16; + j++, noffset++, reloffset++) { /* - * A '\0' at the - * beginning is - * obviously wrong. - * Any other '\0' - * means we're done. + * Make sure we're not past + * the end of the buffer; if + * we are, just give up. */ - if (j == 0) + if (noffset >= bufsize) goto tryanother; - else - break; - } else { + /* - * A nonprintable - * character is also - * wrong. + * Make sure we're not past + * the end of the contents; + * if we are, this obviously + * isn't the right offset. */ - if (!isprint(c) || isquote(c)) + if (reloffset >= nh_descsz) goto tryanother; - } - } - /* - * Well, that worked. - */ - if (file_printf(ms, ", from '%.16s'", - &nbuf[doff + prpsoffsets(i)]) == -1) - return size; - return size; - - tryanother: - ; - } - } - break; - } -#endif - return offset; -} - -private int -doshn(struct magic_set *ms, int class, int swap, int fd, off_t off, int num, - size_t size) -{ - Elf32_Shdr sh32; - Elf64_Shdr sh64; - int stripped = 1; - int flags = 0; - void *nbuf; - off_t noff; - - if (size != xsh_sizeof) { - if (file_printf(ms, ", corrupted section header size") == -1) - return -1; - return 0; - } - - if (lseek(fd, off, SEEK_SET) == (off_t)-1) { - file_badseek(ms); - return -1; - } - for ( ; num; num--) { - if (read(fd, xsh_addr, xsh_sizeof) == -1) { - file_badread(ms); - return -1; - } - switch (xsh_type) { - case SHT_SYMTAB: -#if 0 - case SHT_DYNSYM: -#endif - stripped = 0; - break; - case SHT_NOTE: - if ((off = lseek(fd, (off_t)0, SEEK_CUR)) == - (off_t)-1) { - file_badread(ms); - return -1; - } - if ((nbuf = malloc((size_t)xsh_size)) == NULL) { - file_error(ms, errno, "Cannot allocate memory" - " for note"); - return -1; - } - if ((noff = lseek(fd, (off_t)xsh_offset, SEEK_SET)) == - (off_t)-1) { - file_badread(ms); - free(nbuf); - return -1; - } - if (read(fd, nbuf, (size_t)xsh_size) != - (ssize_t)xsh_size) { - free(nbuf); - file_badread(ms); - return -1; - } + c = nbuf[noffset]; + if (c == '\0') { + /* + * A '\0' at the + * beginning is + * obviously wrong. + * Any other '\0' + * means we're done. + */ + if (j == 0) + goto tryanother; + else + break; + } else { + /* + * A nonprintable + * character is also + * wrong. + */ +#define isquote(c) (strchr("'\"`", (c)) != NULL) + if (!isprint(c) || + isquote(c)) + goto tryanother; + } + } - noff = 0; - for (;;) { - if (noff >= (size_t)xsh_size) - break; - noff = donote(ms, nbuf, (size_t)noff, - (size_t)xsh_size, class, swap, 4, - &flags); - if (noff == 0) + /* + * Well, that worked. + */ + printf(", from '%.16s'", + &nbuf[offset + prpsoffsets(i)]); break; - } - if ((lseek(fd, off, SEEK_SET)) == (off_t)-1) { - free(nbuf); - file_badread(ms); - return -1; - } - free(nbuf); - break; - } - } - if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1) - return -1; - return 0; -} - -/* - * Look through the program headers of an executable image, searching - * for a PT_INTERP section; if one is found, it's dynamically linked, - * otherwise it's statically linked. - */ -private int -dophn_exec(struct magic_set *ms, int class, int swap, int fd, off_t off, - int num, size_t size) -{ - Elf32_Phdr ph32; - Elf64_Phdr ph64; - const char *linking_style = "statically"; - const char *shared_libraries = ""; - unsigned char nbuf[BUFSIZ]; - int bufsize; - size_t offset, align; - off_t savedoffset; - int flags = 0; - - if (size != xph_sizeof) { - if (file_printf(ms, ", corrupted program header size") == -1) - return -1; - return 0; - } - if (lseek(fd, off, SEEK_SET) == (off_t)-1) { - file_badseek(ms); - return -1; - } - for ( ; num; num--) { - if (read(fd, xph_addr, xph_sizeof) == -1) { - file_badread(ms); - return -1; - } - if ((savedoffset = lseek(fd, (off_t)0, SEEK_CUR)) == (off_t)-1) { - file_badseek(ms); - return -1; - } - - switch (xph_type) { - case PT_DYNAMIC: - linking_style = "dynamically"; - break; - case PT_INTERP: - shared_libraries = " (uses shared libs)"; - break; - case PT_NOTE: - if ((align = xph_align) & 0x80000000) { - if (file_printf(ms, - ", invalid note alignment 0x%lx", - (unsigned long)align) == -1) - return -1; - align = 4; - } - /* - * This is a PT_NOTE section; loop through all the notes - * in the section. - */ - if (lseek(fd, (off_t)xph_offset, SEEK_SET) - == (off_t)-1) { - file_badseek(ms); - return -1; - } - bufsize = read(fd, nbuf, ((xph_filesz < sizeof(nbuf)) ? - xph_filesz : sizeof(nbuf))); - if (bufsize == -1) { - file_badread(ms); - return -1; - } - offset = 0; - for (;;) { - if (offset >= (size_t)bufsize) - break; - offset = donote(ms, nbuf, offset, - (size_t)bufsize, class, swap, align, - &flags); - if (offset == 0) - break; - } - if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) { - file_badseek(ms); - return -1; + tryanother: + ; + } + break; } - break; + offset += nh_descsz; + offset = ((offset + 3)/4)*4; } + out: + ; } - if (file_printf(ms, ", %s linked%s", linking_style, shared_libraries) - == -1) - return -1; - return 0; } +#endif - -protected int -file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf, - size_t nbytes) +void +tryelf(fd, buf, nbytes) + int fd; + unsigned char *buf; + int nbytes; { union { - int32_t l; - char c[sizeof (int32_t)]; + int32 l; + char c[sizeof (int32)]; } u; int class; int swap; /* - * If we cannot seek, it must be a pipe, socket or fifo. - */ - if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE)) - fd = file_pipe2file(ms, fd, buf, nbytes); - - /* * ELF executables have multiple section headers in arbitrary * file locations and thus file(1) cannot determine it from easily. * Instead we traverse thru all section headers until a symbol table @@ -864,7 +422,7 @@ file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf, if (buf[EI_MAG0] != ELFMAG0 || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1) || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) - return 0; + return; class = buf[4]; @@ -872,78 +430,88 @@ file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf, if (class == ELFCLASS32) { Elf32_Ehdr elfhdr; if (nbytes <= sizeof (Elf32_Ehdr)) - return 0; + return; u.l = 1; (void) memcpy(&elfhdr, buf, sizeof elfhdr); - swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[5]; + swap = (u.c[sizeof(int32) - 1] + 1) != elfhdr.e_ident[5]; - if (getu16(swap, elfhdr.e_type) == ET_CORE) { + if (getu16(swap, elfhdr.e_type) == ET_CORE) #ifdef ELFCORE - if (dophn_core(ms, class, swap, fd, - (off_t)getu32(swap, elfhdr.e_phoff), - getu16(swap, elfhdr.e_phnum), - (size_t)getu16(swap, elfhdr.e_phentsize)) == -1) - return -1; + dophn_core(class, swap, + fd, + getu32(swap, elfhdr.e_phoff), + getu16(swap, elfhdr.e_phnum), + getu16(swap, elfhdr.e_phentsize)); #else ; #endif - } else { + else { if (getu16(swap, elfhdr.e_type) == ET_EXEC) { - if (dophn_exec(ms, class, swap, - fd, (off_t)getu32(swap, elfhdr.e_phoff), - getu16(swap, elfhdr.e_phnum), - (size_t)getu16(swap, elfhdr.e_phentsize)) - == -1) - return -1; + dophn_exec(class, swap, + fd, + getu32(swap, elfhdr.e_phoff), + getu16(swap, elfhdr.e_phnum), + getu16(swap, elfhdr.e_phentsize)); } - if (doshn(ms, class, swap, fd, - (off_t)getu32(swap, elfhdr.e_shoff), - getu16(swap, elfhdr.e_shnum), - (size_t)getu16(swap, elfhdr.e_shentsize)) == -1) - return -1; + doshn(class, swap, + fd, + getu32(swap, elfhdr.e_shoff), + getu16(swap, elfhdr.e_shnum), + getu16(swap, elfhdr.e_shentsize)); } - return 1; + return; } if (class == ELFCLASS64) { Elf64_Ehdr elfhdr; if (nbytes <= sizeof (Elf64_Ehdr)) - return 0; + return; u.l = 1; (void) memcpy(&elfhdr, buf, sizeof elfhdr); - swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[5]; + swap = (u.c[sizeof(int32) - 1] + 1) != elfhdr.e_ident[5]; - if (getu16(swap, elfhdr.e_type) == ET_CORE) { + if (getu16(swap, elfhdr.e_type) == ET_CORE) #ifdef ELFCORE - if (dophn_core(ms, class, swap, fd, - (off_t)elf_getu64(swap, elfhdr.e_phoff), - getu16(swap, elfhdr.e_phnum), - (size_t)getu16(swap, elfhdr.e_phentsize)) == -1) - return -1; + dophn_core(class, swap, + fd, +#ifdef USE_ARRAY_FOR_64BIT_TYPES + getu32(swap, elfhdr.e_phoff[1]), +#else + getu64(swap, elfhdr.e_phoff), +#endif + getu16(swap, elfhdr.e_phnum), + getu16(swap, elfhdr.e_phentsize)); #else ; #endif - } else { + else + { if (getu16(swap, elfhdr.e_type) == ET_EXEC) { - if (dophn_exec(ms, class, swap, fd, - (off_t)elf_getu64(swap, elfhdr.e_phoff), - getu16(swap, elfhdr.e_phnum), - (size_t)getu16(swap, elfhdr.e_phentsize)) - == -1) - return -1; + dophn_exec(class, swap, + fd, +#ifdef USE_ARRAY_FOR_64BIT_TYPES + getu32(swap, elfhdr.e_phoff[1]), +#else + getu64(swap, elfhdr.e_phoff), +#endif + getu16(swap, elfhdr.e_phnum), + getu16(swap, elfhdr.e_phentsize)); } - if (doshn(ms, class, swap, fd, - (off_t)elf_getu64(swap, elfhdr.e_shoff), - getu16(swap, elfhdr.e_shnum), - (size_t)getu16(swap, elfhdr.e_shentsize)) == -1) - return -1; + doshn(class, swap, + fd, +#ifdef USE_ARRAY_FOR_64BIT_TYPES + getu32(swap, elfhdr.e_shoff[1]), +#else + getu64(swap, elfhdr.e_shoff), +#endif + getu16(swap, elfhdr.e_shnum), + getu16(swap, elfhdr.e_shentsize)); } - return 1; + return; } - return 0; } #endif |
