|
@@ -305,6 +305,7 @@ static void reclaim_gaps(unsigned char *base, Phdr *ph, size_t phent, size_t phc
|
|
|
static void *map_library(int fd, struct dso *dso)
|
|
|
{
|
|
|
Ehdr buf[(896+sizeof(Ehdr))/sizeof(Ehdr)];
|
|
|
+ void *allocated_buf=0;
|
|
|
size_t phsize;
|
|
|
size_t addr_min=SIZE_MAX, addr_max=0, map_len;
|
|
|
size_t this_min, this_max;
|
|
@@ -312,23 +313,28 @@ static void *map_library(int fd, struct dso *dso)
|
|
|
Ehdr *eh;
|
|
|
Phdr *ph, *ph0;
|
|
|
unsigned prot;
|
|
|
- unsigned char *map, *base;
|
|
|
+ unsigned char *map=MAP_FAILED, *base;
|
|
|
size_t dyn=0;
|
|
|
size_t tls_image=0;
|
|
|
size_t i;
|
|
|
|
|
|
ssize_t l = read(fd, buf, sizeof buf);
|
|
|
- if (l<(int)sizeof *eh) return 0;
|
|
|
eh = buf;
|
|
|
- if (eh->e_type != ET_DYN && eh->e_type != ET_EXEC) {
|
|
|
- errno = ENOEXEC;
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ if (l<0) return 0;
|
|
|
+ if (l<sizeof *eh || (eh->e_type != ET_DYN && eh->e_type != ET_EXEC))
|
|
|
+ goto noexec;
|
|
|
phsize = eh->e_phentsize * eh->e_phnum;
|
|
|
- if (phsize + sizeof *eh > l) return 0;
|
|
|
- if (eh->e_phoff + phsize > l) {
|
|
|
+ if (phsize > sizeof buf - sizeof *eh) {
|
|
|
+ allocated_buf = malloc(phsize);
|
|
|
+ if (!allocated_buf) return 0;
|
|
|
+ l = pread(fd, allocated_buf, phsize, eh->e_phoff);
|
|
|
+ if (l < 0) goto error;
|
|
|
+ if (l != phsize) goto noexec;
|
|
|
+ ph = ph0 = allocated_buf;
|
|
|
+ } else if (eh->e_phoff + phsize > l) {
|
|
|
l = pread(fd, buf+1, phsize, eh->e_phoff);
|
|
|
- if (l != phsize) return 0;
|
|
|
+ if (l < 0) goto error;
|
|
|
+ if (l != phsize) goto noexec;
|
|
|
ph = ph0 = (void *)(buf + 1);
|
|
|
} else {
|
|
|
ph = ph0 = (void *)((char *)buf + eh->e_phoff);
|
|
@@ -354,7 +360,7 @@ static void *map_library(int fd, struct dso *dso)
|
|
|
addr_max = ph->p_vaddr+ph->p_memsz;
|
|
|
}
|
|
|
}
|
|
|
- if (!dyn) return 0;
|
|
|
+ if (!dyn) goto noexec;
|
|
|
addr_max += PAGE_SIZE-1;
|
|
|
addr_max &= -PAGE_SIZE;
|
|
|
addr_min &= -PAGE_SIZE;
|
|
@@ -365,7 +371,7 @@ static void *map_library(int fd, struct dso *dso)
|
|
|
* use the invalid part; we just need to reserve the right
|
|
|
* amount of virtual address space to map over later. */
|
|
|
map = mmap((void *)addr_min, map_len, prot, MAP_PRIVATE, fd, off_start);
|
|
|
- if (map==MAP_FAILED) return 0;
|
|
|
+ if (map==MAP_FAILED) goto error;
|
|
|
/* If the loaded file is not relocatable and the requested address is
|
|
|
* not available, then the load operation must fail. */
|
|
|
if (eh->e_type != ET_DYN && addr_min && map!=(void *)addr_min) {
|
|
@@ -416,8 +422,11 @@ static void *map_library(int fd, struct dso *dso)
|
|
|
dso->dynv = (void *)(base+dyn);
|
|
|
if (dso->tls_size) dso->tls_image = (void *)(base+tls_image);
|
|
|
return map;
|
|
|
+noexec:
|
|
|
+ errno = ENOEXEC;
|
|
|
error:
|
|
|
- munmap(map, map_len);
|
|
|
+ if (map!=MAP_FAILED) munmap(map, map_len);
|
|
|
+ free(allocated_buf);
|
|
|
return 0;
|
|
|
}
|
|
|
|