Index: libexec/rtld-elf/map_object.c =================================================================== --- libexec/rtld-elf/map_object.c +++ libexec/rtld-elf/map_object.c @@ -38,7 +38,7 @@ #include "debug.h" #include "rtld.h" -static Elf_Ehdr *get_elf_header(int, const char *, const struct stat *); +static int get_elf_header(int, const char *, Elf_Ehdr **, size_t *); static int convert_flags(int); /* Elf flags -> mmap flags */ int __getosreldate(void); @@ -56,6 +56,7 @@ { Obj_Entry *obj; Elf_Ehdr *hdr; + size_t hdrsize; int i; Elf_Phdr *phdr; Elf_Phdr *phlimit; @@ -91,9 +92,10 @@ Elf_Addr note_end; char *note_map; size_t note_map_len; + int error; - hdr = get_elf_header(fd, path, sb); - if (hdr == NULL) + error = get_elf_header(fd, path, &hdr, &hdrsize); + if (error != 0) return (NULL); /* @@ -153,8 +155,8 @@ break; case PT_NOTE: - if (phdr->p_offset > PAGE_SIZE || - phdr->p_offset + phdr->p_filesz > PAGE_SIZE) { + if (phdr->p_offset > hdrsize || + phdr->p_offset + phdr->p_filesz > hdrsize) { note_map_len = round_page(phdr->p_offset + phdr->p_filesz) - trunc_page(phdr->p_offset); note_map = mmap(NULL, note_map_len, PROT_READ, @@ -315,7 +317,7 @@ digest_notes(obj, note_start, note_end); if (note_map != NULL) munmap(note_map, note_map_len); - munmap(hdr, PAGE_SIZE); + free(hdr); return (obj); error1: @@ -323,26 +325,37 @@ error: if (note_map != NULL && note_map != MAP_FAILED) munmap(note_map, note_map_len); - munmap(hdr, PAGE_SIZE); + free(hdr); return (NULL); } -static Elf_Ehdr * -get_elf_header(int fd, const char *path, const struct stat *sbp) +static int +get_elf_header(int fd, const char *path, Elf_Ehdr **hdrp, size_t *hdrsizep) { Elf_Ehdr *hdr; + size_t hdrsize; + ssize_t retval; - /* Make sure file has enough data for the ELF header */ - if (sbp != NULL && sbp->st_size < sizeof(Elf_Ehdr)) { - _rtld_error("%s: invalid file format", path); - return (NULL); - } + hdr = xmalloc(PAGE_SIZE); - 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); + /* + * The value "14" was chosen rather arbitrarily, to (almost) + * match GNU/libc, which just hardcodes buffer size of 832. + */ + hdrsize = sizeof(Elf_Ehdr) + sizeof(Elf_Phdr) * 14; + + retval = pread(fd, hdr, hdrsize, 0); + if (retval != hdrsize) { + if (retval < 0) { + _rtld_error("%s: read error: %s", + path, rtld_strerror(errno)); + goto error; + } + if (retval < sizeof(Elf_Ehdr)) { + _rtld_error("%s: invalid file format", path); + goto error; + } + hdrsize = retval; } /* Make sure the file is valid */ @@ -384,11 +397,26 @@ _rtld_error("%s: program header too large", path); goto error; } - return (hdr); + if (hdr->e_phoff + hdr->e_phnum * sizeof(Elf_Phdr) > hdrsize) { + retval = pread(fd, (char *)hdr + hdrsize, + PAGE_SIZE - hdrsize, hdrsize); + if (retval != PAGE_SIZE - hdrsize) { + if (retval < 0) { + _rtld_error("%s: read error: %s", + path, rtld_strerror(errno)); + goto error; + } + } + hdrsize += retval; + } + *hdrp = hdr; + *hdrsizep = hdrsize; + return (0); + error: - munmap(hdr, PAGE_SIZE); - return (NULL); + free(hdr); + return (-1); } void