From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id EB6FA1395E8 for ; Tue, 24 Jan 2017 06:50:12 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 3C6CFE0DD5; Tue, 24 Jan 2017 06:50:12 +0000 (UTC) Received: from smtp.gentoo.org (woodpecker.gentoo.org [IPv6:2001:470:ea4a:1:5054:ff:fec7:86e4]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 0DE00E0DD5 for ; Tue, 24 Jan 2017 06:50:11 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 4BD013416B9 for ; Tue, 24 Jan 2017 06:50:10 +0000 (UTC) Received: from localhost.localdomain (localhost [127.0.0.1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id B89742D57 for ; Tue, 24 Jan 2017 06:50:08 +0000 (UTC) From: "Mike Frysinger" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Mike Frysinger" Message-ID: <1485224720.95e5489534ac9e9324c5096286899b688e19ae00.vapier@gentoo> Subject: [gentoo-commits] proj/pax-utils:master commit in: / X-VCS-Repository: proj/pax-utils X-VCS-Files: scanelf.c X-VCS-Directories: / X-VCS-Committer: vapier X-VCS-Committer-Name: Mike Frysinger X-VCS-Revision: 95e5489534ac9e9324c5096286899b688e19ae00 X-VCS-Branch: master Date: Tue, 24 Jan 2017 06:50:08 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Archives-Salt: 1bbb3a8c-767d-4064-b481-0eaf2ff95468 X-Archives-Hash: 5a9325e112db260fdb5c471f7fdad052 commit: 95e5489534ac9e9324c5096286899b688e19ae00 Author: Mike Frysinger gentoo org> AuthorDate: Tue Jan 24 02:25:20 2017 +0000 Commit: Mike Frysinger gentoo org> CommitDate: Tue Jan 24 02:25:20 2017 +0000 URL: https://gitweb.gentoo.org/proj/pax-utils.git/commit/?id=95e54895 scanelf: add helper for walking dynamic tags We have many loops that operate on dynamic tags which all crash when given an ELF with a corrupt dynamic table. Add a helper to walk the table so we can centralize bounds checking in one place. Reported-by: Agostino Sarubbo gentoo.org> scanelf.c | 131 +++++++++++++++++--------------------------------------------- 1 file changed, 35 insertions(+), 96 deletions(-) diff --git a/scanelf.c b/scanelf.c index 52c436a..ceec26d 100644 --- a/scanelf.c +++ b/scanelf.c @@ -189,6 +189,14 @@ static void *scanelf_file_get_pt_dynamic(elfobj *elf) return NULL; } +#define scanelf_dt_for_each(B, elf, dyn) \ + { \ + Elf##B##_Phdr *_phdr = scanelf_file_get_pt_dynamic(elf); \ + dyn = (_phdr == NULL) ? elf->data_end : DYN##B(elf->vdata + EGET(_phdr->p_offset)); \ + } \ + --dyn; \ + while ((void *)++dyn < elf->data_end - sizeof(*dyn) && EGET(dyn->d_tag) != DT_NULL) + /* sub-funcs for scanelf_fileat() */ static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **str) { @@ -258,10 +266,9 @@ static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **str) size_t i; \ static Elf ## B ## _Shdr sym_shdr, str_shdr; \ Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ - Elf ## B ## _Phdr *phdr; \ + Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ Elf ## B ## _Addr vsym, vstr, vhash, vgnu_hash; \ Elf ## B ## _Dyn *dyn; \ - Elf ## B ## _Off doffset; \ \ /* lookup symbols used at runtime with DT_SYMTAB / DT_STRTAB */ \ vsym = vstr = vhash = vgnu_hash = 0; \ @@ -269,13 +276,7 @@ static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **str) memset(&str_shdr, 0, sizeof(str_shdr)); \ \ /* Find the dynamic headers */ \ - phdr = scanelf_file_get_pt_dynamic(elf); \ - if (phdr == NULL) \ - break; \ - doffset = EGET(phdr->p_offset); \ - \ - dyn = DYN ## B (elf->vdata + doffset); \ - while (EGET(dyn->d_tag) != DT_NULL) { \ + scanelf_dt_for_each(B, elf, dyn) { \ switch (EGET(dyn->d_tag)) { \ case DT_SYMTAB: vsym = EGET(dyn->d_un.d_val); break; \ case DT_SYMENT: sym_shdr.sh_entsize = dyn->d_un.d_val; break; \ @@ -284,13 +285,11 @@ static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **str) case DT_HASH: vhash = EGET(dyn->d_un.d_val); break; \ /*case DT_GNU_HASH: vgnu_hash = EGET(dyn->d_un.d_val); break;*/ \ } \ - ++dyn; \ } \ if (!vsym || !vstr || !(vhash || vgnu_hash)) \ return; \ \ /* calc offset into the ELF by finding the load addr of the syms */ \ - phdr = PHDR ## B (elf->phdr); \ for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ Elf ## B ## _Addr vaddr = EGET(phdr[i].p_vaddr); \ Elf ## B ## _Addr filesz = EGET(phdr[i].p_filesz); \ @@ -539,23 +538,13 @@ static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel) #define SHOW_TEXTREL(B) \ Elf ## B ## _Dyn *dyn; \ - Elf ## B ## _Phdr *phdr; \ - Elf ## B ## _Off offset; \ - \ - /* Find the dynamic headers */ \ - phdr = scanelf_file_get_pt_dynamic(elf); \ - if (phdr == NULL) \ - break; \ - offset = EGET(phdr->p_offset); \ \ - dyn = DYN ## B (elf->vdata + offset); \ - while (EGET(dyn->d_tag) != DT_NULL) { \ + scanelf_dt_for_each(B, elf, dyn) { \ if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ *found_textrel = 1; \ /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \ return (be_wewy_wewy_quiet ? NULL : ret); \ } \ - ++dyn; \ } if (elf->phdr) SCANELF_ELF_SIZED(SHOW_TEXTREL); @@ -588,7 +577,6 @@ static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *foun size_t i; \ Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ Elf ## B ## _Phdr *phdr; \ - Elf ## B ## _Off offset; \ Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ Elf ## B ## _Rel *rel; \ @@ -596,16 +584,9 @@ static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *foun Elf ## B ## _Dyn *dyn, *drel, *drelsz, *drelent, *dpltrel; \ uint32_t pltrel; \ \ - /* Find the dynamic headers */ \ - phdr = scanelf_file_get_pt_dynamic(elf); \ - if (phdr == NULL) \ - break; \ - offset = EGET(phdr->p_offset); \ - \ /* Walk all the dynamic tags to find relocation info */ \ - dyn = DYN ## B (elf->vdata + offset); \ drel = drelsz = drelent = dpltrel = NULL; \ - while (EGET(dyn->d_tag) != DT_NULL) { \ + scanelf_dt_for_each(B, elf, dyn) { \ switch (EGET(dyn->d_tag)) { \ case DT_REL: \ case DT_RELA: \ @@ -623,7 +604,6 @@ static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *foun dpltrel = dyn; \ break; \ } \ - ++dyn; \ } \ if (!drel || !drelsz || !drelent || !dpltrel) { \ warnf("ELF is missing relocation information"); \ @@ -796,26 +776,18 @@ static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_ #define SHOW_RPATH(B) \ Elf ## B ## _Dyn *dyn; \ - Elf ## B ## _Phdr *phdr; \ Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ Elf ## B ## _Off offset; \ Elf ## B ## _Xword word; \ \ - /* Find the dynamic headers */ \ - phdr = scanelf_file_get_pt_dynamic(elf); \ - if (phdr == NULL) \ - break; \ - offset = EGET(phdr->p_offset); \ - \ /* Just scan dynamic RPATH/RUNPATH headers */ \ - dyn = DYN ## B (elf->vdata + offset); \ - while ((word=EGET(dyn->d_tag)) != DT_NULL) { \ + scanelf_dt_for_each(B, elf, dyn) { \ + word = EGET(dyn->d_tag); \ if (word == DT_RPATH) { \ r = &rpath; \ } else if (word == DT_RUNPATH) { \ r = &runpath; \ } else { \ - ++dyn; \ continue; \ } \ /* Verify the memory is somewhat sane */ \ @@ -900,7 +872,6 @@ static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_ *found_rpath = 1; \ } \ } \ - ++dyn; \ } if (elf->phdr && strtbl_void) SCANELF_ELF_SIZED(SHOW_RPATH); @@ -956,26 +927,15 @@ static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char #define SHOW_NEEDED(B) \ Elf ## B ## _Dyn *dyn; \ - Elf ## B ## _Phdr *phdr; \ Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ - Elf ## B ## _Off offset; \ size_t matched = 0; \ \ - /* Find the dynamic headers */ \ - phdr = scanelf_file_get_pt_dynamic(elf); \ - if (phdr == NULL) \ - break; \ - offset = EGET(phdr->p_offset); \ - \ /* Walk all the dynamic tags to find NEEDED entries */ \ - dyn = DYN ## B (elf->vdata + offset); \ - while (EGET(dyn->d_tag) != DT_NULL) { \ + scanelf_dt_for_each(B, elf, dyn) { \ if (EGET(dyn->d_tag) == DT_NEEDED) { \ - offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ - if (offset >= (Elf ## B ## _Off)elf->len) { \ - ++dyn; \ + Elf ## B ## _Off offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ + if (offset >= (Elf ## B ## _Off)elf->len) \ continue; \ - } \ needed = elf->data + offset; \ if (op == 0) { \ /* -n -> print all entries */ \ @@ -1010,7 +970,6 @@ static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char } \ } \ } \ - ++dyn; \ } if (elf->phdr && strtbl_void) { SCANELF_ELF_SIZED(SHOW_NEEDED); @@ -1066,7 +1025,6 @@ static char *scanelf_file_interp(elfobj *elf, char *found_interp) } static const char *scanelf_file_bind(elfobj *elf, char *found_bind) { - unsigned long i; struct stat s; bool dynamic = false; @@ -1075,24 +1033,15 @@ static const char *scanelf_file_bind(elfobj *elf, char *found_bind) #define SHOW_BIND(B) \ Elf ## B ## _Dyn *dyn; \ - Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ - Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ - Elf ## B ## _Off offset; \ - for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ - if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \ + \ + scanelf_dt_for_each(B, elf, dyn) { \ dynamic = true; \ - offset = EGET(phdr[i].p_offset); \ - if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ - dyn = DYN ## B (elf->vdata + offset); \ - while (EGET(dyn->d_tag) != DT_NULL) { \ - if (EGET(dyn->d_tag) == DT_BIND_NOW || \ - (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \ - { \ - if (be_quiet) return NULL; \ - *found_bind = 1; \ - return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \ - } \ - ++dyn; \ + if (EGET(dyn->d_tag) == DT_BIND_NOW || \ + (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) { \ + if (be_quiet) \ + return NULL; \ + *found_bind = 1; \ + return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \ } \ } SCANELF_ELF_SIZED(SHOW_BIND); @@ -1109,7 +1058,6 @@ static const char *scanelf_file_bind(elfobj *elf, char *found_bind) } static char *scanelf_file_soname(elfobj *elf, char *found_soname) { - unsigned long i; char *soname; void *strtbl_void; @@ -1120,29 +1068,20 @@ static char *scanelf_file_soname(elfobj *elf, char *found_soname) #define SHOW_SONAME(B) \ Elf ## B ## _Dyn *dyn; \ Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ - Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ - Elf ## B ## _Off offset; \ + \ /* only look for soname in shared objects */ \ if (EGET(ehdr->e_type) != ET_DYN) \ return NULL; \ - for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ - if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \ - offset = EGET(phdr[i].p_offset); \ - if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ - dyn = DYN ## B (elf->vdata + offset); \ - while (EGET(dyn->d_tag) != DT_NULL) { \ - if (EGET(dyn->d_tag) == DT_SONAME) { \ - offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ - if (offset >= (Elf ## B ## _Off)elf->len) { \ - ++dyn; \ - continue; \ - } \ - soname = elf->data + offset; \ - *found_soname = 1; \ - return (be_wewy_wewy_quiet ? NULL : soname); \ - } \ - ++dyn; \ + \ + scanelf_dt_for_each(B, elf, dyn) { \ + if (EGET(dyn->d_tag) == DT_SONAME) { \ + Elf ## B ## _Off offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ + if (offset >= (Elf ## B ## _Off)elf->len) \ + continue; \ + soname = elf->data + offset; \ + *found_soname = 1; \ + return (be_wewy_wewy_quiet ? NULL : soname); \ } \ } if (elf->phdr && strtbl_void)