https://git.reactos.org/?p=reactos.git;a=commitdiff;h=daf9743c7bcffb0eab59abef342b536489da1610

commit daf9743c7bcffb0eab59abef342b536489da1610
Author:     Pierre Schweitzer <pie...@reactos.org>
AuthorDate: Thu Dec 20 08:49:00 2018 +0100
Commit:     Pierre Schweitzer <pie...@reactos.org>
CommitDate: Thu Dec 20 08:50:51 2018 +0100

    [NTOSKRNL] Check that caller has the priviliege to unload a driver
    
    Also, probe the service name when unloading a driver if called from
    user-mode. This will avoid that userland applications can trigger an
    invalid read in the kernel (and thus, a BSOD).
    
    CORE-15468
---
 ntoskrnl/io/iomgr/driver.c | 47 ++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 41 insertions(+), 6 deletions(-)

diff --git a/ntoskrnl/io/iomgr/driver.c b/ntoskrnl/io/iomgr/driver.c
index 4e1814dcab..a1584f5810 100644
--- a/ntoskrnl/io/iomgr/driver.c
+++ b/ntoskrnl/io/iomgr/driver.c
@@ -1187,17 +1187,43 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, 
BOOLEAN UnloadPnpDrivers)
     NTSTATUS Status;
     PWSTR Start;
     BOOLEAN SafeToUnload = TRUE;
-
-    DPRINT("IopUnloadDriver('%wZ', %u)\n", DriverServiceName, 
UnloadPnpDrivers);
+    KPROCESSOR_MODE PreviousMode;
+    UNICODE_STRING CapturedServiceName;
 
     PAGED_CODE();
 
+    PreviousMode = ExGetPreviousMode();
+
+    /* Need the appropriate priviliege */
+    if (!SeSinglePrivilegeCheck(SeLoadDriverPrivilege, PreviousMode))
+    {
+        DPRINT1("No unload privilege!\n");
+        return STATUS_PRIVILEGE_NOT_HELD;
+    }
+
+    /* Capture the service name */
+    Status = ProbeAndCaptureUnicodeString(&CapturedServiceName, PreviousMode, 
DriverServiceName);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    DPRINT("IopUnloadDriver('%wZ', %u)\n", &CapturedServiceName, 
UnloadPnpDrivers);
+
+
+    /* We need a service name */
+    if (CapturedServiceName.Length == 0)
+    {
+        ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
+        return STATUS_INVALID_PARAMETER;
+    }
+
     /*
      * Get the service name from the registry key name
      */
-    Start = wcsrchr(DriverServiceName->Buffer, L'\\');
+    Start = wcsrchr(CapturedServiceName.Buffer, L'\\');
     if (Start == NULL)
-        Start = DriverServiceName->Buffer;
+        Start = CapturedServiceName.Buffer;
     else
         Start++;
 
@@ -1211,7 +1237,11 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, 
BOOLEAN UnloadPnpDrivers)
     ObjectName.Buffer = ExAllocatePoolWithTag(PagedPool,
                                               ObjectName.MaximumLength,
                                               TAG_IO);
-    if (!ObjectName.Buffer) return STATUS_INSUFFICIENT_RESOURCES;
+    if (!ObjectName.Buffer)
+    {
+        ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
     wcscpy(ObjectName.Buffer, DRIVER_ROOT_NAME);
     memcpy(ObjectName.Buffer + 8, Start, ObjectName.Length - 8 * 
sizeof(WCHAR));
     ObjectName.Buffer[ObjectName.Length/sizeof(WCHAR)] = UNICODE_NULL;
@@ -1232,6 +1262,7 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, 
BOOLEAN UnloadPnpDrivers)
     {
         DPRINT1("Can't locate driver object for %wZ\n", &ObjectName);
         ExFreePoolWithTag(ObjectName.Buffer, TAG_IO);
+        ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
         return Status;
     }
 
@@ -1243,6 +1274,7 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, 
BOOLEAN UnloadPnpDrivers)
     {
         DPRINT1("Driver deletion pending\n");
         ObDereferenceObject(DriverObject);
+        ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
         return STATUS_DELETE_PENDING;
     }
 
@@ -1258,11 +1290,14 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, 
BOOLEAN UnloadPnpDrivers)
     QueryTable[0].EntryContext = &ImagePath;
 
     Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
-                                    DriverServiceName->Buffer,
+                                    CapturedServiceName.Buffer,
                                     QueryTable,
                                     NULL,
                                     NULL);
 
+    /* We no longer need service name */
+    ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
+
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);

Reply via email to