diff --git a/libexec/rtld-elf/Makefile b/libexec/rtld-elf/Makefile index 7c20398..0a6b60f 100644 --- a/libexec/rtld-elf/Makefile +++ b/libexec/rtld-elf/Makefile @@ -11,6 +11,7 @@ MAN= rtld.1 CSTD?= gnu99 CFLAGS+= -Wall -DFREEBSD_ELF -DIN_RTLD CFLAGS+= -I${.CURDIR}/${MACHINE_ARCH} -I${.CURDIR} +CFLAGS+= -DDEBUG -g LDFLAGS+= -nostdlib -e .rtld_start INSTALLFLAGS= -C -b PRECIOUSPROG= diff --git a/libexec/rtld-elf/map_object.c b/libexec/rtld-elf/map_object.c index 2d06074..028ac80 100644 --- a/libexec/rtld-elf/map_object.c +++ b/libexec/rtld-elf/map_object.c @@ -91,8 +91,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]); @@ -153,8 +152,8 @@ map_object(int fd, const char *path, const struct stat *sb) mapsize = base_vlimit - base_vaddr; base_addr = hdr->e_type == ET_EXEC ? (caddr_t) base_vaddr : NULL; - mapbase = mmap(base_addr, mapsize, convert_prot(segs[0]->p_flags), - convert_flags(segs[0]->p_flags), fd, base_offset); + mapbase = mmap(base_addr, mapsize, PROT_NONE, MAP_ANON | MAP_PRIVATE | + MAP_NOCORE, -1, 0); if (mapbase == (caddr_t) -1) { _rtld_error("%s: mmap of entire address space failed: %s", path, strerror(errno)); @@ -167,7 +166,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); @@ -175,8 +174,7 @@ map_object(int fd, const char *path, const struct stat *sb) data_addr = mapbase + (data_vaddr - base_vaddr); 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 (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; @@ -207,9 +205,8 @@ map_object(int fd, const char *path, const struct stat *sb) bss_vlimit = round_page(segs[i]->p_vaddr + segs[i]->p_memsz); bss_addr = mapbase + (bss_vaddr - base_vaddr); if (bss_vlimit > bss_vaddr) { /* There is something to do */ - if (mmap(bss_addr, bss_vlimit - bss_vaddr, data_prot, - MAP_PRIVATE|MAP_FIXED|MAP_ANON, -1, 0) == (caddr_t) -1) { - _rtld_error("%s: mmap of bss failed: %s", path, + if (mprotect(bss_addr, bss_vlimit - bss_vaddr, data_prot) == -1) { + _rtld_error("%s: mprotect of bss failed: %s", path, strerror(errno)); return NULL; } diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index f395be8..718c890 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -2217,6 +2217,16 @@ vm_map_wire(vm_map_t map, vm_offset_t start, vm_offset_t end, * */ if (entry->wired_count == 0) { + if ((entry->protection & (VM_PROT_READ|VM_PROT_EXECUTE)) + == 0) { + if ((flags & VM_MAP_WIRE_HOLESOK) == 0) { + end = entry->end; + rv = KERN_INVALID_ADDRESS; + goto done; + } + entry->eflags |= MAP_ENTRY_WIRE_SKIPPED; + goto next_entry; + } entry->wired_count++; saved_start = entry->start; saved_end = entry->end; @@ -2274,6 +2284,7 @@ vm_map_wire(vm_map_t map, vm_offset_t start, vm_offset_t end, * Check the map for holes in the specified region. * If VM_MAP_WIRE_HOLESOK was specified, skip this check. */ + next_entry: if (((flags & VM_MAP_WIRE_HOLESOK) == 0) && (entry->end < end && (entry->next == &map->header || entry->next->start > entry->end))) { @@ -2295,6 +2306,8 @@ done: } entry = first_entry; while (entry != &map->header && entry->start < end) { + if ((entry->eflags & MAP_ENTRY_WIRE_SKIPPED) != 0) + goto next_entry_done; if (rv == KERN_SUCCESS) { if (user_wire) entry->eflags |= MAP_ENTRY_USER_WIRED; @@ -2317,9 +2330,10 @@ done: entry->object.vm_object->type == OBJT_DEVICE); } } + next_entry_done: KASSERT(entry->eflags & MAP_ENTRY_IN_TRANSITION, ("vm_map_wire: in-transition flag missing")); - entry->eflags &= ~MAP_ENTRY_IN_TRANSITION; + entry->eflags &= ~(MAP_ENTRY_IN_TRANSITION|MAP_ENTRY_WIRE_SKIPPED); if (entry->eflags & MAP_ENTRY_NEEDS_WAKEUP) { entry->eflags &= ~MAP_ENTRY_NEEDS_WAKEUP; need_wakeup = TRUE; diff --git a/sys/vm/vm_map.h b/sys/vm/vm_map.h index 34b183b..70c3a0b 100644 --- a/sys/vm/vm_map.h +++ b/sys/vm/vm_map.h @@ -137,6 +137,8 @@ struct vm_map_entry { #define MAP_ENTRY_GROWS_DOWN 0x1000 /* Top-down stacks */ #define MAP_ENTRY_GROWS_UP 0x2000 /* Bottom-up stacks */ +#define MAP_ENTRY_WIRE_SKIPPED 0x4000 + #ifdef _KERNEL static __inline u_char vm_map_entry_behavior(vm_map_entry_t entry)