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