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
FxRegKey(PFX_DRIVER_GLOBALS FxDriverGlobals)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
__drv_maxIRQL(PASSIVE_LEVEL)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
__drv_maxIRQL(PASSIVE_LEVEL)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_
__drv_maxIRQL(PASSIVE_LEVEL)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_
__drv_maxIRQL(PASSIVE_LEVEL)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_
__drv_maxIRQL(PASSIVE_LEVEL)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_
__drv_maxIRQL(PASSIVE_LEVEL)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_
__drv_maxIRQL(PASSIVE_LEVEL)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_
__drv_maxIRQL(PASSIVE_LEVEL)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