From 3c5938e7d4064541eab1d5e02de61237e05a1699 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 23 Nov 2016 18:35:58 -0500 Subject: dumpelf: add support for dumping notes --- dumpelf.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- paxelf.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++ paxelf.h | 1 + paxinc.h | 6 +++++ 4 files changed, 151 insertions(+), 9 deletions(-) diff --git a/dumpelf.c b/dumpelf.c index d95a161..066a239 100644 --- a/dumpelf.c +++ b/dumpelf.c @@ -14,7 +14,7 @@ const char argv0[] = "dumpelf"; static void dumpelf(const char *filename, size_t file_cnt); static void dump_ehdr(elfobj *elf, const void *ehdr); static void dump_phdr(elfobj *elf, const void *phdr, size_t phdr_cnt); -static void dump_shdr(elfobj *elf, const void *shdr, size_t shdr_cnt, const char *name); +static void dump_shdr(elfobj *elf, const void *shdr, size_t shdr_cnt, const char *section_name); static void dump_dyn(elfobj *elf, const void *dyn, size_t dyn_cnt); #if 0 static void dump_sym(elfobj *elf, const void *sym); @@ -203,6 +203,56 @@ static void dump_ehdr(elfobj *elf, const void *ehdr_void) DUMP_EHDR(64) } +static void dump_notes(elfobj *elf, size_t B, const void *memory, const void *memory_end) +{ + /* While normally we'd worry about Elf32_Nhdr vs Elf64_Nhdr, in the ELF + * world, the two structs are exactly the same. So avoid ugly CPP. + */ + size_t i; + const void *ndata = memory; + const char *name; + const unsigned char *desc; + uint32_t namesz, descsz; + const Elf32_Nhdr *note; + /* The first few bytes are the same between 32 & 64 bit ELFs. */ + uint16_t e_type = EGET(((const Elf32_Ehdr *)elf->ehdr)->e_type); + + if (memory_end > elf->data_end) { + printf("\n\t/%c note section is corrupt */\n", '*'); + return; + } + + printf("\n\t/%c note section dump:\n", '*'); + for (i = 0; ndata < memory_end; ++i) { + note = ndata; + namesz = EGET(note->n_namesz); + descsz = EGET(note->n_descsz); + name = namesz ? ndata + sizeof(*note) : ""; + desc = descsz ? ndata + sizeof(*note) + ALIGN_UP(namesz, 4) : ""; + ndata += sizeof(*note) + ALIGN_UP(namesz, 4) + ALIGN_UP(descsz, 4); + + if (ndata > memory_end) { + printf("\tNote is corrupt\n"); + break; + } + + printf("\t * Elf%zu_Nhdr note%zu = {\n", B, i); + printf("\t * \t.n_namesz = %u, (bytes) [%s]\n", namesz, name); + printf("\t * \t.n_descsz = %u, (bytes)", descsz); + if (descsz) { + printf(" [ "); + for (i = 0; i < descsz; ++i) + printf("%.2X ", desc[i]); + printf("]"); + } + printf("\n"); + printf("\t * \t.n_type = %"PRIX64", [%s]\n", + EGET(note->n_type), get_elfnttype(e_type, name, EGET(note->n_type))); + printf("\t * };\n"); + } + printf("\t */\n"); +} + static const char *dump_p_flags(uint32_t type, uint32_t flags) { static char buf[1024]; @@ -240,6 +290,8 @@ static void dump_phdr(elfobj *elf, const void *phdr_void, size_t phdr_cnt) #define DUMP_PHDR(B) \ if (elf->elf_class == ELFCLASS ## B) { \ const Elf ## B ## _Phdr *phdr = PHDR ## B (phdr_void); \ + Elf ## B ## _Off offset = EGET(phdr->p_offset); \ + void *vdata = elf->vdata + offset; \ uint32_t p_type = EGET(phdr->p_type); \ switch (p_type) { \ case PT_DYNAMIC: phdr_dynamic_void = phdr_void; break; \ @@ -254,21 +306,33 @@ static void dump_phdr(elfobj *elf, const void *phdr_void, size_t phdr_cnt) printf("\t.p_memsz = %-10"PRIu64" , /* (bytes in mem at runtime) */\n", EGET(phdr->p_memsz)); \ printf("\t.p_flags = 0x%-8X , /* %s */\n", (uint32_t)EGET(phdr->p_flags), dump_p_flags(p_type, EGET(phdr->p_flags))); \ printf("\t.p_align = %-10"PRIu64" , /* (min mem alignment in bytes) */\n", EGET(phdr->p_align)); \ + \ + if ((off_t)EGET(phdr->p_offset) > elf->len) { \ + printf("\t/* Warning: Program segment is corrupt. */\n"); \ + goto done##B; \ + } \ + \ + switch (p_type) { \ + case PT_NOTE: \ + dump_notes(elf, B, vdata, vdata + EGET(phdr->p_filesz)); \ + break; \ + } \ + done##B: \ printf("},\n"); \ } DUMP_PHDR(32) DUMP_PHDR(64) } -static void dump_shdr(elfobj *elf, const void *shdr_void, size_t shdr_cnt, const char *name) +static void dump_shdr(elfobj *elf, const void *shdr_void, size_t shdr_cnt, const char *section_name) { size_t i; /* Make sure the string is valid. */ - if ((void *)name >= elf->data_end) - name = ""; - else if (memchr(name, 0, elf->len - (name - elf->data)) == NULL) - name = ""; + if ((void *)section_name >= elf->data_end) + section_name = ""; + else if (memchr(section_name, 0, elf->len - (section_name - elf->data)) == NULL) + section_name = ""; #define DUMP_SHDR(B) \ if (elf->elf_class == ELFCLASS ## B) { \ @@ -278,7 +342,7 @@ static void dump_shdr(elfobj *elf, const void *shdr_void, size_t shdr_cnt, const uint ## B ## _t size = EGET(shdr->sh_size); \ \ printf("/* Section Header #%zu '%s' 0x%tX */\n{\n", \ - shdr_cnt, name, (uintptr_t)shdr_void - elf->udata); \ + shdr_cnt, section_name, (uintptr_t)shdr_void - elf->udata); \ printf("\t.sh_name = %-10u ,\n", (uint32_t)EGET(shdr->sh_name)); \ printf("\t.sh_type = %-10u , /* [%s] */\n", (uint32_t)EGET(shdr->sh_type), get_elfshttype(type)); \ printf("\t.sh_flags = %-10"PRIu64" ,\n", EGET(shdr->sh_flags)); \ @@ -301,11 +365,11 @@ static void dump_shdr(elfobj *elf, const void *shdr_void, size_t shdr_cnt, const unsigned char *data = vdata; \ switch (type) { \ case SHT_PROGBITS: { \ - if (strcmp(name, ".interp") == 0) { \ + if (strcmp(section_name, ".interp") == 0) { \ printf("\n\t/* ELF interpreter: %s */\n", data); \ break; \ } \ - if (strcmp(name, ".comment") != 0) \ + if (strcmp(section_name, ".comment") != 0) \ break; \ break; \ } \ @@ -345,6 +409,9 @@ static void dump_shdr(elfobj *elf, const void *shdr_void, size_t shdr_cnt, const printf("\t */\n"); \ break; \ } \ + case SHT_NOTE: \ + dump_notes(elf, B, vdata, vdata + EGET(shdr->sh_size)); \ + break; \ default: { \ if (be_verbose <= 1) \ break; \ diff --git a/paxelf.c b/paxelf.c index 5b6fe24..c614e2d 100644 --- a/paxelf.c +++ b/paxelf.c @@ -480,6 +480,74 @@ const char *get_elfshntype(int type) return find_pairtype(elf_shntypes, type); } +/* translate elf NT_ defines */ +static pairtype elf_nttypes_GNU[] = { + QUERY(NT_GNU_ABI_TAG), + QUERY(NT_GNU_HWCAP), + QUERY(NT_GNU_BUILD_ID), + QUERY(NT_GNU_GOLD_VERSION), + { 0, 0 } +}; +static pairtype elf_nttypes_core[] = { + QUERY(NT_PRSTATUS), + QUERY(NT_FPREGSET), + QUERY(NT_PRPSINFO), + QUERY(NT_PRXREG), + QUERY(NT_TASKSTRUCT), + QUERY(NT_PLATFORM), + QUERY(NT_AUXV), + QUERY(NT_GWINDOWS), + QUERY(NT_ASRS), + QUERY(NT_PSTATUS), + QUERY(NT_PSINFO), + QUERY(NT_PRCRED), + QUERY(NT_UTSNAME), + QUERY(NT_LWPSTATUS), + QUERY(NT_LWPSINFO), + QUERY(NT_PRFPXREG), + QUERY(NT_SIGINFO), + QUERY(NT_FILE), + QUERY(NT_PRXFPREG), + QUERY(NT_PPC_VMX), + QUERY(NT_PPC_SPE), + QUERY(NT_PPC_VSX), + QUERY(NT_386_TLS), + QUERY(NT_386_IOPERM), + QUERY(NT_X86_XSTATE), + QUERY(NT_S390_HIGH_GPRS), + QUERY(NT_S390_TIMER), + QUERY(NT_S390_TODCMP), + QUERY(NT_S390_TODPREG), + QUERY(NT_S390_CTRS), + QUERY(NT_S390_PREFIX), + QUERY(NT_S390_LAST_BREAK), + QUERY(NT_S390_SYSTEM_CALL), + QUERY(NT_S390_TDB), + QUERY(NT_ARM_VFP), + QUERY(NT_ARM_TLS), + QUERY(NT_ARM_HW_BREAK), + QUERY(NT_ARM_HW_WATCH), + { 0, 0 } +}; +static pairtype elf_nttypes_fallback[] = { + QUERY(NT_VERSION), + { 0, 0 } +}; +const char *get_elfnttype(uint16_t e_type, const char *name, int type) +{ + if (name) { + if (!strcmp(name, "GNU")) + return find_pairtype(elf_nttypes_GNU, type); + + /* Unknown extension, so just fallback to common ones. */ + } + + if (e_type == ET_CORE) + return find_pairtype(elf_nttypes_core, type); + else + return find_pairtype(elf_nttypes_fallback, type); +} + /* Read an ELF into memory */ #define IS_ELF_BUFFER(buff) \ (buff[EI_MAG0] == ELFMAG0 && \ diff --git a/paxelf.h b/paxelf.h index aa34ca6..56fa9f3 100644 --- a/paxelf.h +++ b/paxelf.h @@ -69,6 +69,7 @@ extern const char *get_elfshttype(int type); extern const char *get_elfstbtype(int type); extern const char *get_elfstvtype(int type); extern const char *get_elfstttype(int type); +extern const char *get_elfnttype(uint16_t e_type, const char *name, int type); extern void *elf_findsecbyname(elfobj *elf, const char *name); extern unsigned int get_etype(elfobj *elf); extern unsigned int get_emtype(elfobj *elf); diff --git a/paxinc.h b/paxinc.h index 82f7d1f..6d433b9 100644 --- a/paxinc.h +++ b/paxinc.h @@ -102,6 +102,12 @@ const char *strfileperms(const char *fname); } else { errf("ESET failed :( (size(Y) == %i)", (int)sizeof(Y)); } \ } while (0) +/* alignment helpers */ +#define ALIGN_DOWN(base, size) ((base) & -((__typeof__(base)) (size))) +#define ALIGN_UP(base, size) ALIGN_DOWN((base) + (size) - 1, (size)) +#define PTR_ALIGN_DOWN(base, size) ((__typeof__(base))ALIGN_DOWN((uintptr_t)(base), (size))) +#define PTR_ALIGN_UP(base, size) ((__typeof__(base))ALIGN_UP ((uintptr_t)(base), (size))) + /* helper functions for showing errors */ extern const char *NORM, *RED, *YELLOW; void color_init(bool disable); -- cgit v1.2.3-65-gdbad