aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2016-11-25 00:40:39 -0500
committerMike Frysinger <vapier@gentoo.org>2016-11-25 00:40:39 -0500
commitba31869401a628a7f0167ea51ade7254c58714d8 (patch)
treee14bf523d648d66567089a7e03557d9c180acd50
parentscanelf: standardize macro indentation levels (diff)
downloadpax-utils-ba31869401a628a7f0167ea51ade7254c58714d8.tar.gz
pax-utils-ba31869401a628a7f0167ea51ade7254c58714d8.tar.bz2
pax-utils-ba31869401a628a7f0167ea51ade7254c58714d8.zip
scanelf: add helper funcs for looking up program headers
-rw-r--r--scanelf.c404
1 files changed, 222 insertions, 182 deletions
diff --git a/scanelf.c b/scanelf.c
index 5632527..2a7c0ce 100644
--- a/scanelf.c
+++ b/scanelf.c
@@ -140,6 +140,55 @@ static const char *which(const char *fname, const char *envvar)
return NULL;
}
+/*
+ * Return the index into the program header table for the |p_type| segment.
+ * Useful only when there is one instance of a particular type.
+ */
+static ssize_t scanelf_file_find_phdr(elfobj *elf, uint32_t p_type)
+{
+ ssize_t ret = -1;
+
+#define FIND_PT_TYPE(B) \
+ size_t i; \
+ Elf##B##_Ehdr *ehdr = EHDR ## B (elf->ehdr); \
+ Elf##B##_Phdr *phdr = PHDR ## B (elf->phdr); \
+ \
+ for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
+ if (EGET(phdr[i].p_type) != p_type) \
+ continue; \
+ \
+ if (ret == -1) \
+ ret = i; \
+ else \
+ warnf("ELF has more than one %s segment !?", get_elfptype(p_type)); \
+ }
+ if (elf->phdr)
+ SCANELF_ELF_SIZED(FIND_PT_TYPE);
+
+ return ret;
+}
+
+static void *scanelf_file_get_pt_dynamic(elfobj *elf)
+{
+ ssize_t i = scanelf_file_find_phdr(elf, PT_DYNAMIC);
+ if (i == -1)
+ return NULL;
+
+#define CHECK_PT_DYNAMIC(B) \
+ Elf##B##_Phdr *phdr = &PHDR##B(elf->phdr)[i]; \
+ Elf##B##_Off offset; \
+ \
+ if (EGET(phdr->p_filesz) == 0) \
+ break; \
+ offset = EGET(phdr->p_offset); \
+ if (offset >= elf->len - sizeof(Elf##B##_Dyn)) \
+ break; \
+ return phdr;
+ SCANELF_ELF_SIZED(CHECK_PT_DYNAMIC);
+
+ return NULL;
+}
+
/* sub-funcs for scanelf_fileat() */
static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **str)
{
@@ -209,7 +258,7 @@ 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 = PHDR ## B (elf->phdr); \
+ Elf ## B ## _Phdr *phdr; \
Elf ## B ## _Addr vsym, vstr, vhash, vgnu_hash; \
Elf ## B ## _Dyn *dyn; \
Elf ## B ## _Off offset; \
@@ -218,28 +267,24 @@ static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **str)
vsym = vstr = vhash = vgnu_hash = 0; \
memset(&sym_shdr, 0, sizeof(sym_shdr)); \
memset(&str_shdr, 0, sizeof(str_shdr)); \
- for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
- if (EGET(phdr[i].p_type) != PT_DYNAMIC) \
- 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) { \
- 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; \
- case DT_STRTAB: vstr = EGET(dyn->d_un.d_val); break; \
- case DT_STRSZ: str_shdr.sh_size = dyn->d_un.d_val; break; \
- 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; \
+ \
+ /* 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) { \
+ 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; \
+ case DT_STRTAB: vstr = EGET(dyn->d_un.d_val); break; \
+ case DT_STRSZ: str_shdr.sh_size = dyn->d_un.d_val; break; \
+ case DT_HASH: vhash = EGET(dyn->d_un.d_val); break; \
+ /*case DT_GNU_HASH: vgnu_hash = EGET(dyn->d_un.d_val); break;*/ \
} \
- if (vsym && vstr) \
- break; \
+ ++dyn; \
} \
if (!vsym || !vstr || !(vhash || vgnu_hash)) \
return; \
@@ -486,7 +531,6 @@ static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro,
static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
{
static const char *ret = "TEXTREL";
- unsigned long i;
if (!show_textrel && !show_textrels) return NULL;
@@ -494,22 +538,23 @@ static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
#define SHOW_TEXTREL(B) \
Elf ## B ## _Dyn *dyn; \
- Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
- Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
+ Elf ## B ## _Phdr *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; \
- 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_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; \
+ \
+ /* 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) { \
+ 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);
@@ -680,7 +725,6 @@ static void rpath_security_checks(elfobj *elf, char *item, const char *dt_type)
}
static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
{
- unsigned long i;
char *rpath, *runpath, **r;
void *strtbl_void;
@@ -691,112 +735,111 @@ static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_
#define SHOW_RPATH(B) \
Elf ## B ## _Dyn *dyn; \
- Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
- Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
+ Elf ## B ## _Phdr *phdr; \
Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
Elf ## B ## _Off offset; \
Elf ## B ## _Xword word; \
- /* Scan all the program headers */ \
- for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
- /* Just scan dynamic headers */ \
- 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; \
- /* Just scan dynamic RPATH/RUNPATH headers */ \
- dyn = DYN ## B (elf->vdata + offset); \
- while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
- if (word == DT_RPATH) { \
- r = &rpath; \
- } else if (word == DT_RUNPATH) { \
- r = &runpath; \
- } else { \
- ++dyn; \
- continue; \
+ \
+ /* 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) { \
+ if (word == DT_RPATH) { \
+ r = &rpath; \
+ } else if (word == DT_RUNPATH) { \
+ r = &runpath; \
+ } else { \
+ ++dyn; \
+ continue; \
+ } \
+ /* Verify the memory is somewhat sane */ \
+ offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
+ if (offset < (Elf ## B ## _Off)elf->len) { \
+ if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
+ *r = elf->data + offset; \
+ /* cache the length in case we need to nuke this section later on */ \
+ if (fix_elf) \
+ offset = strlen(*r); \
+ /* If quiet, don't output paths in ld.so.conf */ \
+ if (be_quiet) { \
+ size_t len; \
+ char *start, *end; \
+ /* note that we only 'chop' off leading known paths. */ \
+ /* since *r is read-only memory, we can only move the ptr forward. */ \
+ start = *r; \
+ /* scan each path in : delimited list */ \
+ while (start) { \
+ rpath_security_checks(elf, start, get_elfdtype(word)); \
+ end = strchr(start, ':'); \
+ len = (end ? abs(end - start) : strlen(start)); \
+ if (use_ldcache) { \
+ size_t n; \
+ const char *ldpath; \
+ array_for_each(ldpaths, n, ldpath) \
+ if (!strncmp(ldpath, start, len) && !ldpath[len]) { \
+ *r = end; \
+ /* corner case ... if RPATH reads "/usr/lib:", we want \
+ * to show ':' rather than '' */ \
+ if (end && end[1] != '\0') \
+ (*r)++; \
+ break; \
+ } \
+ } \
+ if (!*r || !end) \
+ break; \
+ else \
+ start = start + len + 1; \
+ } \
} \
- /* Verify the memory is somewhat sane */ \
- offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
- if (offset < (Elf ## B ## _Off)elf->len) { \
- if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
- *r = elf->data + offset; \
- /* cache the length in case we need to nuke this section later on */ \
- if (fix_elf) \
- offset = strlen(*r); \
- /* If quiet, don't output paths in ld.so.conf */ \
- if (be_quiet) { \
- size_t len; \
+ if (*r) { \
+ if (fix_elf > 2 || (fix_elf && **r == '\0')) { \
+ /* just nuke it */ \
+ nuke_it##B: \
+ memset(*r, 0x00, offset); \
+ *r = NULL; \
+ ESET(dyn->d_tag, DT_DEBUG); \
+ ESET(dyn->d_un.d_ptr, 0); \
+ } else if (fix_elf) { \
+ /* try to clean "bad" paths */ \
+ size_t len, tmpdir_len; \
char *start, *end; \
- /* note that we only 'chop' off leading known paths. */ \
- /* since *r is read-only memory, we can only move the ptr forward. */ \
+ const char *tmpdir; \
start = *r; \
- /* scan each path in : delimited list */ \
- while (start) { \
- rpath_security_checks(elf, start, get_elfdtype(word)); \
+ tmpdir = (getenv("TMPDIR") ? : "."); \
+ tmpdir_len = strlen(tmpdir); \
+ while (1) { \
end = strchr(start, ':'); \
- len = (end ? abs(end - start) : strlen(start)); \
- if (use_ldcache) { \
- size_t n; \
- const char *ldpath; \
- array_for_each(ldpaths, n, ldpath) \
- if (!strncmp(ldpath, start, len) && !ldpath[len]) { \
- *r = end; \
- /* corner case ... if RPATH reads "/usr/lib:", we want \
- * to show ':' rather than '' */ \
- if (end && end[1] != '\0') \
- (*r)++; \
- break; \
- } \
+ if (start == end) { \
+ eat_this_path##B: \
+ len = strlen(end); \
+ memmove(start, end+1, len); \
+ start[len-1] = '\0'; \
+ end = start - 1; \
+ } else if (tmpdir && !strncmp(start, tmpdir, tmpdir_len)) { \
+ if (!end) { \
+ if (start == *r) \
+ goto nuke_it##B; \
+ *--start = '\0'; \
+ } else \
+ goto eat_this_path##B; \
} \
- if (!*r || !end) \
+ if (!end) \
break; \
- else \
- start = start + len + 1; \
+ start = end + 1; \
} \
+ if (**r == '\0') \
+ goto nuke_it##B; \
} \
- if (*r) { \
- if (fix_elf > 2 || (fix_elf && **r == '\0')) { \
- /* just nuke it */ \
- nuke_it##B: \
- memset(*r, 0x00, offset); \
- *r = NULL; \
- ESET(dyn->d_tag, DT_DEBUG); \
- ESET(dyn->d_un.d_ptr, 0); \
- } else if (fix_elf) { \
- /* try to clean "bad" paths */ \
- size_t len, tmpdir_len; \
- char *start, *end; \
- const char *tmpdir; \
- start = *r; \
- tmpdir = (getenv("TMPDIR") ? : "."); \
- tmpdir_len = strlen(tmpdir); \
- while (1) { \
- end = strchr(start, ':'); \
- if (start == end) { \
- eat_this_path##B: \
- len = strlen(end); \
- memmove(start, end+1, len); \
- start[len-1] = '\0'; \
- end = start - 1; \
- } else if (tmpdir && !strncmp(start, tmpdir, tmpdir_len)) { \
- if (!end) { \
- if (start == *r) \
- goto nuke_it##B; \
- *--start = '\0'; \
- } else \
- goto eat_this_path##B; \
- } \
- if (!end) \
- break; \
- start = end + 1; \
- } \
- if (**r == '\0') \
- goto nuke_it##B; \
- } \
- if (*r) \
- *found_rpath = 1; \
- } \
+ if (*r) \
+ *found_rpath = 1; \
} \
- ++dyn; \
} \
+ ++dyn; \
}
if (elf->phdr && strtbl_void)
SCANELF_ELF_SIZED(SHOW_RPATH);
@@ -837,7 +880,6 @@ static char *lookup_config_lib(const char *fname)
static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
{
- unsigned long i;
char *needed;
void *strtbl_void;
char *p;
@@ -853,63 +895,61 @@ static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char
#define SHOW_NEEDED(B) \
Elf ## B ## _Dyn *dyn; \
- Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
- Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
+ Elf ## B ## _Phdr *phdr; \
Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
Elf ## B ## _Off offset; \
size_t matched = 0; \
- /* Walk all the program headers to find the PT_DYNAMIC */ \
- 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; \
- /* Walk all the dynamic tags to find NEEDED entries */ \
- dyn = DYN ## B (elf->vdata + offset); \
- while (EGET(dyn->d_tag) != DT_NULL) { \
- 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; \
- continue; \
- } \
- needed = elf->data + offset; \
- if (op == 0) { \
- /* -n -> print all entries */ \
- if (!be_wewy_wewy_quiet) { \
- if (*found_needed) xchrcat(ret, ',', ret_len); \
- if (use_ldpath) { \
- if ((p = lookup_config_lib(needed)) != NULL) \
- needed = p; \
- } else if (use_ldcache) { \
- if ((p = ldso_cache_lookup_lib(elf, needed)) != NULL) \
- needed = p; \
- } \
- xstrcat(ret, needed, ret_len); \
- } \
- *found_needed = 1; \
- } else { \
- /* -N -> print matching entries */ \
- size_t n; \
- const char *find_lib_name; \
- \
- array_for_each(find_lib_arr, n, find_lib_name) { \
- int invert = 1; \
- if (find_lib_name[0] == '!') \
- invert = 0, ++find_lib_name; \
- if ((!strcmp(find_lib_name, needed)) == invert) \
- ++matched; \
- } \
- \
- if (matched == array_cnt(find_lib_arr)) { \
- *found_lib = 1; \
- return (be_wewy_wewy_quiet ? NULL : find_lib); \
+ \
+ /* 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) { \
+ 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; \
+ continue; \
+ } \
+ needed = elf->data + offset; \
+ if (op == 0) { \
+ /* -n -> print all entries */ \
+ if (!be_wewy_wewy_quiet) { \
+ if (*found_needed) xchrcat(ret, ',', ret_len); \
+ if (use_ldpath) { \
+ if ((p = lookup_config_lib(needed)) != NULL) \
+ needed = p; \
+ } else if (use_ldcache) { \
+ if ((p = ldso_cache_lookup_lib(elf, needed)) != NULL) \
+ needed = p; \
} \
+ xstrcat(ret, needed, ret_len); \
+ } \
+ *found_needed = 1; \
+ } else { \
+ /* -N -> print matching entries */ \
+ size_t n; \
+ const char *find_lib_name; \
+ \
+ array_for_each(find_lib_arr, n, find_lib_name) { \
+ int invert = 1; \
+ if (find_lib_name[0] == '!') \
+ invert = 0, ++find_lib_name; \
+ if ((!strcmp(find_lib_name, needed)) == invert) \
+ ++matched; \
+ } \
+ \
+ if (matched == array_cnt(find_lib_arr)) { \
+ *found_lib = 1; \
+ return (be_wewy_wewy_quiet ? NULL : find_lib); \
} \
} \
- ++dyn; \
} \
+ ++dyn; \
}
if (elf->phdr && strtbl_void) {
SCANELF_ELF_SIZED(SHOW_NEEDED);