summaryrefslogtreecommitdiffstats
path: root/contrib/file/src/readelf.c
diff options
context:
space:
mode:
authordelphij <delphij@FreeBSD.org>2016-04-18 07:36:24 +0000
committerdelphij <delphij@FreeBSD.org>2016-04-18 07:36:24 +0000
commit1852c3675cd08e58d07e956f9023f5b3eee5ca3c (patch)
tree7811b5b9831ebf5066c7eae2d213b5e48f66deb7 /contrib/file/src/readelf.c
parentcb410646fdaa9c6e3285e1d015ad0095ba9b012b (diff)
parent3c98cb6b19e2270fd5235eb16a8ae98de4fb0b5f (diff)
downloadFreeBSD-src-1852c3675cd08e58d07e956f9023f5b3eee5ca3c.zip
FreeBSD-src-1852c3675cd08e58d07e956f9023f5b3eee5ca3c.tar.gz
MFV r298178:
Update file to 5.26. MFC after: 2 weeks Relnotes: yes
Diffstat (limited to 'contrib/file/src/readelf.c')
-rw-r--r--contrib/file/src/readelf.c219
1 files changed, 199 insertions, 20 deletions
diff --git a/contrib/file/src/readelf.c b/contrib/file/src/readelf.c
index 2a7fc01..39598f7 100644
--- a/contrib/file/src/readelf.c
+++ b/contrib/file/src/readelf.c
@@ -27,7 +27,7 @@
#include "file.h"
#ifndef lint
-FILE_RCSID("@(#)$File: readelf.c,v 1.122 2015/09/10 13:59:32 christos Exp $")
+FILE_RCSID("@(#)$File: readelf.c,v 1.127 2015/11/18 12:29:29 christos Exp $")
#endif
#ifdef BUILTIN_ELF
@@ -50,7 +50,7 @@ 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,
off_t, int, int, int *, uint16_t *);
private size_t donote(struct magic_set *, void *, size_t, size_t, int,
- int, size_t, int *, uint16_t *);
+ int, size_t, int *, uint16_t *, int, off_t, int, off_t);
#define ELF_ALIGN(a) ((((a) + align - 1) / align) * align)
@@ -177,6 +177,11 @@ getu64(int swap, uint64_t value)
elf_getu32(swap, ph32.p_align) : 4) \
: (off_t) (ph64.p_align ? \
elf_getu64(swap, ph64.p_align) : 4)))
+#define xph_vaddr (size_t)((clazz == ELFCLASS32 \
+ ? (off_t) (ph32.p_vaddr ? \
+ elf_getu32(swap, ph32.p_vaddr) : 4) \
+ : (off_t) (ph64.p_vaddr ? \
+ elf_getu64(swap, ph64.p_vaddr) : 4)))
#define xph_filesz (size_t)((clazz == ELFCLASS32 \
? elf_getu32(swap, ph32.p_filesz) \
: elf_getu64(swap, ph64.p_filesz)))
@@ -187,8 +192,8 @@ getu64(int swap, uint64_t value)
? elf_getu32(swap, ph32.p_memsz) \
: elf_getu64(swap, ph64.p_memsz)))
#define xnh_sizeof (clazz == ELFCLASS32 \
- ? sizeof nh32 \
- : sizeof nh64)
+ ? sizeof(nh32) \
+ : sizeof(nh64))
#define xnh_type (clazz == ELFCLASS32 \
? elf_getu32(swap, nh32.n_type) \
: elf_getu32(swap, nh64.n_type))
@@ -213,6 +218,18 @@ getu64(int swap, uint64_t value)
#define xcap_val (clazz == ELFCLASS32 \
? elf_getu32(swap, cap32.c_un.c_val) \
: elf_getu64(swap, cap64.c_un.c_val))
+#define xauxv_addr (clazz == ELFCLASS32 \
+ ? (void *)&auxv32 \
+ : (void *)&auxv64)
+#define xauxv_sizeof (clazz == ELFCLASS32 \
+ ? sizeof(auxv32) \
+ : sizeof(auxv64))
+#define xauxv_type (clazz == ELFCLASS32 \
+ ? elf_getu32(swap, auxv32.a_type) \
+ : elf_getu64(swap, auxv64.a_type))
+#define xauxv_val (clazz == ELFCLASS32 \
+ ? elf_getu32(swap, auxv32.a_v) \
+ : elf_getu64(swap, auxv64.a_v))
#ifdef ELFCORE
/*
@@ -302,6 +319,7 @@ private const char os_style_names[][8] = {
#define FLAGS_DID_NETBSD_CMODEL 0x040
#define FLAGS_DID_NETBSD_UNKNOWN 0x080
#define FLAGS_IS_CORE 0x100
+#define FLAGS_DID_AUXV 0x200
private int
dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
@@ -312,6 +330,8 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
size_t offset, len;
unsigned char nbuf[BUFSIZ];
ssize_t bufsize;
+ off_t ph_off = off;
+ int ph_num = num;
if (size != xph_sizeof) {
if (file_printf(ms, ", corrupted program header size") == -1)
@@ -351,7 +371,8 @@ dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
if (offset >= (size_t)bufsize)
break;
offset = donote(ms, nbuf, offset, (size_t)bufsize,
- clazz, swap, 4, flags, notecount);
+ clazz, swap, 4, flags, notecount, fd, ph_off,
+ ph_num, fsize);
if (offset == 0)
break;
@@ -813,9 +834,157 @@ do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
return 0;
}
+private off_t
+get_offset_from_virtaddr(struct magic_set *ms, int swap, int clazz, int fd,
+ off_t off, int num, off_t fsize, uint64_t virtaddr)
+{
+ Elf32_Phdr ph32;
+ Elf64_Phdr ph64;
+
+ /*
+ * Loop through all the program headers and find the header with
+ * virtual address in which the "virtaddr" belongs to.
+ */
+ for ( ; num; num--) {
+ if (pread(fd, xph_addr, xph_sizeof, off) < (ssize_t)xph_sizeof) {
+ file_badread(ms);
+ return -1;
+ }
+ off += xph_sizeof;
+
+ if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
+ /* Perhaps warn here */
+ continue;
+ }
+
+ if (virtaddr >= xph_vaddr && virtaddr < xph_vaddr + xph_filesz)
+ return xph_offset + (virtaddr - xph_vaddr);
+ }
+ return 0;
+}
+
+private size_t
+get_string_on_virtaddr(struct magic_set *ms,
+ int swap, int clazz, int fd, off_t ph_off, int ph_num,
+ off_t fsize, uint64_t virtaddr, char *buf, ssize_t buflen)
+{
+ char *bptr;
+ off_t offset;
+
+ if (buflen == 0)
+ return 0;
+
+ offset = get_offset_from_virtaddr(ms, swap, clazz, fd, ph_off, ph_num,
+ fsize, virtaddr);
+ if ((buflen = pread(fd, buf, buflen, offset)) <= 0) {
+ file_badread(ms);
+ return 0;
+ }
+
+ buf[buflen - 1] = '\0';
+
+ /* 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++)
+ continue;
+ if (*bptr != '\0')
+ return 0;
+
+ return bptr - buf;
+}
+
+
+private int
+do_auxv_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
+ int swap, uint32_t namesz __attribute__((__unused__)),
+ uint32_t descsz __attribute__((__unused__)),
+ size_t noff __attribute__((__unused__)), size_t doff,
+ int *flags, size_t size __attribute__((__unused__)), int clazz,
+ int fd, off_t ph_off, int ph_num, off_t fsize)
+{
+#ifdef ELFCORE
+ Aux32Info auxv32;
+ Aux64Info auxv64;
+ size_t elsize = xauxv_sizeof;
+ const char *tag;
+ int is_string;
+ size_t nval;
+
+ if (type != NT_AUXV || (*flags & FLAGS_IS_CORE) == 0)
+ return 0;
+
+ *flags |= FLAGS_DID_AUXV;
+
+ nval = 0;
+ for (size_t off = 0; off + elsize <= descsz; off += elsize) {
+ (void)memcpy(xauxv_addr, &nbuf[doff + off], xauxv_sizeof);
+ /* Limit processing to 50 vector entries to prevent DoS */
+ if (nval++ >= 50) {
+ file_error(ms, 0, "Too many ELF Auxv elements");
+ return 1;
+ }
+
+ switch(xauxv_type) {
+ case AT_LINUX_EXECFN:
+ is_string = 1;
+ tag = "execfn";
+ break;
+ case AT_LINUX_PLATFORM:
+ is_string = 1;
+ tag = "platform";
+ break;
+ case AT_LINUX_UID:
+ is_string = 0;
+ tag = "real uid";
+ break;
+ case AT_LINUX_GID:
+ is_string = 0;
+ tag = "real gid";
+ break;
+ case AT_LINUX_EUID:
+ is_string = 0;
+ tag = "effective uid";
+ break;
+ case AT_LINUX_EGID:
+ is_string = 0;
+ tag = "effective gid";
+ break;
+ default:
+ is_string = 0;
+ tag = NULL;
+ break;
+ }
+
+ if (tag == NULL)
+ continue;
+
+ if (is_string) {
+ char buf[256];
+ ssize_t buflen;
+ buflen = get_string_on_virtaddr(ms, swap, clazz, fd,
+ ph_off, ph_num, fsize, xauxv_val, buf, sizeof(buf));
+
+ if (buflen == 0)
+ continue;
+
+ if (file_printf(ms, ", %s: '%s'", tag, buf) == -1)
+ return 0;
+ } else {
+ if (file_printf(ms, ", %s: %d", tag, (int) xauxv_val)
+ == -1)
+ return 0;
+ }
+ }
+ return 1;
+#else
+ return 0;
+#endif
+}
+
private size_t
donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
- int clazz, int swap, size_t align, int *flags, uint16_t *notecount)
+ int clazz, int swap, size_t align, int *flags, uint16_t *notecount,
+ int fd, off_t ph_off, int ph_num, off_t fsize)
{
Elf32_Nhdr nh32;
Elf64_Nhdr nh64;
@@ -839,6 +1008,7 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
namesz = xnh_namesz;
descsz = xnh_descsz;
+
if ((namesz == 0) && (descsz == 0)) {
/*
* We're out of note headers.
@@ -876,28 +1046,36 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
return (offset >= size) ? offset : size;
}
+
if ((*flags & FLAGS_DID_OS_NOTE) == 0) {
if (do_os_note(ms, nbuf, xnh_type, swap,
namesz, descsz, noff, doff, flags))
- return size;
+ return offset;
}
if ((*flags & FLAGS_DID_BUILD_ID) == 0) {
if (do_bid_note(ms, nbuf, xnh_type, swap,
namesz, descsz, noff, doff, flags))
- return size;
+ return offset;
}
if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) {
if (do_pax_note(ms, nbuf, xnh_type, swap,
namesz, descsz, noff, doff, flags))
- return size;
+ return offset;
}
if ((*flags & FLAGS_DID_CORE) == 0) {
if (do_core_note(ms, nbuf, xnh_type, swap,
namesz, descsz, noff, doff, flags, size, clazz))
- return size;
+ return offset;
+ }
+
+ if ((*flags & FLAGS_DID_AUXV) == 0) {
+ if (do_auxv_note(ms, nbuf, xnh_type, swap,
+ namesz, descsz, noff, doff, flags, size, clazz,
+ fd, ph_off, ph_num, fsize))
+ return offset;
}
if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0) {
@@ -905,32 +1083,32 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
descsz = 100;
switch (xnh_type) {
case NT_NETBSD_VERSION:
- return size;
+ return offset;
case NT_NETBSD_MARCH:
if (*flags & FLAGS_DID_NETBSD_MARCH)
- return size;
+ return offset;
*flags |= FLAGS_DID_NETBSD_MARCH;
if (file_printf(ms, ", compiled for: %.*s",
(int)descsz, (const char *)&nbuf[doff]) == -1)
- return size;
+ return offset;
break;
case NT_NETBSD_CMODEL:
if (*flags & FLAGS_DID_NETBSD_CMODEL)
- return size;
+ return offset;
*flags |= FLAGS_DID_NETBSD_CMODEL;
if (file_printf(ms, ", compiler model: %.*s",
(int)descsz, (const char *)&nbuf[doff]) == -1)
- return size;
+ return offset;
break;
default:
if (*flags & FLAGS_DID_NETBSD_UNKNOWN)
- return size;
+ return offset;
*flags |= FLAGS_DID_NETBSD_UNKNOWN;
if (file_printf(ms, ", note=%u", xnh_type) == -1)
- return size;
+ return offset;
break;
}
- return size;
+ return offset;
}
return offset;
@@ -1080,7 +1258,8 @@ doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
if (noff >= (off_t)xsh_size)
break;
noff = donote(ms, nbuf, (size_t)noff,
- xsh_size, clazz, swap, 4, flags, notecount);
+ xsh_size, clazz, swap, 4, flags, notecount,
+ fd, 0, 0, 0);
if (noff == 0)
break;
}
@@ -1329,7 +1508,7 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
break;
offset = donote(ms, nbuf, offset,
(size_t)bufsize, clazz, swap, align,
- flags, notecount);
+ flags, notecount, fd, 0, 0, 0);
if (offset == 0)
break;
}
OpenPOWER on IntegriCloud