Added patches with various PE loader fixes for 8k demos.

This commit is contained in:
Sebastian Lackner 2017-01-11 23:30:14 +01:00
parent 2660a14433
commit 634b0e2877
7 changed files with 298 additions and 0 deletions

View File

@ -0,0 +1,53 @@
From 003af598b273d00e79add3fae33aa6e3d008d93f Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Mon, 2 Jan 2017 15:34:21 +0800
Subject: server: All fields up to CheckSum are mandatory regardless of
SizeOfOptionalHeader value.
---
server/mapping.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/server/mapping.c b/server/mapping.c
index 7fce12f953d..44fbe637933 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -470,11 +470,10 @@ static unsigned int get_image_params( struct mapping *mapping, file_pos_t file_s
if (dos.e_magic != IMAGE_DOS_SIGNATURE) return STATUS_INVALID_IMAGE_NOT_MZ;
pos = dos.e_lfanew;
+ /* zero out header in the case it's not present or partial */
+ memset( &nt, 0, sizeof(nt) );
size = pread( unix_fd, &nt, sizeof(nt), pos );
if (size < sizeof(nt.Signature) + sizeof(nt.FileHeader)) return STATUS_INVALID_IMAGE_FORMAT;
- /* zero out Optional header in the case it's not present or partial */
- size = min( size, sizeof(nt.Signature) + sizeof(nt.FileHeader) + nt.FileHeader.SizeOfOptionalHeader );
- if (size < sizeof(nt)) memset( (char *)&nt + size, 0, sizeof(nt) - size );
if (nt.Signature != IMAGE_NT_SIGNATURE)
{
if (*(WORD *)&nt.Signature == IMAGE_OS2_SIGNATURE) return STATUS_INVALID_IMAGE_NE_FORMAT;
@@ -513,6 +512,10 @@ static unsigned int get_image_params( struct mapping *mapping, file_pos_t file_s
switch (nt.opt.hdr32.Magic)
{
case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
+ /* All fields up to CheckSum are mandatory regardless of SizeOfOptionalHeader value */
+ size = max( nt.FileHeader.SizeOfOptionalHeader, offsetof(IMAGE_OPTIONAL_HEADER32, CheckSum) );
+ if (size < sizeof(nt.opt.hdr32)) memset( (char *)&nt.opt.hdr32 + size, 0, sizeof(nt.opt.hdr32) - size );
+
mapping->image.base = nt.opt.hdr32.ImageBase;
mapping->image.entry_point = nt.opt.hdr32.ImageBase + nt.opt.hdr32.AddressOfEntryPoint;
mapping->image.map_size = ROUND_SIZE( nt.opt.hdr32.SizeOfImage );
@@ -527,6 +530,10 @@ static unsigned int get_image_params( struct mapping *mapping, file_pos_t file_s
mapping->image.checksum = nt.opt.hdr32.CheckSum;
break;
case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
+ /* All fields up to CheckSum are mandatory regardless of SizeOfOptionalHeader value */
+ size = max( nt.FileHeader.SizeOfOptionalHeader, offsetof(IMAGE_OPTIONAL_HEADER64, CheckSum) );
+ if (size < sizeof(nt.opt.hdr64)) memset( (char *)&nt.opt.hdr64 + size, 0, sizeof(nt.opt.hdr64) - size );
+
mapping->image.base = nt.opt.hdr64.ImageBase;
mapping->image.entry_point = nt.opt.hdr64.ImageBase + nt.opt.hdr64.AddressOfEntryPoint;
mapping->image.map_size = ROUND_SIZE( nt.opt.hdr64.SizeOfImage );
--
2.11.0

View File

@ -0,0 +1,31 @@
From bbc0ffba68c07dbd27ba4c33b8b6f1a66783b8ff Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Mon, 2 Jan 2017 15:35:41 +0800
Subject: ntdll: If PE image size is larger than the backed file size then
treat file as removable.
---
dlls/ntdll/virtual.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c
index bdf94063871..1a60fec7cfd 100644
--- a/dlls/ntdll/virtual.c
+++ b/dlls/ntdll/virtual.c
@@ -1163,6 +1163,13 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, SIZE_T total_siz
/* unaligned sections, this happens for native subsystem binaries */
/* in that case Windows simply maps in the whole file */
+ /* if the image size is larger than the backed file size we can't mmap it */
+ if (total_size > ROUND_SIZE( 0, st.st_size ))
+ {
+ close_handle( dup_mapping );
+ dup_mapping = 0;
+ }
+
if (map_file_into_view( view, fd, 0, total_size, 0, VPROT_COMMITTED | VPROT_READ | VPROT_WRITECOPY,
!dup_mapping ) != STATUS_SUCCESS) goto error;
--
2.11.0

View File

@ -0,0 +1,38 @@
From 3f4b08acc72791d1c9bb244c39f0721b8da180de Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Mon, 2 Jan 2017 15:38:48 +0800
Subject: kernel32: On process entry store PEB address in %ebx.
8k demo custom PE loader depends on this.
---
dlls/kernel32/process.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c
index fdf272f61b0..231844b80a7 100644
--- a/dlls/kernel32/process.c
+++ b/dlls/kernel32/process.c
@@ -1073,12 +1073,19 @@ __ASM_GLOBAL_FUNC( call_process_entry,
__ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
"movl %esp,%ebp\n\t"
__ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
+ "pushl %ebx\n\t"
+ __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t")
+ "subl $12,%esp\n\t"
"pushl 4(%ebp)\n\t" /* deliberately mis-align the stack by 8, Doom 3 needs this */
"pushl 4(%ebp)\n\t" /* Driller expects readable address at this offset */
"pushl 4(%ebp)\n\t"
"pushl 8(%ebp)\n\t"
+ "movl 8(%ebp),%ebx\n\t"
"call *12(%ebp)\n\t"
- "leave\n\t"
+ "leal -4(%ebp),%esp\n\t"
+ "popl %ebx\n\t"
+ __ASM_CFI(".cfi_same_value %ebx\n\t")
+ "popl %ebp\n\t"
__ASM_CFI(".cfi_def_cfa %esp,4\n\t")
__ASM_CFI(".cfi_same_value %ebp\n\t")
"ret" )
--
2.11.0

View File

@ -0,0 +1,25 @@
From 0aaa4c217073d55d35e7c85bd8ca44b19bb31ede Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Mon, 2 Jan 2017 15:47:52 +0800
Subject: kernel32/tests: Fix a module reference leak leading to an undeletable
temporary file.
---
dlls/kernel32/tests/loader.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c
index 4f72c3e599b..9ddfd8d7922 100644
--- a/dlls/kernel32/tests/loader.c
+++ b/dlls/kernel32/tests/loader.c
@@ -1457,6 +1457,7 @@ static void test_import_resolution(void)
ok( ptr->thunks[0].u1.Function == 0xdeadbeef, "thunk resolved to %p for %s.%s\n",
(void *)ptr->thunks[0].u1.Function, data.module, data.function.name );
ok( ptr->tls_index == 9999, "wrong tls index %d\n", ptr->tls_index );
+ FreeLibrary( mod2 );
FreeLibrary( mod );
break;
case 2: /* load without IMAGE_FILE_DLL doesn't resolve imports */
--
2.11.0

View File

@ -0,0 +1,112 @@
From b2443dc0deaec8c5e7d70f1bf2004181d2240177 Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Mon, 2 Jan 2017 15:50:01 +0800
Subject: kernel32/tests: Add a PE test image that resembles format of some of
8k demos.
---
dlls/kernel32/tests/loader.c | 39 +++++++++++++++++++++++++++++++++++++--
1 file changed, 37 insertions(+), 2 deletions(-)
diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c
index 9ddfd8d7922..a74647b3d40 100644
--- a/dlls/kernel32/tests/loader.c
+++ b/dlls/kernel32/tests/loader.c
@@ -184,7 +184,7 @@ static DWORD create_test_dll( const IMAGE_DOS_HEADER *dos_header, UINT dos_size,
{
SetLastError(0xdeadbeef);
ret = WriteFile(hfile, &nt_header->OptionalHeader,
- min(nt_header->FileHeader.SizeOfOptionalHeader, sizeof(IMAGE_OPTIONAL_HEADER)),
+ sizeof(IMAGE_OPTIONAL_HEADER),
&dummy, NULL);
ok(ret, "WriteFile error %d\n", GetLastError());
if (nt_header->FileHeader.SizeOfOptionalHeader > sizeof(IMAGE_OPTIONAL_HEADER))
@@ -200,6 +200,8 @@ static DWORD create_test_dll( const IMAGE_DOS_HEADER *dos_header, UINT dos_size,
assert(nt_header->FileHeader.NumberOfSections <= 1);
if (nt_header->FileHeader.NumberOfSections)
{
+ SetFilePointer(hfile, dos_size + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + nt_header->FileHeader.SizeOfOptionalHeader, NULL, FILE_BEGIN);
+
section.SizeOfRawData = 10;
if (nt_header->OptionalHeader.SectionAlignment >= page_size)
@@ -224,6 +226,17 @@ static DWORD create_test_dll( const IMAGE_DOS_HEADER *dos_header, UINT dos_size,
ret = WriteFile(hfile, section_data, sizeof(section_data), &dummy, NULL);
ok(ret, "WriteFile error %d\n", GetLastError());
}
+
+ /* Minimal PE image that Windows7+ is able to load: 268 bytes */
+ size = GetFileSize(hfile, NULL);
+ if (size < 268)
+ {
+ file_align = 268 - size;
+ SetLastError(0xdeadbeef);
+ ret = WriteFile(hfile, filler, file_align, &dummy, NULL);
+ ok(ret, "WriteFile error %d\n", GetLastError());
+ }
+
size = GetFileSize(hfile, NULL);
CloseHandle(hfile);
return size;
@@ -294,7 +307,8 @@ static void query_image_section( int id, const char *dll_name, const IMAGE_NT_HE
image.LoaderFlags, nt_header->OptionalHeader.LoaderFlags );
ok( image.ImageFileSize == file_size || broken(!image.ImageFileSize), /* winxpsp1 */
"%u: ImageFileSize wrong %08x / %08x\n", id, image.ImageFileSize, file_size );
- ok( image.CheckSum == nt_header->OptionalHeader.CheckSum, "%u: CheckSum wrong %08x / %08x\n", id,
+ ok( image.CheckSum == nt_header->OptionalHeader.CheckSum || broken(truncated),
+ "%u: CheckSum wrong %08x / %08x\n", id,
image.CheckSum, nt_header->OptionalHeader.CheckSum );
/* FIXME: needs more work: */
/* image.GpValue */
@@ -444,6 +458,7 @@ static void test_Loader(void)
/* Mandatory are all fields up to SizeOfHeaders, everything else
* is really optional (at least that's true for XP).
*/
+#if 0 /* 32-bit Windows 8 crashes inside of LoadLibrary */
{ sizeof(dos_header),
1, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
sizeof(dos_header) + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum) + sizeof(IMAGE_SECTION_HEADER) + 0x10,
@@ -451,6 +466,7 @@ static void test_Loader(void)
{ ERROR_SUCCESS, ERROR_BAD_EXE_FORMAT, ERROR_INVALID_ADDRESS,
ERROR_NOACCESS }
},
+#endif
{ sizeof(dos_header),
0, FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, CheckSum), 0x200, 0x200,
0xd0, /* beyond of the end of file */
@@ -519,6 +535,14 @@ static void test_Loader(void)
0x40, /* minimal image size that Windows7 accepts */
0,
{ ERROR_SUCCESS }
+ },
+ /* the following data mimics the PE image which 8k demos have */
+ { 0x04,
+ 0, 0x08,
+ 0x04 /* also serves as e_lfanew in the truncated MZ header */, 0x04,
+ 0x200000,
+ 0x40,
+ { ERROR_SUCCESS }
}
};
int i;
@@ -709,6 +733,17 @@ static void test_Loader(void)
ret = FreeLibrary(hlib_as_data_file);
ok(ret, "FreeLibrary error %d\n", GetLastError());
+ SetLastError(0xdeadbeef);
+ ret = DeleteFileA(dll_name);
+ ok(ret, "DeleteFile error %d\n", GetLastError());
+
+ nt_header.OptionalHeader.AddressOfEntryPoint = 0x12345678;
+ file_size = create_test_dll( &dos_header, td[i].size_of_dos_header, &nt_header, dll_name );
+ if (!file_size)
+ {
+ ok(0, "could not create %s\n", dll_name);
+ break;
+ }
query_image_section( i, dll_name, &nt_header );
}
else
--
2.11.0

View File

@ -0,0 +1,2 @@
Fixes: [42125] Various PE loader fixes for 8k demos
Depends: kernel32-Misalign_Workaround

View File

@ -183,6 +183,7 @@ patch_enable_all ()
enable_kernel32_MoveFile="$1"
enable_kernel32_Named_Pipe="$1"
enable_kernel32_NeedCurrentDirectoryForExePath="$1"
enable_kernel32_PE_Loader_Fixes="$1"
enable_kernel32_Profile="$1"
enable_kernel32_SCSI_Sysfs="$1"
enable_kernel32_SetFileCompletionNotificationModes="$1"
@ -744,6 +745,9 @@ patch_enable ()
kernel32-NeedCurrentDirectoryForExePath)
enable_kernel32_NeedCurrentDirectoryForExePath="$2"
;;
kernel32-PE_Loader_Fixes)
enable_kernel32_PE_Loader_Fixes="$2"
;;
kernel32-Profile)
enable_kernel32_Profile="$2"
;;
@ -2351,6 +2355,13 @@ if test "$enable_ntdll_CLI_Images" -eq 1; then
enable_mscoree_CorValidateImage=1
fi
if test "$enable_kernel32_PE_Loader_Fixes" -eq 1; then
if test "$enable_kernel32_Misalign_Workaround" -gt 1; then
abort "Patchset kernel32-Misalign_Workaround disabled, but kernel32-PE_Loader_Fixes depends on that."
fi
enable_kernel32_Misalign_Workaround=1
fi
if test "$enable_kernel32_Named_Pipe" -eq 1; then
if test "$enable_server_Desktop_Refcount" -gt 1; then
abort "Patchset server-Desktop_Refcount disabled, but kernel32-Named_Pipe depends on that."
@ -4619,6 +4630,32 @@ if test "$enable_kernel32_NeedCurrentDirectoryForExePath" -eq 1; then
) >> "$patchlist"
fi
# Patchset kernel32-PE_Loader_Fixes
# |
# | This patchset has the following (direct or indirect) dependencies:
# | * kernel32-Misalign_Workaround
# |
# | This patchset fixes the following Wine bugs:
# | * [#42125] Various PE loader fixes for 8k demos
# |
# | Modified files:
# | * dlls/kernel32/process.c, dlls/kernel32/tests/loader.c, dlls/ntdll/virtual.c, server/mapping.c
# |
if test "$enable_kernel32_PE_Loader_Fixes" -eq 1; then
patch_apply kernel32-PE_Loader_Fixes/0001-server-All-fields-up-to-CheckSum-are-mandatory-regar.patch
patch_apply kernel32-PE_Loader_Fixes/0002-ntdll-If-PE-image-size-is-larger-than-the-backed-fil.patch
patch_apply kernel32-PE_Loader_Fixes/0003-kernel32-On-process-entry-store-PEB-address-in-ebx.patch
patch_apply kernel32-PE_Loader_Fixes/0004-kernel32-tests-Fix-a-module-reference-leak-leading-t.patch
patch_apply kernel32-PE_Loader_Fixes/0005-kernel32-tests-Add-a-PE-test-image-that-resembles-fo.patch
(
echo '+ { "Dmitry Timoshkov", "server: All fields up to CheckSum are mandatory regardless of SizeOfOptionalHeader value.", 1 },';
echo '+ { "Dmitry Timoshkov", "ntdll: If PE image size is larger than the backed file size then treat file as removable.", 1 },';
echo '+ { "Dmitry Timoshkov", "kernel32: On process entry store PEB address in %ebx.", 1 },';
echo '+ { "Dmitry Timoshkov", "kernel32/tests: Fix a module reference leak leading to an undeletable temporary file.", 1 },';
echo '+ { "Dmitry Timoshkov", "kernel32/tests: Add a PE test image that resembles format of some of 8k demos.", 1 },';
) >> "$patchlist"
fi
# Patchset kernel32-Profile
# |
# | This patchset fixes the following Wine bugs: