diff options
author | kib <kib@FreeBSD.org> | 2015-10-28 11:32:39 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2015-10-28 11:32:39 +0000 |
commit | 324b84edb0064bc61d02c7c2070de80fdb21ff51 (patch) | |
tree | 39f263c7830ce00ba2ccdbed1c8475e4cd2c38df /libexec/rtld-elf/map_object.c | |
parent | 0c6038d37ec7f485754130b6e93063e32f851625 (diff) | |
download | FreeBSD-src-324b84edb0064bc61d02c7c2070de80fdb21ff51.zip FreeBSD-src-324b84edb0064bc61d02c7c2070de80fdb21ff51.tar.gz |
MFC r289324:
Allow PT_NOTES segments to be located anywhere in the executable
image.
Diffstat (limited to 'libexec/rtld-elf/map_object.c')
-rw-r--r-- | libexec/rtld-elf/map_object.c | 24 |
1 files changed, 21 insertions, 3 deletions
diff --git a/libexec/rtld-elf/map_object.c b/libexec/rtld-elf/map_object.c index 2e17fbf..6012015 100644 --- a/libexec/rtld-elf/map_object.c +++ b/libexec/rtld-elf/map_object.c @@ -88,6 +88,8 @@ map_object(int fd, const char *path, const struct stat *sb) size_t relro_size; Elf_Addr note_start; Elf_Addr note_end; + char *note_map; + size_t note_map_len; hdr = get_elf_header(fd, path); if (hdr == NULL) @@ -108,6 +110,7 @@ map_object(int fd, const char *path, const struct stat *sb) relro_size = 0; note_start = 0; note_end = 0; + note_map = NULL; segs = alloca(sizeof(segs[0]) * hdr->e_phnum); stack_flags = RTLD_DEFAULT_STACK_PF_EXEC | PF_R | PF_W; while (phdr < phlimit) { @@ -150,9 +153,20 @@ map_object(int fd, const char *path, const struct stat *sb) case PT_NOTE: if (phdr->p_offset > PAGE_SIZE || - phdr->p_offset + phdr->p_filesz > PAGE_SIZE) - break; - note_start = (Elf_Addr)(char *)hdr + phdr->p_offset; + phdr->p_offset + phdr->p_filesz > PAGE_SIZE) { + 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, + MAP_PRIVATE, fd, trunc_page(phdr->p_offset)); + if (note_map == MAP_FAILED) { + _rtld_error("%s: error mapping PT_NOTE (%d)", path, errno); + goto error; + } + note_start = (Elf_Addr)(note_map + phdr->p_offset - + trunc_page(phdr->p_offset)); + } else { + note_start = (Elf_Addr)(char *)hdr + phdr->p_offset; + } note_end = note_start + phdr->p_filesz; break; } @@ -295,12 +309,16 @@ map_object(int fd, const char *path, const struct stat *sb) obj->relro_size = round_page(relro_size); if (note_start < note_end) digest_notes(obj, note_start, note_end); + if (note_map != NULL) + munmap(note_map, note_map_len); munmap(hdr, PAGE_SIZE); return (obj); error1: munmap(mapbase, mapsize); error: + if (note_map != NULL && note_map != MAP_FAILED) + munmap(note_map, note_map_len); munmap(hdr, PAGE_SIZE); return (NULL); } |