Commit 29f265fa authored by Alexandre Julliard's avatar Alexandre Julliard

Set the correct permissions on the PE image sections.

parent 786d2490
...@@ -378,90 +378,6 @@ DWORD PE_fixup_imports( WINE_MODREF *wm ) ...@@ -378,90 +378,6 @@ DWORD PE_fixup_imports( WINE_MODREF *wm )
return 0; return 0;
} }
/***********************************************************************
* do_relocations
*
* Apply the relocations to a mapped PE image
*/
static int do_relocations( char *base, const IMAGE_NT_HEADERS *nt, const char *filename )
{
const IMAGE_DATA_DIRECTORY *dir;
const IMAGE_BASE_RELOCATION *rel;
int delta = base - (char *)nt->OptionalHeader.ImageBase;
dir = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
rel = (IMAGE_BASE_RELOCATION *)(base + dir->VirtualAddress);
WARN("Info: base relocations needed for %s\n", filename);
if (!dir->VirtualAddress || !dir->Size)
{
if (nt->OptionalHeader.ImageBase == 0x400000)
ERR("Standard load address for a Win32 program (0x00400000) not available - security-patched kernel ?\n");
else
ERR( "FATAL: Need to relocate %s from addr %lx, but %s\n",
filename, nt->OptionalHeader.ImageBase,
(nt->FileHeader.Characteristics&IMAGE_FILE_RELOCS_STRIPPED)?
"relocation records are stripped" : "no relocation records present" );
return 0;
}
/* FIXME: If we need to relocate a system DLL (base > 2GB) we should
* really make sure that the *new* base address is also > 2GB.
* Some DLLs really check the MSB of the module handle :-/
*/
if ((nt->OptionalHeader.ImageBase & 0x80000000) && !((DWORD)base & 0x80000000))
ERR( "Forced to relocate system DLL (base > 2GB). This is not good.\n" );
for ( ; ((char *)rel < base + dir->VirtualAddress + dir->Size) && rel->SizeOfBlock;
rel = (IMAGE_BASE_RELOCATION*)((char*)rel + rel->SizeOfBlock))
{
char *page = base + rel->VirtualAddress;
WORD *TypeOffset = (WORD *)(rel + 1);
int i, count = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(*TypeOffset);
if (!count) continue;
/* sanity checks */
if ((char *)rel + rel->SizeOfBlock > base + dir->VirtualAddress + dir->Size ||
page > base + nt->OptionalHeader.SizeOfImage)
{
ERR_(module)("invalid relocation %p,%lx,%ld at %p,%lx,%lx\n",
rel, rel->VirtualAddress, rel->SizeOfBlock,
base, dir->VirtualAddress, dir->Size );
return 0;
}
TRACE_(module)("%ld relocations for page %lx\n", rel->SizeOfBlock, rel->VirtualAddress);
/* patching in reverse order */
for (i = 0 ; i < count; i++)
{
int offset = TypeOffset[i] & 0xFFF;
int type = TypeOffset[i] >> 12;
switch(type)
{
case IMAGE_REL_BASED_ABSOLUTE:
break;
case IMAGE_REL_BASED_HIGH:
*(short*)(page+offset) += HIWORD(delta);
break;
case IMAGE_REL_BASED_LOW:
*(short*)(page+offset) += LOWORD(delta);
break;
case IMAGE_REL_BASED_HIGHLOW:
*(int*)(page+offset) += delta;
/* FIXME: if this is an exported address, fire up enhanced logic */
break;
default:
FIXME_(module)("Unknown/unsupported fixup type %d.\n", type);
break;
}
}
}
return 1;
}
/********************************************************************** /**********************************************************************
* PE_LoadImage * PE_LoadImage
* Load one PE format DLL/EXE into memory * Load one PE format DLL/EXE into memory
...@@ -487,22 +403,10 @@ HMODULE PE_LoadImage( HANDLE hFile, LPCSTR filename, DWORD flags ) ...@@ -487,22 +403,10 @@ HMODULE PE_LoadImage( HANDLE hFile, LPCSTR filename, DWORD flags )
CloseHandle( mapping ); CloseHandle( mapping );
if (!base) return 0; if (!base) return 0;
hModule = (HMODULE)base; /* virus check */
/* perform base relocation, if necessary */
hModule = (HMODULE)base;
nt = PE_HEADER( hModule ); nt = PE_HEADER( hModule );
if (hModule != nt->OptionalHeader.ImageBase)
{
if (!do_relocations( base, nt, filename ))
{
UnmapViewOfFile( base );
SetLastError( ERROR_BAD_EXE_FORMAT );
return 0;
}
}
/* virus check */
if (nt->OptionalHeader.AddressOfEntryPoint) if (nt->OptionalHeader.AddressOfEntryPoint)
{ {
......
...@@ -491,6 +491,67 @@ static void *anon_mmap_aligned( void *base, unsigned int size, int prot, int fla ...@@ -491,6 +491,67 @@ static void *anon_mmap_aligned( void *base, unsigned int size, int prot, int fla
/*********************************************************************** /***********************************************************************
* do_relocations
*
* Apply the relocations to a mapped PE image
*/
static int do_relocations( char *base, const IMAGE_DATA_DIRECTORY *dir,
int delta, DWORD total_size )
{
IMAGE_BASE_RELOCATION *rel;
for (rel = (IMAGE_BASE_RELOCATION *)(base + dir->VirtualAddress);
((char *)rel < base + dir->VirtualAddress + dir->Size) && rel->SizeOfBlock;
rel = (IMAGE_BASE_RELOCATION*)((char*)rel + rel->SizeOfBlock) )
{
char *page = base + rel->VirtualAddress;
WORD *TypeOffset = (WORD *)(rel + 1);
int i, count = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(*TypeOffset);
if (!count) continue;
/* sanity checks */
if ((char *)rel + rel->SizeOfBlock > base + dir->VirtualAddress + dir->Size ||
page > base + total_size)
{
ERR_(module)("invalid relocation %p,%lx,%ld at %p,%lx,%lx\n",
rel, rel->VirtualAddress, rel->SizeOfBlock,
base, dir->VirtualAddress, dir->Size );
return 0;
}
TRACE_(module)("%ld relocations for page %lx\n", rel->SizeOfBlock, rel->VirtualAddress);
/* patching in reverse order */
for (i = 0 ; i < count; i++)
{
int offset = TypeOffset[i] & 0xFFF;
int type = TypeOffset[i] >> 12;
switch(type)
{
case IMAGE_REL_BASED_ABSOLUTE:
break;
case IMAGE_REL_BASED_HIGH:
*(short*)(page+offset) += HIWORD(delta);
break;
case IMAGE_REL_BASED_LOW:
*(short*)(page+offset) += LOWORD(delta);
break;
case IMAGE_REL_BASED_HIGHLOW:
*(int*)(page+offset) += delta;
/* FIXME: if this is an exported address, fire up enhanced logic */
break;
default:
FIXME_(module)("Unknown/unsupported fixup type %d.\n", type);
break;
}
}
}
return 1;
}
/***********************************************************************
* map_image * map_image
* *
* Map an executable (PE format) image into memory. * Map an executable (PE format) image into memory.
...@@ -648,15 +709,65 @@ static LPVOID map_image( HANDLE hmapping, int fd, char *base, DWORD total_size, ...@@ -648,15 +709,65 @@ static LPVOID map_image( HANDLE hmapping, int fd, char *base, DWORD total_size,
} }
} }
/* perform base relocation, if necessary */
if (ptr != base)
{
const IMAGE_DATA_DIRECTORY *relocs;
relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
if (!relocs->VirtualAddress || !relocs->Size)
{
if (nt->OptionalHeader.ImageBase == 0x400000)
ERR("Standard load address for a Win32 program (0x00400000) not available - security-patched kernel ?\n");
else
ERR( "FATAL: Need to relocate module from addr %lx, but there are no relocation records\n",
nt->OptionalHeader.ImageBase );
SetLastError( ERROR_BAD_EXE_FORMAT );
goto error;
}
/* FIXME: If we need to relocate a system DLL (base > 2GB) we should
* really make sure that the *new* base address is also > 2GB.
* Some DLLs really check the MSB of the module handle :-/
*/
if ((nt->OptionalHeader.ImageBase & 0x80000000) && !((DWORD)base & 0x80000000))
ERR( "Forced to relocate system DLL (base > 2GB). This is not good.\n" );
if (!do_relocations( ptr, relocs, ptr - base, total_size ))
{
SetLastError( ERROR_BAD_EXE_FORMAT );
goto error;
}
}
if (removable) hmapping = 0; /* don't keep handle open on removable media */ if (removable) hmapping = 0; /* don't keep handle open on removable media */
if (!(view = VIRTUAL_CreateView( ptr, total_size, 0, if (!(view = VIRTUAL_CreateView( ptr, total_size, 0, VPROT_COMMITTED|VPROT_READ, hmapping )))
VPROT_COMMITTED|VPROT_READ|VPROT_WRITE|VPROT_WRITECOPY,
hmapping )))
{ {
SetLastError( ERROR_OUTOFMEMORY ); SetLastError( ERROR_OUTOFMEMORY );
goto error; goto error;
} }
/* set the image protections */
sec = (IMAGE_SECTION_HEADER*)((char *)&nt->OptionalHeader+nt->FileHeader.SizeOfOptionalHeader);
for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
{
DWORD size = ROUND_SIZE( sec->VirtualAddress, sec->Misc.VirtualSize );
BYTE vprot = VPROT_COMMITTED;
if (sec->Characteristics & IMAGE_SCN_MEM_READ) vprot |= VPROT_READ;
if (sec->Characteristics & IMAGE_SCN_MEM_WRITE) vprot |= VPROT_WRITE|VPROT_WRITECOPY;
if (sec->Characteristics & IMAGE_SCN_MEM_EXECUTE) vprot |= VPROT_EXEC;
/* make sure the import directory is writable */
if (imports && imports->VirtualAddress >= sec->VirtualAddress &&
imports->VirtualAddress < sec->VirtualAddress + size)
vprot |= VPROT_READ|VPROT_WRITE|VPROT_WRITECOPY;
VIRTUAL_SetProt( view, ptr + sec->VirtualAddress, size, vprot );
}
SetLastError( err ); /* restore last error */ SetLastError( err ); /* restore last error */
close( fd ); close( fd );
if (shared_fd != -1) close( shared_fd ); if (shared_fd != -1) close( shared_fd );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment