]> granicus.if.org Git - file/commitdiff
add AUXV section processing (Jan Kaluza)
authorChristos Zoulas <christos@zoulas.com>
Thu, 5 Nov 2015 16:58:31 +0000 (16:58 +0000)
committerChristos Zoulas <christos@zoulas.com>
Thu, 5 Nov 2015 16:58:31 +0000 (16:58 +0000)
src/readelf.c
src/readelf.h

index d8ef8b526ae1cb6b902574099f0a557c0f4b85eb..bef1488234c7120fa1505305a8f7d025e18faf01 100644 (file)
@@ -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.123 2015/10/09 14:38:47 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,175 @@ 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;
+       size_t prev_vaddr = 0;
+       size_t prev_off = 0;
+
+       /*
+        * 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 >= prev_vaddr && virtaddr < xph_vaddr) {
+                       /*
+                        * The previous program header was the right one, so
+                        * compute the file offset and return.
+                        */
+                       return prev_off + (virtaddr - prev_vaddr);
+               }
+
+               prev_vaddr = xph_vaddr;
+               prev_off = xph_offset;
+
+       }
+       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 (pread(fd, buf, buflen, offset) != buflen) {
+               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;
+       uint32_t val[30];
+       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);
+               for (size_t i = 0; i < nval; i++)
+                       if (val[i] == (uint32_t)xauxv_type) {
+                               file_error(ms, 0, "Repeated ELF Auxv type %u",
+                                   val[i]);
+                               return 1;
+                       }
+               if (nval >= __arraycount(val)) {
+                       file_error(ms, 0, "Too many ELF Auxv elements");
+                       return 1;
+               }
+               val[nval++] = (uint32_t)xauxv_type;
+
+               switch(xauxv_type) {
+               case AT_LINUX_EXECFN:
+                       is_string = 1;
+                       tag = "from";
+                       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;
@@ -876,6 +1063,7 @@ 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))
@@ -900,6 +1088,13 @@ donote(struct magic_set *ms, void *vbuf, size_t offset, size_t 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) {
                if (descsz > 100)
                        descsz = 100;
@@ -1080,7 +1275,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 +1525,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;
                        }
index 732b20c88e728761ba19ee2d8c75d619420c4fc1..959f5ce16a1e29595a706719dc4e06a7e9ea2d79 100644 (file)
@@ -53,6 +53,42 @@ typedef uint8_t              Elf64_Char;
 
 #define        EI_NIDENT       16
 
+typedef struct {
+       Elf32_Word      a_type;         /* 32-bit id */
+       Elf32_Word      a_v;            /* 32-bit id */
+} Aux32Info;
+
+typedef struct {
+       Elf64_Word      a_type;         /* 32-bit id */
+       Elf64_Xword     a_v;            /* 64-bit id */
+} Aux64Info;
+
+#define AT_NULL   0     /* end of vector */
+#define AT_IGNORE 1     /* entry should be ignored */
+#define AT_EXECFD 2     /* file descriptor of program */
+#define AT_PHDR   3     /* program headers for program */
+#define AT_PHENT  4     /* size of program header entry */
+#define AT_PHNUM  5     /* number of program headers */
+#define AT_PAGESZ 6     /* system page size */
+#define AT_BASE   7     /* base address of interpreter */
+#define AT_FLAGS  8     /* flags */
+#define AT_ENTRY  9     /* entry point of program */
+#define AT_LINUX_NOTELF 10    /* program is not ELF */
+#define AT_LINUX_UID    11    /* real uid */
+#define AT_LINUX_EUID   12    /* effective uid */
+#define AT_LINUX_GID    13    /* real gid */
+#define AT_LINUX_EGID   14    /* effective gid */
+#define AT_LINUX_PLATFORM 15  /* string identifying CPU for optimizations */
+#define AT_LINUX_HWCAP  16    /* arch dependent hints at CPU capabilities */
+#define AT_LINUX_CLKTCK 17    /* frequency at which times() increments */
+/* AT_* values 18 through 22 are reserved */
+#define AT_LINUX_SECURE 23   /* secure mode boolean */
+#define AT_LINUX_BASE_PLATFORM 24     /* string identifying real platform, may
+                                 * differ from AT_PLATFORM. */
+#define AT_LINUX_RANDOM 25    /* address of 16 random bytes */
+#define AT_LINUX_HWCAP2 26    /* extension of AT_HWCAP */
+#define AT_LINUX_EXECFN 31   /* filename of program */
+
 typedef struct {
     Elf32_Char e_ident[EI_NIDENT];
     Elf32_Half e_type;