diff options
Diffstat (limited to 'src/readelf.c')
-rw-r--r-- | src/readelf.c | 301 |
1 files changed, 188 insertions, 113 deletions
diff --git a/src/readelf.c b/src/readelf.c index db0b35a506a71..ef61d4cd600fe 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -1,7 +1,7 @@ /* * 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: @@ -11,7 +11,7 @@ * 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 @@ -27,7 +27,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: readelf.c,v 1.144 2018/07/08 23:37:33 christos Exp $") +FILE_RCSID("@(#)$File: readelf.c,v 1.165 2019/05/07 02:27:11 christos Exp $") #endif #ifdef BUILTIN_ELF @@ -69,7 +69,7 @@ toomany(struct magic_set *ms, const char *name, uint16_t num) { if (file_printf(ms, ", too many %s (%u)", name, num) == -1) return -1; - return 0; + return 1; } private uint16_t @@ -85,7 +85,7 @@ getu16(int swap, uint16_t value) retval.c[0] = tmpval.c[1]; retval.c[1] = tmpval.c[0]; - + return retval.ui; } else return value; @@ -106,7 +106,7 @@ getu32(int swap, uint32_t value) retval.c[1] = tmpval.c[2]; retval.c[2] = tmpval.c[1]; retval.c[3] = tmpval.c[0]; - + return retval.ui; } else return value; @@ -131,7 +131,7 @@ getu64(int swap, uint64_t value) retval.c[5] = tmpval.c[2]; retval.c[6] = tmpval.c[1]; retval.c[7] = tmpval.c[0]; - + return retval.ui; } else return value; @@ -262,7 +262,10 @@ static const size_t prpsoffsets32[] = { 84, /* SunOS 5.x (short name) */ 44, /* Linux (command line) */ - 28, /* Linux 2.0.36 (short name) */ + 28, /* Linux (short name) */ + + 48, /* Linux PowerPC (command line) */ + 32, /* Linux PowerPC (short name) */ 8, /* FreeBSD */ }; @@ -282,8 +285,8 @@ static const size_t prpsoffsets64[] = { 16, /* FreeBSD, 64-bit */ }; -#define NOFFSETS32 (sizeof(prpsoffsets32) / sizeof(prpsoffsets32[0])) -#define NOFFSETS64 (sizeof(prpsoffsets64) / sizeof(prpsoffsets64[0])) +#define NOFFSETS32 __arraycount(prpsoffsets32) +#define NOFFSETS64 __arraycount(prpsoffsets64) #define NOFFSETS (clazz == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64) @@ -352,6 +355,11 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, off_t ph_off = off; int ph_num = num; + if (num == 0) { + if (file_printf(ms, ", no program header") == -1) + return -1; + return 0; + } if (size != xph_sizeof) { if (file_printf(ms, ", corrupted program header size") == -1) return -1; @@ -388,9 +396,9 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, } offset = 0; for (;;) { - if (offset >= (size_t)bufsize) + if (offset >= CAST(size_t, bufsize)) break; - offset = donote(ms, nbuf, offset, (size_t)bufsize, + offset = donote(ms, nbuf, offset, CAST(size_t, bufsize), clazz, swap, 4, flags, notecount, fd, ph_off, ph_num, fsize); if (offset == 0) @@ -402,7 +410,7 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, } #endif -static void +static int do_note_netbsd_version(struct magic_set *ms, int swap, void *v) { uint32_t desc; @@ -410,7 +418,7 @@ do_note_netbsd_version(struct magic_set *ms, int swap, void *v) desc = elf_getu32(swap, desc); if (file_printf(ms, ", for NetBSD") == -1) - return; + return -1; /* * The version number used to be stuck as 199905, and was thus * basically content-free. Newer versions of NetBSD have fixed @@ -430,24 +438,25 @@ do_note_netbsd_version(struct magic_set *ms, int swap, void *v) uint32_t ver_maj = desc / 100000000; if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1) - return; + return -1; if (ver_rel == 0 && ver_patch != 0) { if (file_printf(ms, ".%u", ver_patch) == -1) - return; + return -1; } else if (ver_rel != 0) { while (ver_rel > 26) { if (file_printf(ms, "Z") == -1) - return; + return -1; ver_rel -= 26; } if (file_printf(ms, "%c", 'A' + ver_rel - 1) == -1) - return; + return -1; } } + return 0; } -static void +static int do_note_freebsd_version(struct magic_set *ms, int swap, void *v) { uint32_t desc; @@ -455,71 +464,72 @@ do_note_freebsd_version(struct magic_set *ms, int swap, void *v) memcpy(&desc, v, sizeof(desc)); desc = elf_getu32(swap, desc); if (file_printf(ms, ", for FreeBSD") == -1) - return; + return -1; /* * 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; + return -1; } else if (desc < 460100) { if (file_printf(ms, " %d.%d", desc / 100000, desc / 10000 % 10) == -1) - return; + return -1; if (desc / 1000 % 10 > 0) if (file_printf(ms, ".%d", desc / 1000 % 10) == -1) - return; + return -1; if ((desc % 1000 > 0) || (desc % 100000 == 0)) if (file_printf(ms, " (%d)", desc) == -1) - return; + return -1; } else if (desc < 500000) { if (file_printf(ms, " %d.%d", desc / 100000, desc / 10000 % 10 + desc / 1000 % 10) == -1) - return; + return -1; if (desc / 100 % 10 > 0) { if (file_printf(ms, " (%d)", desc) == -1) - return; + return -1; } else if (desc / 10 % 10 > 0) { if (file_printf(ms, ".%d", desc / 10 % 10) == -1) - return; + return -1; } } else { if (file_printf(ms, " %d.%d", desc / 100000, desc / 1000 % 100) == -1) - return; + return -1; if ((desc / 100 % 10 > 0) || (desc % 100000 / 100 == 0)) { if (file_printf(ms, " (%d)", desc) == -1) - return; + return -1; } else if (desc / 10 % 10 > 0) { if (file_printf(ms, ".%d", desc / 10 % 10) == -1) - return; + return -1; } } + return 0; } private int @@ -528,7 +538,7 @@ do_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, int swap __attribute__((__unused__)), uint32_t namesz, uint32_t descsz, size_t noff, size_t doff, int *flags) { - if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && + if (namesz == 4 && strcmp(RCAST(char *, &nbuf[noff]), "GNU") == 0 && type == NT_GNU_BUILD_ID && (descsz >= 4 && descsz <= 20)) { uint8_t desc[20]; const char *btype; @@ -549,18 +559,18 @@ do_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, break; } if (file_printf(ms, ", BuildID[%s]=", btype) == -1) - return 1; + return -1; memcpy(desc, &nbuf[doff], descsz); for (i = 0; i < descsz; i++) if (file_printf(ms, "%02x", desc[i]) == -1) - return 1; + return -1; return 1; } - if (namesz == 4 && strcmp((char *)&nbuf[noff], "Go") == 0 && + if (namesz == 4 && strcmp(RCAST(char *, &nbuf[noff]), "Go") == 0 && type == NT_GO_BUILD_ID && descsz < 128) { - if (file_printf(ms, ", Go BuildID=%s", - (char *)&nbuf[doff]) == -1) - return 1; + if (file_printf(ms, ", Go BuildID=%.*s", + CAST(int, descsz), RCAST(char *, &nbuf[doff])) == -1) + return -1; return 1; } return 0; @@ -571,88 +581,95 @@ do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, int swap, uint32_t namesz, uint32_t descsz, size_t noff, size_t doff, int *flags) { - if (namesz == 5 && strcmp((char *)&nbuf[noff], "SuSE") == 0 && - type == NT_GNU_VERSION && descsz == 2) { - *flags |= FLAGS_DID_OS_NOTE; - file_printf(ms, ", for SuSE %d.%d", nbuf[doff], nbuf[doff + 1]); + const char *name = RCAST(const char *, &nbuf[noff]); + + if (namesz == 5 && strcmp(name, "SuSE") == 0 && + type == NT_GNU_VERSION && descsz == 2) { + *flags |= FLAGS_DID_OS_NOTE; + if (file_printf(ms, ", for SuSE %d.%d", nbuf[doff], + nbuf[doff + 1]) == -1) + return -1; return 1; } - if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && + if (namesz == 4 && strcmp(name, "GNU") == 0 && type == NT_GNU_VERSION && descsz == 16) { uint32_t desc[4]; memcpy(desc, &nbuf[doff], sizeof(desc)); *flags |= FLAGS_DID_OS_NOTE; if (file_printf(ms, ", for GNU/") == -1) - return 1; + return -1; switch (elf_getu32(swap, desc[0])) { case GNU_OS_LINUX: if (file_printf(ms, "Linux") == -1) - return 1; + return -1; break; case GNU_OS_HURD: if (file_printf(ms, "Hurd") == -1) - return 1; + return -1; break; case GNU_OS_SOLARIS: if (file_printf(ms, "Solaris") == -1) - return 1; + return -1; break; case GNU_OS_KFREEBSD: if (file_printf(ms, "kFreeBSD") == -1) - return 1; + return -1; break; case GNU_OS_KNETBSD: if (file_printf(ms, "kNetBSD") == -1) - return 1; + return -1; break; default: if (file_printf(ms, "<unknown>") == -1) - return 1; + return -1; } if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]), elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1) - return 1; + return -1; return 1; } - if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) { + if (namesz == 7 && strcmp(name, "NetBSD") == 0) { if (type == NT_NETBSD_VERSION && descsz == 4) { *flags |= FLAGS_DID_OS_NOTE; - do_note_netbsd_version(ms, swap, &nbuf[doff]); + if (do_note_netbsd_version(ms, swap, &nbuf[doff]) == -1) + return -1; return 1; } } - if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0) { + if (namesz == 8 && strcmp(name, "FreeBSD") == 0) { if (type == NT_FREEBSD_VERSION && descsz == 4) { *flags |= FLAGS_DID_OS_NOTE; - do_note_freebsd_version(ms, swap, &nbuf[doff]); + if (do_note_freebsd_version(ms, swap, &nbuf[doff]) + == -1) + return -1; return 1; } } - if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 && + if (namesz == 8 && strcmp(name, "OpenBSD") == 0 && type == NT_OPENBSD_VERSION && descsz == 4) { *flags |= FLAGS_DID_OS_NOTE; if (file_printf(ms, ", for OpenBSD") == -1) - return 1; + return -1; /* Content of note is always 0 */ return 1; } - if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 && + if (namesz == 10 && strcmp(name, "DragonFly") == 0 && type == NT_DRAGONFLY_VERSION && descsz == 4) { uint32_t desc; *flags |= FLAGS_DID_OS_NOTE; if (file_printf(ms, ", for DragonFly") == -1) - return 1; + return -1; memcpy(&desc, &nbuf[doff], sizeof(desc)); desc = elf_getu32(swap, desc); if (file_printf(ms, " %d.%d.%d", desc / 100000, desc / 10000 % 10, desc % 10000) == -1) - return 1; + return -1; return 1; } return 0; @@ -663,7 +680,9 @@ do_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, int swap, uint32_t namesz, uint32_t descsz, size_t noff, size_t doff, int *flags) { - if (namesz == 4 && strcmp((char *)&nbuf[noff], "PaX") == 0 && + const char *name = RCAST(const char *, &nbuf[noff]); + + if (namesz == 4 && strcmp(name, "PaX") == 0 && type == NT_NETBSD_PAX && descsz == 4) { static const char *pax[] = { "+mprotect", @@ -682,14 +701,14 @@ do_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, desc = elf_getu32(swap, desc); if (desc && file_printf(ms, ", PaX: ") == -1) - return 1; + return -1; for (i = 0; i < __arraycount(pax); i++) { - if (((1 << (int)i) & desc) == 0) + if (((1 << CAST(int, i)) & desc) == 0) continue; if (file_printf(ms, "%s%s", did++ ? "," : "", pax[i]) == -1) - return 1; + return -1; } return 1; } @@ -702,6 +721,8 @@ do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, size_t noff, size_t doff, int *flags, size_t size, int clazz) { #ifdef ELFCORE + const char *name = RCAST(const char *, &nbuf[noff]); + int os_style = -1; /* * Sigh. The 2.0.36 kernel in Debian 2.1, at @@ -717,16 +738,16 @@ do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, * 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)) { + if ((namesz == 4 && strncmp(name, "CORE", 4) == 0) || + (namesz == 5 && strcmp(name, "CORE") == 0)) { os_style = OS_STYLE_SVR4; - } + } - if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) { + if ((namesz == 8 && strcmp(name, "FreeBSD") == 0)) { os_style = OS_STYLE_FREEBSD; } - if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11) + if ((namesz >= 11 && strncmp(name, "NetBSD-CORE", 11) == 0)) { os_style = OS_STYLE_NETBSD; } @@ -734,7 +755,7 @@ do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) { if (file_printf(ms, ", %s-style", os_style_names[os_style]) == -1) - return 1; + return -1; *flags |= FLAGS_DID_CORE_STYLE; *flags |= os_style; } @@ -745,26 +766,48 @@ do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, char sbuf[512]; struct NetBSD_elfcore_procinfo pi; memset(&pi, 0, sizeof(pi)); - memcpy(&pi, nbuf + doff, descsz); + memcpy(&pi, nbuf + doff, MIN(descsz, sizeof(pi))); if (file_printf(ms, ", from '%.31s', pid=%u, uid=%u, " "gid=%u, nlwps=%u, lwp=%u (signal %u/code %u)", file_printable(sbuf, sizeof(sbuf), - CAST(char *, pi.cpi_name)), - elf_getu32(swap, (uint32_t)pi.cpi_pid), + RCAST(char *, pi.cpi_name), sizeof(pi.cpi_name)), + elf_getu32(swap, CAST(uint32_t, pi.cpi_pid)), elf_getu32(swap, pi.cpi_euid), elf_getu32(swap, pi.cpi_egid), elf_getu32(swap, pi.cpi_nlwps), - elf_getu32(swap, (uint32_t)pi.cpi_siglwp), + elf_getu32(swap, CAST(uint32_t, pi.cpi_siglwp)), elf_getu32(swap, pi.cpi_signo), elf_getu32(swap, pi.cpi_sigcode)) == -1) - return 1; + return -1; *flags |= FLAGS_DID_CORE; return 1; } break; + case OS_STYLE_FREEBSD: + if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) { + size_t argoff, pidoff; + + if (clazz == ELFCLASS32) + argoff = 4 + 4 + 17; + else + argoff = 4 + 4 + 8 + 17; + if (file_printf(ms, ", from '%.80s'", nbuf + doff + + argoff) == -1) + return -1; + pidoff = argoff + 81 + 2; + if (doff + pidoff + 4 <= size) { + if (file_printf(ms, ", pid=%u", + elf_getu32(swap, *RCAST(uint32_t *, (nbuf + + doff + pidoff)))) == -1) + return -1; + } + *flags |= FLAGS_DID_CORE; + } + break; + default: if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) { size_t i, j; @@ -847,8 +890,8 @@ do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, i = k; } - cname = (unsigned char *) - &nbuf[doff + prpsoffsets(i)]; + cname = CAST(unsigned char *, + &nbuf[doff + prpsoffsets(i)]); for (cp = cname; cp < nbuf + size && *cp && isprint(*cp); cp++) continue; @@ -859,8 +902,8 @@ do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, while (cp > cname && isspace(cp[-1])) cp--; if (file_printf(ms, ", from '%.*s'", - (int)(cp - cname), cname) == -1) - return 1; + CAST(int, cp - cname), cname) == -1) + return -1; *flags |= FLAGS_DID_CORE; return 1; @@ -886,7 +929,8 @@ get_offset_from_virtaddr(struct magic_set *ms, int swap, int clazz, int fd, * virtual address in which the "virtaddr" belongs to. */ for ( ; num; num--) { - if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) { + if (pread(fd, xph_addr, xph_sizeof, off) < + CAST(ssize_t, xph_sizeof)) { file_badread(ms); return -1; } @@ -916,7 +960,8 @@ get_string_on_virtaddr(struct magic_set *ms, offset = get_offset_from_virtaddr(ms, swap, clazz, fd, ph_off, ph_num, fsize, virtaddr); - if ((buflen = pread(fd, buf, CAST(size_t, buflen), offset)) <= 0) { + if (offset < 0 || + (buflen = pread(fd, buf, CAST(size_t, buflen), offset)) <= 0) { file_badread(ms); return 0; } @@ -925,7 +970,7 @@ get_string_on_virtaddr(struct magic_set *ms, /* We expect only printable characters, so return if buffer contains * non-printable character before the '\0' or just '\0'. */ - for (bptr = buf; *bptr && isprint((unsigned char)*bptr); bptr++) + for (bptr = buf; *bptr && isprint(CAST(unsigned char, *bptr)); bptr++) continue; if (*bptr != '\0') return 0; @@ -1027,13 +1072,13 @@ do_auxv_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type, if (buflen == 0) continue; - + if (file_printf(ms, ", %s: '%s'", tag, buf) == -1) - return 0; + return -1; } else { - if (file_printf(ms, ", %s: %d", tag, (int) xauxv_val) - == -1) - return 0; + if (file_printf(ms, ", %s: %d", tag, + CAST(int, xauxv_val)) == -1) + return -1; } } return 1; @@ -1062,7 +1107,7 @@ dodynamic(struct magic_set *ms, void *vbuf, size_t offset, size_t size, switch (xdh_tag) { case DT_FLAGS_1: - if (xdh_val == DF_1_PIE) + if (xdh_val & DF_1_PIE) ms->mode |= 0111; else ms->mode &= ~0111; @@ -1110,14 +1155,16 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, } if (namesz & 0x80000000) { - file_printf(ms, ", bad note name size %#lx", - CAST(unsigned long, namesz)); + if (file_printf(ms, ", bad note name size %#lx", + CAST(unsigned long, namesz)) == -1) + return -1; return 0; } if (descsz & 0x80000000) { - file_printf(ms, ", bad note description size %#lx", - CAST(unsigned long, descsz)); + if (file_printf(ms, ", bad note description size %#lx", + CAST(unsigned long, descsz)) == -1) + return -1; return 0; } @@ -1151,7 +1198,7 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, namesz, descsz, noff, doff, flags)) return offset; } - + if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) { if (do_pax_note(ms, nbuf, xnh_type, swap, namesz, descsz, noff, doff, flags)) @@ -1171,7 +1218,7 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, return offset; } - if (namesz == 7 && strcmp(CAST(char *, &nbuf[noff]), "NetBSD") == 0) { + if (namesz == 7 && strcmp(RCAST(char *, &nbuf[noff]), "NetBSD") == 0) { int descw, flag; const char *str, *tag; if (descsz > 100) @@ -1202,7 +1249,7 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, if (*flags & flag) return offset; - str = CAST(const char *, &nbuf[doff]); + str = RCAST(const char *, &nbuf[doff]); descw = CAST(int, descsz); *flags |= flag; file_printf(ms, ", %s: %.*s", tag, descw, str); @@ -1278,6 +1325,11 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, char name[50]; ssize_t namesize; + if (num == 0) { + if (file_printf(ms, ", no section header") == -1) + return -1; + return 0; + } if (size != xsh_sizeof) { if (file_printf(ms, ", corrupted section header size") == -1) return -1; @@ -1343,7 +1395,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, CAST(uintmax_t, xsh_size), CAST(uintmax_t, fsize)) == -1) return -1; - return 0; + return 0; } if ((nbuf = malloc(xsh_size)) == NULL) { file_error(ms, errno, "Cannot allocate memory" @@ -1428,7 +1480,7 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, return -1; break; } - // gnu attributes + // gnu attributes #endif break; } @@ -1548,7 +1600,12 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, char interp[BUFSIZ]; ssize_t bufsize; size_t offset, align, len; - + + if (num == 0) { + if (file_printf(ms, ", no program header") == -1) + return -1; + return 0; + } if (size != xph_sizeof) { if (file_printf(ms, ", corrupted program header size") == -1) return -1; @@ -1558,7 +1615,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, interp[0] = '\0'; for ( ; num; num--) { int doread; - if (pread(fd, xph_addr, xph_sizeof, off) < + if (pread(fd, xph_addr, xph_sizeof, off) < CAST(ssize_t, xph_sizeof)) { file_badread(ms); return -1; @@ -1579,7 +1636,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, continue; if (((align = xph_align) & 0x80000000UL) != 0 || align < 4) { - if (file_printf(ms, + if (file_printf(ms, ", invalid note alignment %#lx", CAST(unsigned long, align)) == -1) return -1; @@ -1613,8 +1670,10 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, switch (xph_type) { case PT_DYNAMIC: offset = 0; + // Let DF_1 determine if we are PIE or not. + ms->mode &= ~0111; for (;;) { - if (offset >= (size_t)bufsize) + if (offset >= CAST(size_t, bufsize)) break; offset = dodynamic(ms, nbuf, offset, CAST(size_t, bufsize), clazz, swap); @@ -1626,7 +1685,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, case PT_INTERP: if (bufsize && nbuf[0]) { nbuf[bufsize - 1] = '\0'; - memcpy(interp, nbuf, bufsize); + memcpy(interp, nbuf, CAST(size_t, bufsize)); } else strlcpy(interp, "*empty*", sizeof(interp)); break; @@ -1637,7 +1696,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, */ offset = 0; for (;;) { - if (offset >= (size_t)bufsize) + if (offset >= CAST(size_t, bufsize)) break; offset = donote(ms, nbuf, offset, CAST(size_t, bufsize), clazz, swap, align, @@ -1655,7 +1714,8 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, return -1; if (interp[0]) if (file_printf(ms, ", interpreter %s", - file_printable(ibuf, sizeof(ibuf), interp)) == -1) + file_printable(ibuf, sizeof(ibuf), interp, sizeof(interp))) + == -1) return -1; return 0; } @@ -1665,7 +1725,7 @@ protected int file_tryelf(struct magic_set *ms, const struct buffer *b) { int fd = b->fd; - const unsigned char *buf = b->fbuf; + const unsigned char *buf = CAST(const unsigned char *, b->fbuf); size_t nbytes = b->flen; union { int32_t l; @@ -1674,6 +1734,7 @@ file_tryelf(struct magic_set *ms, const struct buffer *b) int clazz; int swap; struct stat st; + const struct stat *stp; off_t fsize; int flags = 0; Elf32_Ehdr elf32hdr; @@ -1687,7 +1748,8 @@ file_tryelf(struct magic_set *ms, const struct buffer *b) * file locations and thus file(1) cannot determine it from easily. * Instead we traverse thru all section headers until a symbol table * one is found or else the binary is stripped. - * Return immediately if it's not ELF (so we avoid pipe2file unless needed). + * Return immediately if it's not ELF (so we avoid pipe2file unless + * needed). */ if (buf[EI_MAG0] != ELFMAG0 || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1) @@ -1701,12 +1763,25 @@ file_tryelf(struct magic_set *ms, const struct buffer *b) && (errno == ESPIPE)) fd = file_pipe2file(ms, fd, buf, nbytes); - if (fstat(fd, &st) == -1) { - file_badread(ms); + if (fd == -1) { + file_badread(ms); return -1; } - if (S_ISREG(st.st_mode) || st.st_size != 0) - fsize = st.st_size; + + stp = &b->st; + /* + * b->st.st_size != 0 if previous fstat() succeeded, + * which is likely, we can avoid extra stat() call. + */ + if (b->st.st_size == 0) { + stp = &st; + if (fstat(fd, &st) == -1) { + file_badread(ms); + return -1; + } + } + if (S_ISREG(stp->st_mode) || stp->st_size != 0) + fsize = stp->st_size; else fsize = SIZE_UNKNOWN; |