I am intermittently trying to get Wine to play nicely with a big EDA tool, and it is doing not too badly today with the 20040309 snapshot on Fedora Core 1.
The thing that I think is stopping it working is that whatever is done to stack-shield by the prepending "setarch i386" on invocation is not inherited by the .exe that the program calls. Net result is that I get the "..... security-patched kernel ?" error message from the child process instead of the parent. Progress of a sort.
Is there anything, short of turning off exec-shield entirely, that can be done about this?
The full set of messages it emits (with program identities obscured to avoid identifying the much-cheaper-when-bought-as-windows-binary application) is below. The printer message mentions an extant queue.
----8<--------8<--------8<--------8<--------8<--------8<---- err:dosmem:setup_dos_mem Cannot use first megabyte for DOS address space, please report err:dosmem:setup_dos_mem Cannot use first megabyte for DOS address space, please report err:dosmem:setup_dos_mem Cannot use first megabyte for DOS address space, please report fixme:console:SetConsoleCtrlHandler (0x41a8af,1) - no error checking or testing yet err:comm:GetCommState tcgetattr error 'Invalid argument' fixme:commdlg:PRINTDLG_OpenDefaultPrinter Could not open printer pica_duplex?! fixme:console:SetConsoleCtrlHandler (0x7800f03e,1) - no error checking or testing yet err:virtual:map_image Standard load address for a Win32 program (0x00400000) not available - security-patched kernel ? wine: could not load L"G:\path\to\my\child.exe" as Win32 binary ----8<--------8<--------8<--------8<--------8<--------8<----
Peter
Peter Riocreux par+wine_devel@silistix.com writes:
I am intermittently trying to get Wine to play nicely with a big EDA tool, and it is doing not too badly today with the 20040309 snapshot on Fedora Core 1.
The thing that I think is stopping it working is that whatever is done to stack-shield by the prepending "setarch i386" on invocation is not inherited by the .exe that the program calls. Net result is that I get the "..... security-patched kernel ?" error message from the child process instead of the parent. Progress of a sort.
Is there anything, short of turning off exec-shield entirely, that can be done about this?
Test shows that the system behaves the same after I issue:
echo 0 > /proc/sys/kernel/exec-shield echo 0 > /proc/sys/kernel/exec-shield-randomize
cat /proc/sys/kernel/exec-shield
and
cat /proc/sys/kernel/exec-shield-randomize
both give a 0 back.now.
I am a bit mystified by that. Is the "..... security-patched kernel ?" message that is still there not caused by exec-shield?
Peter
On Thu, 08 Apr 2004 14:28:51 +0100, Peter Riocreux wrote:
I am a bit mystified by that. Is the "..... security-patched kernel ?" message that is still there not caused by exec-shield?
The problem is probably caused by prelink.
Like Mike said, I have a 90% working solution to this sitting in my arch archive. However it's not fully integrated yet. I'll get back to it soon enough I expect, and hopefully me and Mike can merge his efficiency techniques into what I've done...
thanks -mike
Hi Peter,
I'm not familiar with the using "setarch i386" to solve the problem...
I've also been working on the exec-shield problem over the last couple of days. My solution is similar to Mike Hearn's approach, but faster and more compact, since it doesn't require loading of libc twice or static linking with glibc. The idea is to use a staticly linked ELF object, reserve memory and then load the target dynamicly linked object.
It seems to do what I want, but will require a patch or two to wine to use MAP_FIXED when mapping the first megabyte of address space, and to make sure newly forked processes are forked with it as the (pre)loader.
I've attached the source code. The idea is to run it like this:
wld /home/mike/wine/loader/wine-pthread my.exe
Mike
Peter Riocreux wrote:
I am intermittently trying to get Wine to play nicely with a big EDA tool, and it is doing not too badly today with the 20040309 snapshot on Fedora Core 1.
The thing that I think is stopping it working is that whatever is done to stack-shield by the prepending "setarch i386" on invocation is not inherited by the .exe that the program calls. Net result is that I get the "..... security-patched kernel ?" error message from the child process instead of the parent. Progress of a sort.
Is there anything, short of turning off exec-shield entirely, that can be done about this?
CFLAGS=-Wall CC=gcc OBJS=wld.o sysdeps.o
all: wld test
wld: wld.o sysdeps.o $(CC) -nostartfiles -nodefaultlibs -static -Wl,"-Ttext=0x7fff1000" -o $@ $(OBJS)
$(OBJS:.c=.o): sysdeps.h
test: testmain ld-mine.so
testmain: testmain.o $(CC) -Wl,--dynamic-linker=ld-mine.so -o $@ testmain.o
ld-mine.so: testld.o $(CC) -nostartfiles -nodefaultlibs -static -Wl,"-Ttext=0x3eee0000" -o $@ testld.o
clean: rm -f wld $(OBJS) ld-mine.so testld.o testmain testmain.o
/* mini loader for ld.so - x86 Linux 2.4.x+ kernels only
Copyright 2004 Mike McCormack for Codeweavers
Copyright (C) 1995,96,97,98,99,2000,2001,2002 Free Software Foundation, Inc.
The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */
#include <syscall.h> #include "sysdeps.h"
/* * The _start function is the entry and exit point of this program * * It calls wld_start, passing a pointer to the args it receives * then jumps to the address wld_start returns after removing the * first argv[] value, and decrementing argc */ void _start(void); __asm ( ".align 4\n" "\t.global _start\n" "\t.type _start,@function\n" "_start:\n" "\tcall wld_start\n" "\tpop %ebx\n" "\tadd $4,%esp\n" "\tdec %ebx\n" "\tpush %ebx\n" "\tpush %eax\n" "\txor %eax,%eax\n" "\txor %ebx,%ebx\n" "\txor %ecx,%ecx\n" "\tret\n" );
/* * various Linux system calls that we need */ void wld_exit(int val) { asm( "\tint $0x80\n" : :"a"(SYS_exit), "b"(val) ); }
int wld_close(int fd) { int r; asm( "\tint $0x80\n" : "=a"(r) :"a"(SYS_close), "b"(fd) ); return r; }
void* wld_brk(void *end) { void* r; asm( "\tint $0x80\n" : "=a"(r) :"a"(SYS_brk), "b"(end) ); return r; }
#if 0 void* wld_mmap( void *addr, unsigned int len, unsigned int prot, unsigned int flags, int fd, unsigned int pgoff ) { void* r; pgoff = pgoff >> 12; asm("\tpush %ebp\n" "\tmov %6, %ebp\n" "\tint $0x80\n" "\tpop %ebp\n" : "=a"(r) :"a"(SYS_mmap2), "b"(addr), "c"(len), "d"(prot), "S"(flags), "D"(fd), "n"(pgoff) ); return r; } #endif #if 0 void* wld_mmap( void *addr, unsigned int len, unsigned int prot, unsigned int flags, int fd, unsigned int pgoff ); __asm ( "\t.align 4\n" "\t.global wld_mmap\n" "\t.type wld_mmap,@function\n" "wld_mmap:\n" "\tpush %ebx\n" "\tpush %ecx\n" "\tpush %edx\n" "\tpush %esi\n" "\tpush %edi\n" "\tpush %ebp\n" "\tmovl $192, %eax\n" "\tmovl 28(%esp), %ebx\n" "\tmovl 32(%esp), %ecx\n" "\tmovl 36(%esp), %edx\n" "\tmovl 40(%esp), %esi\n" "\tmovl 44(%esp), %edi\n" "\tmovl 48(%esp), %ebp\n" "\tshrl $12, %ebp\n" "\tint $0x80\n" "\tpop %ebp\n" "\tpop %edi\n" "\tpop %esi\n" "\tpop %edx\n" "\tpop %ecx\n" "\tpop %ebx\n" "\tret\n" "wld_mmap_end:\n" "\t.size wld_mmap, wld_mmap_end - wld_mmap\n" ); #endif #if 1 void* wld_mmap( void *addr, unsigned int len, unsigned int prot, unsigned int flags, int fd, unsigned int pgoff ) { void *r; asm( "\tint $0x80\n" :"=a"(r) :"a"(SYS_mmap), "b"(&addr) :"%ecx","%edx" ); return r; }
#endif
int wld_mprotect( const void* address, size_t len, int prot ) { int r; asm( "\tint $0x80\n" : "=a"(r) :"a"(SYS_mprotect), "b"(address), "c"(len), "d"(prot) ); return r; }
int wld_read( int fd, void *buffer, int len ) { int r; asm( "\tint $0x80\n" : "=a"(r) :"a"(SYS_read), "b"(fd), "c"(buffer), "d"(len) ); return r; }
int wld_write( int fd, void *buffer, int len ) { int r; asm( "\tint $0x80\n" : "=a"(r) :"a"(SYS_write), "b"(fd), "c"(buffer), "d"(len) ); return r; }
int wld_open( char *file, int flags, int mode ) { int r; asm( "\tint $0x80\n" : "=a"(r) :"a"(SYS_open), "b"(file), "c"(flags), "d"(mode) ); return r; }
/* mini loader for ld.so - x86 Linux 2.4.x+ kernels only
Copyright 2004 Mike McCormack for Codeweavers
Copyright (C) 1995,96,97,98,99,2000,2001,2002 Free Software Foundation, Inc.
The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */
#include <linux/types.h> #include <linux/fcntl.h> #include <linux/mman.h>
#define LD_SO "/lib/ld-linux.so.2"
/* ELF definitions */ #define ELF_PREFERRED_ADDRESS(loader, maplength, mapstartpref) (mapstartpref) #define ELF_FIXED_ADDRESS(loader, mapstart) ((void) 0)
#define __ELF_NATIVE_CLASS 32 #define MAP_BASE_ADDR(l) 0 #define MAP_COPY MAP_PRIVATE #define ANONFD -1
#define ElfW(type) _ElfW (Elf, __ELF_NATIVE_CLASS, type) #define _ElfW(e,w,t) _ElfW_1 (e, w, _##t) #define _ElfW_1(e,w,t) e##w##t
void wld_exit(int val); int wld_close(int fd); void* wld_brk(void *end); void* wld_mmap( void *addr, unsigned int len, unsigned int prot, unsigned int flags, int fd, unsigned int pgoff ); int wld_mprotect( const void* address, size_t len, int prot ); int wld_read( int fd, void *buffer, int len ); int wld_write( int fd, void *buffer, int len ); int wld_open( char *file, int flags, int mode );
#define __close wld_close #define __mmap wld_mmap #define __mprotect wld_mprotect #define memset __builtin_memset
#define GL(x) x
extern unsigned int GL(dl_pagesize);
/* mini loader for ld.so - x86 Linux 2.4.x+ kernels only
Copyright 2004 Mike McCormack for Codeweavers
Copyright (C) 1995,96,97,98,99,2000,2001,2002 Free Software Foundation, Inc.
The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */
/* * Design notes * * The goal of this program is to be a workaround for exec-shield, as used * by the Linux kernel distributed with Fedora Core and other distros. * * To do this, we implement a small program that reserves memory that is * important to Wine, and then loads the Wine executable and the shared object * loader (ELF interpreter), usually ld-linux.so.2 * * As Wine is i386 specific, we are not too worried about portability issues, * but will do our best to keep the system dependencies (syscalls) seperate to * the rest (ELF loader and printf) part of the program. * * Since we want to be loaded first, we will not link to any other libraries, * including the standard C library (libc) or the dynamic linker itself. Do * do that this program needs to be fully self contained, implementing it's own * library function and system call interface. Since we only need enough * functionality to load an binary, this isn't a problem. * * This program will be invoked as follows: * * wld <full path to ELF executable to be loaded> <args...> * * We will try to set up the stack an memory area so that the program that * loads after us (eg. the wine binary) never knows we were here, except that * areas of memory it needs are already magically reserved. * * The following memory areas are important to Wine: * 0x00000000 - the DOS area * 0x00400000 - the standard Win32 load address * 0x65430000 - the shared heap at * * Before passing control to the loaded binary, we will fix the argc and argv[] * values passed to the program. * * There are a few things that will be different after this program passes * control of execution to the loaded binary: * 1) The _ variable in the environment (will be the name of this exe) * 2) The brk area returned by brk(2) * 3) This program will still be mapped into memory. * 4) The command line kept by the kernel in kernel memory (/proc/self/cmdline) * * Limitations: * - The name of the target ELF executable needs to be a full path name */
/* * References (things I consulted to understand how ELF loading works): * * glibc 2.3.2 elf/dl-load.c * http://www.gnu.org/directory/glibc.html * * Linux 2.6.4 fs/binfmt_elf.c * ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.4.tar.bz2 * * Userland exec, by grugq@hcunix.net * http://cert.uni-stuttgart.de/archive/bugtraq/2004/01/msg00002.html * * The ELF specification: * http://www.linuxbase.org/spec/booksets/LSB-Embedded/LSB-Embedded/book387.htm... */
#include "sysdeps.h"
#include <linux/types.h> #include <linux/fcntl.h> #include <linux/mman.h>
#include <syscall.h> #include <elf.h>
/* debugging */ #undef DUMP_SEGMENTS #undef DUMP_ARG #undef DUMP_AUX_INFO
unsigned int GL(dl_pagesize) = 0x0000;
/* * wld_printf - just the basics * * %x prints a hex number * %s prints a string */ void wld_sprintf(char *str, char *fmt, int *args ) { char *p = fmt;
while( *p ) { if( *p == '%' ) { p++; if( *p == 'x' ) { int ch, i, x = *++args; for(i=7; i>=0; i--) { ch = (x>>(i*4))&0xf; ch += '0'; if(ch>'9') ch+=('A'-10-'0'); *str++ = ch; } } else if( *p == 's' ) { char *s = (char*)*++args; while(*s) *str++ = *s++; } else if( *p == 0 ) break; p++; } *str++ = *p++; } *str = 0; }
int wld_strlen(char *str) { int n = 0; while( str[n] ) n++; return n; }
void wld_printf(char *fmt, ... ) { char buffer[100]; int n;
buffer[0]=0; wld_sprintf(buffer, fmt, (int*)&fmt ); n = wld_strlen( buffer ); wld_write(2, buffer, n); }
void wld_strncpy(char *dest, char *src, int count ) { while( (*dest++ = *src++) && --count ) ; *dest = 0; }
/* * Dump interesting bits of the ELF auxv_t structure that is passed * as the 4th parameter to the _start function */ void wld_dump_auxilary( ElfW(auxv_t) *av ) { for ( ; av->a_type != AT_NULL; av++) switch (av->a_type) { case AT_PAGESZ: GL(dl_pagesize) = av->a_un.a_val; #ifndef DUMP_AUX_INFO break; #else wld_printf("AT_PAGESZ = %x\n",av->a_un.a_val); break; case AT_PHDR: wld_printf("AT_PHDR = %x\n",av->a_un.a_ptr); break; case AT_PHNUM: wld_printf("AT_PHNUM = %x\n",av->a_un.a_val); break; case AT_ENTRY: wld_printf("AT_ENTRY = %x\n",av->a_un.a_val); break; case AT_BASE: wld_printf("AT_BASE = %x\n",av->a_un.a_val); break; #endif } }
/* * wld_set_auxilary * * Set a field of the auxillary structure */ void wld_set_auxilary( ElfW(auxv_t) *av, int type, long int val ) { for ( ; av->a_type != AT_NULL; av++) if( av->a_type == type ) av->a_un.a_val = val; }
/* * wld_map_so * * modelled after _dl_map_object_from_fd() from glibc-2.3.1/elf/dl-load.c * * This function maps the segments from an ELF object, and optionally * stores information about the mapping into the auxv_t structure. */ void* wld_map_so( int fd, void* buf, size_t buflen, ElfW(auxv_t)* av, char* interp, int interp_sz ) { ElfW(Ehdr) *header = buf; ElfW(Phdr) *phdr, *ph; struct link_map { ElfW(Addr) l_addr; ElfW(Dyn) *l_ld; const ElfW(Phdr) *l_phdr; ElfW(Addr) l_entry; ElfW(Half) l_ldnum; ElfW(Half) l_phnum; ElfW(Addr) l_map_start, l_map_end; } lmap,*l = &lmap; /* Scan the program header table, collecting its load commands. */ struct loadcmd { ElfW(Addr) mapstart, mapend, dataend, allocend; off_t mapoff; int prot; } loadcmds[header->e_phnum], *c; size_t nloadcmds = 0, maplength;
header = buf; phdr = (void*) (buf + header->e_phoff);
if( header->e_ident[0] != 0x7f && header->e_ident[0] != 'E' && header->e_ident[0] != 'L' && header->e_ident[0] != 'F' ) { wld_printf("Not an ELF binary... don't know how to load it\n"); return NULL; }
if( header->e_machine != EM_386 ) { wld_printf("Not an i386 ELF binary... don't know how to load it\n"); return NULL; }
maplength = header->e_phnum * sizeof (ElfW(Phdr)); if (header->e_phoff + maplength > (size_t) buflen) { wld_printf("oops... not enough space for ELF headers\n"); wld_exit(1); }
l->l_ld = 0; l->l_addr = 0; l->l_phnum = header->e_phnum; l->l_entry = header->e_entry;
for (ph = phdr; ph < &phdr[l->l_phnum]; ++ph) {
#ifdef DUMP_SEGMENTS wld_printf( "ph = %x\n", ph ); wld_printf( " p_type = %x\n", ph->p_type ); wld_printf( " p_flags = %x\n", ph->p_flags ); wld_printf( " p_offset = %x\n", ph->p_offset ); wld_printf( " p_vaddr = %x\n", ph->p_vaddr ); wld_printf( " p_paddr = %x\n", ph->p_paddr ); wld_printf( " p_filesz = %x\n", ph->p_filesz ); wld_printf( " p_memsz = %x\n", ph->p_memsz ); wld_printf( " p_align = %x\n", ph->p_align ); #endif
switch (ph->p_type) { /* These entries tell us where to find things once the file's segments are mapped in. We record the addresses it says verbatim, and later correct for the run-time load address. */ case PT_DYNAMIC: l->l_ld = (void *) ph->p_vaddr; l->l_ldnum = ph->p_memsz / sizeof (Elf32_Dyn); break;
case PT_PHDR: l->l_phdr = (void *) ph->p_vaddr; break;
case PT_TLS: /* * We don't need to set anything up because we're * emulating the kernel, not ld-linux.so.2 * The ELF loader will set up the TLS data itself. */ break;
case PT_LOAD: { if ((ph->p_align & (GL(dl_pagesize) - 1)) != 0) { wld_printf("ELF load command alignment not page-aligned"); return NULL; } if (((ph->p_vaddr - ph->p_offset) & (ph->p_align - 1)) != 0) { wld_printf("ELF load command address/offset not properly aligned"); return NULL; }
c = &loadcmds[nloadcmds++]; c->mapstart = ph->p_vaddr & ~(ph->p_align - 1); c->mapend = ((ph->p_vaddr + ph->p_filesz + GL(dl_pagesize) - 1) & ~(GL(dl_pagesize) - 1)); c->dataend = ph->p_vaddr + ph->p_filesz; c->allocend = ph->p_vaddr + ph->p_memsz; c->mapoff = ph->p_offset & ~(ph->p_align - 1);
c->prot = 0; if (ph->p_flags & PF_R) c->prot |= PROT_READ; if (ph->p_flags & PF_W) c->prot |= PROT_WRITE; if (ph->p_flags & PF_X) c->prot |= PROT_EXEC; } break;
case PT_INTERP: { char *str = (char *) buf+ph->p_offset; wld_strncpy(interp, str, interp_sz); } break;
case PT_SHLIB: case PT_NOTE: case PT_GNU_EH_FRAME: break;
default: wld_printf("unknown header type %x\n", ph->p_type); break; } }
/* Now process the load commands and map segments into memory. */ c = loadcmds;
/* Length of the sections to be loaded. */ maplength = loadcmds[nloadcmds - 1].allocend - c->mapstart;
if( header->e_type == ET_DYN ) { ElfW(Addr) mappref; mappref = (ELF_PREFERRED_ADDRESS (loader, maplength, c->mapstart) - MAP_BASE_ADDR (l));
/* Remember which part of the address space this object uses. */ l->l_map_start = (ElfW(Addr)) __mmap ((void *) mappref, maplength, c->prot, MAP_COPY | MAP_FILE, fd, c->mapoff); /* wld_printf("set : offset = %x\n", c->mapoff); */ /* wld_printf("l->l_map_start = %x\n", l->l_map_start); */
l->l_map_end = l->l_map_start + maplength; l->l_addr = l->l_map_start - c->mapstart;
__mprotect ((caddr_t) (l->l_addr + c->mapend), loadcmds[nloadcmds - 1].allocend - c->mapend, PROT_NONE); goto postmap; } else { ELF_FIXED_ADDRESS (loader, c->mapstart); }
/* Remember which part of the address space this object uses. */ l->l_map_start = c->mapstart + l->l_addr; l->l_map_end = l->l_map_start + maplength;
while (c < &loadcmds[nloadcmds]) { if (c->mapend > c->mapstart) /* Map the segment contents from the file. */ __mmap ((void *) (l->l_addr + c->mapstart), c->mapend - c->mapstart, c->prot, MAP_FIXED | MAP_COPY | MAP_FILE, fd, c->mapoff);
postmap: if (l->l_phdr == 0 && (ElfW(Off)) c->mapoff <= header->e_phoff && ((size_t) (c->mapend - c->mapstart + c->mapoff) >= header->e_phoff + header->e_phnum * sizeof (ElfW(Phdr)))) /* Found the program header in this segment. */ l->l_phdr = (void *) (c->mapstart + header->e_phoff - c->mapoff);
if (c->allocend > c->dataend) { /* Extra zero pages should appear at the end of this segment, after the data mapped from the file. */ ElfW(Addr) zero, zeroend, zeropage;
zero = l->l_addr + c->dataend; zeroend = l->l_addr + c->allocend; zeropage = ((zero + GL(dl_pagesize) - 1) & ~(GL(dl_pagesize) - 1));
/* * This is different to the dl-load load... * ld-linux.so.2 relies on the whole page being zero'ed */ zeroend = (zeroend +GL(dl_pagesize) - 1) & ~(GL(dl_pagesize) - 1);
if (zeroend < zeropage) { /* All the extra data is in the last page of the segment. We can just zero it. */ zeropage = zeroend; }
if (zeropage > zero) { /* Zero the final part of the last page of the segment. */ if ((c->prot & PROT_WRITE) == 0) { /* Dag nab it. */ __mprotect ((caddr_t) (zero & ~(GL(dl_pagesize) - 1)), GL(dl_pagesize), c->prot|PROT_WRITE); } memset ((void *) zero, '\0', zeropage - zero); if ((c->prot & PROT_WRITE) == 0) __mprotect ((caddr_t) (zero & ~(GL(dl_pagesize) - 1)), GL(dl_pagesize), c->prot); }
if (zeroend > zeropage) { /* Map the remaining zero pages in from the zero fill FD. */ caddr_t mapat; mapat = __mmap ((caddr_t) zeropage, zeroend - zeropage, c->prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED, ANONFD, 0); } }
++c; }
if (l->l_phdr == NULL) { wld_printf("no program header\n"); wld_exit(1); }
(ElfW(Addr)) l->l_phdr += l->l_addr; (ElfW(Addr)) l->l_entry += l->l_addr;
if( !interp ) wld_set_auxilary( av, AT_BASE, l->l_addr ); else { wld_set_auxilary( av, AT_PHDR, (unsigned long)l->l_phdr ); wld_set_auxilary( av, AT_PHNUM, l->l_phnum ); wld_set_auxilary( av, AT_ENTRY, l->l_entry ); }
return (void*)l->l_entry; }
/* * wld_reserve_wine_memory * * This is the reason we are here. * We want to reserve address space so that the kernel doesn't * map stuff there. We do this by getting in first before * anything else is mapped (except this program) and reserve * the memory we want. */ void wld_reserve_wine_memory() { wld_mmap((void*)0x00000000, 0x3fffffff, PROT_NONE, MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0); /* wld_mmap((void*)0x65430000, 0x00400000, PROT_NONE, MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0); */ }
/* * wld_start * * Repeat the actions the kernel would do when loading a dynamically linked .so * Load the ELF interperter ld-linux.so and then binary itself. * * Note, we assume that the binary is a dynamically linked ELF shared object * and that ld-linux.so is its ELF interpreter. */ void* wld_start( int argc ) { int fd; unsigned char buf[0x800], interp[0x100]; void *start; char **argv = (char**) &argc, **p; ElfW(auxv_t)* av;
if( argc < 2 ) { wld_printf( "need to specify a program name\n"); wld_exit(1); }
/* skip over the parameters */ p = ++argv; #ifdef DUMP_ARG { int i; for( i = 0; i<argc; i++ ) wld_printf("argv[%x] = %s\n", i, *p++); if(*p++) wld_printf("argv[argc] not NULL!!\n"); } #else p+=(argc+1); #endif
/* skip over the environment */ while( *p++ ) ;
av = (ElfW(auxv_t)*) p; wld_dump_auxilary( av );
/* reserve memory that Wine needs */ wld_reserve_wine_memory();
/* load the binary itself */ fd = wld_open( argv[1], O_RDONLY, 0); if( fd < 0 ) { wld_printf( "error: fd = %x\n", fd); wld_exit(1); } wld_read( fd, buf, sizeof buf ); interp[0] = 0; start = wld_map_so( fd, buf, sizeof buf, av, interp, sizeof interp ); if( !start ) wld_exit(0); wld_close( fd );
if( interp[0] ) { /* load the dynamic loader */ fd = wld_open( interp, O_RDONLY, 0); if( fd < 0 ) { wld_printf( "error: fd = %x\n", fd); wld_exit(1); } wld_read( fd, buf, sizeof buf ); start = wld_map_so( fd, buf, sizeof buf, av, NULL, 0); wld_close( fd ); } if( !start ) wld_exit(0);
#ifdef DUMP_AUX_INFO wld_printf("New auxillary info:\n"); wld_dump_auxilary( av ); wld_printf("jumping to %x\n", start); #endif
return start; }
Mike McCormack mike@codeweavers.com writes:
Hi Peter,
I'm not familiar with the using "setarch i386" to solve the problem...
I've also been working on the exec-shield problem over the last couple of days. My solution is similar to Mike Hearn's approach, but faster and more compact, since it doesn't require loading of libc twice or static linking with glibc. The idea is to use a staticly linked ELF object, reserve memory and then load the target dynamicly linked object.
It seems to do what I want, but will require a patch or two to wine to use MAP_FIXED when mapping the first megabyte of address space, and to make sure newly forked processes are forked with it as the (pre)loader.
I've attached the source code. The idea is to run it like this:
wld /home/mike/wine/loader/wine-pthread my.exe
Built and tried this out.
First up, I get two instances of the following:
unknown header type 6474E551
It makes the first load work, - giving the same result as the setarch idea (I know (or at least I *think* I know) it is by a different means), but it doesn't solve the inheritance/forking problem. I assume that is what the patches you mention would do.
To make this a bit clearer, A creates children B then C. With setarch or wld when exec-shield is ON, A loads, but B doesn't. With exec-shield OFF, B loads, but C doesn't! I don't understand the latter at all.
In case it is relevant, I suspect that the child processes are created by a built-in scripting language engine.
Am open to trying out other things to get round the remaining part of this.
Peter
Hi Peter,
Yeah, I'm aware of the problem with interitance... there might be a tricky way to fix it by setting WINELOADER to the name of a script that runs "wld $winebinary"... otherwise wine will need to be modified.
I just downloaded the source to setarch. We may be able to incorporate it into wine-glibc.c ...
Mike
Peter Riocreux wrote:
Built and tried this out.
First up, I get two instances of the following:
unknown header type 6474E551
It makes the first load work, - giving the same result as the setarch idea (I know (or at least I *think* I know) it is by a different means), but it doesn't solve the inheritance/forking problem. I assume that is what the patches you mention would do.
To make this a bit clearer, A creates children B then C. With setarch or wld when exec-shield is ON, A loads, but B doesn't. With exec-shield OFF, B loads, but C doesn't! I don't understand the latter at all.
In case it is relevant, I suspect that the child processes are created by a built-in scripting language engine.
Am open to trying out other things to get round the remaining part of this.
Peter
Mike McCormack mike@codeweavers.com writes:
Yeah, I'm aware of the problem with interitance... there might be a tricky way to fix it by setting WINELOADER to the name of a script that runs "wld $winebinary"... otherwise wine will need to be modified.
If wld knew (hardcoded or from an environment variable) where to find wine (the binary), no script would be necessary and it would be even simpler. At configure/compile time Wine could know/detect/be told whether the default loader had to be wine (the binary) or wld.
Thinking further, why not, if wld is needed, call what is now wine something else (e.g. winefoo for this discussion) and wld be called wine. Then no source modification is needed to existing wine code and invocation using wine rahter than wld is possible, maintaining users' mental compatibility and script compatibility (IYSWIM).
Peter
On Thu, 8 Apr 2004, Mike McCormack wrote:
I've attached the source code. The idea is to run it like this:
wld /home/mike/wine/loader/wine-pthread my.exe
Cool. One small nit: for consistency, can we name it wineld instead? Or is it winepreld more apropriate? I'm thinking that wineld will seem to be the counterpart of winegcc...
On Thu, 08 Apr 2004 15:10:35 -0400, Dimitrie O. Paun wrote:
Cool. One small nit: for consistency, can we name it wineld instead? Or is it winepreld more apropriate? I'm thinking that wineld will seem to be the counterpart of winegcc...
In the tree I'm working on it'll be called wineclient, as the name we choose for this will be what appears in "ps ax". wineclient and wineserver seem to make more sense than seeing lots of "winepreld" processes, don't you think?
thanks -mike