diff --git a/libexec/rtld-elf/map_object.c b/libexec/rtld-elf/map_object.c index 2d06074..3266af0 100644 --- a/libexec/rtld-elf/map_object.c +++ b/libexec/rtld-elf/map_object.c @@ -83,6 +83,7 @@ map_object(int fd, const char *path, const struct stat *sb) Elf_Addr bss_vaddr; Elf_Addr bss_vlimit; caddr_t bss_addr; + size_t hole; hdr = get_elf_header(fd, path); if (hdr == NULL) @@ -91,8 +92,7 @@ map_object(int fd, const char *path, const struct stat *sb) /* * Scan the program header entries, and save key information. * - * We rely on there being exactly two load segments, text and data, - * in that order. + * We expect that the loadable segments are ordered by load address. */ phdr = (Elf_Phdr *) ((char *)hdr + hdr->e_phoff); phsize = hdr->e_phnum * sizeof (phdr[0]); @@ -167,7 +167,7 @@ map_object(int fd, const char *path, const struct stat *sb) return NULL; } - for (i = 0; i <= nsegs; i++) { + for (i = 0; i <= nsegs; i++) { /* Overlay the segment onto the proper region. */ data_offset = trunc_page(segs[i]->p_offset); data_vaddr = trunc_page(segs[i]->p_vaddr); @@ -176,7 +176,7 @@ map_object(int fd, const char *path, const struct stat *sb) data_prot = convert_prot(segs[i]->p_flags); data_flags = convert_flags(segs[i]->p_flags) | MAP_FIXED; /* Do not call mmap on the first segment - this is redundant */ - if (i && mmap(data_addr, data_vlimit - data_vaddr, data_prot, + if (i != 0 && mmap(data_addr, data_vlimit - data_vaddr, data_prot, data_flags, fd, data_offset) == (caddr_t) -1) { _rtld_error("%s: mmap of data failed: %s", path, strerror(errno)); return NULL; @@ -214,6 +214,17 @@ map_object(int fd, const char *path, const struct stat *sb) return NULL; } } + + /* Unmap the region between two non-adjusted ELF segments */ + if (i < nsegs) { + hole = trunc_page(segs[i + 1]->p_vaddr) - bss_vlimit; + if (hole > 0 && munmap(mapbase + bss_vlimit, hole) == -1) { + _rtld_error("%s: munmap hole failed: %s", path, + strerror(errno)); + return NULL; + } + } + if (phdr_vaddr == 0 && data_offset <= hdr->e_phoff && (data_vlimit - data_vaddr + data_offset) >= (hdr->e_phoff + hdr->e_phnum * sizeof (Elf_Phdr))) {