summaryrefslogtreecommitdiff
path: root/src/readelf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/readelf.c')
-rw-r--r--src/readelf.c301
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;