aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2016-11-23 18:35:58 -0500
committerMike Frysinger <vapier@gentoo.org>2016-11-23 18:35:58 -0500
commit3c5938e7d4064541eab1d5e02de61237e05a1699 (patch)
treec9fd7ccb738d02689d532474028e6c1a831bfdce
parentdumpelf: clean up types all over the place (diff)
downloadpax-utils-3c5938e7d4064541eab1d5e02de61237e05a1699.tar.gz
pax-utils-3c5938e7d4064541eab1d5e02de61237e05a1699.tar.bz2
pax-utils-3c5938e7d4064541eab1d5e02de61237e05a1699.zip
dumpelf: add support for dumping notes
-rw-r--r--dumpelf.c85
-rw-r--r--paxelf.c68
-rw-r--r--paxelf.h1
-rw-r--r--paxinc.h6
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 = "<corrupt>";
- else if (memchr(name, 0, elf->len - (name - elf->data)) == NULL)
- name = "<corrupt>";
+ if ((void *)section_name >= elf->data_end)
+ section_name = "<corrupt>";
+ else if (memchr(section_name, 0, elf->len - (section_name - elf->data)) == NULL)
+ section_name = "<corrupt>";
#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);