1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxRegKey.cpp 8 9 Abstract: 10 11 Author: 12 13 Environment: 14 15 kernel mode only 16 17 Revision History: 18 19 --*/ 20 21 #include "fxsupportpch.hpp" 22 23 extern "C" { 24 // #include "FxRegKeyKM.tmh" 25 } 26 27 #define AT_PASSIVE() ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL) 28 29 FxRegKey::FxRegKey( 30 PFX_DRIVER_GLOBALS FxDriverGlobals 31 ) : 32 FxPagedObject(FX_TYPE_REG_KEY, sizeof(FxRegKey), FxDriverGlobals), 33 m_Key(NULL), 34 m_Globals(FxDriverGlobals) 35 { 36 } 37 38 __drv_maxIRQL(PASSIVE_LEVEL) 39 FxRegKey::~FxRegKey() 40 { 41 if (m_Key != NULL) { 42 ZwClose(m_Key); 43 m_Key = NULL; 44 } 45 } 46 47 __drv_maxIRQL(PASSIVE_LEVEL) 48 NTSTATUS 49 FxRegKey::_Close( 50 __in HANDLE Key 51 ) 52 { 53 return ZwClose(Key); 54 } 55 56 _Must_inspect_result_ 57 __drv_maxIRQL(PASSIVE_LEVEL) 58 NTSTATUS 59 FxRegKey::_Create( 60 __in_opt HANDLE ParentKey, 61 __in PCUNICODE_STRING KeyName, 62 __out HANDLE* NewKey, 63 __in ACCESS_MASK DesiredAccess, 64 __in ULONG CreateOptions, 65 __out_opt PULONG CreateDisposition 66 ) 67 { 68 OBJECT_ATTRIBUTES oa; 69 70 AT_PASSIVE(); 71 72 // 73 // Force OBJ_KERNEL_HANDLE because we are never passing the handle back 74 // up to a process and we don't want to create a handle in an arbitrary 75 // process from which that process can close the handle out from underneath 76 // us. 77 // 78 InitializeObjectAttributes( 79 &oa, 80 (PUNICODE_STRING) KeyName, 81 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 82 ParentKey, 83 NULL); 84 85 return ZwCreateKey(NewKey, 86 DesiredAccess, 87 &oa, 88 0, 89 0, 90 CreateOptions, 91 CreateDisposition); 92 } 93 94 _Must_inspect_result_ 95 __drv_maxIRQL(PASSIVE_LEVEL) 96 NTSTATUS 97 FxRegKey::_OpenKey( 98 __in_opt HANDLE ParentKey, 99 __in PCUNICODE_STRING KeyName, 100 __out HANDLE* Key, 101 __in ACCESS_MASK DesiredAccess 102 ) 103 { 104 OBJECT_ATTRIBUTES oa; 105 106 AT_PASSIVE(); 107 108 // 109 // Force OBJ_KERNEL_HANDLE because we are never passing the handle back 110 // up to a process and we don't want to create a handle in an arbitrary 111 // process from which that process can close the handle out from underneath 112 // us. 113 // 114 InitializeObjectAttributes( 115 &oa, 116 (PUNICODE_STRING)KeyName, 117 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 118 ParentKey, 119 NULL); 120 121 return ZwOpenKey(Key, DesiredAccess, &oa); 122 } 123 124 _Must_inspect_result_ 125 __drv_maxIRQL(PASSIVE_LEVEL) 126 NTSTATUS 127 FxRegKey::_SetValue( 128 _In_ HANDLE Key, 129 __in PCUNICODE_STRING ValueName, 130 __in ULONG ValueType, 131 __in_bcount(ValueLength) PVOID Value, 132 __in ULONG ValueLength 133 ) 134 { 135 AT_PASSIVE(); 136 137 return ZwSetValueKey(Key, 138 (PUNICODE_STRING)ValueName, 139 0, 140 ValueType, 141 Value, 142 ValueLength); 143 } 144 145 _Must_inspect_result_ 146 __drv_maxIRQL(PASSIVE_LEVEL) 147 NTSTATUS 148 FxRegKey::_QueryValue( 149 __in PFX_DRIVER_GLOBALS FxDriverGlobals, 150 __in HANDLE Key, 151 __in PCUNICODE_STRING ValueName, 152 __in ULONG ValueLength, 153 __out_bcount_opt(ValueLength) PVOID Value, 154 __out_opt PULONG ValueLengthQueried, 155 __out_opt PULONG ValueType 156 ) 157 { 158 KEY_VALUE_PARTIAL_INFORMATION *pPartial, partial; 159 NTSTATUS status; 160 ULONG length; 161 162 if (Value == NULL) { 163 // 164 // Caller wants just the length 165 // 166 pPartial = &partial; 167 length = _ComputePartialSize(0); 168 RtlZeroMemory(&partial, length); 169 } 170 else { 171 length = _ComputePartialSize(ValueLength); 172 pPartial = (PKEY_VALUE_PARTIAL_INFORMATION) 173 MxMemory::MxAllocatePoolWithTag(PagedPool, length, FxDriverGlobals->Tag); 174 175 if (pPartial == NULL) { 176 return STATUS_INSUFFICIENT_RESOURCES; 177 } 178 } 179 180 // 181 // We always pass a buffer of at least sizeof(KEY_VALUE_PARTIAL_INFORMATION) 182 // to ZwQueryValueKey. This means that ZwQueryValueKey will write at least 183 // some information to the buffer it receives, even if the user-supplied data 184 // buffer is NULL or too small. 185 // 186 // According to ZwQueryValueKey's contract, this means that it will never return 187 // STATUS_BUFFER_TOO_SMALL (returned when no data is written). Therefore, if the 188 // user passes a NULL or insufficient buffer and the value exists in the registry, 189 // ZwQueryValueKey will return STATUS_BUFFER_OVERFLOW. 190 // 191 status = ZwQueryValueKey(Key, 192 (PUNICODE_STRING)ValueName, 193 KeyValuePartialInformation, 194 pPartial, 195 length, 196 &length); 197 198 if (NT_SUCCESS(status) && Value != NULL && (ValueLength >= pPartial->DataLength)) { 199 RtlCopyMemory(Value, &pPartial->Data[0], pPartial->DataLength); 200 } 201 202 if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) { 203 if (ValueLengthQueried != NULL) { 204 *ValueLengthQueried = pPartial->DataLength; 205 } 206 if (ValueType != NULL) { 207 *ValueType = pPartial->Type; 208 } 209 } 210 211 if (pPartial != &partial) { 212 MxMemory::MxFreePool(pPartial); 213 } 214 215 return status; 216 } 217 218 _Must_inspect_result_ 219 __drv_maxIRQL(PASSIVE_LEVEL) 220 NTSTATUS 221 FxRegKey::_QueryULong( 222 __in HANDLE Key, 223 __in PCUNICODE_STRING ValueName, 224 __out PULONG Value 225 ) 226 { 227 NTSTATUS status; 228 ULONG length; 229 230 PKEY_VALUE_PARTIAL_INFORMATION pPartial; 231 UCHAR buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)+(sizeof(ULONG))]; 232 233 length = sizeof(buffer); 234 pPartial = (PKEY_VALUE_PARTIAL_INFORMATION) &buffer[0]; 235 236 status = ZwQueryValueKey(Key, 237 (PUNICODE_STRING)ValueName, 238 KeyValuePartialInformation, 239 pPartial, 240 length, 241 &length); 242 243 if ((NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) && 244 pPartial->Type != REG_DWORD) { 245 status = STATUS_OBJECT_TYPE_MISMATCH; 246 } 247 248 if (NT_SUCCESS(status)) { 249 ASSERT(sizeof(ULONG) == pPartial->DataLength); 250 251 RtlCopyMemory(Value, &pPartial->Data[0], sizeof(ULONG)); 252 } 253 254 return status; 255 } 256 257 _Must_inspect_result_ 258 __drv_maxIRQL(PASSIVE_LEVEL) 259 NTSTATUS 260 FxRegKey::_QueryQuadWord( 261 __in HANDLE Key, 262 __in PCUNICODE_STRING ValueName, 263 __out PLARGE_INTEGER Value 264 ) 265 { 266 NTSTATUS status; 267 ULONG length; 268 269 PKEY_VALUE_PARTIAL_INFORMATION pPartial; 270 UCHAR buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)+(sizeof(LARGE_INTEGER))]; 271 272 length = sizeof(buffer); 273 pPartial = (PKEY_VALUE_PARTIAL_INFORMATION) &buffer[0]; 274 275 status = ZwQueryValueKey(Key, 276 (PUNICODE_STRING)ValueName, 277 KeyValuePartialInformation, 278 pPartial, 279 length, 280 &length); 281 282 if ((NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) && 283 pPartial->Type != REG_QWORD) { 284 status = STATUS_OBJECT_TYPE_MISMATCH; 285 } 286 287 if (NT_SUCCESS(status)) { 288 ASSERT(sizeof(LARGE_INTEGER) == pPartial->DataLength); 289 290 RtlCopyMemory(Value, &pPartial->Data[0], sizeof(LARGE_INTEGER)); 291 } 292 293 return status; 294 } 295 296 297