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.
This commit is contained in:
Ben Gras 2012-06-22 11:55:11 +02:00
parent 3f40eb3511
commit 6a6b7b5769
2 changed files with 35 additions and 47 deletions

View file

@ -38,6 +38,7 @@ __RCSID("$NetBSD: map_object.c,v 1.41 2010/10/16 10:27:07 skrll Exp $");
#endif /* not lint */ #endif /* not lint */
#include <errno.h> #include <errno.h>
#include <stdio.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -49,55 +50,27 @@ __RCSID("$NetBSD: map_object.c,v 1.41 2010/10/16 10:27:07 skrll Exp $");
#include "debug.h" #include "debug.h"
#include "rtld.h" #include "rtld.h"
#ifdef __minix
#define munmap minix_munmap
#endif
#define MINIXVERBOSE 0
static int protflags(int); /* Elf flags -> mmap protection */ static int protflags(int); /* Elf flags -> mmap protection */
#define EA_UNDEF (~(Elf_Addr)0) #define EA_UNDEF (~(Elf_Addr)0)
#ifdef __minix static void Pread(void *addr, size_t size, int fd, off_t off)
#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
#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 s;
int mapflags; if((s=pread(fd,addr, size, off)) < 0) {
size_t s; _rtld_error("pread failed");
exit(1);
mapflags = flags & (MAP_FIXED);
#ifdef MINIXVERBOSE
if(addrhint) {
fprintf(stderr, "0x%lx-0x%lx requested\n", addrhint,
(char *) addrhint + size);
} }
#if MINIXVERBOSE
fprintf(stderr, "read 0x%lx bytes from offset 0x%lx to addr 0x%lx\n", size, off, addr);
#endif #endif
if((ret = minix_mmap(addrhint, size, PROT_READ|PROT_WRITE,
MAP_ANON|MAP_PRIVATE|MAP_PREALLOC|mapflags, -1, 0)) == MAP_FAILED) {
return ret;
}
if(!(mapflags & MAP_ANON)) {
if((s=pread(fd, ret, size, off)) <= 0) {
munmap(ret, size);
return MAP_FAILED;
}
}
#ifdef MINIXVERBOSE
fprintf(stderr, "0x%lx-0x%lx mapped\n",
ret, (char *) ret + size);
#endif
return ret;
} }
/* /*
@ -159,8 +132,17 @@ _rtld_map_object(const char *path, int fd, const struct stat *sb)
obj->ino = sb->st_ino; 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, ehdr = mmap(NULL, _rtld_pagesz, PROT_READ, MAP_FILE | MAP_SHARED, fd,
(off_t)0); (off_t)0);
#endif
obj->ehdr = ehdr; obj->ehdr = ehdr;
if (ehdr == MAP_FAILED) { if (ehdr == MAP_FAILED) {
_rtld_error("%s: read error: %s", path, xstrerror(errno)); _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, mapbase = mmap(base_addr, mapsize, text_flags,
mapflags | MAP_FILE | MAP_PRIVATE, fd, base_offset); mapflags | MAP_FILE | MAP_PRIVATE, fd, base_offset);
#else #else
/* minix doesn't want overlapping mmap()s */ mapbase = minix_mmap(base_addr, mapsize, PROT_READ|PROT_WRITE,
mapbase = mmap(base_addr, obj->textsize, text_flags, MAP_ANON | MAP_PREALLOC, -1, 0);
mapflags | MAP_FILE | MAP_PRIVATE, fd, base_offset); #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 #endif
if (mapbase == MAP_FAILED) { if (mapbase == MAP_FAILED) {
_rtld_error("mmap of entire address space failed: %s", _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. */ /* Overlay the data segment onto the proper region. */
data_addr = mapbase + (data_vaddr - base_vaddr); 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, if (mmap(data_addr, data_vlimit - data_vaddr, data_flags,
MAP_FILE | MAP_PRIVATE | MAP_FIXED, fd, data_offset) == MAP_FILE | MAP_PRIVATE | MAP_FIXED, fd, data_offset) ==
MAP_FAILED) { MAP_FAILED) {
_rtld_error("mmap of data failed: %s", xstrerror(errno)); _rtld_error("mmap of data failed: %s", xstrerror(errno));
goto bad; goto bad;
} }
#endif
#ifndef __minix
bsssize= base_vlimit - data_vlimit; bsssize= base_vlimit - data_vlimit;
if(bsssize > 0) { if(bsssize > 0) {
/* Overlay the bss segment onto the proper region. */ /* 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_addr = mapbase + round_up(text_vlimit - base_vaddr);
gap_size = data_addr - gap_addr; gap_size = data_addr - gap_addr;
#ifndef __minix
if (gap_size != 0 && mprotect(gap_addr, gap_size, PROT_NONE) == -1) { if (gap_size != 0 && mprotect(gap_addr, gap_size, PROT_NONE) == -1) {
_rtld_error("mprotect of text -> data gap failed: %s", _rtld_error("mprotect of text -> data gap failed: %s",
xstrerror(errno)); xstrerror(errno));

View file

@ -18,7 +18,6 @@ long modfunction(long v1, long *argcookie, long v2) {
} }
*argcookie = MAGIC3; *argcookie = MAGIC3;
cookie = MAGIC2; cookie = MAGIC2;
atexit(exithandler);
return MAGIC1; return MAGIC1;
} }