From 6a6b7b5769ff69a2282a5505ad3ca3bcea10a345 Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Fri, 22 Jun 2012 11:55:11 +0200 Subject: [PATCH] ld.so: be more mmap()-behaviour-independent . if the layout of virtual address regions as returned by mmap() without a location hint changes, ld.so could trip itself up (under minix). this change allocates the full size it needs for every object that's loaded so that if that succeeds, it's sure there's virtual address space for the whole thing no matter what other bits happen to be there already. . this fix exposed a bug in the test; at atexit() execution time the loaded object is unmapped, so that part of the test is removed. --- libexec/ld.elf_so/map_object.c | 77 +++++++++++++++------------------- test/mod.c | 1 - 2 files changed, 33 insertions(+), 45 deletions(-) diff --git a/libexec/ld.elf_so/map_object.c b/libexec/ld.elf_so/map_object.c index 7f6d0bb87..409cf51c9 100644 --- a/libexec/ld.elf_so/map_object.c +++ b/libexec/ld.elf_so/map_object.c @@ -38,6 +38,7 @@ __RCSID("$NetBSD: map_object.c,v 1.41 2010/10/16 10:27:07 skrll Exp $"); #endif /* not lint */ #include +#include #include #include #include @@ -49,55 +50,27 @@ __RCSID("$NetBSD: map_object.c,v 1.41 2010/10/16 10:27:07 skrll Exp $"); #include "debug.h" #include "rtld.h" -static int protflags(int); /* Elf flags -> mmap protection */ - -#define EA_UNDEF (~(Elf_Addr)0) - #ifdef __minix -#define mmap minix_mmap_emulator -#define munmap minix_munmap - -/* for minix, ignore MAP_SHARED and MAP_FILE for now. */ -#define MAP_SHARED 0 -#define MAP_FILE 0 +#define munmap minix_munmap #endif -#undef MINIXVERBOSE - -static void * minix_mmap_emulator(void *addrhint, size_t size, int prot, int flags, int fd, off_t off) -{ - void *ret; - int mapflags; - size_t s; - - mapflags = flags & (MAP_FIXED); +#define MINIXVERBOSE 0 -#ifdef MINIXVERBOSE - if(addrhint) { - fprintf(stderr, "0x%lx-0x%lx requested\n", addrhint, - (char *) addrhint + size); - } -#endif +static int protflags(int); /* Elf flags -> mmap protection */ - if((ret = minix_mmap(addrhint, size, PROT_READ|PROT_WRITE, - MAP_ANON|MAP_PRIVATE|MAP_PREALLOC|mapflags, -1, 0)) == MAP_FAILED) { - return ret; - } +#define EA_UNDEF (~(Elf_Addr)0) - if(!(mapflags & MAP_ANON)) { - if((s=pread(fd, ret, size, off)) <= 0) { - munmap(ret, size); - return MAP_FAILED; - } +static void Pread(void *addr, size_t size, int fd, off_t off) +{ + int s; + if((s=pread(fd,addr, size, off)) < 0) { + _rtld_error("pread failed"); + exit(1); } -#ifdef MINIXVERBOSE - fprintf(stderr, "0x%lx-0x%lx mapped\n", - ret, (char *) ret + size); - +#if MINIXVERBOSE + fprintf(stderr, "read 0x%lx bytes from offset 0x%lx to addr 0x%lx\n", size, off, addr); #endif - - return ret; } /* @@ -159,8 +132,17 @@ _rtld_map_object(const char *path, int fd, const struct stat *sb) obj->ino = sb->st_ino; } +#ifdef __minix + ehdr = minix_mmap(NULL, _rtld_pagesz, PROT_READ|PROT_WRITE, + MAP_PREALLOC|MAP_ANON, -1, (off_t)0); + Pread(ehdr, _rtld_pagesz, fd, 0); +#if MINIXVERBOSE + fprintf(stderr, "minix mmap for header: 0x%lx\n", ehdr); +#endif +#else ehdr = mmap(NULL, _rtld_pagesz, PROT_READ, MAP_FILE | MAP_SHARED, fd, (off_t)0); +#endif obj->ehdr = ehdr; if (ehdr == MAP_FAILED) { _rtld_error("%s: read error: %s", path, xstrerror(errno)); @@ -349,9 +331,12 @@ _rtld_map_object(const char *path, int fd, const struct stat *sb) mapbase = mmap(base_addr, mapsize, text_flags, mapflags | MAP_FILE | MAP_PRIVATE, fd, base_offset); #else - /* minix doesn't want overlapping mmap()s */ - mapbase = mmap(base_addr, obj->textsize, text_flags, - mapflags | MAP_FILE | MAP_PRIVATE, fd, base_offset); + mapbase = minix_mmap(base_addr, mapsize, PROT_READ|PROT_WRITE, + MAP_ANON | MAP_PREALLOC, -1, 0); +#if MINIXVERBOSE + fprintf(stderr, "minix mmap for whole block: 0x%lx-0x%lx\n", mapbase, mapbase+mapsize); +#endif + Pread(mapbase, obj->textsize, fd, 0); #endif if (mapbase == MAP_FAILED) { _rtld_error("mmap of entire address space failed: %s", @@ -361,13 +346,18 @@ _rtld_map_object(const char *path, int fd, const struct stat *sb) /* Overlay the data segment onto the proper region. */ data_addr = mapbase + (data_vaddr - base_vaddr); +#ifdef __minix + Pread(data_addr, data_vlimit - data_vaddr, fd, data_offset); +#else if (mmap(data_addr, data_vlimit - data_vaddr, data_flags, MAP_FILE | MAP_PRIVATE | MAP_FIXED, fd, data_offset) == MAP_FAILED) { _rtld_error("mmap of data failed: %s", xstrerror(errno)); goto bad; } +#endif +#ifndef __minix bsssize= base_vlimit - data_vlimit; if(bsssize > 0) { /* Overlay the bss segment onto the proper region. */ @@ -384,7 +374,6 @@ _rtld_map_object(const char *path, int fd, const struct stat *sb) gap_addr = mapbase + round_up(text_vlimit - base_vaddr); gap_size = data_addr - gap_addr; -#ifndef __minix if (gap_size != 0 && mprotect(gap_addr, gap_size, PROT_NONE) == -1) { _rtld_error("mprotect of text -> data gap failed: %s", xstrerror(errno)); diff --git a/test/mod.c b/test/mod.c index 1cc168c96..0226c9909 100644 --- a/test/mod.c +++ b/test/mod.c @@ -18,7 +18,6 @@ long modfunction(long v1, long *argcookie, long v2) { } *argcookie = MAGIC3; cookie = MAGIC2; - atexit(exithandler); return MAGIC1; } -- 2.44.0