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