windows-nt/Source/XPSP1/NT/base/ntos/wmi/wmi.c

3239 lines
105 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1997-1999 Microsoft Corporation
Module Name:
wmi.c
Abstract:
Device driver interface for WMI
Author:
AlanWar
Environment:
Kernel mode
Revision History:
--*/
#include "wmikmp.h"
#ifndef MEMPHIS
#include "evntrace.h"
#include "tracep.h"
#endif
NTSTATUS
WmipOpenCloseCleanup(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
WmipIoControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS WmipObjectToPDO(
PFILE_OBJECT FileObject,
PDEVICE_OBJECT DeviceObject,
PDEVICE_OBJECT *PDO
);
BOOLEAN
WmipFastIoDeviceControl(
IN PFILE_OBJECT FileObject,
IN BOOLEAN Wait,
IN PVOID InputBuffer OPTIONAL,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer OPTIONAL,
IN ULONG OutputBufferLength,
IN ULONG IoControlCode,
OUT PIO_STATUS_BLOCK IoStatus,
IN struct _DEVICE_OBJECT *DeviceObject
);
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
NTSTATUS WmipProbeWnodeAllData(
PWNODE_ALL_DATA Wnode,
ULONG InBufferLen,
ULONG OutBufferLen
);
NTSTATUS WmipProbeWnodeSingleInstance(
PWNODE_SINGLE_INSTANCE Wnode,
ULONG InBufferLen,
ULONG OutBufferLen,
BOOLEAN OutBound
);
NTSTATUS WmipProbeWnodeSingleItem(
PWNODE_SINGLE_ITEM Wnode,
ULONG InBufferLen
);
NTSTATUS WmipProbeWnodeMethodItem(
PWNODE_METHOD_ITEM Wnode,
ULONG InBufferLen,
ULONG OutBufferLen
);
NTSTATUS WmipProbeWnodeWorker(
PWNODE_HEADER WnodeHeader,
ULONG MinWnodeSize,
ULONG InstanceNameOffset,
ULONG DataBlockOffset,
ULONG DataBlockSize,
ULONG InBufferLen,
ULONG OutBufferLen,
BOOLEAN CheckOutBound,
BOOLEAN CheckInBound
);
NTSTATUS
WmipSystemControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS WmipSendWmiIrp(
UCHAR MinorFunction,
ULONG ProviderId,
PVOID DataPath,
ULONG BufferLength,
PVOID Buffer,
PIO_STATUS_BLOCK Iosb
);
NTSTATUS WmipProbeWmiRegRequest(
IN PWMIREGREQUEST Buffer,
IN ULONG InBufferLen,
IN ULONG OutBufferLen
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,WmipDriverEntry)
#pragma alloc_text(INIT,DriverEntry)
#pragma alloc_text(PAGE,WmipOpenCloseCleanup)
#pragma alloc_text(PAGE,WmipIoControl)
#pragma alloc_text(PAGE,WmipForwardWmiIrp)
#pragma alloc_text(PAGE,WmipObjectToPDO)
#pragma alloc_text(PAGE,WmipTranslateFileHandle)
#pragma alloc_text(PAGE,WmipProbeWnodeAllData)
#pragma alloc_text(PAGE,WmipProbeWnodeSingleInstance)
#pragma alloc_text(PAGE,WmipProbeWnodeSingleItem)
#pragma alloc_text(PAGE,WmipProbeWnodeMethodItem)
#pragma alloc_text(PAGE,WmipProbeWnodeWorker)
#pragma alloc_text(PAGE,WmipProbeWmiOpenGuidBlock)
#pragma alloc_text(PAGE,WmipProbeAndCaptureGuidObjectAttributes)
#pragma alloc_text(PAGE,WmipUpdateDeviceStackSize)
#pragma alloc_text(PAGE,WmipSystemControl)
#pragma alloc_text(PAGE,WmipGetDevicePDO)
#pragma alloc_text(PAGE,WmipSendWmiIrp)
#pragma alloc_text(PAGE,WmipProbeWmiRegRequest)
#ifndef MEMPHIS
#pragma alloc_text(PAGE,WmipFastIoDeviceControl)
#endif
#endif
PDEVICE_OBJECT WmipServiceDeviceObject;
//
// This specifies the maximum size that an event can be
ULONG WmipMaxKmWnodeEventSize = DEFAULTMAXKMWNODEEVENTSIZE;
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg("PAGEDATA")
#endif
#if defined(_AMD64_) || defined(_IA64_) || defined(i386)
PVOID WmipDockUndockNotificationEntry;
#endif
KMUTEX WmipSMMutex;
KMUTEX WmipTLMutex;
//
// This maintains the registry path for the wmi device
UNICODE_STRING WmipRegistryPath;
#ifndef MEMPHIS
FAST_IO_DISPATCH WmipFastIoDispatch;
#endif
#ifdef ALLOC_DATA_PRAGMA
#pragma const_seg("PAGECONST")
#endif
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
UNREFERENCED_PARAMETER(DriverObject);
UNREFERENCED_PARAMETER(RegistryPath);
// Never called
return(STATUS_SUCCESS);
}
NTSTATUS
WmipDriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
This is the callback function when we call IoCreateDriver to create a
WMI Driver Object. In this function, we need to remember the
DriverObject, create a device object and then create a Win32 visible
symbolic link name so that the WMI user mode component can access us.
Arguments:
DriverObject - Pointer to the driver object created by the system.
RegistryPath - is NULL.
Return Value:
STATUS_SUCCESS
--*/
{
NTSTATUS Status;
UNICODE_STRING DeviceName;
UNICODE_STRING ServiceSymbolicLinkName;
#ifndef MEMPHIS
PFAST_IO_DISPATCH fastIoDispatch;
#endif
ANSI_STRING AnsiString;
PAGED_CODE();
UNREFERENCED_PARAMETER(RegistryPath);
//
// First thing to do is make sure our critical section has been initalized
//
KeInitializeMutex(&WmipSMMutex, 0);
KeInitializeMutex(&WmipTLMutex, 0);
//
// Initialize internal WMI data structrurs
//
WmipInitializeRegistration(0);
WmipInitializeNotifications();
Status = WmipInitializeDataStructs();
if (! NT_SUCCESS(Status))
{
return(Status);
}
//
// Since Io does not pass a registry path for this device we need to make
// up one
RtlInitAnsiString(&AnsiString,
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\WMI");
Status = RtlAnsiStringToUnicodeString(&WmipRegistryPath,
&AnsiString,
TRUE);
#ifndef MEMPHIS
Status = WmipInitializeSecurity();
if (!NT_SUCCESS(Status))
{
return(Status);
}
#endif
//
// Create the service device object and symbolic link
//
RtlInitUnicodeString( &DeviceName, WMIServiceDeviceObjectName );
Status = IoCreateDevice(
DriverObject,
0,
&DeviceName,
FILE_DEVICE_UNKNOWN,
#ifdef MEMPHIS
0,
#else
FILE_DEVICE_SECURE_OPEN, // No standard device characteristics
#endif
FALSE, // This isn't an exclusive device
&WmipServiceDeviceObject
);
if (! NT_SUCCESS(Status))
{
return(Status);
}
RtlInitUnicodeString( &ServiceSymbolicLinkName,
WMIServiceSymbolicLinkName );
Status = IoCreateSymbolicLink( &ServiceSymbolicLinkName,
&DeviceName );
if (! NT_SUCCESS(Status))
{
IoDeleteDevice( WmipServiceDeviceObject );
return(Status);
}
//
// Establish an initial irp stack size
WmipServiceDeviceObject->StackSize = WmiDeviceStackSize;
//
// Create dispatch entrypoints
//
DriverObject->MajorFunction[IRP_MJ_CREATE] = WmipOpenCloseCleanup;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = WmipOpenCloseCleanup;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = WmipIoControl;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = WmipOpenCloseCleanup;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = WmipSystemControl;
DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = WmipShutdown;
//
// Register for notification of docking events
#if defined(_AMD64_) || defined(_IA64_) || defined(i386)
IoRegisterPlugPlayNotification(
EventCategoryHardwareProfileChange,
0,
NULL,
DriverObject,
WmipDockUndockEventCallback,
NULL,
&WmipDockUndockNotificationEntry);
#endif
//
// We reset this flag to let the IO manager know that the device
// is ready to receive requests. We only do this for the kernel
// dll since the IO manager does it when WMI loads as a normal
// device.
WmipServiceDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
#ifndef MEMPHIS
IoWMIRegistrationControl(WmipServiceDeviceObject,
WMIREG_ACTION_REGISTER);
#endif
#ifndef MEMPHIS
fastIoDispatch = &WmipFastIoDispatch;
RtlZeroMemory(fastIoDispatch, sizeof(FAST_IO_DISPATCH));
fastIoDispatch->SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
fastIoDispatch->FastIoDeviceControl = WmipFastIoDeviceControl;
DriverObject->FastIoDispatch = fastIoDispatch;
RtlZeroMemory(&WmipRefCount[0], MAXLOGGERS*sizeof(ULONG));
RtlZeroMemory(&WmipLoggerContext[0], MAXLOGGERS*sizeof(PWMI_LOGGER_CONTEXT));
WmipStartGlobalLogger(); // Try and see if we need to start this
IoRegisterShutdownNotification(WmipServiceDeviceObject);
#endif // MEMPHIS
SharedUserData->TraceLogging = 0; //Initialize the Heap and Crisec Coll tracing status off
return(Status);
}
NTSTATUS
WmipOpenCloseCleanup(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PAGED_CODE();
UNREFERENCED_PARAMETER(DeviceObject);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
return STATUS_SUCCESS;
}
void WmipUpdateDeviceStackSize(
CCHAR NewStackSize
)
/*++
Routine Description:
This routine will update the stack size that is specified in the WMI
device's device object. This needs to be protected since it can be updated
when a device registers and whenever an irp is forwarded to a device.
WMI needs to maintain a stack size one greater than the stack size of the
largest device stack to which it forwards irps to. Consider a bottom
driver that registers with WMI and has a stack size of 1. If 2 device
attach on top of it then WMI will forward to the topmost in the stack
which would need a stack size of 3, so the original WMI irp (ie the one
created by the IOCTL to the WMI device) would need a stack size of 4.
Arguments:
NewStackSize is the new stack size needed
Return Value:
NT status ccode
--*/
{
PAGED_CODE();
WmipEnterSMCritSection();
if (WmipServiceDeviceObject->StackSize < NewStackSize)
{
WmipServiceDeviceObject->StackSize = NewStackSize;
}
WmipLeaveSMCritSection();
}
NTSTATUS
WmipIoControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS Status;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
ULONG InBufferLen = irpStack->Parameters.DeviceIoControl.InputBufferLength;
ULONG OutBufferLen = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
PVOID Buffer = Irp->AssociatedIrp.SystemBuffer;
PWNODE_HEADER Wnode = (PWNODE_HEADER)Buffer;
ULONG SizeNeeded;
ULONG Ioctl;
PAGED_CODE();
UNREFERENCED_PARAMETER(DeviceObject);
Ioctl = irpStack->Parameters.DeviceIoControl.IoControlCode;
switch (Ioctl)
{
#ifndef MEMPHIS
case IOCTL_WMI_OPEN_GUID:
case IOCTL_WMI_OPEN_GUID_FOR_QUERYSET:
case IOCTL_WMI_OPEN_GUID_FOR_EVENTS:
{
WMIOPENGUIDBLOCK CapturedGuidBlock;
OBJECT_ATTRIBUTES CapturedObjectAttributes;
UNICODE_STRING CapturedGuidString;
WCHAR CapturedGuidBuffer[WmiGuidObjectNameLength + 1];
PWMIOPENGUIDBLOCK InGuidBlock;
HANDLE Handle;
ULONG DesiredAccess;
InGuidBlock = (PWMIOPENGUIDBLOCK)Buffer;
Status = WmipProbeWmiOpenGuidBlock(&CapturedObjectAttributes,
&CapturedGuidString,
CapturedGuidBuffer,
&DesiredAccess,
InGuidBlock,
InBufferLen,
OutBufferLen);
if (NT_SUCCESS(Status))
{
Status = WmipOpenBlock(Ioctl,
UserMode,
&CapturedObjectAttributes,
DesiredAccess,
&Handle);
if (NT_SUCCESS(Status))
{
#if defined(_WIN64)
if (IoIs32bitProcess(NULL))
{
((PWMIOPENGUIDBLOCK32)InGuidBlock)->Handle.Handle32 = PtrToUlong(Handle);
}
else
#endif
{
InGuidBlock->Handle.Handle = Handle;
}
}
}
break;
}
#endif
case IOCTL_WMI_QUERY_ALL_DATA:
{
if (OutBufferLen < sizeof(WNODE_ALL_DATA))
{
//
// WMI will not send any request whose output buffer is not
// at least the size of a WNODE_TOO_SMALL.
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
Status = WmipProbeWnodeAllData((PWNODE_ALL_DATA)Wnode,
InBufferLen,
OutBufferLen);
if (NT_SUCCESS(Status))
{
Status = WmipQueryAllData(NULL,
Irp,
UserMode,
(PWNODE_ALL_DATA)Wnode,
OutBufferLen,
&OutBufferLen);
} else {
WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Invalid IOCTL_WMI_QUERY_ALL_DATA Wnode\n"));
}
break;
}
case IOCTL_WMI_QAD_MULTIPLE:
{
PWMIQADMULTIPLE QadMultiple;
if ((InBufferLen >= sizeof(WMIQADMULTIPLE)) &&
(OutBufferLen >= sizeof(WNODE_TOO_SMALL)))
{
QadMultiple = (PWMIQADMULTIPLE)Buffer;
if ((QadMultiple->HandleCount < QUERYMULIPLEHANDLELIMIT) &&
(InBufferLen >= (FIELD_OFFSET(WMIQADMULTIPLE, Handles) +
(QadMultiple->HandleCount * sizeof(HANDLE3264)))))
{
Status = WmipQueryAllDataMultiple(0,
NULL,
Irp,
UserMode,
Buffer,
OutBufferLen,
QadMultiple,
&OutBufferLen);
} else {
Status = STATUS_INVALID_PARAMETER;
}
} else {
Status = STATUS_INVALID_PARAMETER;
}
break;
}
case IOCTL_WMI_QUERY_SINGLE_INSTANCE:
{
if (OutBufferLen < sizeof(WNODE_TOO_SMALL))
{
//
// WMI will not send any request whose output buffer is not
// at least the size of a WNODE_TOO_SMALL.
Status = STATUS_BUFFER_TOO_SMALL;
break;
}
Status = WmipProbeWnodeSingleInstance((PWNODE_SINGLE_INSTANCE)Wnode,
InBufferLen,
OutBufferLen,
TRUE);
if (NT_SUCCESS(Status))
{
Status = WmipQuerySetExecuteSI(NULL,
Irp,
UserMode,
IRP_MN_QUERY_SINGLE_INSTANCE,
Wnode,
OutBufferLen,
&OutBufferLen);
if (NT_SUCCESS(Status))
{
WmipAssert(Irp->IoStatus.Information <= OutBufferLen);
}
} else {
WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Invalid IOCTL_WMI_SINGLE_INSTANCE Wnode\n"));
}
break;
}
case IOCTL_WMI_QSI_MULTIPLE:
{
PWMIQSIMULTIPLE QsiMultiple;
if ((InBufferLen >= sizeof(WMIQSIMULTIPLE)) &&
(OutBufferLen >= sizeof(WNODE_TOO_SMALL)))
{
QsiMultiple = (PWMIQSIMULTIPLE)Buffer;
if ((QsiMultiple->QueryCount < QUERYMULIPLEHANDLELIMIT) &&
(InBufferLen >= (FIELD_OFFSET(WMIQSIMULTIPLE, QsiInfo) +
(QsiMultiple->QueryCount * sizeof(WMIQSIINFO)))))
{
Status = WmipQuerySingleMultiple(Irp,
UserMode,
Buffer,
OutBufferLen,
QsiMultiple,
QsiMultiple->QueryCount,
NULL,
NULL,
&OutBufferLen);
} else {
Status = STATUS_INVALID_PARAMETER;
}
} else {
Status = STATUS_INVALID_PARAMETER;
}
break;
}
case IOCTL_WMI_SET_SINGLE_INSTANCE:
{
Status = WmipProbeWnodeSingleInstance((PWNODE_SINGLE_INSTANCE)Wnode,
InBufferLen,
OutBufferLen,
FALSE);
if (NT_SUCCESS(Status))
{
Status = WmipQuerySetExecuteSI(NULL,
Irp,
UserMode,
IRP_MN_CHANGE_SINGLE_INSTANCE,
Wnode,
InBufferLen,
&OutBufferLen);
OutBufferLen = 0;
} else {
WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Invalid IOCTL_WMI_SET_SINGLE_INSTANCE Wnode\n"));
}
break;
}
case IOCTL_WMI_SET_SINGLE_ITEM:
{
Status = WmipProbeWnodeSingleItem((PWNODE_SINGLE_ITEM)Wnode,
InBufferLen);
if (NT_SUCCESS(Status))
{
Status = WmipQuerySetExecuteSI(NULL,
Irp,
UserMode,
IRP_MN_CHANGE_SINGLE_ITEM,
Wnode,
InBufferLen,
&OutBufferLen);
OutBufferLen = 0;
} else {
WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Invalid IOCTL_WMI_SET_SINGLE_ITEM Wnode\n"));
}
break;
}
case IOCTL_WMI_EXECUTE_METHOD:
{
//
// The buffer passed is the InputWnode directly followed by the
// method wnode. This is so that the driver can fill in the
// output WNODE directly on top of the input wnode.
PWNODE_METHOD_ITEM MethodWnode = (PWNODE_METHOD_ITEM)Wnode;
Status = WmipProbeWnodeMethodItem(MethodWnode,
InBufferLen,
OutBufferLen);
if (NT_SUCCESS(Status))
{
Status = WmipQuerySetExecuteSI(NULL,
Irp,
UserMode,
IRP_MN_EXECUTE_METHOD,
Wnode,
OutBufferLen,
&OutBufferLen);
if (NT_SUCCESS(Status))
{
WmipAssert(Irp->IoStatus.Information <= OutBufferLen);
}
}
break;
}
case IOCTL_WMI_TRANSLATE_FILE_HANDLE:
{
if (InBufferLen != FIELD_OFFSET(WMIFHTOINSTANCENAME,
InstanceNames))
{
Status = STATUS_UNSUCCESSFUL;
} else {
Status = WmipTranslateFileHandle((PWMIFHTOINSTANCENAME)Buffer,
&OutBufferLen,
NULL,
NULL,
NULL,
NULL);
}
break;
}
case IOCTL_WMI_GET_VERSION:
{
if (OutBufferLen < sizeof(WMIVERSIONINFO))
{
Status = STATUS_BUFFER_TOO_SMALL;
} else {
((PWMIVERSIONINFO)Buffer)->Version = WMI_CURRENT_VERSION;
OutBufferLen = sizeof(WMIVERSIONINFO);
Status = STATUS_SUCCESS;
}
break;
}
case IOCTL_WMI_ENUMERATE_GUIDS_AND_PROPERTIES:
case IOCTL_WMI_ENUMERATE_GUIDS:
{
if (OutBufferLen < FIELD_OFFSET(WMIGUIDLISTINFO, GuidList))
{
Status = STATUS_BUFFER_TOO_SMALL;
} else {
Status = WmipEnumerateGuids(Ioctl,
(PWMIGUIDLISTINFO)Buffer,
OutBufferLen,
&OutBufferLen);
}
break;
}
case IOCTL_WMI_QUERY_GUID_INFO:
{
if (OutBufferLen < sizeof(WMIQUERYGUIDINFO))
{
Status = STATUS_BUFFER_TOO_SMALL;
} else {
Status = WmipQueryGuidInfo((PWMIQUERYGUIDINFO)Buffer);
OutBufferLen = sizeof(WMIQUERYGUIDINFO);
}
break;
}
case IOCTL_WMI_ENUMERATE_MOF_RESOURCES:
{
if (OutBufferLen >= sizeof(WMIMOFLIST))
{
Status = WmipEnumerateMofResources((PWMIMOFLIST)Buffer,
OutBufferLen,
&OutBufferLen);
} else {
Status = STATUS_INVALID_PARAMETER;
}
break;
}
case IOCTL_WMI_RECEIVE_NOTIFICATIONS:
{
PWMIRECEIVENOTIFICATION ReceiveNotification;
ULONG CountExpected;
if ((InBufferLen >= sizeof(WMIRECEIVENOTIFICATION)) &&
(OutBufferLen >= sizeof(WNODE_TOO_SMALL)))
{
ReceiveNotification = (PWMIRECEIVENOTIFICATION)Buffer;
CountExpected = (InBufferLen -
FIELD_OFFSET(WMIRECEIVENOTIFICATION, Handles)) /
sizeof(HANDLE3264);
if (ReceiveNotification->HandleCount <= CountExpected)
{
Status = WmipReceiveNotifications(ReceiveNotification,
&OutBufferLen,
Irp);
} else {
//
// Input buffer not large enough which is an error
//
Status = STATUS_INVALID_DEVICE_REQUEST;
}
} else {
//
// Input and or output buffers not large enough
// which is an error
//
Status = STATUS_INVALID_DEVICE_REQUEST;
}
break;
}
case IOCTL_WMI_MARK_HANDLE_AS_CLOSED:
{
PWMIMARKASCLOSED MarkAsClosed;
if (InBufferLen >= sizeof(WMIMARKASCLOSED))
{
MarkAsClosed = (PWMIMARKASCLOSED)Buffer;
Status = WmipMarkHandleAsClosed(MarkAsClosed->Handle.Handle);
OutBufferLen = 0;
} else {
Status = STATUS_INVALID_DEVICE_REQUEST;
}
break;
}
case IOCTL_WMI_NOTIFY_LANGUAGE_CHANGE:
{
LPGUID LanguageGuid;
PWMILANGUAGECHANGE LanguageChange;
if (InBufferLen == sizeof(WMILANGUAGECHANGE))
{
LanguageChange = (PWMILANGUAGECHANGE)Buffer;
if (LanguageChange->Flags & WMILANGUAGECHANGE_FLAG_ADDED)
{
LanguageGuid = &GUID_MOF_RESOURCE_ADDED_NOTIFICATION;
} else if (LanguageChange->Flags & WMILANGUAGECHANGE_FLAG_REMOVED) {
LanguageGuid = &GUID_MOF_RESOURCE_REMOVED_NOTIFICATION;
} else {
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
WmipGenerateMofResourceNotification(LanguageChange->Language,
L"",
LanguageGuid,
MOFEVENT_ACTION_LANGUAGE_CHANGE);
OutBufferLen = 0;
Status = STATUS_SUCCESS;
} else {
Status = STATUS_INVALID_DEVICE_REQUEST;
}
break;
}
#ifndef MEMPHIS
// Event trace logging IOCTLS
case IOCTL_WMI_UNREGISTER_GUIDS:
{
if ((InBufferLen == sizeof(WMIUNREGGUIDS)) &&
(OutBufferLen == sizeof(WMIUNREGGUIDS)))
{
Status = WmipUnregisterGuids((PWMIUNREGGUIDS)Buffer);
} else {
Status = STATUS_INVALID_PARAMETER;
}
break;
}
case IOCTL_WMI_REGISTER_GUIDS:
{
//
// Register guids for user mode provider
//
Status = WmipProbeWmiRegRequest(
Buffer,
InBufferLen,
OutBufferLen
);
if (NT_SUCCESS(Status))
{
HANDLE RequestHandle;
PWMIREGREQUEST WmiRegRequest;
PWMIREGINFOW WmiRegInfo;
ULONG WmiRegInfoSize;
ULONG GuidCount;
ULONG TraceGuidMapSize;
PWMIREGRESULTS WmiRegResults;
PWMIREGINFOW WmiRegInfoThunk = NULL;
WmiRegRequest = (PWMIREGREQUEST)Buffer;
WmiRegInfo = (PWMIREGINFOW)OffsetToPtr(Buffer, sizeof(WMIREGREQUEST));
WmiRegInfoSize = InBufferLen - sizeof(WMIREGREQUEST);
GuidCount = WmiRegRequest->GuidCount;
TraceGuidMapSize = GuidCount * sizeof(TRACEGUIDMAP);
WmiRegResults = (PWMIREGRESULTS)OffsetToPtr(Buffer, TraceGuidMapSize);
//
// For WOW64, WMIREGINFOW and WMIREGGUIDW structures both need
// to be thunked here because of padding and ULONG_PTR in them.
//
#if defined(_WIN64)
if (IoIs32bitProcess(NULL))
{
ULONG SizeNeeded, SizeToCopy, i;
PWMIREGINFOW WmiRegInfo32;
PWMIREGGUIDW WmiRegGuid;
PUCHAR pSource, pTarget;
ULONG ImageNameLength = 0;
ULONG ResourceNameLength = 0;
ULONG Offset = 0;
//
// Find the GuidCount and allocate storage here.
//
if (WmiRegInfo->RegistryPath > 0)
{
pSource = OffsetToPtr(WmiRegInfo, WmiRegInfo->RegistryPath);
ImageNameLength = *( (PUSHORT) pSource) + sizeof(USHORT);
}
if (WmiRegInfo->MofResourceName > 0)
{
pSource = OffsetToPtr(WmiRegInfo, WmiRegInfo->MofResourceName);
ResourceNameLength = *((PUSHORT)pSource) + sizeof(USHORT);
}
SizeNeeded = sizeof(WMIREGINFOW) +
GuidCount * sizeof(WMIREGGUIDW) +
ImageNameLength + ResourceNameLength;
SizeNeeded = (SizeNeeded + 7) & ~7;
WmiRegInfoThunk = (PWMIREGINFOW) WmipAlloc(SizeNeeded);
if (WmiRegInfoThunk == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
OutBufferLen = 0;
break;
}
RtlZeroMemory(WmiRegInfoThunk, SizeNeeded);
pTarget = (PUCHAR)WmiRegInfoThunk;
pSource = (PUCHAR)WmiRegInfo;
SizeToCopy = WmiRegRequest->WmiRegInfo32Size;
RtlCopyMemory(pTarget, pSource, SizeToCopy);
pTarget += FIELD_OFFSET(WMIREGINFOW, WmiRegGuid);
pSource += SizeToCopy;
SizeToCopy = WmiRegRequest->WmiRegGuid32Size;
Offset = FIELD_OFFSET(WMIREGINFOW, WmiRegGuid);
for (i=0; i < GuidCount; i++)
{
RtlCopyMemory(pTarget, pSource, SizeToCopy);
//
// The InstanceCount checks are done here because the
// source may not be aligned.
//
WmiRegGuid = (PWMIREGGUIDW) pTarget;
if ( (WmiRegGuid->InstanceCount > 0) ||
(WmiRegGuid->InstanceNameList > 0) )
{
return STATUS_UNSUCCESSFUL;
}
pTarget += sizeof(WMIREGGUIDW);
pSource += SizeToCopy;
Offset += sizeof(WMIREGGUIDW);
}
if (ImageNameLength > 0)
{
pSource = OffsetToPtr(WmiRegInfo, WmiRegInfo->RegistryPath);
RtlCopyMemory(pTarget, pSource, ImageNameLength);
pTarget += ImageNameLength;
WmiRegInfoThunk->RegistryPath = Offset;
Offset += ImageNameLength;
}
if (ResourceNameLength > 0)
{
pSource = OffsetToPtr(WmiRegInfo, WmiRegInfo->MofResourceName);
RtlCopyMemory(pTarget, pSource, ResourceNameLength);
pTarget += ResourceNameLength;
WmiRegInfoThunk->MofResourceName = Offset;
Offset += ResourceNameLength;
}
WmiRegInfo = WmiRegInfoThunk;
WmiRegInfoSize = SizeNeeded;
WmiRegInfo->BufferSize = SizeNeeded;
}
#endif
Status = WmipRegisterUMGuids(WmiRegRequest->ObjectAttributes,
WmiRegRequest->Cookie,
WmiRegInfo,
WmiRegInfoSize,
(PTRACEGUIDMAP)Buffer,
GuidCount,
&RequestHandle,
&WmiRegResults->LoggerContext);
if (NT_SUCCESS(Status))
{
#if defined(_WIN64)
if (IoIs32bitProcess(NULL))
{
WmiRegResults->RequestHandle.Handle64 = 0;
WmiRegResults->RequestHandle.Handle32 = PtrToUlong(RequestHandle);
}
else
#endif
{
WmiRegResults->RequestHandle.Handle = RequestHandle;
}
OutBufferLen = sizeof(WMIREGRESULTS) + TraceGuidMapSize;
}
if (WmiRegInfoThunk != NULL)
{
WmipFree(WmiRegInfoThunk);
}
}
break;
}
case IOCTL_WMI_CREATE_UM_LOGGER:
{
//
// Create User mode logger
//
PWNODE_HEADER Wnode;
ULONG MinLength;
#if defined(_WIN64)
if (IoIs32bitProcess(NULL))
{
ULONG SizeNeeded;
PUCHAR src, dest;
PWMICREATEUMLOGGER32 WmiCreateUmLogger32 = (PWMICREATEUMLOGGER32)Buffer;
PWMICREATEUMLOGGER WmiCreateUmLoggerThunk;
MinLength = sizeof(WMICREATEUMLOGGER32) + sizeof(WNODE_HEADER);
if (InBufferLen < MinLength) {
Status = STATUS_INVALID_PARAMETER;
OutBufferLen = 0;
break;
}
Wnode = (PWNODE_HEADER)((PUCHAR)WmiCreateUmLogger32 + sizeof(WMICREATEUMLOGGER32));
if (Wnode->BufferSize > (InBufferLen-sizeof(WMICREATEUMLOGGER32)) ) {
Status = STATUS_INVALID_PARAMETER;
OutBufferLen = 0;
break;
}
SizeNeeded = InBufferLen + sizeof(WMICREATEUMLOGGER) - sizeof(WMICREATEUMLOGGER32);
SizeNeeded = (SizeNeeded + 7) & ~7;
WmiCreateUmLoggerThunk = (PWMICREATEUMLOGGER) WmipAlloc(SizeNeeded);
if (WmiCreateUmLoggerThunk == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
OutBufferLen = 0;
break;
}
RtlZeroMemory(WmiCreateUmLoggerThunk, SizeNeeded);
WmiCreateUmLoggerThunk->ObjectAttributes =
UlongToPtr(WmiCreateUmLogger32->ObjectAttributes);
WmiCreateUmLoggerThunk->ControlGuid = WmiCreateUmLogger32->ControlGuid;
dest = (PUCHAR)WmiCreateUmLoggerThunk + sizeof(WMICREATEUMLOGGER);
src = (PUCHAR)WmiCreateUmLogger32 + sizeof(WMICREATEUMLOGGER32);
RtlCopyMemory(dest, src, Wnode->BufferSize);
Status = WmipCreateUMLogger(WmiCreateUmLoggerThunk);
WmiCreateUmLogger32->ReplyHandle.Handle64 = 0;
WmiCreateUmLogger32->ReplyHandle.Handle32 = PtrToUlong(WmiCreateUmLoggerThunk->ReplyHandle.Handle);
WmiCreateUmLogger32->ReplyCount = WmiCreateUmLoggerThunk->ReplyCount;
WmipFree(WmiCreateUmLoggerThunk);
}
else
#endif
{
MinLength = sizeof(WMICREATEUMLOGGER) + sizeof(WNODE_HEADER);
if (InBufferLen < MinLength) {
Status = STATUS_INVALID_PARAMETER;
OutBufferLen = 0;
break;
}
Wnode = (PWNODE_HEADER) ((PUCHAR)Buffer + sizeof(WMICREATEUMLOGGER));
if (Wnode->BufferSize > (InBufferLen-sizeof(WMICREATEUMLOGGER)) ) {
Status = STATUS_INVALID_PARAMETER;
OutBufferLen = 0;
break;
}
Status = WmipCreateUMLogger((PWMICREATEUMLOGGER)Buffer);
}
break;
}
case IOCTL_WMI_MB_REPLY:
{
//
// MB Reply message
//
PUCHAR Message;
ULONG MessageSize;
PWMIMBREPLY WmiMBReply;
if (InBufferLen >= FIELD_OFFSET(WMIMBREPLY, Message))
{
WmiMBReply = (PWMIMBREPLY)Buffer;
Message = (PUCHAR)Buffer + FIELD_OFFSET(WMIMBREPLY, Message);
MessageSize = InBufferLen - FIELD_OFFSET(WMIMBREPLY, Message);
Status = WmipMBReply(WmiMBReply->Handle.Handle,
WmiMBReply->ReplyIndex,
Message,
MessageSize);
} else {
Status = STATUS_INVALID_PARAMETER;
}
OutBufferLen = 0;
}
case IOCTL_WMI_ENABLE_DISABLE_TRACELOG:
{
PWMITRACEENABLEDISABLEINFO TraceEnableInfo;
OutBufferLen = 0;
if (InBufferLen == sizeof(WMITRACEENABLEDISABLEINFO))
{
TraceEnableInfo = (PWMITRACEENABLEDISABLEINFO)Buffer;
Status = WmipEnableDisableTrace(Ioctl,
TraceEnableInfo);
} else {
Status = STATUS_UNSUCCESSFUL;
}
break;
}
case IOCTL_WMI_START_LOGGER:
{
PWMI_LOGGER_INFORMATION LoggerInfo;
ULONG LoggerBuf, LogFileBuf;
if ((InBufferLen < sizeof(WMI_LOGGER_INFORMATION)) ||
(OutBufferLen < sizeof(WMI_LOGGER_INFORMATION)) ) {
OutBufferLen = 0;
Status = STATUS_UNSUCCESSFUL;
break;
}
if ( !(Wnode->Flags & WNODE_FLAG_TRACED_GUID) ) {
OutBufferLen = 0;
Status = STATUS_UNSUCCESSFUL;
break;
}
LoggerInfo = (PWMI_LOGGER_INFORMATION) Wnode;
#ifdef _WIN64
if (IoIs32bitProcess(Irp)) {
LoggerBuf = ( (PUNICODE_STRING32) &LoggerInfo->LoggerName)->Buffer;
LoggerInfo->LoggerName.Buffer = UlongToPtr(LoggerBuf);
LogFileBuf = ( (PUNICODE_STRING32) &LoggerInfo->LogFileName)->Buffer;
LoggerInfo->LogFileName.Buffer = UlongToPtr(LogFileBuf);
}
#endif
Status = WmipStartLogger( LoggerInfo );
OutBufferLen = sizeof (WMI_LOGGER_INFORMATION);
#ifdef _WIN64
if (IoIs32bitProcess(Irp)) {
( (PUNICODE_STRING32) &LoggerInfo->LoggerName)->Buffer = LoggerBuf;
( (PUNICODE_STRING32) &LoggerInfo->LogFileName)->Buffer = LogFileBuf;
}
#endif
break;
}
case IOCTL_WMI_STOP_LOGGER:
{
PWMI_LOGGER_INFORMATION LoggerInfo;
ULONG LoggerBuf, LogFileBuf;
if ((InBufferLen < sizeof(WMI_LOGGER_INFORMATION)) ||
(OutBufferLen < sizeof(WMI_LOGGER_INFORMATION)) ) {
OutBufferLen = 0;
Status = STATUS_UNSUCCESSFUL;
break;
}
if ( !(Wnode->Flags & WNODE_FLAG_TRACED_GUID) ) {
OutBufferLen = 0;
Status = STATUS_UNSUCCESSFUL;
break;
}
LoggerInfo = (PWMI_LOGGER_INFORMATION) Wnode;
#ifdef _WIN64
if (IoIs32bitProcess(Irp)) {
LoggerBuf = ( (PUNICODE_STRING32) &LoggerInfo->LoggerName)->Buffer;
LoggerInfo->LoggerName.Buffer = UlongToPtr(LoggerBuf);
LogFileBuf = ( (PUNICODE_STRING32) &LoggerInfo->LogFileName)->Buffer;
LoggerInfo->LogFileName.Buffer = UlongToPtr(LogFileBuf);
}
#endif
Status = WmiStopTrace( LoggerInfo );
OutBufferLen = sizeof (WMI_LOGGER_INFORMATION);
#ifdef _WIN64
if (IoIs32bitProcess(Irp)) {
( (PUNICODE_STRING32) &LoggerInfo->LoggerName)->Buffer = LoggerBuf;
( (PUNICODE_STRING32) &LoggerInfo->LogFileName)->Buffer = LogFileBuf;
}
#endif
break;
}
case IOCTL_WMI_QUERY_LOGGER:
{
PWMI_LOGGER_INFORMATION LoggerInfo;
ULONG LoggerBuf, LogFileBuf;
if ((InBufferLen < sizeof(WMI_LOGGER_INFORMATION)) ||
(OutBufferLen < sizeof(WMI_LOGGER_INFORMATION)) ) {
OutBufferLen = 0;
Status = STATUS_UNSUCCESSFUL;
break;
}
if ( !(Wnode->Flags & WNODE_FLAG_TRACED_GUID) ) {
OutBufferLen = 0;
Status = STATUS_UNSUCCESSFUL;
break;
}
LoggerInfo = (PWMI_LOGGER_INFORMATION) Wnode;
#ifdef _WIN64
if (IoIs32bitProcess(Irp)) {
LoggerBuf = ( (PUNICODE_STRING32) &LoggerInfo->LoggerName)->Buffer;
LoggerInfo->LoggerName.Buffer = UlongToPtr(LoggerBuf);
LogFileBuf = ( (PUNICODE_STRING32) &LoggerInfo->LogFileName)->Buffer;
LoggerInfo->LogFileName.Buffer = UlongToPtr(LogFileBuf);
}
#endif
Status = WmipQueryLogger( LoggerInfo, NULL );
OutBufferLen = sizeof (WMI_LOGGER_INFORMATION);
#ifdef _WIN64
if (IoIs32bitProcess(Irp)) {
( (PUNICODE_STRING32) &LoggerInfo->LoggerName)->Buffer = LoggerBuf;
( (PUNICODE_STRING32) &LoggerInfo->LogFileName)->Buffer = LogFileBuf;
}
#endif
break;
}
case IOCTL_WMI_UPDATE_LOGGER:
{
PWMI_LOGGER_INFORMATION LoggerInfo;
ULONG LoggerBuf, LogFileBuf;
if ((InBufferLen < sizeof(WMI_LOGGER_INFORMATION)) ||
(OutBufferLen < sizeof(WMI_LOGGER_INFORMATION)) ) {
OutBufferLen = 0;
Status = STATUS_UNSUCCESSFUL;
break;
}
if ( !(Wnode->Flags & WNODE_FLAG_TRACED_GUID) ) {
OutBufferLen = 0;
Status = STATUS_UNSUCCESSFUL;
break;
}
LoggerInfo = (PWMI_LOGGER_INFORMATION) Wnode;
#ifdef _WIN64
if (IoIs32bitProcess(Irp)) {
LoggerBuf = ( (PUNICODE_STRING32) &LoggerInfo->LoggerName)->Buffer;
LoggerInfo->LoggerName.Buffer = UlongToPtr(LoggerBuf);
LogFileBuf = ( (PUNICODE_STRING32) &LoggerInfo->LogFileName)->Buffer;
LoggerInfo->LogFileName.Buffer = UlongToPtr(LogFileBuf);
}
#endif
Status = WmiUpdateTrace( LoggerInfo );
OutBufferLen = sizeof (WMI_LOGGER_INFORMATION);
#ifdef _WIN64
if (IoIs32bitProcess(Irp)) {
( (PUNICODE_STRING32) &LoggerInfo->LoggerName)->Buffer = LoggerBuf;
( (PUNICODE_STRING32) &LoggerInfo->LogFileName)->Buffer = LogFileBuf;
}
#endif
break;
}
case IOCTL_WMI_FLUSH_LOGGER:
{
PWMI_LOGGER_INFORMATION LoggerInfo;
ULONG LoggerBuf, LogFileBuf;
if ((InBufferLen < sizeof(WMI_LOGGER_INFORMATION)) ||
(OutBufferLen < sizeof(WMI_LOGGER_INFORMATION)) ) {
OutBufferLen = 0;
Status = STATUS_UNSUCCESSFUL;
break;
}
if ( !(Wnode->Flags & WNODE_FLAG_TRACED_GUID) ) {
OutBufferLen = 0;
Status = STATUS_UNSUCCESSFUL;
break;
}
LoggerInfo = (PWMI_LOGGER_INFORMATION) Wnode;
#ifdef _WIN64
if (IoIs32bitProcess(Irp)) {
LoggerBuf = ( (PUNICODE_STRING32) &LoggerInfo->LoggerName)->Buffer;
LoggerInfo->LoggerName.Buffer = UlongToPtr(LoggerBuf);
LogFileBuf = ( (PUNICODE_STRING32) &LoggerInfo->LogFileName)->Buffer;
LoggerInfo->LogFileName.Buffer = UlongToPtr(LogFileBuf);
}
#endif
Status = WmiFlushTrace( LoggerInfo );
OutBufferLen = sizeof (WMI_LOGGER_INFORMATION);
#ifdef _WIN64
if (IoIs32bitProcess(Irp)) {
( (PUNICODE_STRING32) &LoggerInfo->LoggerName)->Buffer = LoggerBuf;
( (PUNICODE_STRING32) &LoggerInfo->LogFileName)->Buffer = LogFileBuf;
}
#endif
break;
}
case IOCTL_WMI_TRACE_EVENT:
{ // NOTE: This relies on WmiTraceEvent to probe the buffer!
OutBufferLen = 0;
if ( InBufferLen < sizeof(WNODE_HEADER) ) {
Status = STATUS_UNSUCCESSFUL;
break;
}
Status = WmiTraceEvent(
(PWNODE_HEADER)
irpStack->Parameters.DeviceIoControl.Type3InputBuffer,
KeGetPreviousMode()
);
break;
}
case IOCTL_WMI_TRACE_MESSAGE:
{ // NOTE: This relies on WmiTraceUserMessage to probe the buffer!
OutBufferLen = 0;
if ( InBufferLen < sizeof(MESSAGE_TRACE_USER) ) {
Status = STATUS_UNSUCCESSFUL;
break;
}
Status = WmiTraceUserMessage(
(PMESSAGE_TRACE_USER)
irpStack->Parameters.DeviceIoControl.Type3InputBuffer,
InBufferLen
);
break;
}
case IOCTL_WMI_SET_MARK:
{
OutBufferLen = 0;
if ( InBufferLen <= FIELD_OFFSET(WMI_SET_MARK_INFORMATION, Mark)) {
Status = STATUS_UNSUCCESSFUL;
break;
}
Status = WmiSetMark( (PVOID) Wnode, InBufferLen );
break;
}
case IOCTL_WMI_CLOCK_TYPE:
{
if ((InBufferLen < sizeof(WMI_LOGGER_INFORMATION)) ||
(OutBufferLen < sizeof(WMI_LOGGER_INFORMATION))) {
OutBufferLen = 0;
Status = STATUS_INFO_LENGTH_MISMATCH;
break;
}
WmipValidateClockType((PWMI_LOGGER_INFORMATION) Wnode);
Status = STATUS_SUCCESS;
break;
}
#ifdef NTPERF
case IOCTL_WMI_SWITCH_BUFFER:
{
if ((InBufferLen < sizeof(PWMI_SWITCH_PERFMEM_BUFFER_INFORMATION)) ||
(OutBufferLen < sizeof(PWMI_SWITCH_PERFMEM_BUFFER_INFORMATION)) ) {
OutBufferLen = 0;
Status = STATUS_UNSUCCESSFUL;
break;
}
Status = WmipSwitchPerfmemBuffer((PWMI_SWITCH_PERFMEM_BUFFER_INFORMATION) Wnode );
OutBufferLen = sizeof (PVOID);
break;
}
#endif
#endif // if not MEMPHIS
case IOCTL_WMI_NTDLL_LOGGERINFO:
{
if ((InBufferLen < sizeof(WMINTDLLLOGGERINFO)) ||
(OutBufferLen < sizeof(WMINTDLLLOGGERINFO))) {
OutBufferLen = 0;
Status = STATUS_UNSUCCESSFUL;
break;
}
Status = WmipNtDllLoggerInfo((PWMINTDLLLOGGERINFO)Buffer);
break;
}
default:
{
WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Unsupported IOCTL %x\n",
irpStack->Parameters.DeviceIoControl.IoControlCode));
Status = STATUS_INVALID_DEVICE_REQUEST;
}
}
if (Status != STATUS_PENDING)
{
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = NT_SUCCESS(Status) ? OutBufferLen : 0;
IoCompleteRequest( Irp, IO_NO_INCREMENT );
}
return(Status);
}
NTSTATUS
WmipSystemControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PAGED_CODE();
return(IoWMISystemControl((PWMILIB_INFO)&WmipWmiLibInfo,
DeviceObject,
Irp));
}
NTSTATUS WmipWmiIrpCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
WMI forwarded IRP completion routine. Set an event and return
STATUS_MORE_PROCESSING_REQUIRED. WmipForwardWmiIrp will wait on this
event and then re-complete the irp after cleaning up.
Arguments:
DeviceObject is the device object of the WMI driver
Irp is the WMI irp that was just completed
Context is a PKEVENT that WmipForwardWmiIrp will wait on
Return Value:
NT status code
--*/
{
PIRPCOMPCTX IrpCompCtx;
PREGENTRY RegEntry;
PKEVENT Event;
UNREFERENCED_PARAMETER(DeviceObject);
UNREFERENCED_PARAMETER(Irp);
IrpCompCtx = (PIRPCOMPCTX)Context;
RegEntry = IrpCompCtx->RegEntry;
Event = &IrpCompCtx->Event;
WmipDecrementIrpCount(RegEntry);
KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
return(STATUS_MORE_PROCESSING_REQUIRED);
}
NTSTATUS WmipGetDevicePDO(
PDEVICE_OBJECT DeviceObject,
PDEVICE_OBJECT *PDO
)
{
PIRP Irp;
PIO_STACK_LOCATION IrpSp;
IO_STATUS_BLOCK IoStatusBlock;
PDEVICE_RELATIONS DeviceRelations;
NTSTATUS Status;
KEVENT Event;
PAGED_CODE();
*PDO = NULL;
KeInitializeEvent( &Event,
NotificationEvent,
FALSE );
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
DeviceObject,
NULL,
0,
NULL,
&Event,
&IoStatusBlock );
if (Irp == NULL)
{
return(STATUS_INSUFFICIENT_RESOURCES);
}
IrpSp = IoGetNextIrpStackLocation( Irp );
IrpSp->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
IrpSp->Parameters.QueryDeviceRelations.Type = TargetDeviceRelation;
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
Status = IoCallDriver( DeviceObject, Irp );
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL );
Status = IoStatusBlock.Status;
}
if (NT_SUCCESS(Status))
{
DeviceRelations = (PDEVICE_RELATIONS)IoStatusBlock.Information;
ASSERT(DeviceRelations);
ASSERT(DeviceRelations->Count == 1);
*PDO = DeviceRelations->Objects[0];
ExFreePool(DeviceRelations);
}
return(Status);
}
NTSTATUS WmipObjectToPDO(
PFILE_OBJECT FileObject,
PDEVICE_OBJECT DeviceObject,
PDEVICE_OBJECT *PDO
)
/*++
Routine Description:
This routine will determine the PDO which is the target of a file handle.
The mechananism is to build a IRP_MJ_PNP irp with IRP_MN_QUERY_RELATIONS
and query for TargetDeviceRelation. This irp is supposed to be passed down
a device stack until it hits the PDO which will fill in its device object
and return. Note that some drivers may not support this.
Arguments:
FileObject is the file object for device that is being queried
DeviceObject is the device object that is being queried
*PDO returns with the PDO that is targeted by the file object. When
the caller has finished using the PDO it must ObDereferenceObject it.
Return Value:
NT status code
--*/
{
NTSTATUS Status;
PAGED_CODE();
if (DeviceObject == NULL)
{
DeviceObject = IoGetRelatedDeviceObject(FileObject);
}
if (DeviceObject != NULL)
{
Status = WmipGetDevicePDO(DeviceObject, PDO);
} else {
Status = STATUS_NO_SUCH_DEVICE;
}
return(Status);
}
NTSTATUS WmipForwardWmiIrp(
PIRP Irp,
UCHAR MinorFunction,
ULONG ProviderId,
PVOID DataPath,
ULONG BufferLength,
PVOID Buffer
)
/*++
Routine Description:
If the provider is a driver then this routine will allocate a new irp
with the correct stack size and send it to the driver. If the provider
is a callback then it is called directly.
It is assumed that the caller has performed any security checks required
Arguments:
Irp is the IOCTL irp that initiated the request
MinorFunction specifies the minor function code of the WMI Irp
WmiRegistrationId is the id passed by the user mode code. This routine
will look it up to determine the device object pointer.
DataPath is the value for the DataPath parameter of the WMI irp
BufferLength is the value for the BufferLength parameter of the WMI irp
Buffer is the value for the Buffer parameter of the WMI irp
Return Value:
NT status code
--*/
{
PREGENTRY RegEntry;
NTSTATUS Status;
PIO_STACK_LOCATION irpStack;
PDEVICE_OBJECT TargetDeviceObject;
CCHAR DeviceStackSize;
IRPCOMPCTX IrpCompCtx;
PWNODE_HEADER Wnode = (PWNODE_HEADER)Buffer;
BOOLEAN IsPnPIdRequest;
PDEVICE_OBJECT DeviceObject;
PAGED_CODE();
WmipAssert( (MinorFunction >= IRP_MN_QUERY_ALL_DATA) &&
(MinorFunction <= IRP_MN_REGINFO_EX) );
irpStack = IoGetCurrentIrpStackLocation(Irp);
//
// For non-file handle based requests we get the registration entry
// to validate the target and check for a callback
RegEntry = WmipFindRegEntryByProviderId(ProviderId, TRUE);
if (RegEntry != NULL)
{
if (RegEntry->Flags & REGENTRY_FLAG_NOT_ACCEPTING_IRPS)
{
WmipUnreferenceRegEntry(RegEntry);
WmipDecrementIrpCount(RegEntry);
if ((MinorFunction == IRP_MN_QUERY_SINGLE_INSTANCE) ||
(MinorFunction == IRP_MN_CHANGE_SINGLE_INSTANCE))
{
Status = STATUS_WMI_INSTANCE_NOT_FOUND;
} else {
Status = STATUS_UNSUCCESSFUL;
}
return(Status);
}
DeviceObject = RegEntry->DeviceObject;
#ifndef MEMPHIS
if (RegEntry->Flags & REGENTRY_FLAG_CALLBACK)
{
ULONG Size = 0;
//
// This guy registered as a callback so do the callback and go.
Status = (*RegEntry->WmiEntry)(MinorFunction,
DataPath,
BufferLength,
Buffer,
RegEntry->WmiEntry,
&Size
);
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = Size;
WmipUnreferenceRegEntry(RegEntry);
WmipDecrementIrpCount(RegEntry);
return(Status);
}
#endif
} else {
WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: Invalid device object passed from user mode %x\n",
ProviderId));
if ((MinorFunction == IRP_MN_QUERY_SINGLE_INSTANCE) ||
(MinorFunction == IRP_MN_CHANGE_SINGLE_INSTANCE))
{
Status = STATUS_WMI_INSTANCE_NOT_FOUND;
} else {
Status = STATUS_UNSUCCESSFUL;
}
return(Status);
}
//
// Determine if this is a query for the device pnp id guid
IsPnPIdRequest = ((MinorFunction != IRP_MN_REGINFO) &&
(MinorFunction != IRP_MN_REGINFO_EX)) &&
((IsEqualGUID(&Wnode->Guid, &WmipDataProviderPnpidGuid)) ||
(IsEqualGUID(&Wnode->Guid, &WmipDataProviderPnPIdInstanceNamesGuid)));
if (IsPnPIdRequest && (RegEntry->PDO != NULL))
{
//
// Its the PnPId request and WMI is handling it on behalf of the
// device then switch the device object to our own
DeviceObject = WmipServiceDeviceObject;
IsPnPIdRequest = FALSE;
}
//
// Get the top of the device stack for our targer WMI device. Note that
// IoGetAttachedDeviceReference also takes an object reference
// which we get rid of after the the irp is completed by the
// data provider driver.
TargetDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
DeviceStackSize = TargetDeviceObject->StackSize + 1;
//
// Check that there are enough stack locations in our irp so that we
// can forward it to the top of the device stack. We must also check
// if our target device is the WMI data or service device otherwise
// the number of stack locations for it will keep increementing until
// the machine crashes
if ((DeviceStackSize <= WmipServiceDeviceObject->StackSize) ||
(TargetDeviceObject == WmipServiceDeviceObject))
{
//
// There are enough stack locations in the WMI irp to forward
// Remember some context information in our irp stack and use
// it as our completion context value
KeInitializeEvent( &IrpCompCtx.Event,
SynchronizationEvent,
FALSE );
IrpCompCtx.RegEntry = RegEntry;
IoSetCompletionRoutine(Irp,
WmipWmiIrpCompletion,
(PVOID)&IrpCompCtx,
TRUE,
TRUE,
TRUE);
//
// Setup next irp stack location with WMI irp info
irpStack = IoGetNextIrpStackLocation(Irp);
irpStack->MajorFunction = IRP_MJ_SYSTEM_CONTROL;
irpStack->MinorFunction = MinorFunction;
irpStack->Parameters.WMI.ProviderId = (ULONG_PTR)DeviceObject;
irpStack->Parameters.WMI.DataPath = DataPath;
irpStack->Parameters.WMI.BufferSize = BufferLength;
irpStack->Parameters.WMI.Buffer = Buffer;
//
// Initialize irp status to STATUS_NOT_SUPPORTED so that we can
// detect the case where no data provider responded to the irp
Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
IoMarkIrpPending(Irp);
Status = IoCallDriver(TargetDeviceObject, Irp);
if (Status == STATUS_PENDING) {
KeWaitForSingleObject( &IrpCompCtx.Event,
Executive,
KernelMode,
FALSE,
(PLARGE_INTEGER) NULL );
Status = Irp->IoStatus.Status;
}
//
// Check if the status code is still STATUS_NOT_SUPPORTED. If this is
// the case then most likely no data provider responded to the irp.
// So we want to change the status code to something more relevant
// to WMI like STATUS_WMI_GUID_NOT_FOUND
if (Status == STATUS_NOT_SUPPORTED)
{
Status = STATUS_WMI_GUID_NOT_FOUND;
Irp->IoStatus.Status = STATUS_WMI_GUID_NOT_FOUND;
}
#if DBG
if (((MinorFunction == IRP_MN_REGINFO) || (MinorFunction == IRP_MN_REGINFO_EX)) &&
(NT_SUCCESS(Status)) &&
(Irp->IoStatus.Information == 0))
{
WmipDebugPrintEx((DPFLTR_WMICORE_ID, DPFLTR_INFO_LEVEL,"WMI: %p completed IRP_MN_REGINFO with size 0 (%p, %x)\n",
DeviceObject, Buffer, BufferLength));
}
#endif
//
// If this was a registration request then we need to see if there are
// any PDOs that need to be translated into static instance names.
if (((MinorFunction == IRP_MN_REGINFO) ||
(MinorFunction == IRP_MN_REGINFO_EX)) &&
(NT_SUCCESS(Status)) &&
(Irp->IoStatus.Information > FIELD_OFFSET(WMIREGINFOW,
WmiRegGuid)))
{
WmipTranslatePDOInstanceNames(Irp,
MinorFunction,
BufferLength,
RegEntry);
}
//
// Dereference regentry which was taken when forwarding the irp
WmipUnreferenceRegEntry(RegEntry);
} else {
//
// There are not enough stack locations to forward this irp.
// We bump the stack count for the WMI device and return
// an error asking to try the irp again.
WmipUnreferenceRegEntry(RegEntry);
WmipDecrementIrpCount(RegEntry);
WmipUpdateDeviceStackSize(DeviceStackSize);
Status = STATUS_WMI_TRY_AGAIN;
}
//
// Dereference the target device which was the top of the stack to
// which we forwarded the irp.
ObDereferenceObject(TargetDeviceObject);
return(Status);
}
NTSTATUS WmipSendWmiIrp(
UCHAR MinorFunction,
ULONG ProviderId,
PVOID DataPath,
ULONG BufferLength,
PVOID Buffer,
PIO_STATUS_BLOCK Iosb
)
/*++
Routine Description:
This routine will allocate a new irp and then forward it on as a WMI
irp appropriately. The routine handles the case where the stack size
is too small and will retry the irp.
Arguments:
See WmipForwardWmiIrp
Return Value:
NT status code
--*/
{
PIRP Irp;
PIO_STACK_LOCATION IrpStack;
NTSTATUS Status;
PAGED_CODE();
Irp = NULL;
do
{
Irp = IoAllocateIrp((CCHAR)(WmipServiceDeviceObject->StackSize+1),
FALSE);
if (Irp == NULL)
{
return(STATUS_INSUFFICIENT_RESOURCES);
}
IoSetNextIrpStackLocation(Irp);
IrpStack = IoGetCurrentIrpStackLocation(Irp);
IrpStack->DeviceObject = WmipServiceDeviceObject;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
Irp->AssociatedIrp.SystemBuffer = Buffer;
Status = WmipForwardWmiIrp(
Irp,
MinorFunction,
ProviderId,
DataPath,
BufferLength,
Buffer);
*Iosb = Irp->IoStatus;
IoFreeIrp(Irp);
} while (Status == STATUS_WMI_TRY_AGAIN);
return(Status);
}
NTSTATUS WmipTranslateFileHandle(
IN OUT PWMIFHTOINSTANCENAME FhToInstanceName,
IN OUT PULONG OutBufferLen,
IN HANDLE FileHandle,
IN PDEVICE_OBJECT DeviceObject,
IN PWMIGUIDOBJECT GuidObject,
OUT PUNICODE_STRING InstanceNameString
)
/*++
Routine Description:
This routine will translate a file handle or device object into the
device instance name for the target PDO of the device object
pointed to by the file handle.
Arguments:
FhToInstanceName passes in the file handle and returns the device
instance name.
Return Value:
NT status code
--*/
{
PDEVICE_OBJECT PDO;
UNICODE_STRING DeviceInstanceName;
PFILE_OBJECT FileObject;
NTSTATUS Status;
ULONG SizeNeeded;
PWCHAR InstanceName;
ULONG Length;
PWCHAR HandleName;
ULONG HandleNameLen;
PWCHAR BaseName;
ULONG BaseNameLen;
PBGUIDENTRY GuidEntry;
PLIST_ENTRY InstanceSetList;
PBINSTANCESET InstanceSet;
ULONG BaseIndex;
PAGED_CODE();
if (FhToInstanceName != NULL)
{
WmipAssert(FileHandle == NULL);
WmipAssert(GuidObject == NULL);
WmipAssert(InstanceNameString == NULL);
WmipAssert(DeviceObject == NULL);
FileHandle = FhToInstanceName->FileHandle.Handle;
if (FileHandle == NULL)
{
return(STATUS_INVALID_HANDLE);
}
}
if (FileHandle != NULL)
{
//
// Make reference to the file object so it doesn't go away
//
Status = ObReferenceObjectByHandle(FileHandle,
0,
IoFileObjectType,
KernelMode,
&FileObject,
NULL);
} else {
//
// Make regerence to the device object so it doesn't go away
//
Status = ObReferenceObjectByPointer(DeviceObject,
FILE_ALL_ACCESS,
NULL,
KernelMode);
}
if (NT_SUCCESS(Status))
{
Status = WmipObjectToPDO(FileObject,
DeviceObject,
&PDO);
if (NT_SUCCESS(Status))
{
//
// Map file object to PDO
Status = WmipPDOToDeviceInstanceName(PDO,
&DeviceInstanceName);
if (NT_SUCCESS(Status))
{
//
// Now see if we can find an instance name
//
HandleName = DeviceInstanceName.Buffer;
HandleNameLen = DeviceInstanceName.Length / sizeof(WCHAR);
if (FhToInstanceName != NULL)
{
Status = ObReferenceObjectByHandle(FhToInstanceName->KernelHandle.Handle,
WMIGUID_QUERY,
WmipGuidObjectType,
UserMode,
&GuidObject,
NULL);
} else {
Status = ObReferenceObjectByPointer(GuidObject,
WMIGUID_QUERY,
WmipGuidObjectType,
KernelMode);
}
if (NT_SUCCESS(Status))
{
Status = STATUS_WMI_INSTANCE_NOT_FOUND;
GuidEntry = GuidObject->GuidEntry;
WmipEnterSMCritSection();
if (GuidEntry->ISCount > 0)
{
InstanceSetList = GuidEntry->ISHead.Flink;
while ((InstanceSetList != &GuidEntry->ISHead) &&
! NT_SUCCESS(Status))
{
InstanceSet = CONTAINING_RECORD(InstanceSetList,
INSTANCESET,
GuidISList);
if (InstanceSet->Flags & IS_INSTANCE_BASENAME)
{
BaseName = InstanceSet->IsBaseName->BaseName;
BaseNameLen = wcslen(BaseName);
//
// If the instance set has a base name
// and the beginning of it matches the
// PnPId and it has only an _ after it
// then we have got a match
//
if ((_wcsnicmp(BaseName,
HandleName,
HandleNameLen) == 0) &&
(BaseNameLen == (HandleNameLen+1)) &&
(BaseName[BaseNameLen-1] == L'_'))
{
BaseIndex = InstanceSet->IsBaseName->BaseIndex;
Status = STATUS_SUCCESS;
}
}
InstanceSetList = InstanceSetList->Flink;
}
}
WmipLeaveSMCritSection();
if (NT_SUCCESS(Status))
{
if (FhToInstanceName != NULL)
{
FhToInstanceName->BaseIndex = BaseIndex;
SizeNeeded = DeviceInstanceName.Length + 2 * sizeof(WCHAR) +
FIELD_OFFSET(WMIFHTOINSTANCENAME,
InstanceNames);
if (*OutBufferLen >= SizeNeeded)
{
InstanceName = &FhToInstanceName->InstanceNames[0];
Length = DeviceInstanceName.Length;
FhToInstanceName->InstanceNameLength = (USHORT)(Length + 2 * sizeof(WCHAR));
RtlCopyMemory(InstanceName,
DeviceInstanceName.Buffer,
DeviceInstanceName.Length);
//
// Double NUL terminate string
//
Length /= 2;
InstanceName[Length++] = UNICODE_NULL;
InstanceName[Length] = UNICODE_NULL;
*OutBufferLen = SizeNeeded;
} else if (*OutBufferLen >= sizeof(ULONG)) {
FhToInstanceName->SizeNeeded = SizeNeeded;
*OutBufferLen = sizeof(ULONG);
} else {
Status = STATUS_UNSUCCESSFUL;
}
} else {
InstanceName = ExAllocatePoolWithTag(PagedPool,
DeviceInstanceName.Length + 32,
WmipInstanceNameTag);
if (InstanceName != NULL)
{
Length = swprintf(InstanceName,
L"%ws_%d",
DeviceInstanceName.Buffer,
BaseIndex);
InstanceNameString->Buffer = InstanceName;
InstanceNameString->Length = (USHORT)Length * sizeof(WCHAR);
InstanceNameString->MaximumLength = (USHORT)Length * sizeof(WCHAR);
} else {
Status = STATUS_INSUFFICIENT_RESOURCES;
}
}
}
ObDereferenceObject(GuidObject);
}
RtlFreeUnicodeString(&DeviceInstanceName);
}
ObDereferenceObject(PDO);
}
if (FileHandle != NULL)
{
ObDereferenceObject(FileObject);
} else {
ObDereferenceObject(DeviceObject);
}
}
return(Status);
}
#ifndef MEMPHIS
BOOLEAN
WmipFastIoDeviceControl(
IN PFILE_OBJECT FileObject,
IN BOOLEAN Wait,
IN PVOID InputBuffer OPTIONAL,
IN ULONG InputBufferLength,
OUT PVOID OutputBuffer OPTIONAL,
IN ULONG OutputBufferLength,
IN ULONG IoControlCode,
OUT PIO_STATUS_BLOCK IoStatus,
IN struct _DEVICE_OBJECT *DeviceObject
)
{
PAGED_CODE();
UNREFERENCED_PARAMETER(FileObject);
UNREFERENCED_PARAMETER(Wait);
UNREFERENCED_PARAMETER(OutputBuffer);
UNREFERENCED_PARAMETER(OutputBufferLength);
UNREFERENCED_PARAMETER(DeviceObject);
if (IoControlCode == IOCTL_WMI_TRACE_EVENT) {
if (InputBufferLength < sizeof(EVENT_TRACE_HEADER))
return FALSE;
IoStatus->Status = WmiTraceEvent( InputBuffer, KeGetPreviousMode() );
return TRUE;
} else if (IoControlCode == IOCTL_WMI_TRACE_MESSAGE) {
if (InputBufferLength < sizeof(MESSAGE_TRACE_USER))
return FALSE;
IoStatus->Status = WmiTraceUserMessage( InputBuffer, InputBufferLength );
return TRUE;
}
return FALSE;
}
#endif
NTSTATUS WmipProbeWnodeWorker(
PWNODE_HEADER WnodeHeader,
ULONG MinWnodeSize,
ULONG InstanceNameOffset,
ULONG DataBlockOffset,
ULONG DataBlockSize,
ULONG InBufferLen,
ULONG OutBufferLen,
BOOLEAN CheckOutBound,
BOOLEAN CheckInBound
)
/*++
Routine Description:
Probe the incoming Wnode to ensure that any offsets in the
header point to memory that is valid within the buffer. Also validate
that the Wnode is properly formed.
This routine assumes that the input and output buffers has been
probed enough to determine that it is at least as large as
MinWnodeSize and MinWnodeSize must be at least as large as
sizeof(WNODE_HEADER)
WNODE Rules:
9. For outbound data WnodeDataBlockOffset != 0
5. For inbound Wnode->DataBlockOffset must be 0 (implying no data) or
Wnode->DataBlockOffset must be <= incoming buffer size and >=
sizeof(WNODE_SINGLE_INSTANCE), that is
the data block must start in the incoming buffer, but after the
WNODE_SINGLE_INSTANCE header.
6. Wnode and Wnode->DataBlockOffset must be aligned on an 8 byte boundry.
7. For inbound data (SetSingleInstance) (Wnode->DataBlockOffset +
Wnode->DataBlockSize) < incoming buffer length. That is the entire
data block must fit within the incoming buffer.
8. For outbound data (QuerySingleInstance) Wnode->DataBlockOffset
must be <= outgoing buffer length. That is the start of the outgoing
data block must fit within the outgoing data buffer. Note that it is
the provider's responsibility to determine if there will be enough
space in the outgoing buffer to write the returned data.
10. Wnode->OffsetInstanceNames must be aligned on a 2 byte boundry
11. Wnode->OffsetInstanceNames must be <= (incoming buffer size) +
sizeof(USHORT), that is it must start within the incoming buffer and
the USHORT that specifies the length must be within the incoming
buffer.
12. The entire instance name string must fit with the incoming buffer
13. For outbound data (QuerySingleInstance) the entire instance name
must start and fit within the output buffer.
14. Wnode->DataBlockOffset must be placed after any instance name and
not overlap the instance name.
Arguments:
WnodeHeader - pointer to WNODE to be probed
InBufferLen - Size of the incoming buffer
OutBufferLen - Size of the outgoing buffer
MinWnodeSize - minimum size that the WNODE can be
InstanceNameOffset - Offset within WNODE to instance name
DataBlockOffset - Offset within WNODE to data block
DataBlockSize - Size of data block
CheckOutBound - If TRUE, WNODE needs to be validated for provider to
return data.
CheckInBound - If TRUE WNODE needs to be validated for provider to
receive data
Return Value:
NT status code
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PWCHAR InstanceNamePtr;
PAGED_CODE();
if (InstanceNameOffset != 0)
{
#if DBG
//
// Validate instance name begins beyond WNODE header
if (InstanceNameOffset < MinWnodeSize)
{
return(STATUS_UNSUCCESSFUL);
}
#endif
//
// Validate InstanceName is aligned properly. This is left
// in the free build since alphas may have alignment requiremnts
// in handling USHORTs and WCHARs
//
// Validate that USHORT holding instance name length is within
// WNODE
if (( ! WmipIsAligned(InstanceNameOffset, 2)) ||
(InstanceNameOffset > InBufferLen - sizeof(USHORT)) )
{
return(STATUS_UNSUCCESSFUL);
}
//
// Validate Dynamic Instance Name text is fully within
// input buffer and output buffer for outbound WNODEs
InstanceNamePtr = (PWCHAR)OffsetToPtr(WnodeHeader,
InstanceNameOffset);
InstanceNameOffset += sizeof(USHORT) + *InstanceNamePtr;
if ( (InstanceNameOffset > InBufferLen) ||
( (CheckOutBound) && (InstanceNameOffset > OutBufferLen)) )
{
return(STATUS_UNSUCCESSFUL);
}
#if DBG
//
// If data block is specified then it must be placed after the
// end of the instance name
if ((DataBlockOffset != 0) &&
(DataBlockOffset < InstanceNameOffset))
{
return(STATUS_UNSUCCESSFUL);
}
#endif
}
#if DBG
//
// Ensure data block offset is placed after the WNODE header
// header
if ((DataBlockOffset != 0) &&
(DataBlockOffset < MinWnodeSize))
{
return(STATUS_UNSUCCESSFUL);
}
#endif
//
// Ensure data block is aligned properly
if (! WmipIsAligned(DataBlockOffset, 8))
{
return(STATUS_UNSUCCESSFUL);
}
//
// For incoming WNODE, make sure the data block
// does not extend beyond the input buffer.
if ((CheckInBound) &&
(DataBlockOffset != 0) &&
( (DataBlockSize > InBufferLen) ||
(DataBlockOffset > InBufferLen - DataBlockSize) ) )
{
return(STATUS_UNSUCCESSFUL);
}
if (CheckOutBound)
{
//
// For outgoing WNODE make sure there is
// enough room to write the WNODE header
//
// For outgoing WNODE make sure the data block
// offset is within the bounds of the output buffer
if ( (OutBufferLen < MinWnodeSize) ||
(DataBlockOffset > OutBufferLen) )
{
return(STATUS_UNSUCCESSFUL);
}
#if DBG
//
// Make sure that the data block offset is specified so provider
// can know where to write data
if (DataBlockOffset == 0)
{
return(STATUS_UNSUCCESSFUL);
}
#endif
}
return(Status);
}
NTSTATUS WmipProbeWnodeAllData(
PWNODE_ALL_DATA Wnode,
ULONG InBufferLen,
ULONG OutBufferLen
)
/*++
Routine Description:
Probe the incoming WNODE_ALL_DATA to ensure that any offsets in the
header point to memory that is valid within the buffer. Also validate
that the WNODE_ALL_DATA is properly formed.
This routine MUST succeed before any fields in the WNODE_ALL_DATA can be
used by any kernel components when passed in from user mode. Note that
we can trust that the input and output buffer are properly sized since
the WMI IOCTLs are METHOD_BUFFERED and the IO manager does that for us.
WNODE_ALL_DATA_RULES:
1. Wnode is aligned on a 8 byte boundry
2. The incoming buffer must be at least as large as sizeof(WNODE_HEADER)
3. The outgoing buffer must be at least as large as sizeof(WNODE_ALL_DATA)
5. WnodeHeader->BufferSize must equal incoming bufffer size
Arguments:
Wnode - WNODE_ALL_DATA to be validated
InBufferLen - Size of the incoming buffer
OutBufferLen - Size of the outgoing buffer
Return Value:
NT status code
--*/
{
NTSTATUS Status;
PWNODE_HEADER WnodeHeader = (PWNODE_HEADER)Wnode;
PAGED_CODE();
#if DBG
//
// Make sure WNODE is on a 8 byte boundry
// if (! WmipIsAligned((PUCHAR)Wnode, 8))
// {
// return(STATUS_UNSUCCESSFUL);
// }
#endif
//
// Make sure that enough of the WNODE_ALL_DATA was passed so that we
// can look at it and the drivers can fill it in
if ((InBufferLen < sizeof(WNODE_HEADER)) ||
(OutBufferLen < sizeof(WNODE_ALL_DATA)))
{
return(STATUS_UNSUCCESSFUL);
}
Status = WmipValidateWnodeHeader(WnodeHeader,
InBufferLen,
sizeof(WNODE_HEADER),
WNODE_FLAG_ALL_DATA,
0xffffff7e);
return(Status);
}
NTSTATUS WmipProbeWnodeSingleInstance(
PWNODE_SINGLE_INSTANCE Wnode,
ULONG InBufferLen,
ULONG OutBufferLen,
BOOLEAN OutBound
)
/*++
Routine Description:
Probe the incoming WNODE_SINGLE_INSTANCE to ensure that any offsets in the
header point to memory that is valid within the buffer. Also validate
that the WNODE_SINGLE_INSTANCE is properly formed.
This routine MUST succeed before any fields in the WNODE_SINGLE_INSTANCE
can be used by any kernel components when passed in from user mode.
Note that we can trust that the input and output buffer are properly
sized since the WMI IOCTLs are METHOD_BUFFERED and the IO manager does
that for us.
WNODE_SINGLE_INSTANCE Rules:
1. The incoming buffer must be at least as large as
sizeof(WNODE_SINGLE_INSTANCE)
2. The outgoing buffer must be at least as large as
sizeof(WNODE_SINGLE_INSTANCE)
3. WnodeHeader->ProviderId must be non null, Actual value validated when
irp is forwarded.
4. WnodeHeader->BufferSize must equal incoming bufffer size
5. Wnode->DataBlockOffset must be 0 (implying no data) or
Wnode->DataBlockOffset must be <= incoming buffer size and >=
sizeof(WNODE_SINGLE_INSTANCE), that is
the data block must start in the incoming buffer, but after the
WNODE_SINGLE_INSTANCE header.
6. Wnode and Wnode->DataBlockOffset must be aligned on an 8 byte boundry.
7. For inbound data (SetSingleInstance) (Wnode->DataBlockOffset +
Wnode->DataBlockSize) <= incoming buffer length. That is the entire
data block must fit within the incoming buffer.
8. For outbound data (QuerySingleInstance) Wnode->DataBlockOffset
must be <= outgoing buffer length. That is the start of the outgoing
data block must fit within the outgoing data buffer. Note that it is
the provider's responsibility to determine if there will be enough
space in the outgoing buffer to write the returned data.
9. For outbound data (QuerySingleInstance) WnodeDataBlockOffset != 0
10. Wnode->OffsetInstanceNames must be aligned on a 2 byte boundry
11. Wnode->OffsetInstanceNames + sizeof(USHORT) must be <= incoming
buffer size, that is it must start within the incoming buffer and
the USHORT that specifies the length must be within the incoming
buffer.
12. The entire instance name string must fit with the incoming buffer
13. For outbound data (QuerySingleInstance) the entire instance name
must start and fit within the output buffer.
14. Wnode->DataBlockOffset must be placed after any instance name and
not overlap the instance name.
Arguments:
Wnode - WNODE_SINGLE_INSTANCE to be validated
InBufferLen - Size of the incoming buffer
OutBufferLen - Size of the outgoing buffer
OutBound - If FALSE, WNODE_SINGLE_INSTANCE has inbound data that must be
validated to be within the input buffer. If FALSE,
WNODE_SINGLE_INSTANCE is expected to be filled with data
by the driver so insure that data buffer is validated to
be within the output buffer.
Return Value:
NT status code
--*/
{
PWNODE_HEADER WnodeHeader = (PWNODE_HEADER)Wnode;
NTSTATUS Status;
PAGED_CODE();
//
// Make sure WNODE is on a 8 byte boundry
#if DBG
// if (! WmipIsAligned((PUCHAR)Wnode, 8))
// {
// return(STATUS_UNSUCCESSFUL);
// }
#endif
//
// Make sure that enough of the WNODE_SINGLE_INSTANCE was passed
// so that we can look at it
if ((InBufferLen < FIELD_OFFSET(WNODE_SINGLE_INSTANCE, VariableData)) ||
( (OutBound) && (OutBufferLen < FIELD_OFFSET(WNODE_SINGLE_INSTANCE,
VariableData))))
{
return(STATUS_UNSUCCESSFUL);
}
Status = WmipProbeWnodeWorker(WnodeHeader,
FIELD_OFFSET(WNODE_SINGLE_INSTANCE,
VariableData),
Wnode->OffsetInstanceName,
Wnode->DataBlockOffset,
Wnode->SizeDataBlock,
InBufferLen,
OutBufferLen,
OutBound,
(BOOLEAN)(! OutBound));
if (NT_SUCCESS(Status))
{
Status = WmipValidateWnodeHeader(WnodeHeader,
InBufferLen,
FIELD_OFFSET(WNODE_SINGLE_INSTANCE,
VariableData),
WNODE_FLAG_SINGLE_INSTANCE,
0xffffff7d);
}
return(Status);
}
NTSTATUS WmipProbeWnodeSingleItem(
PWNODE_SINGLE_ITEM Wnode,
ULONG InBufferLen
)
/*++
Routine Description:
Probe the incoming WNODE_SINGLE_ITEM to ensure that any offsets in the
header point to memory that is valid within the buffer. Also validate
that the WNODE_SINGLE_ITEM is properly formed.
This routine MUST succeed before any fields in the WNODE_SINGLE_INSTANCE
can be used by any kernel components when passed in from user mode.
Note that we can trust that the input and output buffer are properly
sized since the WMI IOCTLs are METHOD_BUFFERED and the IO manager does
that for us.
WNODE_SINGLE_ITEM rules:
1. The incoming buffer must be at least as large as
sizeof(WNODE_SINGLE_ITEM)
2. The outgoing buffer must be at least as large as
sizeof(WNODE_SINGLE_ITEM)
3. WnodeHeader->ProviderId must be non null, Actual value validated when
irp is forwarded.
4. WnodeHeader->BufferSize must equal incoming bufffer size
5. Wnode->DataBlockOffset must be 0 (implying no data) or
Wnode->DataBlockOffset must be <= incoming buffer size and >=
sizeof(WNODE_SINGLE_ITEM), that is
the data block must start in the incoming buffer, but after the
WNODE_SINGLE_ITEM header.
6. Wnode and Wnode->DataBlockOffset must be aligned on an 8 byte boundry.
7. (Wnode->DataBlockOffset + Wnode->SizeDataItem) <
incoming buffer length. That is the entire
data block must fit within the incoming buffer.
8. Wnode->DataItemId must not be 0
9. Wnode->OffsetInstanceNames must be aligned on a 2 byte boundry
10. Wnode->OffsetInstanceNames must be <= (incoming buffer size) +
sizeof(USHORT), that is it must start within the incoming buffer and
the USHORT that specifies the length must be within the incoming
buffer.
11. The entire instance name string must fit with the incoming buffer
12. Wnode->DataBlockOffset must be placed after any instance name and
not overlap the instance name.
Arguments:
Wnode - WNODE_SINGLE_ITEM to be validated
InBufferLen - Size of the incoming buffer
Return Value:
NT status code
--*/
{
PWNODE_HEADER WnodeHeader = (PWNODE_HEADER)Wnode;
NTSTATUS Status;
PAGED_CODE();
//
// Make sure WNODE is on a 8 byte boundry
#if DBG
// if (! WmipIsAligned((PUCHAR)Wnode, 8))
// {
// return(STATUS_UNSUCCESSFUL);
// }
#endif
//
// Make sure that enough of the WNODE_SINGLE_ITEM was passed
// so that we can look at it
if (InBufferLen < FIELD_OFFSET(WNODE_SINGLE_ITEM, VariableData))
{
return(STATUS_UNSUCCESSFUL);
}
#if DBG
// if (Wnode->ItemId == 0)
// {
// return(STATUS_UNSUCCESSFUL);
// }
#endif
//
// We don't use sizeof(WNODE_SINGLE_ITEM), but rather use the offset
// to the variable data since in the case of WNODE_SINGLE_ITEM they are
// different. The C compiler will round up the packing to 8 bytes so
// the former is 48 and the later is 44.
Status = WmipProbeWnodeWorker(WnodeHeader,
(ULONG)((ULONG_PTR)(&((PWNODE_SINGLE_ITEM)0)->VariableData)),
Wnode->OffsetInstanceName,
Wnode->DataBlockOffset,
Wnode->SizeDataItem,
InBufferLen,
0,
FALSE,
TRUE);
if (NT_SUCCESS(Status))
{
Status = WmipValidateWnodeHeader(WnodeHeader,
InBufferLen,
FIELD_OFFSET(WNODE_SINGLE_ITEM,
VariableData),
WNODE_FLAG_SINGLE_ITEM,
0xffffff7b);
}
return(Status);
}
NTSTATUS WmipProbeWnodeMethodItem(
PWNODE_METHOD_ITEM Wnode,
ULONG InBufferLen,
ULONG OutBufferLen
)
/*++
Routine Description:
Probe the incoming WNODE_METHOD_ITEM to ensure that any offsets in the
header point to memory that is valid within the buffer. Also validate
that the WNODE_METHOD_ITEM is properly formed.
This routine MUST succeed before any fields in the WNODE_METHOD_INSTANCE
can be used by any kernel components when passed in from user mode.
Note that we can trust that the input and output buffer are properly
sized since the WMI IOCTLs are METHOD_BUFFERED and the IO manager does
that for us.
WNODE_METHOD_ITEM Rules:
1. The incoming buffer must be at least as large as
sizeof(WNODE_METHOD_ITEM)
2. The outgoing buffer must be at least as large as
sizeof(WNODE_METHOD_ITEM)
3. WnodeHeader->ProviderId must be non null, Actual value validated when
irp is forwarded and Wnode->MethodId must not be 0
4. WnodeHeader->BufferSize must equal incoming bufffer size
5. Wnode->DataBlockOffset must be 0 (implying no data) or
Wnode->DataBlockOffset must be <= incoming buffer size and >=
sizeof(WNODE_METHOD_ITEM), that is
the data block must start in the incoming buffer, but after the
WNODE_METHOD_ITEM header.
6. Wnode and Wnode->DataBlockOffset must be aligned on an 8 byte boundry.
7. For inbound data (Wnode->DataBlockOffset +
Wnode->DataBlockSize) < incoming buffer length. That is the entire
data block must fit within the incoming buffer.
8. For outbound data Wnode->DataBlockOffset
must be <= outgoing buffer length. That is the start of the outgoing
data block must fit within the outgoing data buffer. Note that it is
the provider's responsibility to determine if there will be enough
space in the outgoing buffer to write the returned data.
9. WnodeDataBlockOffset != 0
10. Wnode->OffsetInstanceNames must be aligned on a 2 byte boundry
11. Wnode->OffsetInstanceNames must be <= (incoming buffer size) +
sizeof(USHORT), that is it must start within the incoming buffer and
the USHORT that specifies the length must be within the incoming
buffer.
12. The entire instance name string must fit with the incoming buffer
13. For outbound data the entire instance name
must start and fit within the output buffer.
14. Wnode->DataBlockOffset must be placed after any instance name and
not overlap the instance name.
Arguments:
Wnode - WNODE_METHOD_ITEM to be validated
InBufferLen - Size of the incoming buffer
OutBufferLen - Size of the Output buffer
Return Value:
NT status code
--*/
{
PWNODE_HEADER WnodeHeader = (PWNODE_HEADER)Wnode;
NTSTATUS Status;
PAGED_CODE();
//
// Make sure WNODE is on a 8 byte boundry
#if DBG
// if (! WmipIsAligned((PUCHAR)Wnode, 8))
// {
// return(STATUS_UNSUCCESSFUL);
// }
#endif
//
// Make sure that enough of the WNODE_METHOD_ITEM was passed
// so that we can look at it
if (InBufferLen < FIELD_OFFSET(WNODE_METHOD_ITEM, VariableData))
{
return(STATUS_UNSUCCESSFUL);
}
#if DBG
if (Wnode->MethodId == 0)
{
return(STATUS_UNSUCCESSFUL);
}
#endif
Status = WmipProbeWnodeWorker(WnodeHeader,
(ULONG)((ULONG_PTR)(&((PWNODE_METHOD_ITEM)0)->VariableData)),
Wnode->OffsetInstanceName,
Wnode->DataBlockOffset,
Wnode->SizeDataBlock,
InBufferLen,
OutBufferLen,
TRUE,
TRUE);
if (NT_SUCCESS(Status))
{
Status = WmipValidateWnodeHeader(WnodeHeader,
InBufferLen,
FIELD_OFFSET(WNODE_METHOD_ITEM,
VariableData),
WNODE_FLAG_METHOD_ITEM,
0xffff7f7f);
}
return(Status);
}
NTSTATUS WmipProbeAndCaptureGuidObjectAttributes(
POBJECT_ATTRIBUTES CapturedObjectAttributes,
PUNICODE_STRING CapturedGuidString,
PWCHAR CapturedGuidBuffer,
POBJECT_ATTRIBUTES ObjectAttributes
)
{
PAGED_CODE();
#if defined(_WIN64)
if (IoIs32bitProcess(NULL))
{
POBJECT_ATTRIBUTES32 ObjectAttributes32;
PUNICODE_STRING32 GuidString32;
//
// Probe the embedded object attributes and string name
//
ObjectAttributes32 = (POBJECT_ATTRIBUTES32)ObjectAttributes;
try
{
//
// Probe, capture and validate the OBJECT_ATTRIBUTES
//
ProbeForRead( ObjectAttributes32,
sizeof(OBJECT_ATTRIBUTES32),
sizeof(ULONG) );
CapturedObjectAttributes->Length = sizeof(OBJECT_ATTRIBUTES);
CapturedObjectAttributes->RootDirectory = UlongToPtr(ObjectAttributes32->RootDirectory);
CapturedObjectAttributes->Attributes = ObjectAttributes32->Attributes;
CapturedObjectAttributes->SecurityDescriptor = UlongToPtr(ObjectAttributes32->SecurityDescriptor);
CapturedObjectAttributes->SecurityQualityOfService = UlongToPtr(ObjectAttributes32->SecurityQualityOfService);
//
// Now probe and validate the guid nane string passed
//
GuidString32 = UlongToPtr(ObjectAttributes32->ObjectName);
ProbeForRead(GuidString32,
sizeof(UNICODE_STRING32),
sizeof(ULONG));
CapturedGuidString->Length = GuidString32->Length;
CapturedGuidString->MaximumLength = GuidString32->MaximumLength;
CapturedGuidString->Buffer = UlongToPtr(GuidString32->Buffer);
if (CapturedGuidString->Length != (WmiGuidObjectNameLength * sizeof(WCHAR)))
{
return(STATUS_INVALID_PARAMETER);
}
ProbeForRead(CapturedGuidString->Buffer,
CapturedGuidString->Length,
sizeof(UCHAR));
RtlCopyMemory(CapturedGuidBuffer,
CapturedGuidString->Buffer,
WmiGuidObjectNameLength * sizeof(WCHAR));
CapturedGuidBuffer[WmiGuidObjectNameLength] = UNICODE_NULL;
CapturedGuidString->Buffer = CapturedGuidBuffer;
} except(EXCEPTION_EXECUTE_HANDLER) {
return(GetExceptionCode());
}
}
else
#endif
{
PUNICODE_STRING GuidString;
//
// Probe the embedded object attributes and string name
//
try
{
//
// Probe, capture and validate the OBJECT_ATTRIBUTES
//
*CapturedObjectAttributes = ProbeAndReadStructure( ObjectAttributes,
OBJECT_ATTRIBUTES);
//
// Now probe and validate the guid nane string passed
//
GuidString = CapturedObjectAttributes->ObjectName;
*CapturedGuidString = ProbeAndReadUnicodeString(GuidString);
if (CapturedGuidString->Length != (WmiGuidObjectNameLength * sizeof(WCHAR)))
{
return(STATUS_INVALID_PARAMETER);
}
ProbeForRead(CapturedGuidString->Buffer,
CapturedGuidString->Length,
sizeof(UCHAR));
RtlCopyMemory(CapturedGuidBuffer,
CapturedGuidString->Buffer,
WmiGuidObjectNameLength * sizeof(WCHAR));
CapturedGuidBuffer[WmiGuidObjectNameLength] = UNICODE_NULL;
CapturedGuidString->Buffer = CapturedGuidBuffer;
} except(EXCEPTION_EXECUTE_HANDLER) {
return(GetExceptionCode());
}
}
CapturedObjectAttributes->ObjectName = CapturedGuidString;
return(STATUS_SUCCESS);
}
NTSTATUS WmipProbeWmiOpenGuidBlock(
POBJECT_ATTRIBUTES CapturedObjectAttributes,
PUNICODE_STRING CapturedGuidString,
PWCHAR CapturedGuidBuffer,
PULONG DesiredAccess,
PWMIOPENGUIDBLOCK InGuidBlock,
ULONG InBufferLen,
ULONG OutBufferLen
)
{
NTSTATUS Status;
POBJECT_ATTRIBUTES ObjectAttributes;
PAGED_CODE();
#if defined(_WIN64)
if (IoIs32bitProcess(NULL))
{
PWMIOPENGUIDBLOCK32 InGuidBlock32;
if ((InBufferLen != sizeof(WMIOPENGUIDBLOCK32)) ||
(OutBufferLen != sizeof(WMIOPENGUIDBLOCK32)))
{
return(STATUS_UNSUCCESSFUL);
}
//
// Probe the embedded object attributes and string name
//
InGuidBlock32 = (PWMIOPENGUIDBLOCK32)InGuidBlock;
ObjectAttributes = ULongToPtr(InGuidBlock32->ObjectAttributes);
*DesiredAccess = InGuidBlock32->DesiredAccess;
}
else
#endif
{
//
// Ensure the input and output buffer sizes are correct
//
if ((InBufferLen != sizeof(WMIOPENGUIDBLOCK)) ||
(OutBufferLen != sizeof(WMIOPENGUIDBLOCK)))
{
return(STATUS_UNSUCCESSFUL);
}
//
// Probe the embedded object attributes and string name
//
ObjectAttributes = InGuidBlock->ObjectAttributes;
*DesiredAccess = InGuidBlock->DesiredAccess;
}
Status = WmipProbeAndCaptureGuidObjectAttributes(CapturedObjectAttributes,
CapturedGuidString,
CapturedGuidBuffer,
ObjectAttributes);
if (NT_SUCCESS(Status))
{
if ((CapturedObjectAttributes->RootDirectory != NULL) ||
(CapturedObjectAttributes->Attributes != 0) ||
(CapturedObjectAttributes->SecurityDescriptor != NULL) ||
(CapturedObjectAttributes->SecurityQualityOfService != NULL))
{
Status = STATUS_INVALID_PARAMETER;
}
}
return(Status);
}
NTSTATUS WmipProbeWmiRegRequest(
PWMIREGREQUEST Buffer,
ULONG InBufferLen,
ULONG OutBufferLen
)
/*++
Routine Description:
Probe the incoming WMIREGREQUEST to ensure that any offsets in the
header point to memory that is valid within the buffer. Also validate
that the WMIREGINFO is properly formed.
This routine MUST succeed before any fields in the WMI_REG_INFO
can be used by any kernel components when passed in from user mode.
Note that we can trust that the input and output buffer are properly
sized since the WMI IOCTLs are METHOD_BUFFERED and the IO manager does
that for us.
WMIREGREQUEST Rules:
1. The incoming buffer must be at least as large as
sizeof(WMIREGREQUEST) + sizeof(WMIREGINFOW)
2. The outgoing buffer must be at least as large as
sizeof(WMIREGRESULTS)
3. WmiRegInfo->BufferSize must be less than incoming Buffer size minus
sizeof(WMIREGREQUEST)
4. GuidCount must be at least 1 and less than MAXWMIGUIDCOUNT
5. WmiRegInfo->BufferSize must be greater than equal to
sizeof(WMIREGINFOW) + WmiRegInfo->GuidCount * sizeof(WMIREGGUIDW)
5. WmiRegInfo->RegistryPath offset must be within the incoming buffer
6. WmiRegInfo->MofResourcePath offset must be within the incomoing buffer
7. RegistryPath and MofResourceName strings are counted unicode strings.
Their length must be within the incoming buffer
8. For WOW64, RefInfo32Size and RegGuid32Size passed in must be non-zero and
cannot be larger than their 64 bit counter part.
9. Since we decipher the counted strings at a buffer offset, the offset
must be aligned to 2 bytes (for USHORT).
10. Trace Registrations do not use InstanceNames within REGGUIDW.
Therefore InstanceCount and InstanceNameList fields must be zero.
Arguments:
Buffer - WMIREGREQUEST to be validated
InBufferLen - Size of the incoming buffer
OutBufferLen - Size of the Output buffer
Return Value:
NT status code
--*/
{
HANDLE RequestHandle;
ULONG WmiRegInfoSize;
PWMIREGINFOW WmiRegInfo;
PWMIREGRESULTS WmiRegResults;
PWMIREGREQUEST WmiRegRequest;
PWMIREGINFOW WmiRegInfoThunk = NULL;
PWMIREGGUIDW WmiRegGuid;
ULONG GuidCount;
ULONG SizeNeeded;
ULONG ImageNameLength=0;
ULONG ResourceNameLength=0;
PUCHAR pSource;
ULONG i;
PAGED_CODE();
//
// Incoming Buffer must be atleast the sizeof WMIREGREQUEST + WMIREGINFO
//
if (InBufferLen >= (sizeof(WMIREGREQUEST) + sizeof(WMIREGINFO)))
{
WmiRegRequest = (PWMIREGREQUEST)Buffer;
WmiRegInfo = (PWMIREGINFOW) OffsetToPtr (Buffer, sizeof(WMIREGREQUEST));
WmiRegInfoSize = WmiRegInfo->BufferSize;
GuidCount = WmiRegRequest->GuidCount;
// We are rejecting any MOF notifications.
WmiRegInfo->RegistryPath = 0;
WmiRegInfo->MofResourceName = 0;
//
// BufferSize specified must be within the size of incoming Buffer.
//
if (WmiRegInfoSize <= (InBufferLen - sizeof(WMIREGREQUEST)) )
{
if ((GuidCount == 0) || (GuidCount > WMIMAXREGGUIDCOUNT))
{
return STATUS_UNSUCCESSFUL;
}
//
// Make sure the RegistryPath and MofResourceName offsets are
// within the REGINFO buffer.
//
if ( (WmiRegInfo->RegistryPath >= WmiRegInfoSize) ||
(WmiRegInfo->MofResourceName >= WmiRegInfoSize) ) {
return STATUS_UNSUCCESSFUL;
}
//
// Validate the Counted Strings.
//
if (WmiRegInfo->RegistryPath > 0)
{
//
// String Offsets need to be aligned to 2 Bytes
//
if (( WmiRegInfo->RegistryPath & 1) != 0)
{
return STATUS_UNSUCCESSFUL;
}
ImageNameLength = *((PUSHORT)OffsetToPtr(WmiRegInfo, WmiRegInfo->RegistryPath) );
ImageNameLength += sizeof(USHORT);
if ((WmiRegInfo->RegistryPath + ImageNameLength ) > WmiRegInfoSize)
{
return STATUS_UNSUCCESSFUL;
}
}
if (WmiRegInfo->MofResourceName > 0)
{
if ((WmiRegInfo->MofResourceName & 1) != 0)
{
return STATUS_UNSUCCESSFUL;
}
ResourceNameLength = *((PUSHORT)OffsetToPtr(WmiRegInfo, WmiRegInfo->MofResourceName));
ResourceNameLength += sizeof(USHORT);
if ( (WmiRegInfo->MofResourceName + ResourceNameLength) > WmiRegInfoSize)
{
return STATUS_UNSUCCESSFUL;
}
}
// Note: If the ImagePath and MofResource trample over each other but stayed
// within BufferSize , we will not catch it.
#if defined(_WIN64)
if (IoIs32bitProcess(NULL))
{
//
// Check to make sure the 32 bit structure sizes passed in
// by the caller is comparable to the 64-bit counterparts
//
if ((WmiRegRequest->WmiRegInfo32Size == 0) ||
(WmiRegRequest->WmiRegInfo32Size > sizeof(WMIREGINFOW)) )
{
return STATUS_UNSUCCESSFUL;
}
if ((WmiRegRequest->WmiRegGuid32Size == 0) ||
(WmiRegRequest->WmiRegGuid32Size > sizeof(WMIREGGUIDW)) )
{
return STATUS_UNSUCCESSFUL;
}
//
// InstanceCount and InstanceNameList in
// WMIREGGUIDW structure must be zero. This check is
// done after thunking gor WOW64.
//
SizeNeeded = WmiRegRequest->WmiRegInfo32Size +
GuidCount * WmiRegRequest->WmiRegGuid32Size +
ImageNameLength +
ResourceNameLength;
}
else
#endif
{
//
// Check to see if the InstanceCount and InstanceNameList in
// WMIREGGUIDW structure is zero
//
pSource = OffsetToPtr(WmiRegInfo, sizeof(WMIREGINFOW) );
for (i=0; i < GuidCount; i++) {
WmiRegGuid = (PWMIREGGUIDW) pSource;
if ( (WmiRegGuid->InstanceCount > 0) ||
(WmiRegGuid->InstanceNameList > 0) )
{
return STATUS_UNSUCCESSFUL;
}
pSource += sizeof(WMIREGGUIDW);
}
SizeNeeded = sizeof(WMIREGINFOW) +
GuidCount * sizeof(WMIREGGUIDW) +
ImageNameLength +
ResourceNameLength;
}
if (SizeNeeded > WmiRegInfoSize) {
return STATUS_UNSUCCESSFUL;
}
//
// Now validate the OutBuffer size needed
//
SizeNeeded = sizeof(TRACEGUIDMAP) * GuidCount + sizeof(WMIREGRESULTS);
if (SizeNeeded > OutBufferLen)
{
return STATUS_UNSUCCESSFUL;
}
//
// All tests passed. Return SUCCESS
//
return STATUS_SUCCESS;
}
}
return STATUS_UNSUCCESSFUL;
}