Author: sir_richard
Date: Wed Apr 21 16:14:45 2010
New Revision: 46978
URL:
http://svn.reactos.org/svn/reactos?rev=46978&view=rev
Log:
[NTOS]: Support unload of system modules by parsing the LoadedImports (implement
MiDereferenceImports which was just a stub) and calling MiCallDllUnloadAndUnloadDll.
[NTOS]: Fix a bug in MiClearImports.
Modified:
trunk/reactos/ntoskrnl/mm/sysldr.c
Modified: trunk/reactos/ntoskrnl/mm/sysldr.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/sysldr.c?rev=4…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/sysldr.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/sysldr.c [iso-8859-1] Wed Apr 21 16:14:45 2010
@@ -191,53 +191,10 @@
return Status;
}
-NTSTATUS
-NTAPI
-MiDereferenceImports(IN PLOAD_IMPORTS ImportList)
-{
- SIZE_T i;
-
- /* Check if there's no imports or if we're a boot driver */
- if ((ImportList == (PVOID)-1) ||
- (ImportList == (PVOID)-2) ||
- (ImportList->Count == 0))
- {
- /* Then there's nothing to do */
- return STATUS_SUCCESS;
- }
-
- /* Otherwise, FIXME */
- DPRINT1("%u imports not dereferenced!\n", ImportList->Count);
- for (i = 0; i < ImportList->Count; i++)
- {
- DPRINT1("%wZ <%wZ>\n",
&ImportList->Entry[i]->FullDllName,
&ImportList->Entry[i]->BaseDllName);
- }
- return STATUS_UNSUCCESSFUL;
-}
-
-VOID
-NTAPI
-MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
-{
- PAGED_CODE();
-
- /* Check if there's no imports or we're a boot driver or only one entry */
- if ((LdrEntry->LoadedImports == (PVOID)-1) ||
- (LdrEntry->LoadedImports == (PVOID)-2) ||
- ((ULONG_PTR)LdrEntry->LoadedImports & 1))
- {
- /* Nothing to do */
- return;
- }
-
- /* Otherwise, free the import list */
- ExFreePool(LdrEntry->LoadedImports);
-}
-
PVOID
NTAPI
-MiFindExportedRoutineByName(IN PVOID DllBase,
- IN PANSI_STRING ExportName)
+MiLocateExportName(IN PVOID DllBase,
+ IN PCHAR ExportName)
{
PULONG NameTable;
PUSHORT OrdinalTable;
@@ -270,7 +227,7 @@
Mid = (Low + High) >> 1;
/* Compare name */
- Ret = strcmp(ExportName->Buffer, (PCHAR)DllBase + NameTable[Mid]);
+ Ret = strcmp(ExportName, (PCHAR)DllBase + NameTable[Mid]);
if (Ret < 0)
{
/* Update high */
@@ -299,16 +256,203 @@
ExportDirectory->AddressOfFunctions);
Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
- /* We found it! */
- ASSERT(!(Function > (PVOID)ExportDirectory) &&
- (Function < (PVOID)((ULONG_PTR)ExportDirectory + ExportSize)));
+ /* Check if the function is actually a forwarder */
+ if (((ULONG_PTR)Function > (ULONG_PTR)ExportDirectory) &&
+ ((ULONG_PTR)Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
+ {
+ /* It is, fail */
+ return NULL;
+ }
+
+ /* We found it */
return Function;
+}
+
+NTSTATUS
+NTAPI
+MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
+ IN PLIST_ENTRY ListHead)
+{
+ UNICODE_STRING ServicesKeyName = RTL_CONSTANT_STRING(
+ L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
+ PMM_DLL_INITIALIZE DllInit;
+ UNICODE_STRING RegPath, ImportName;
+ NTSTATUS Status;
+
+ /* Try to see if the image exports a DllInitialize routine */
+ DllInit = (PMM_DLL_INITIALIZE)MiLocateExportName(LdrEntry->DllBase,
+ "DllInitialize");
+ if (!DllInit) return STATUS_SUCCESS;
+
+ /* Do a temporary copy of BaseDllName called ImportName
+ * because we'll alter the length of the string
+ */
+ ImportName.Length = LdrEntry->BaseDllName.Length;
+ ImportName.MaximumLength = LdrEntry->BaseDllName.MaximumLength;
+ ImportName.Buffer = LdrEntry->BaseDllName.Buffer;
+
+ /* Obtain the path to this dll's service in the registry */
+ RegPath.MaximumLength = ServicesKeyName.Length +
+ ImportName.Length + sizeof(UNICODE_NULL);
+ RegPath.Buffer = ExAllocatePoolWithTag(NonPagedPool,
+ RegPath.MaximumLength,
+ TAG_LDR_WSTR);
+
+ /* Check if this allocation was unsuccessful */
+ if (!RegPath.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
+
+ /* Build and append the service name itself */
+ RegPath.Length = ServicesKeyName.Length;
+ RtlCopyMemory(RegPath.Buffer,
+ ServicesKeyName.Buffer,
+ ServicesKeyName.Length);
+
+ /* Check if there is a dot in the filename */
+ if (wcschr(ImportName.Buffer, L'.'))
+ {
+ /* Remove the extension */
+ ImportName.Length = (wcschr(ImportName.Buffer, L'.') -
+ ImportName.Buffer) * sizeof(WCHAR);
+ }
+
+ /* Append service name (the basename without extension) */
+ RtlAppendUnicodeStringToString(&RegPath, &ImportName);
+
+ /* Now call the DllInit func */
+ DPRINT("Calling DllInit(%wZ)\n", &RegPath);
+ Status = DllInit(&RegPath);
+
+ /* Clean up */
+ ExFreePool(RegPath.Buffer);
+
+ /* Return status value which DllInitialize returned */
+ return Status;
+}
+
+BOOLEAN
+NTAPI
+MiCallDllUnloadAndUnloadDll(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
+{
+ NTSTATUS Status;
+ PMM_DLL_UNLOAD Func;
+ PAGED_CODE();
+
+ /* Get the unload routine */
+ Func = (PMM_DLL_UNLOAD)MiLocateExportName(LdrEntry->DllBase,
"DllUnload");
+ if (!Func) return FALSE;
+
+ /* Call it and check for success */
+ Status = Func();
+ if (!NT_SUCCESS(Status)) return FALSE;
+
+ /* Lie about the load count so we can unload the image */
+ ASSERT(LdrEntry->LoadCount == 0);
+ LdrEntry->LoadCount = 1;
+
+ /* Unload it and return true */
+ MmUnloadSystemImage(LdrEntry);
+ return TRUE;
+}
+
+NTSTATUS
+NTAPI
+MiDereferenceImports(IN PLOAD_IMPORTS ImportList)
+{
+ SIZE_T i;
+ LOAD_IMPORTS SingleEntry;
+ PLDR_DATA_TABLE_ENTRY LdrEntry;
+ PVOID CurrentImports;
+ PAGED_CODE();
+
+ /* Check if there's no imports or if we're a boot driver */
+ if ((ImportList == MM_SYSLDR_NO_IMPORTS) ||
+ (ImportList == MM_SYSLDR_BOOT_LOADED) ||
+ (ImportList->Count == 0))
+ {
+ /* Then there's nothing to do */
+ return STATUS_SUCCESS;
+ }
+
+ /* Check for single-entry */
+ if ((ULONG_PTR)ImportList & MM_SYSLDR_SINGLE_ENTRY)
+ {
+ /* Set it up */
+ SingleEntry.Count = 1;
+ SingleEntry.Entry[0] = (PVOID)((ULONG_PTR)ImportList &~
MM_SYSLDR_SINGLE_ENTRY);
+
+ /* Use this as the import list */
+ ImportList = &SingleEntry;
+ }
+
+ /* Loop the import list */
+ for (i = 0; (i < ImportList->Count) && (ImportList->Entry[i]); i++)
+ {
+ /* Get the entry */
+ LdrEntry = ImportList->Entry[i];
+ DPRINT1("%wZ <%wZ>\n", &LdrEntry->FullDllName,
&LdrEntry->BaseDllName);
+
+ /* Skip boot loaded images */
+ if (LdrEntry->LoadedImports == MM_SYSLDR_BOOT_LOADED) continue;
+
+ /* Dereference the entry */
+ ASSERT(LdrEntry->LoadCount >= 1);
+ if (!--LdrEntry->LoadCount)
+ {
+ /* Save the import data in case unload fails */
+ CurrentImports = LdrEntry->LoadedImports;
+
+ /* This is the last entry */
+ LdrEntry->LoadedImports = MM_SYSLDR_NO_IMPORTS;
+ if (MiCallDllUnloadAndUnloadDll(LdrEntry))
+ {
+ /* Unloading worked, parse this DLL's imports too */
+ MiDereferenceImports(CurrentImports);
+
+ /* Check if we had valid imports */
+ if ((CurrentImports != MM_SYSLDR_BOOT_LOADED) ||
+ (CurrentImports != MM_SYSLDR_NO_IMPORTS) ||
+ !((ULONG_PTR)LdrEntry->LoadedImports &
MM_SYSLDR_SINGLE_ENTRY))
+ {
+ /* Free them */
+ ExFreePool(CurrentImports);
+ }
+ }
+ else
+ {
+ /* Unload failed, restore imports */
+ LdrEntry->LoadedImports = CurrentImports;
+ }
+ }
+ }
+
+ /* Done */
+ return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
+{
+ PAGED_CODE();
+
+ /* Check if there's no imports or we're a boot driver or only one entry */
+ if ((LdrEntry->LoadedImports == MM_SYSLDR_BOOT_LOADED) ||
+ (LdrEntry->LoadedImports == MM_SYSLDR_NO_IMPORTS) ||
+ ((ULONG_PTR)LdrEntry->LoadedImports & MM_SYSLDR_SINGLE_ENTRY))
+ {
+ /* Nothing to do */
+ return;
+ }
+
+ /* Otherwise, free the import list */
+ ExFreePool(LdrEntry->LoadedImports);
+ LdrEntry->LoadedImports = MM_SYSLDR_BOOT_LOADED;
}
PVOID
NTAPI
-MiLocateExportName(IN PVOID DllBase,
- IN PCHAR ExportName)
+MiFindExportedRoutineByName(IN PVOID DllBase,
+ IN PANSI_STRING ExportName)
{
PULONG NameTable;
PUSHORT OrdinalTable;
@@ -341,7 +485,7 @@
Mid = (Low + High) >> 1;
/* Compare name */
- Ret = strcmp(ExportName, (PCHAR)DllBase + NameTable[Mid]);
+ Ret = strcmp(ExportName->Buffer, (PCHAR)DllBase + NameTable[Mid]);
if (Ret < 0)
{
/* Update high */
@@ -370,77 +514,10 @@
ExportDirectory->AddressOfFunctions);
Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
- /* Check if the function is actually a forwarder */
- if (((ULONG_PTR)Function > (ULONG_PTR)ExportDirectory) &&
- ((ULONG_PTR)Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
- {
- /* It is, fail */
- return NULL;
- }
-
- /* We found it */
+ /* We found it! */
+ ASSERT(!(Function > (PVOID)ExportDirectory) &&
+ (Function < (PVOID)((ULONG_PTR)ExportDirectory + ExportSize)));
return Function;
-}
-
-NTSTATUS
-NTAPI
-MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
- IN PLIST_ENTRY ListHead)
-{
- UNICODE_STRING ServicesKeyName = RTL_CONSTANT_STRING(
- L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
- PMM_DLL_INITIALIZE DllInit;
- UNICODE_STRING RegPath, ImportName;
- NTSTATUS Status;
-
- /* Try to see if the image exports a DllInitialize routine */
- DllInit = (PMM_DLL_INITIALIZE)MiLocateExportName(LdrEntry->DllBase,
- "DllInitialize");
- if (!DllInit) return STATUS_SUCCESS;
-
- /* Do a temporary copy of BaseDllName called ImportName
- * because we'll alter the length of the string
- */
- ImportName.Length = LdrEntry->BaseDllName.Length;
- ImportName.MaximumLength = LdrEntry->BaseDllName.MaximumLength;
- ImportName.Buffer = LdrEntry->BaseDllName.Buffer;
-
- /* Obtain the path to this dll's service in the registry */
- RegPath.MaximumLength = ServicesKeyName.Length +
- ImportName.Length + sizeof(UNICODE_NULL);
- RegPath.Buffer = ExAllocatePoolWithTag(NonPagedPool,
- RegPath.MaximumLength,
- TAG_LDR_WSTR);
-
- /* Check if this allocation was unsuccessful */
- if (!RegPath.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
-
- /* Build and append the service name itself */
- RegPath.Length = ServicesKeyName.Length;
- RtlCopyMemory(RegPath.Buffer,
- ServicesKeyName.Buffer,
- ServicesKeyName.Length);
-
- /* Check if there is a dot in the filename */
- if (wcschr(ImportName.Buffer, L'.'))
- {
- /* Remove the extension */
- ImportName.Length = (wcschr(ImportName.Buffer, L'.') -
- ImportName.Buffer) * sizeof(WCHAR);
- }
-
- /* Append service name (the basename without extension) */
- RtlAppendUnicodeStringToString(&RegPath, &ImportName);
-
- /* Now call the DllInit func */
- DPRINT("Calling DllInit(%wZ)\n", &RegPath);
- Status = DllInit(&RegPath);
-
- /* Clean up */
- ExFreePool(RegPath.Buffer);
-
- /* Return status value which DllInitialize returned */
- return Status;
}
VOID