From: Christos Zoulas Date: Thu, 5 Nov 2015 16:58:31 +0000 (+0000) Subject: add AUXV section processing (Jan Kaluza) X-Git-Tag: FILE5_26~102 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b13be14bb0287ade1b244ff4a1b5dffa3a249b3e;p=file add AUXV section processing (Jan Kaluza) --- diff --git a/src/readelf.c b/src/readelf.c index d8ef8b52..bef14882 100644 --- a/src/readelf.c +++ b/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.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; } diff --git a/src/readelf.h b/src/readelf.h index 732b20c8..959f5ce1 100644 --- a/src/readelf.h +++ b/src/readelf.h @@ -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;