mirror of
https://github.com/fluencelabs/musl
synced 2025-05-28 23:21:34 +00:00
improve error handling in map_library and support long phdrs
previously, errno could be meaningless when the caller wrote it to the dlerror string or stderr. try to make it meaningful. also, fix incorrect check for over-long program headers and instead actually support them by allocating memory if needed.
This commit is contained in:
parent
7443dd271c
commit
d5884a574c
@ -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)
|
static void *map_library(int fd, struct dso *dso)
|
||||||
{
|
{
|
||||||
Ehdr buf[(896+sizeof(Ehdr))/sizeof(Ehdr)];
|
Ehdr buf[(896+sizeof(Ehdr))/sizeof(Ehdr)];
|
||||||
|
void *allocated_buf=0;
|
||||||
size_t phsize;
|
size_t phsize;
|
||||||
size_t addr_min=SIZE_MAX, addr_max=0, map_len;
|
size_t addr_min=SIZE_MAX, addr_max=0, map_len;
|
||||||
size_t this_min, this_max;
|
size_t this_min, this_max;
|
||||||
@ -312,23 +313,28 @@ static void *map_library(int fd, struct dso *dso)
|
|||||||
Ehdr *eh;
|
Ehdr *eh;
|
||||||
Phdr *ph, *ph0;
|
Phdr *ph, *ph0;
|
||||||
unsigned prot;
|
unsigned prot;
|
||||||
unsigned char *map, *base;
|
unsigned char *map=MAP_FAILED, *base;
|
||||||
size_t dyn=0;
|
size_t dyn=0;
|
||||||
size_t tls_image=0;
|
size_t tls_image=0;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
ssize_t l = read(fd, buf, sizeof buf);
|
ssize_t l = read(fd, buf, sizeof buf);
|
||||||
if (l<(int)sizeof *eh) return 0;
|
|
||||||
eh = buf;
|
eh = buf;
|
||||||
if (eh->e_type != ET_DYN && eh->e_type != ET_EXEC) {
|
if (l<0) return 0;
|
||||||
errno = ENOEXEC;
|
if (l<sizeof *eh || (eh->e_type != ET_DYN && eh->e_type != ET_EXEC))
|
||||||
return 0;
|
goto noexec;
|
||||||
}
|
|
||||||
phsize = eh->e_phentsize * eh->e_phnum;
|
phsize = eh->e_phentsize * eh->e_phnum;
|
||||||
if (phsize + sizeof *eh > l) return 0;
|
if (phsize > sizeof buf - sizeof *eh) {
|
||||||
if (eh->e_phoff + phsize > l) {
|
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);
|
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);
|
ph = ph0 = (void *)(buf + 1);
|
||||||
} else {
|
} else {
|
||||||
ph = ph0 = (void *)((char *)buf + eh->e_phoff);
|
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;
|
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-1;
|
||||||
addr_max &= -PAGE_SIZE;
|
addr_max &= -PAGE_SIZE;
|
||||||
addr_min &= -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
|
* use the invalid part; we just need to reserve the right
|
||||||
* amount of virtual address space to map over later. */
|
* amount of virtual address space to map over later. */
|
||||||
map = mmap((void *)addr_min, map_len, prot, MAP_PRIVATE, fd, off_start);
|
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
|
/* If the loaded file is not relocatable and the requested address is
|
||||||
* not available, then the load operation must fail. */
|
* not available, then the load operation must fail. */
|
||||||
if (eh->e_type != ET_DYN && addr_min && map!=(void *)addr_min) {
|
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);
|
dso->dynv = (void *)(base+dyn);
|
||||||
if (dso->tls_size) dso->tls_image = (void *)(base+tls_image);
|
if (dso->tls_size) dso->tls_image = (void *)(base+tls_image);
|
||||||
return map;
|
return map;
|
||||||
|
noexec:
|
||||||
|
errno = ENOEXEC;
|
||||||
error:
|
error:
|
||||||
munmap(map, map_len);
|
if (map!=MAP_FAILED) munmap(map, map_len);
|
||||||
|
free(allocated_buf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user