/*++ Copyright (c) Microsoft Corporation Module Name: FxRegKey.cpp Abstract: Author: Environment: kernel mode only Revision History: --*/ #include "FxSupportPch.hpp" extern "C" { #include "FxRegKeyKM.tmh" } #define AT_PASSIVE() ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL) FxRegKey::FxRegKey( PFX_DRIVER_GLOBALS FxDriverGlobals ) : FxPagedObject(FX_TYPE_REG_KEY, sizeof(FxRegKey), FxDriverGlobals), m_Key(NULL), m_Globals(FxDriverGlobals) { } __drv_maxIRQL(PASSIVE_LEVEL) FxRegKey::~FxRegKey() { if (m_Key != NULL) { ZwClose(m_Key); m_Key = NULL; } } __drv_maxIRQL(PASSIVE_LEVEL) NTSTATUS FxRegKey::_Close( __in HANDLE Key ) { return ZwClose(Key); } _Must_inspect_result_ __drv_maxIRQL(PASSIVE_LEVEL) NTSTATUS FxRegKey::_Create( __in_opt HANDLE ParentKey, __in PCUNICODE_STRING KeyName, __out HANDLE* NewKey, __in ACCESS_MASK DesiredAccess, __in ULONG CreateOptions, __out_opt PULONG CreateDisposition ) { OBJECT_ATTRIBUTES oa; AT_PASSIVE(); // // Force OBJ_KERNEL_HANDLE because we are never passing the handle back // up to a process and we don't want to create a handle in an arbitrary // process from which that process can close the handle out from underneath // us. // InitializeObjectAttributes( &oa, (PUNICODE_STRING) KeyName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, ParentKey, NULL); return ZwCreateKey(NewKey, DesiredAccess, &oa, 0, 0, CreateOptions, CreateDisposition); } _Must_inspect_result_ __drv_maxIRQL(PASSIVE_LEVEL) NTSTATUS FxRegKey::_OpenKey( __in_opt HANDLE ParentKey, __in PCUNICODE_STRING KeyName, __out HANDLE* Key, __in ACCESS_MASK DesiredAccess ) { OBJECT_ATTRIBUTES oa; AT_PASSIVE(); // // Force OBJ_KERNEL_HANDLE because we are never passing the handle back // up to a process and we don't want to create a handle in an arbitrary // process from which that process can close the handle out from underneath // us. // InitializeObjectAttributes( &oa, (PUNICODE_STRING)KeyName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, ParentKey, NULL); return ZwOpenKey(Key, DesiredAccess, &oa); } _Must_inspect_result_ __drv_maxIRQL(PASSIVE_LEVEL) NTSTATUS FxRegKey::_SetValue( _In_ HANDLE Key, __in PCUNICODE_STRING ValueName, __in ULONG ValueType, __in_bcount(ValueLength) PVOID Value, __in ULONG ValueLength ) { AT_PASSIVE(); return ZwSetValueKey(Key, (PUNICODE_STRING)ValueName, 0, ValueType, Value, ValueLength); } _Must_inspect_result_ __drv_maxIRQL(PASSIVE_LEVEL) NTSTATUS FxRegKey::_QueryValue( __in PFX_DRIVER_GLOBALS FxDriverGlobals, __in HANDLE Key, __in PCUNICODE_STRING ValueName, __in ULONG ValueLength, __out_bcount_opt(ValueLength) PVOID Value, __out_opt PULONG ValueLengthQueried, __out_opt PULONG ValueType ) { KEY_VALUE_PARTIAL_INFORMATION *pPartial, partial; NTSTATUS status; ULONG length; if (Value == NULL) { // // Caller wants just the length // pPartial = &partial; length = _ComputePartialSize(0); RtlZeroMemory(&partial, length); } else { length = _ComputePartialSize(ValueLength); pPartial = (PKEY_VALUE_PARTIAL_INFORMATION) MxMemory::MxAllocatePoolWithTag(PagedPool, length, FxDriverGlobals->Tag); if (pPartial == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } } // // We always pass a buffer of at least sizeof(KEY_VALUE_PARTIAL_INFORMATION) // to ZwQueryValueKey. This means that ZwQueryValueKey will write at least // some information to the buffer it receives, even if the user-supplied data // buffer is NULL or too small. // // According to ZwQueryValueKey's contract, this means that it will never return // STATUS_BUFFER_TOO_SMALL (returned when no data is written). Therefore, if the // user passes a NULL or insufficient buffer and the value exists in the registry, // ZwQueryValueKey will return STATUS_BUFFER_OVERFLOW. // status = ZwQueryValueKey(Key, (PUNICODE_STRING)ValueName, KeyValuePartialInformation, pPartial, length, &length); if (NT_SUCCESS(status) && Value != NULL && (ValueLength >= pPartial->DataLength)) { RtlCopyMemory(Value, &pPartial->Data[0], pPartial->DataLength); } if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) { if (ValueLengthQueried != NULL) { *ValueLengthQueried = pPartial->DataLength; } if (ValueType != NULL) { *ValueType = pPartial->Type; } } if (pPartial != &partial) { MxMemory::MxFreePool(pPartial); } return status; } _Must_inspect_result_ __drv_maxIRQL(PASSIVE_LEVEL) NTSTATUS FxRegKey::_QueryULong( __in HANDLE Key, __in PCUNICODE_STRING ValueName, __out PULONG Value ) { NTSTATUS status; ULONG length; PKEY_VALUE_PARTIAL_INFORMATION pPartial; UCHAR buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)+(sizeof(ULONG))]; length = sizeof(buffer); pPartial = (PKEY_VALUE_PARTIAL_INFORMATION) &buffer[0]; status = ZwQueryValueKey(Key, (PUNICODE_STRING)ValueName, KeyValuePartialInformation, pPartial, length, &length); if ((NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) && pPartial->Type != REG_DWORD) { status = STATUS_OBJECT_TYPE_MISMATCH; } if (NT_SUCCESS(status)) { ASSERT(sizeof(ULONG) == pPartial->DataLength); RtlCopyMemory(Value, &pPartial->Data[0], sizeof(ULONG)); } return status; } _Must_inspect_result_ __drv_maxIRQL(PASSIVE_LEVEL) NTSTATUS FxRegKey::_QueryQuadWord( __in HANDLE Key, __in PCUNICODE_STRING ValueName, __out PLARGE_INTEGER Value ) { NTSTATUS status; ULONG length; PKEY_VALUE_PARTIAL_INFORMATION pPartial; UCHAR buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)+(sizeof(LARGE_INTEGER))]; length = sizeof(buffer); pPartial = (PKEY_VALUE_PARTIAL_INFORMATION) &buffer[0]; status = ZwQueryValueKey(Key, (PUNICODE_STRING)ValueName, KeyValuePartialInformation, pPartial, length, &length); if ((NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) && pPartial->Type != REG_QWORD) { status = STATUS_OBJECT_TYPE_MISMATCH; } if (NT_SUCCESS(status)) { ASSERT(sizeof(LARGE_INTEGER) == pPartial->DataLength); RtlCopyMemory(Value, &pPartial->Data[0], sizeof(LARGE_INTEGER)); } return status; }