[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
This commit is contained in:
Pierre Schweitzer 2018-12-20 08:49:00 +01:00
parent bc5acd8102
commit daf9743c7b
No known key found for this signature in database
GPG key ID: 7545556C3D585B0B

View file

@ -1187,17 +1187,43 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
NTSTATUS Status; NTSTATUS Status;
PWSTR Start; PWSTR Start;
BOOLEAN SafeToUnload = TRUE; BOOLEAN SafeToUnload = TRUE;
KPROCESSOR_MODE PreviousMode;
DPRINT("IopUnloadDriver('%wZ', %u)\n", DriverServiceName, UnloadPnpDrivers); UNICODE_STRING CapturedServiceName;
PAGED_CODE(); 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 * Get the service name from the registry key name
*/ */
Start = wcsrchr(DriverServiceName->Buffer, L'\\'); Start = wcsrchr(CapturedServiceName.Buffer, L'\\');
if (Start == NULL) if (Start == NULL)
Start = DriverServiceName->Buffer; Start = CapturedServiceName.Buffer;
else else
Start++; Start++;
@ -1211,7 +1237,11 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
ObjectName.Buffer = ExAllocatePoolWithTag(PagedPool, ObjectName.Buffer = ExAllocatePoolWithTag(PagedPool,
ObjectName.MaximumLength, ObjectName.MaximumLength,
TAG_IO); 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); wcscpy(ObjectName.Buffer, DRIVER_ROOT_NAME);
memcpy(ObjectName.Buffer + 8, Start, ObjectName.Length - 8 * sizeof(WCHAR)); memcpy(ObjectName.Buffer + 8, Start, ObjectName.Length - 8 * sizeof(WCHAR));
ObjectName.Buffer[ObjectName.Length/sizeof(WCHAR)] = UNICODE_NULL; 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); DPRINT1("Can't locate driver object for %wZ\n", &ObjectName);
ExFreePoolWithTag(ObjectName.Buffer, TAG_IO); ExFreePoolWithTag(ObjectName.Buffer, TAG_IO);
ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
return Status; return Status;
} }
@ -1243,6 +1274,7 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
{ {
DPRINT1("Driver deletion pending\n"); DPRINT1("Driver deletion pending\n");
ObDereferenceObject(DriverObject); ObDereferenceObject(DriverObject);
ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
return STATUS_DELETE_PENDING; return STATUS_DELETE_PENDING;
} }
@ -1258,11 +1290,14 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
QueryTable[0].EntryContext = &ImagePath; QueryTable[0].EntryContext = &ImagePath;
Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
DriverServiceName->Buffer, CapturedServiceName.Buffer,
QueryTable, QueryTable,
NULL, NULL,
NULL); NULL);
/* We no longer need service name */
ReleaseCapturedUnicodeString(&CapturedServiceName, PreviousMode);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status); DPRINT1("RtlQueryRegistryValues() failed (Status %x)\n", Status);