ntdll: Separate image relocation from NtMapViewOfSection.
This commit is contained in:
parent
9e8b58ee18
commit
e67a00b466
@ -799,15 +799,6 @@ static void test_image_mapping(const char *dll_name, DWORD scn_page_access, BOOL
|
|||||||
size = 0;
|
size = 0;
|
||||||
status = pNtMapViewOfSection(hmap, GetCurrentProcess(), &addr2, 0, 0, &offset,
|
status = pNtMapViewOfSection(hmap, GetCurrentProcess(), &addr2, 0, 0, &offset,
|
||||||
&size, 1 /* ViewShare */, 0, PAGE_READONLY);
|
&size, 1 /* ViewShare */, 0, PAGE_READONLY);
|
||||||
/* FIXME: remove once Wine is fixed */
|
|
||||||
if (status != STATUS_IMAGE_NOT_AT_BASE)
|
|
||||||
{
|
|
||||||
todo_wine {
|
|
||||||
ok(status == STATUS_IMAGE_NOT_AT_BASE, "expected STATUS_IMAGE_NOT_AT_BASE, got %x\n", status);
|
|
||||||
ok(addr2 != 0, "mapped address should be valid\n");
|
|
||||||
}
|
|
||||||
goto wine_is_broken;
|
|
||||||
}
|
|
||||||
ok(status == STATUS_IMAGE_NOT_AT_BASE, "expected STATUS_IMAGE_NOT_AT_BASE, got %x\n", status);
|
ok(status == STATUS_IMAGE_NOT_AT_BASE, "expected STATUS_IMAGE_NOT_AT_BASE, got %x\n", status);
|
||||||
ok(addr2 != 0, "mapped address should be valid\n");
|
ok(addr2 != 0, "mapped address should be valid\n");
|
||||||
ok(addr2 != addr1, "mapped addresses should be different\n");
|
ok(addr2 != addr1, "mapped addresses should be different\n");
|
||||||
@ -861,7 +852,6 @@ static void test_image_mapping(const char *dll_name, DWORD scn_page_access, BOOL
|
|||||||
ok(ret, "FreeLibrary error %d\n", GetLastError());
|
ok(ret, "FreeLibrary error %d\n", GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
wine_is_broken:
|
|
||||||
status = pNtUnmapViewOfSection(GetCurrentProcess(), addr1);
|
status = pNtUnmapViewOfSection(GetCurrentProcess(), addr1);
|
||||||
ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %x\n", status);
|
ok(status == STATUS_SUCCESS, "NtUnmapViewOfSection error %x\n", status);
|
||||||
|
|
||||||
|
@ -1656,6 +1656,81 @@ static void set_security_cookie( void *module, SIZE_T len )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NTSTATUS perform_relocations( void *module, SIZE_T len )
|
||||||
|
{
|
||||||
|
IMAGE_NT_HEADERS *nt;
|
||||||
|
char *base;
|
||||||
|
IMAGE_BASE_RELOCATION *rel, *end;
|
||||||
|
const IMAGE_DATA_DIRECTORY *relocs;
|
||||||
|
const IMAGE_SECTION_HEADER *sec;
|
||||||
|
INT_PTR delta;
|
||||||
|
ULONG protect_old[96], i;
|
||||||
|
|
||||||
|
nt = RtlImageNtHeader( module );
|
||||||
|
base = (char *)nt->OptionalHeader.ImageBase;
|
||||||
|
|
||||||
|
assert( module != base );
|
||||||
|
|
||||||
|
/* no relocations are performed on non page-aligned binaries */
|
||||||
|
if (nt->OptionalHeader.SectionAlignment < page_size)
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
|
if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL) && NtCurrentTeb()->Peb->ImageBaseAddress)
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
|
relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
|
||||||
|
|
||||||
|
if ((nt->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED) ||
|
||||||
|
!relocs->VirtualAddress || !relocs->Size)
|
||||||
|
{
|
||||||
|
WARN( "Need to relocate module from %p to %p, but there are no relocation records\n",
|
||||||
|
base, module );
|
||||||
|
return STATUS_CONFLICTING_ADDRESSES;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nt->FileHeader.NumberOfSections > sizeof(protect_old)/sizeof(protect_old[0]))
|
||||||
|
return STATUS_INVALID_IMAGE_FORMAT;
|
||||||
|
|
||||||
|
sec = (const IMAGE_SECTION_HEADER *)((const char *)&nt->OptionalHeader +
|
||||||
|
nt->FileHeader.SizeOfOptionalHeader);
|
||||||
|
for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
|
||||||
|
{
|
||||||
|
void *addr = get_rva( module, sec[i].VirtualAddress );
|
||||||
|
SIZE_T size = sec[i].SizeOfRawData;
|
||||||
|
NtProtectVirtualMemory( NtCurrentProcess(), &addr,
|
||||||
|
&size, PAGE_READWRITE, &protect_old[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE( "relocating from %p-%p to %p-%p\n",
|
||||||
|
base, base + len, module, (char *)module + len );
|
||||||
|
|
||||||
|
rel = get_rva( module, relocs->VirtualAddress );
|
||||||
|
end = get_rva( module, relocs->VirtualAddress + relocs->Size );
|
||||||
|
delta = (char *)module - base;
|
||||||
|
|
||||||
|
while (rel < end - 1 && rel->SizeOfBlock)
|
||||||
|
{
|
||||||
|
if (rel->VirtualAddress >= len)
|
||||||
|
{
|
||||||
|
WARN( "invalid address %p in relocation %p\n", get_rva( module, rel->VirtualAddress ), rel );
|
||||||
|
return STATUS_ACCESS_VIOLATION;
|
||||||
|
}
|
||||||
|
rel = LdrProcessRelocationBlock( get_rva( module, rel->VirtualAddress ),
|
||||||
|
(rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT),
|
||||||
|
(USHORT *)(rel + 1), delta );
|
||||||
|
if (!rel) return STATUS_INVALID_IMAGE_FORMAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
|
||||||
|
{
|
||||||
|
void *addr = get_rva( module, sec[i].VirtualAddress );
|
||||||
|
SIZE_T size = sec[i].SizeOfRawData;
|
||||||
|
NtProtectVirtualMemory( NtCurrentProcess(), &addr,
|
||||||
|
&size, protect_old[i], &protect_old[i] );
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* load_native_dll (internal)
|
* load_native_dll (internal)
|
||||||
@ -1681,7 +1756,17 @@ static NTSTATUS load_native_dll( LPCWSTR load_path, LPCWSTR name, HANDLE file,
|
|||||||
module = NULL;
|
module = NULL;
|
||||||
status = NtMapViewOfSection( mapping, NtCurrentProcess(),
|
status = NtMapViewOfSection( mapping, NtCurrentProcess(),
|
||||||
&module, 0, 0, &size, &len, ViewShare, 0, PAGE_EXECUTE_READ );
|
&module, 0, 0, &size, &len, ViewShare, 0, PAGE_EXECUTE_READ );
|
||||||
if (status < 0) goto done;
|
|
||||||
|
/* perform base relocation, if necessary */
|
||||||
|
|
||||||
|
if (status == STATUS_IMAGE_NOT_AT_BASE)
|
||||||
|
status = perform_relocations( module, len );
|
||||||
|
|
||||||
|
if (status != STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
if (module) NtUnmapViewOfSection( NtCurrentProcess(), module );
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
/* create the MODREF */
|
/* create the MODREF */
|
||||||
|
|
||||||
|
@ -1073,7 +1073,6 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, SIZE_T total_siz
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
struct file_view *view = NULL;
|
struct file_view *view = NULL;
|
||||||
char *ptr, *header_end, *header_start;
|
char *ptr, *header_end, *header_start;
|
||||||
INT_PTR delta = 0;
|
|
||||||
|
|
||||||
/* zero-map the whole range */
|
/* zero-map the whole range */
|
||||||
|
|
||||||
@ -1236,47 +1235,6 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, SIZE_T total_siz
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* perform base relocation, if necessary */
|
|
||||||
|
|
||||||
if (ptr != base &&
|
|
||||||
((nt->FileHeader.Characteristics & IMAGE_FILE_DLL) ||
|
|
||||||
!NtCurrentTeb()->Peb->ImageBaseAddress) )
|
|
||||||
{
|
|
||||||
IMAGE_BASE_RELOCATION *rel, *end;
|
|
||||||
const IMAGE_DATA_DIRECTORY *relocs;
|
|
||||||
|
|
||||||
if (nt->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
|
|
||||||
{
|
|
||||||
WARN_(module)( "Need to relocate module from %p to %p, but there are no relocation records\n",
|
|
||||||
base, ptr );
|
|
||||||
status = STATUS_CONFLICTING_ADDRESSES;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE_(module)( "relocating from %p-%p to %p-%p\n",
|
|
||||||
base, base + total_size, ptr, ptr + total_size );
|
|
||||||
|
|
||||||
relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
|
|
||||||
rel = (IMAGE_BASE_RELOCATION *)(ptr + relocs->VirtualAddress);
|
|
||||||
end = (IMAGE_BASE_RELOCATION *)(ptr + relocs->VirtualAddress + relocs->Size);
|
|
||||||
delta = ptr - base;
|
|
||||||
|
|
||||||
while (rel < end - 1 && rel->SizeOfBlock)
|
|
||||||
{
|
|
||||||
if (rel->VirtualAddress >= total_size)
|
|
||||||
{
|
|
||||||
WARN_(module)( "invalid address %p in relocation %p\n", ptr + rel->VirtualAddress, rel );
|
|
||||||
status = STATUS_ACCESS_VIOLATION;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
rel = LdrProcessRelocationBlock( ptr + rel->VirtualAddress,
|
|
||||||
(rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT),
|
|
||||||
(USHORT *)(rel + 1), delta );
|
|
||||||
if (!rel) goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set the image protections */
|
/* set the image protections */
|
||||||
|
|
||||||
VIRTUAL_SetProt( view, ptr, ROUND_SIZE( 0, header_size ), VPROT_COMMITTED | VPROT_READ );
|
VIRTUAL_SetProt( view, ptr, ROUND_SIZE( 0, header_size ), VPROT_COMMITTED | VPROT_READ );
|
||||||
@ -1313,7 +1271,7 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, SIZE_T total_siz
|
|||||||
|
|
||||||
*addr_ptr = ptr;
|
*addr_ptr = ptr;
|
||||||
#ifdef VALGRIND_LOAD_PDB_DEBUGINFO
|
#ifdef VALGRIND_LOAD_PDB_DEBUGINFO
|
||||||
VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, delta);
|
VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, ptr - base);
|
||||||
#endif
|
#endif
|
||||||
if (ptr != base) return STATUS_IMAGE_NOT_AT_BASE;
|
if (ptr != base) return STATUS_IMAGE_NOT_AT_BASE;
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user