winedevice: Apply relocations to kernel mode DLLs whose exports are used by driver.
Alexander Morozov
amorozov at etersoft.ru
Mon Dec 15 08:39:53 CST 2008
Changelog:
winedevice: Apply relocations to kernel mode DLLs whose exports are used by
driver.
A driver can call functions exported by kernel mode DLLs which are non
page-aligned binaries. Wine does not apply relocations to these DLLs. This
can result in a crash.
Test: ftp://ftp.etersoft.ru/pub/people/amorozov/exportdrv2.tar.bz2
-------------- next part --------------
From 4e1971097324b946b17ba5566c0c8830d360c3b9 Mon Sep 17 00:00:00 2001
From: Alexander Morozov <amorozov at etersoft.ru>
Date: Mon, 15 Dec 2008 17:16:22 +0300
Subject: [PATCH] winedevice: Apply relocations to kernel mode DLLs whose exports are used by driver.
---
programs/winedevice/device.c | 101 +++++++++++++++++++++++++++++++++++++-----
1 files changed, 90 insertions(+), 11 deletions(-)
diff --git a/programs/winedevice/device.c b/programs/winedevice/device.c
index 7afe97e..c3f8e14 100644
--- a/programs/winedevice/device.c
+++ b/programs/winedevice/device.c
@@ -34,12 +34,19 @@
#include "ddk/wdm.h"
#include "wine/unicode.h"
#include "wine/debug.h"
+#include "wine/list.h"
WINE_DEFAULT_DEBUG_CHANNEL(winedevice);
WINE_DECLARE_DEBUG_CHANNEL(relay);
extern NTSTATUS wine_ntoskrnl_main_loop( HANDLE stop_event );
+struct module_name
+{
+ struct list entry;
+ LPWSTR nameW;
+};
+
static WCHAR *driver_name;
static SERVICE_STATUS_HANDLE service_handle;
static HKEY driver_hkey;
@@ -61,18 +68,17 @@ static LDR_MODULE *find_ldr_module( HMODULE module )
return NULL;
}
-/* load the driver module file */
-static HMODULE load_driver_module( const WCHAR *name )
+/* apply relocations to non page-aligned module */
+static BOOL apply_relocations( HMODULE module, const WCHAR *name )
{
const IMAGE_NT_HEADERS *nt;
size_t page_size = getpagesize();
int delta;
- HMODULE module = LoadLibraryW( name );
- if (!module) return NULL;
+ if (!module) return FALSE;
nt = RtlImageNtHeader( module );
- if (!(delta = (char *)module - (char *)nt->OptionalHeader.ImageBase)) return module;
+ if (!(delta = (char *)module - (char *)nt->OptionalHeader.ImageBase)) return TRUE;
/* the loader does not apply relocations to non page-aligned binaries or executables,
* we have to do it ourselves */
@@ -84,7 +90,8 @@ static HMODULE load_driver_module( const WCHAR *name )
DWORD old;
IMAGE_BASE_RELOCATION *rel, *end;
- if ((rel = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_BASERELOC, &size )))
+ if ((rel = RtlImageDirectoryEntryToData( module, TRUE,
+ IMAGE_DIRECTORY_ENTRY_BASERELOC, &size )))
{
WINE_TRACE( "%s: relocating from %p to %p\n",
wine_dbgstr_w(name), (char *)module - delta, module );
@@ -96,15 +103,87 @@ static HMODULE load_driver_module( const WCHAR *name )
rel = LdrProcessRelocationBlock( page, (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT),
(USHORT *)(rel + 1), delta );
if (old != PAGE_EXECUTE_READWRITE) VirtualProtect( page, page_size, old, NULL );
- if (!rel) goto error;
+ if (!rel) return FALSE;
}
}
}
- return module;
+ return TRUE;
+}
-error:
- FreeLibrary( module );
- return NULL;
+/* recursively add all imports of module to list */
+static BOOL add_imports( HMODULE module, struct list *modules )
+{
+ struct module_name *dll_name, *elem;
+ IMAGE_IMPORT_DESCRIPTOR *import;
+ ULONG size;
+ char *name;
+ LPWSTR nameW;
+
+ import = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size );
+ while (import && import->FirstThunk)
+ {
+ name = (char *)module + import->Name;
+ size = (strlen(name) + 1) * sizeof(WCHAR);
+ nameW = HeapAlloc( GetProcessHeap(), 0, size );
+ if (!nameW) return FALSE;
+ MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, size );
+ LIST_FOR_EACH_ENTRY( elem, modules, struct module_name, entry )
+ {
+ if (!strcmpiW( elem->nameW, nameW ))
+ {
+ HeapFree( GetProcessHeap(), 0, nameW );
+ nameW = NULL;
+ break;
+ }
+ }
+ if (nameW)
+ {
+ dll_name = HeapAlloc( GetProcessHeap(), 0, sizeof(*dll_name) );
+ if (!dll_name)
+ {
+ HeapFree( GetProcessHeap(), 0, nameW );
+ return FALSE;
+ }
+ dll_name->nameW = nameW;
+ list_add_tail( modules, &dll_name->entry );
+ if (!add_imports( GetModuleHandleW( dll_name->nameW ), modules ))
+ return FALSE;
+ }
+ ++import;
+ }
+ return TRUE;
+}
+
+/* load the driver module file */
+static HMODULE load_driver_module( const WCHAR *name )
+{
+ struct module_name *dll_name, *elem;
+ struct list modules = LIST_INIT( modules );
+ HMODULE module = LoadLibraryW( name );
+ BOOL ret;
+
+ ret = apply_relocations( module, name );
+ if (ret) ret = add_imports( module, &modules );
+ if (ret)
+ {
+ LIST_FOR_EACH_ENTRY( dll_name, &modules, struct module_name, entry )
+ {
+ ret = apply_relocations( GetModuleHandleW( dll_name->nameW ), dll_name->nameW );
+ if (!ret) break;
+ }
+ }
+ LIST_FOR_EACH_ENTRY_SAFE( dll_name, elem, &modules, struct module_name, entry )
+ {
+ list_remove( &dll_name->entry );
+ HeapFree( GetProcessHeap(), 0, dll_name->nameW );
+ HeapFree( GetProcessHeap(), 0, dll_name );
+ }
+ if (!ret)
+ {
+ FreeLibrary( module );
+ return NULL;
+ }
+ return module;
}
/* call the driver init entry point */
--
1.6.0.2.GIT
More information about the wine-patches
mailing list