svn commit: r237712 - stable/9/libexec/rtld-elf
Konstantin Belousov
kib at FreeBSD.org
Thu Jun 28 14:13:46 UTC 2012
Author: kib
Date: Thu Jun 28 14:13:45 2012
New Revision: 237712
URL: http://svn.freebsd.org/changeset/base/237712
Log:
MFC r237058:
Eliminate the static buffer used to read the first page of the mapped
object, and eliminate the pread(2) call as well. Mmap the first
page of the object temporaly, and unmap it on error or last use.
Potentially, this leaves one-page gap between succeeding dlopen(3),
but there are other mmap(2) consumers as well.
Fix several cases were the whole mapping of the object leaked on error.
Use MAP_PREFAULT_READ for mmap(2) calls which map real object pages
Modified:
stable/9/libexec/rtld-elf/map_object.c
Directory Properties:
stable/9/libexec/rtld-elf/ (props changed)
Modified: stable/9/libexec/rtld-elf/map_object.c
==============================================================================
--- stable/9/libexec/rtld-elf/map_object.c Thu Jun 28 13:47:07 2012 (r237711)
+++ stable/9/libexec/rtld-elf/map_object.c Thu Jun 28 14:13:45 2012 (r237712)
@@ -38,7 +38,7 @@
#include "debug.h"
#include "rtld.h"
-static Elf_Ehdr *get_elf_header (int, const char *);
+static Elf_Ehdr *get_elf_header(int, const char *);
static int convert_prot(int); /* Elf flags -> mmap protection */
static int convert_flags(int); /* Elf flags -> mmap flags */
@@ -121,7 +121,7 @@ map_object(int fd, const char *path, con
if ((segs[nsegs]->p_align & (PAGE_SIZE - 1)) != 0) {
_rtld_error("%s: PT_LOAD segment %d not page-aligned",
path, nsegs);
- return NULL;
+ goto error;
}
break;
@@ -161,12 +161,12 @@ map_object(int fd, const char *path, con
}
if (phdyn == NULL) {
_rtld_error("%s: object is not dynamically-linked", path);
- return NULL;
+ goto error;
}
if (nsegs < 0) {
_rtld_error("%s: too few PT_LOAD segments", path);
- return NULL;
+ goto error;
}
/*
@@ -183,13 +183,12 @@ map_object(int fd, const char *path, con
if (mapbase == (caddr_t) -1) {
_rtld_error("%s: mmap of entire address space failed: %s",
path, rtld_strerror(errno));
- return NULL;
+ goto error;
}
if (base_addr != NULL && mapbase != base_addr) {
_rtld_error("%s: mmap returned wrong address: wanted %p, got %p",
path, base_addr, mapbase);
- munmap(mapbase, mapsize);
- return NULL;
+ goto error1;
}
for (i = 0; i <= nsegs; i++) {
@@ -201,10 +200,10 @@ map_object(int fd, const char *path, con
data_prot = convert_prot(segs[i]->p_flags);
data_flags = convert_flags(segs[i]->p_flags) | MAP_FIXED;
if (mmap(data_addr, data_vlimit - data_vaddr, data_prot,
- data_flags, fd, data_offset) == (caddr_t) -1) {
+ data_flags | MAP_PREFAULT_READ, fd, data_offset) == (caddr_t) -1) {
_rtld_error("%s: mmap of data failed: %s", path,
rtld_strerror(errno));
- return NULL;
+ goto error1;
}
/* Do BSS setup */
@@ -221,7 +220,7 @@ map_object(int fd, const char *path, con
mprotect(clear_page, PAGE_SIZE, data_prot|PROT_WRITE)) {
_rtld_error("%s: mprotect failed: %s", path,
rtld_strerror(errno));
- return NULL;
+ goto error1;
}
memset(clear_addr, 0, nclear);
@@ -240,7 +239,7 @@ map_object(int fd, const char *path, con
data_flags | MAP_ANON, -1, 0) == (caddr_t)-1) {
_rtld_error("%s: mmap of bss failed: %s", path,
rtld_strerror(errno));
- return NULL;
+ goto error1;
}
}
}
@@ -273,7 +272,7 @@ map_object(int fd, const char *path, con
if (obj->phdr == NULL) {
obj_free(obj);
_rtld_error("%s: cannot allocate program header", path);
- return NULL;
+ goto error1;
}
memcpy((char *)obj->phdr, (char *)hdr + hdr->e_phoff, phsize);
obj->phdr_alloc = true;
@@ -293,63 +292,72 @@ map_object(int fd, const char *path, con
obj->relro_page = obj->relocbase + trunc_page(relro_page);
obj->relro_size = round_page(relro_size);
- return obj;
+ munmap(hdr, PAGE_SIZE);
+ return (obj);
+
+error1:
+ munmap(mapbase, mapsize);
+error:
+ munmap(hdr, PAGE_SIZE);
+ return (NULL);
}
static Elf_Ehdr *
-get_elf_header (int fd, const char *path)
+get_elf_header(int fd, const char *path)
{
- static union {
- Elf_Ehdr hdr;
- char buf[PAGE_SIZE];
- } u;
- ssize_t nbytes;
-
- if ((nbytes = pread(fd, u.buf, PAGE_SIZE, 0)) == -1) {
- _rtld_error("%s: read error: %s", path, rtld_strerror(errno));
- return NULL;
- }
-
- /* Make sure the file is valid */
- if (nbytes < (ssize_t)sizeof(Elf_Ehdr) || !IS_ELF(u.hdr)) {
- _rtld_error("%s: invalid file format", path);
- return NULL;
- }
- if (u.hdr.e_ident[EI_CLASS] != ELF_TARG_CLASS
- || u.hdr.e_ident[EI_DATA] != ELF_TARG_DATA) {
- _rtld_error("%s: unsupported file layout", path);
- return NULL;
- }
- if (u.hdr.e_ident[EI_VERSION] != EV_CURRENT
- || u.hdr.e_version != EV_CURRENT) {
- _rtld_error("%s: unsupported file version", path);
- return NULL;
- }
- if (u.hdr.e_type != ET_EXEC && u.hdr.e_type != ET_DYN) {
- _rtld_error("%s: unsupported file type", path);
- return NULL;
- }
- if (u.hdr.e_machine != ELF_TARG_MACH) {
- _rtld_error("%s: unsupported machine", path);
- return NULL;
- }
+ Elf_Ehdr *hdr;
- /*
- * We rely on the program header being in the first page. This is
- * not strictly required by the ABI specification, but it seems to
- * always true in practice. And, it simplifies things considerably.
- */
- if (u.hdr.e_phentsize != sizeof(Elf_Phdr)) {
- _rtld_error(
- "%s: invalid shared object: e_phentsize != sizeof(Elf_Phdr)", path);
- return NULL;
- }
- if (u.hdr.e_phoff + u.hdr.e_phnum * sizeof(Elf_Phdr) > (size_t)nbytes) {
- _rtld_error("%s: program header too large", path);
- return NULL;
- }
+ hdr = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE | MAP_PREFAULT_READ,
+ fd, 0);
+ if (hdr == (Elf_Ehdr *)MAP_FAILED) {
+ _rtld_error("%s: read error: %s", path, rtld_strerror(errno));
+ return (NULL);
+ }
+
+ /* Make sure the file is valid */
+ if (!IS_ELF(*hdr)) {
+ _rtld_error("%s: invalid file format", path);
+ goto error;
+ }
+ if (hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS ||
+ hdr->e_ident[EI_DATA] != ELF_TARG_DATA) {
+ _rtld_error("%s: unsupported file layout", path);
+ goto error;
+ }
+ if (hdr->e_ident[EI_VERSION] != EV_CURRENT ||
+ hdr->e_version != EV_CURRENT) {
+ _rtld_error("%s: unsupported file version", path);
+ goto error;
+ }
+ if (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN) {
+ _rtld_error("%s: unsupported file type", path);
+ goto error;
+ }
+ if (hdr->e_machine != ELF_TARG_MACH) {
+ _rtld_error("%s: unsupported machine", path);
+ goto error;
+ }
- return (&u.hdr);
+ /*
+ * We rely on the program header being in the first page. This is
+ * not strictly required by the ABI specification, but it seems to
+ * always true in practice. And, it simplifies things considerably.
+ */
+ if (hdr->e_phentsize != sizeof(Elf_Phdr)) {
+ _rtld_error(
+ "%s: invalid shared object: e_phentsize != sizeof(Elf_Phdr)", path);
+ goto error;
+ }
+ if (hdr->e_phoff + hdr->e_phnum * sizeof(Elf_Phdr) >
+ (size_t)PAGE_SIZE) {
+ _rtld_error("%s: program header too large", path);
+ goto error;
+ }
+ return (hdr);
+
+error:
+ munmap(hdr, PAGE_SIZE);
+ return (NULL);
}
void
More information about the svn-src-stable-9
mailing list