diff options
author | Rich Felker <dalias@aerifal.cx> | 2013-07-10 14:38:20 -0400 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2013-07-10 14:38:20 -0400 |
commit | 30763fd01bef85f30e79baa30173674c007690cc (patch) | |
tree | 35f16a19bb39fe7d3f4657f60c90365a57cda584 /src | |
parent | c713d8797804903b54203a645e023e2077c7556d (diff) | |
download | musl-30763fd01bef85f30e79baa30173674c007690cc.tar.gz musl-30763fd01bef85f30e79baa30173674c007690cc.tar.xz musl-30763fd01bef85f30e79baa30173674c007690cc.zip |
fix invalid library phdr pointers passed to callback from dl_iterate_phdr
map_library was saving pointers to an automatic-storage buffer rather than pointers into the mapping. this should be a fairly simple fix, but the patch here is slightly complicated by two issues: 1. supporting gratuitously obfuscated ELF files where the program headers are not right at the beginning of the file. 2. cleaning up the map_library function so that data isn't clobbered by the time we need it.
Diffstat (limited to 'src')
-rw-r--r-- | src/ldso/dynlink.c | 25 |
1 files changed, 16 insertions, 9 deletions
diff --git a/src/ldso/dynlink.c b/src/ldso/dynlink.c index 7031d03a..ff5b738d 100644 --- a/src/ldso/dynlink.c +++ b/src/ldso/dynlink.c @@ -309,7 +309,7 @@ static void *map_library(int fd, struct dso *dso) size_t this_min, this_max; off_t off_start; Ehdr *eh; - Phdr *ph; + Phdr *ph, *ph0; unsigned prot; unsigned char *map, *base; size_t dyn; @@ -324,11 +324,10 @@ static void *map_library(int fd, struct dso *dso) if (eh->e_phoff + phsize > l) { l = pread(fd, buf+1, phsize, eh->e_phoff); if (l != phsize) return 0; - eh->e_phoff = sizeof *eh; + ph = ph0 = (void *)(buf + 1); + } else { + ph = ph0 = (void *)((char *)buf + eh->e_phoff); } - ph = (void *)((char *)buf + eh->e_phoff); - dso->phdr = ph; - dso->phnum = eh->e_phnum; for (i=eh->e_phnum; i; i--, ph=(void *)((char *)ph+eh->e_phentsize)) { if (ph->p_type == PT_DYNAMIC) dyn = ph->p_vaddr; @@ -363,9 +362,18 @@ static void *map_library(int fd, struct dso *dso) map = mmap((void *)addr_min, map_len, prot, MAP_PRIVATE, fd, off_start); if (map==MAP_FAILED) return 0; base = map - addr_min; - ph = (void *)((char *)buf + eh->e_phoff); - for (i=eh->e_phnum; i; i--, ph=(void *)((char *)ph+eh->e_phentsize)) { + dso->phdr = 0; + dso->phnum = 0; + for (ph=ph0, i=eh->e_phnum; i; i--, ph=(void *)((char *)ph+eh->e_phentsize)) { if (ph->p_type != PT_LOAD) continue; + /* Check if the programs headers are in this load segment, and + * if so, record the address for use by dl_iterate_phdr. */ + if (!dso->phdr && eh->e_phoff >= ph->p_offset + && eh->e_phoff+phsize <= ph->p_offset+ph->p_filesz) { + dso->phdr = (void *)(base + ph->p_vaddr + + (eh->e_phoff-ph->p_offset)); + dso->phnum = eh->e_phnum; + } /* Reuse the existing mapping for the lowest-address LOAD */ if ((ph->p_vaddr & -PAGE_SIZE) == addr_min) continue; this_min = ph->p_vaddr & -PAGE_SIZE; @@ -390,8 +398,7 @@ static void *map_library(int fd, struct dso *dso) goto error; break; } - if (!runtime) reclaim_gaps(base, (void *)((char *)buf + eh->e_phoff), - eh->e_phentsize, eh->e_phnum); + if (!runtime) reclaim_gaps(base, ph0, eh->e_phentsize, eh->e_phnum); dso->map = map; dso->map_len = map_len; dso->base = base; |