Fix broken mmap() usage in nlist() by switching to pread()

The offset is not page aligned, which makes mmap() return EINVAL on
Linux. Switch to use pread() which handles unaligned offset and non-page
sized reads, and because we are already loading parts of the executable
by read() calls, so there's not much point in using mmap() anyway.
This commit is contained in:
Guillem Jover 2017-06-14 01:49:25 +02:00
parent e8d340de9e
commit 47013bc92a

View File

@ -36,6 +36,7 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <nlist.h> #include <nlist.h>
@ -131,7 +132,6 @@ __fdnlist(int fd, struct nlist *list)
char *strtab = NULL; char *strtab = NULL;
Elf_Shdr *shdr = NULL; Elf_Shdr *shdr = NULL;
Elf_Word shdr_size; Elf_Word shdr_size;
void *base;
struct stat st; struct stat st;
/* Make sure obj is OK */ /* Make sure obj is OK */
@ -150,12 +150,13 @@ __fdnlist(int fd, struct nlist *list)
return (-1); return (-1);
} }
/* mmap section header table */ shdr = malloc((size_t)shdr_size);
base = mmap(NULL, (size_t)shdr_size, PROT_READ, 0, fd, if (shdr == NULL)
(off_t)ehdr.e_shoff);
if (base == MAP_FAILED)
return (-1); return (-1);
shdr = (Elf_Shdr *)base;
/* Load section header table. */
if (pread(fd, shdr, (size_t)shdr_size, (off_t)ehdr.e_shoff) < 0)
goto done;
/* /*
* Find the symbol table entry and it's corresponding * Find the symbol table entry and it's corresponding
@ -179,16 +180,17 @@ __fdnlist(int fd, struct nlist *list)
goto done; goto done;
} }
/* /*
* Map string table into our address space. This gives us * Load string table into our address space. This gives us
* an easy way to randomly access all the strings, without * an easy way to randomly access all the strings, without
* making the memory allocation permanent as with malloc/free * making the memory allocation permanent as with malloc/free
* (i.e., munmap will return it to the system). * (i.e., munmap will return it to the system).
*/ */
base = mmap(NULL, (size_t)symstrsize, PROT_READ, 0, fd, strtab = malloc((size_t)symstrsize);
(off_t)symstroff); if (strtab == NULL)
if (base == MAP_FAILED) goto done;
if (pread(fd, strtab, (size_t)symstrsize, (off_t)symstroff) < 0)
goto done; goto done;
strtab = (char *)base;
/* /*
* clean out any left-over information for all valid entries. * clean out any left-over information for all valid entries.
@ -230,6 +232,7 @@ __fdnlist(int fd, struct nlist *list)
name = strtab + s->st_name; name = strtab + s->st_name;
if (name[0] == '\0') if (name[0] == '\0')
continue; continue;
for (p = list; !ISLAST(p); p++) { for (p = list; !ISLAST(p); p++) {
if ((p->n_un.n_name[0] == '_' && if ((p->n_un.n_name[0] == '_' &&
strcmp(name, p->n_un.n_name+1) == 0) strcmp(name, p->n_un.n_name+1) == 0)
@ -244,10 +247,8 @@ __fdnlist(int fd, struct nlist *list)
} }
done: done:
errsave = errno; errsave = errno;
if (strtab != NULL) free(strtab);
munmap(strtab, symstrsize); free(shdr);
if (shdr != NULL)
munmap(shdr, shdr_size);
errno = errsave; errno = errsave;
return (nent); return (nent);
} }