Re: Wine and mmap

From: Brian Fundakowski Feldman (green_at_freebsd.org)
Date: 09/11/04

  • Next message: FreeBSD Tinderbox: "[releng_5 tinderbox] failure on alpha/alpha"
    Date: Sat, 11 Sep 2004 14:00:00 -0400
    To: Anish Mistry <mistry.7@osu.edu>
    
    

    On Mon, Sep 06, 2004 at 01:49:35AM -0400, Anish Mistry wrote:
    > On Sunday 05 September 2004 05:15 pm, Gerald Pfeifer wrote:
    > > [ John, sorry for the duplicate message; this is the correct one. ]
    > >
    > > On Fri, 27 Aug 2004, John Birrell wrote:
    > > > Anish Mistry <mistry.7@osu.edu> has developed a patch to choose an
    > > > appropriate mmap address. He posted it to -current. I haven't had time to
    > > > test it.
    > >
    > > Thanks for the note. Will you have time to test/commit this before 5.3?
    > >
    > > Anish, do you have any news on this patch? (Wine has been broken for a
    > > couple of months now, and it would be great to have at least 5.3 fixed.)
    > >
    > Well I guess this is my lucky day. Apply the attached patch for vm_mmap to
    > your kernel and patch the August wine sources with the wine-mmap.patch and
    > compile and install wine (be sure to use gmake). This is working on my dev
    > system with 6-CURRENT as of Saturday night.
    > The wine mmap patch just doesn't reserve the DOS area so DOS programs may not
    > work. This seems to just work around a side effect of the kernel mmap patch.
    > I still think that the kernel mmap patch has issues so I'm hoping Alan can
    > give us some feedback.
    > Anyway this worked for me, YMMV.

    Do these combined work for you, minus any modifications to mmap(2)? I do
    not feel that the kernel mmap(2) should be modified in this manner, that it
    is a strictly userland problem.

    Index: lib/libpthread/thread/thr_stack.c
    ===================================================================
    RCS file: /usr/ncvs/src/lib/libpthread/thread/thr_stack.c,v
    retrieving revision 1.8
    diff -u -r1.8 thr_stack.c
    --- lib/libpthread/thread/thr_stack.c 14 Sep 2003 22:39:44 -0000 1.8
    +++ lib/libpthread/thread/thr_stack.c 11 Sep 2004 17:17:32 -0000
    @@ -61,7 +61,7 @@
      * Base address of the last stack allocated (including its red zone, if
      * there is one). Stacks are allocated contiguously, starting beyond the
      * top of the main stack. When a new stack is created, a red zone is
    - * typically created (actually, the red zone is simply left unmapped) above
    + * typically created (actually, the red zone is mapped with PROT_NONE) above
      * the top of the stack, such that the stack will not be able to grow all
      * the way to the bottom of the next stack. This isn't fool-proof. It is
      * possible for a stack to grow by a large amount, such that it grows into
    @@ -134,6 +134,7 @@
             kse_critical_t crit;
             size_t stacksize;
             size_t guardsize;
    + char *stackaddr;
     
             /*
              * Round up stack size to nearest multiple of _thr_page_size so
    @@ -194,7 +195,7 @@
                                 _thr_guard_default;
     
                     /* Allocate a new stack. */
    - attr->stackaddr_attr = last_stack - stacksize;
    + stackaddr = last_stack - stacksize - guardsize;
     
                     /*
                      * Even if stack allocation fails, we don't want to try to
    @@ -209,11 +210,20 @@
                     KSE_LOCK_RELEASE(curkse, &_thread_list_lock);
                     _kse_critical_leave(crit);
     
    - /* Map the stack, but not the guard page: */
    - if ((attr->stackaddr_attr = mmap(attr->stackaddr_attr,
    - stacksize, PROT_READ | PROT_WRITE, MAP_STACK,
    - -1, 0)) == MAP_FAILED)
    - attr->stackaddr_attr = NULL;
    + /* Map the stack and guard page together, and split guard
    + page from allocated space: */
    + if ((stackaddr = mmap(stackaddr, stacksize+guardsize,
    + PROT_READ | PROT_WRITE, MAP_STACK,
    + -1, 0)) != MAP_FAILED &&
    + (guardsize == 0 ||
    + mprotect(stackaddr, guardsize, PROT_NONE) == 0)) {
    + stackaddr += guardsize;
    + } else {
    + if (stackaddr != MAP_FAILED)
    + munmap(stackaddr, stacksize + guardsize);
    + stackaddr = NULL;
    + }
    + attr->stackaddr_attr = stackaddr;
             }
             if (attr->stackaddr_attr != NULL)
                     return (0);
    Index: libexec/rtld-elf/map_object.c
    ===================================================================
    RCS file: /usr/ncvs/src/libexec/rtld-elf/map_object.c,v
    retrieving revision 1.15
    diff -u -r1.15 map_object.c
    --- libexec/rtld-elf/map_object.c 3 Aug 2004 08:50:58 -0000 1.15
    +++ libexec/rtld-elf/map_object.c 11 Sep 2004 17:41:28 -0000
    @@ -46,12 +46,15 @@
      * Map a shared object into memory. The "fd" argument is a file descriptor,
      * which must be open on the object and positioned at its beginning.
      * The "path" argument is a pathname that is used only for error messages.
    + * The "low_addr" argument allows for addresses below the normal data
    + * area start to be used for mapping if no space is available above.
      *
      * The return value is a pointer to a newly-allocated Obj_Entry structure
      * for the shared object. Returns NULL on failure.
      */
     Obj_Entry *
    -map_object(int fd, const char *path, const struct stat *sb)
    +map_object(int fd, const char *path, const struct stat *sb,
    + unsigned long low_addr)
     {
         Obj_Entry *obj;
         Elf_Ehdr *hdr;
    @@ -152,6 +155,15 @@
     
         mapbase = mmap(base_addr, mapsize, convert_prot(segs[0]->p_flags),
           convert_flags(segs[0]->p_flags), fd, base_offset);
    + /*
    + * If requested and out of space for the library, try again below
    + * the normal minimum data segment address.
    + */
    + if (mapbase == (caddr_t) -1 && base_addr == NULL && low_addr != 0) {
    + base_addr = (caddr_t) low_addr;
    + mapbase = mmap(base_addr, mapsize, convert_prot(segs[0]->p_flags),
    + convert_flags(segs[0]->p_flags), fd, base_offset);
    + }
         if (mapbase == (caddr_t) -1) {
             _rtld_error("%s: mmap of entire address space failed: %s",
               path, strerror(errno));
    Index: libexec/rtld-elf/rtld.c
    ===================================================================
    RCS file: /usr/ncvs/src/libexec/rtld-elf/rtld.c,v
    retrieving revision 1.99
    diff -u -r1.99 rtld.c
    --- libexec/rtld-elf/rtld.c 4 Aug 2004 19:12:14 -0000 1.99
    +++ libexec/rtld-elf/rtld.c 11 Sep 2004 17:51:00 -0000
    @@ -143,6 +143,9 @@
     static char *ld_library_path; /* Environment variable for search path */
     static char *ld_preload; /* Environment variable for libraries to
                                        load first */
    +static unsigned long ld_library_low_addr; /* Environment variable for
    + alternate data area to
    + try to map into */
     static char *ld_tracing; /* Called from ldd to print libs */
     static Obj_Entry *obj_list; /* Head of linked list of shared objects */
     static Obj_Entry **obj_tail; /* Link field of last object in list */
    @@ -287,6 +290,14 @@
     
         ld_bind_now = getenv(LD_ "BIND_NOW");
         if (trust) {
    + const char *env_low_addr = getenv(LD_ "LIBRARY_LOW_ADDR");
    + if (env_low_addr != NULL) {
    + char *low_addr_endptr = NULL;
    + errno = 0;
    + ld_library_low_addr = strtoul(env_low_addr, &low_addr_endptr, 0);
    + if (*low_addr_endptr != '\0' || errno != 0)
    + ld_library_low_addr = 0;
    + }
             ld_debug = getenv(LD_ "DEBUG");
             libmap_disable = getenv(LD_ "LIBMAP_DISABLE") != NULL;
             ld_library_path = getenv(LD_ "LIBRARY_PATH");
    @@ -308,7 +319,7 @@
         if (aux_info[AT_EXECFD] != NULL) { /* Load the main program. */
             int fd = aux_info[AT_EXECFD]->a_un.a_val;
             dbg("loading main program");
    - obj_main = map_object(fd, argv0, NULL);
    + obj_main = map_object(fd, argv0, NULL, 0);
             close(fd);
             if (obj_main == NULL)
                 die();
    @@ -1249,7 +1260,7 @@
     
         if (obj == NULL) { /* First use of this object, so we must map it in */
             dbg("loading \"%s\"", path);
    - obj = map_object(fd, path, &sb);
    + obj = map_object(fd, path, &sb, ld_library_low_addr);
             close(fd);
             if (obj == NULL) {
                 free(path);
    Index: libexec/rtld-elf/rtld.h
    ===================================================================
    RCS file: /usr/ncvs/src/libexec/rtld-elf/rtld.h,v
    retrieving revision 1.34
    diff -u -r1.34 rtld.h
    --- libexec/rtld-elf/rtld.h 3 Aug 2004 08:50:58 -0000 1.34
    +++ libexec/rtld-elf/rtld.h 11 Sep 2004 17:41:45 -0000
    @@ -209,7 +209,8 @@
     } SymCache;
     
     extern void _rtld_error(const char *, ...) __printflike(1, 2);
    -extern Obj_Entry *map_object(int, const char *, const struct stat *);
    +extern Obj_Entry *map_object(int, const char *, const struct stat *,
    + unsigned long);
     extern void *xcalloc(size_t);
     extern void *xmalloc(size_t);
     extern char *xstrdup(const char *);

    -- 
    Brian Fundakowski Feldman                           \'[ FreeBSD ]''''''''''\
      <> green@FreeBSD.org                               \  The Power to Serve! \
     Opinions expressed are my own.                       \,,,,,,,,,,,,,,,,,,,,,,\
    _______________________________________________
    freebsd-current@freebsd.org mailing list
    http://lists.freebsd.org/mailman/listinfo/freebsd-current
    To unsubscribe, send any mail to "freebsd-current-unsubscribe@freebsd.org"
    

  • Next message: FreeBSD Tinderbox: "[releng_5 tinderbox] failure on alpha/alpha"

    Relevant Pages

    • [Full-Disclosure] Re: Buffer overflow prevention
      ... >> that may need executable stack). ... >> need to be compiled into anything but the kernel. ... the GRsec patch is a single option in the kernel ... way grsecurity gets a little to restrictive with things like restericting ...
      (Full-Disclosure)
    • [patch] i386: restore ESP value on return to userspace
      ... exporting the high word of kernel's stack ... Attached patch checks if the userspace ... then kernel switches to the "small" ... done against the Linus tree and/or -mm tree. ...
      (Linux-Kernel)
    • Re: Call for testing: patch that helps Wine on 6.x
      ... gross hack in order to avoid clobbering data in signal info that ... Wine needs. ... hence this lighter weight patch. ... I've patched and recompiled world + kernel using your patch. ...
      (freebsd-stable)
    • Re: Call for testing: patch that helps Wine on 6.x
      ... gross hack in order to avoid clobbering data in signal info that ... Wine needs. ... hence this lighter weight patch. ... I've patched and recompiled world + kernel using your patch. ...
      (freebsd-stable)
    • Re: Call for testing: patch that helps Wine on 6.x
      ... order to avoid clobbering data in signal info that Wine needs. ... that change is too large to be MFC'd, hence this lighter weight patch. ... I've patched and recompiled world + kernel using your patch. ... the siginfo for signals to not contain garbage. ...
      (freebsd-stable)