1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     Version.cpp
8 
9 Abstract:
10 
11     This module forms a loadable library from the WDF core libs
12 
13 Revision History:
14 
15 --*/
16 
17 #include <stdarg.h>
18 #include <stddef.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <ntverp.h>
22 
23 extern "C" {
24 #include <ntddk.h>
25 #include <ntstrsafe.h>
26 }
27 
28 #define  FX_DYNAMICS_GENERATE_TABLE   1
29 
30 #include "fx.hpp"
31 
32 #include <fxldr.h>
33 #include "fxbugcheck.h"
34 #include "wdfversionlog.h"
35 
36 #define DRIVER_OBJECT_EXTENSION_IDENTIFIER      DriverEntry
37 #define DRIVER_PARAMETERS L"Parameters"
38 #define REGISTRY_KMDF_MAJOR_VERSION L"MajorVersion"
39 #define REGISTRY_KMDF_MINOR_VERSION L"MinorVersion"
40 #define REGISTRY_KMDF_BUILD_NUMBER L"BuildNumber"
41 
42 //-----------------------------------------------------------------------------
43 // These header files are referenced in order to make internal structures
44 // available in public symbols. Various WDFKD debug commands use these
45 // internal structures to provide information about WDF.
46 //-----------------------------------------------------------------------------
47 #include "fxifr.h"
48 
49 extern "C" {
50 
51 //
52 // This is the collection of all structure/types to be make public.
53 // This union forces the structure type-info into the PDB file.
54 //
55 union {
56 
57     WDF_IFR_HEADER                    * typeWDF_IFR_HEADER;
58     WDF_IFR_RECORD                    * typeWDF_IFR_RECORD;
59     WDF_IFR_OFFSET                    * typeWDF_IFR_OFFSET;
60     WDF_BIND_INFO                     * typeWDF_BIND_INFO;
61     WDF_OBJECT_CONTEXT_TYPE_INFO      * typeWDF_OBJECT_CONTEXT_TYPE_INFO;
62     WDF_POWER_ROUTINE_TIMED_OUT_DATA  * typeWDF_POWER_ROUTINE_TIMED_OUT_DATA;
63     WDF_BUGCHECK_CODES                * typeWDF_BUGCHECK_CODES;
64     WDF_REQUEST_FATAL_ERROR_CODES     * typeWDF_REQUEST_FATAL_ERROR_CODES;
65     FX_OBJECT_INFO                    * typeFX_OBJECT_INFO;
66     FX_POOL_HEADER                    * typeFX_POOL_HEADER;
67     FX_POOL                           * typeFX_POOL;
68     FxObject                          * typeFxObject;
69     FxContextHeader                   * typeFxContextHeader;
70     FX_DUMP_DRIVER_INFO_ENTRY         * typeFX_DUMP_DRIVER_INFO_ENTRY;
71     FxTargetSubmitSyncParams          * typeFxTargetSubmitSyncParams;
72 
73 } uAllPublicTypes;
74 
75 } // extern "C" end
76 
77 //-----------------------------------------    ------------------------------------
78 
79 extern "C" {
80 
81 #include "fxdynamics.h"
82 
83 #include "fxlibrarycommon.h"
84 
85 #define  KMDF_DEFAULT_NAME   "Wdf" ## \
86                              LITERAL(__WDF_MAJOR_VERSION_STRING)   ## \
87                              "000" //minor version
88 
89 //-----------------------------------------------------------------------------
90 // local prototype definitions
91 //-----------------------------------------------------------------------------
92 extern "C"
93 DRIVER_UNLOAD DriverUnload;
94 
95 extern "C"
96 DRIVER_INITIALIZE DriverEntry;
97 
98 extern "C"
99 __drv_dispatchType(IRP_MJ_CREATE)
100 __drv_dispatchType(IRP_MJ_CLEANUP)
101 __drv_dispatchType(IRP_MJ_CLOSE)
102 DRIVER_DISPATCH FxLibraryDispatch;
103 
104 RTL_OSVERSIONINFOW  gOsVersion = { sizeof(RTL_OSVERSIONINFOW) };
105 
106 ULONG    WdfLdrDbgPrintOn = 0;
107 
108 PCHAR WdfLdrType = KMDF_DEFAULT_NAME;
109 
110 }  // extern "C"
111 
112 
113 //-----------------------------------------------------------------------------
114 //
115 //-----------------------------------------------------------------------------
116 extern "C"
117 _Must_inspect_result_
118 NTSTATUS
119 WDF_LIBRARY_COMMISSION(
120     VOID
121     );
122 
123 extern "C"
124 _Must_inspect_result_
125 NTSTATUS
126 WDF_LIBRARY_DECOMMISSION(
127     VOID
128     );
129 
130 extern "C"
131 _Must_inspect_result_
132 NTSTATUS
133 WDF_LIBRARY_REGISTER_CLIENT(
134     __inout  PWDF_BIND_INFO             Info,
135     __deref_out   PWDF_DRIVER_GLOBALS * WdfDriverGlobals,
136     __deref_inout PVOID               * Context
137     );
138 
139 extern "C"
140 _Must_inspect_result_
141 NTSTATUS
142 WDF_LIBRARY_UNREGISTER_CLIENT(
143     __in PWDF_BIND_INFO        Info,
144     __in PWDF_DRIVER_GLOBALS   WdfDriverGlobals
145     );
146 
147 extern "C"
148 VOID
149 FxLibraryDeleteDevice(
150     VOID
151     );
152 
153 VOID
154 FxLibraryCleanup(
155     VOID
156     );
157 
158 VOID
159 WdfWriteKmdfVersionToRegistry(
160     __in PDRIVER_OBJECT   DriverObject,
161     __in PUNICODE_STRING  RegistryPath
162     );
163 
164 VOID
165 WdfDeleteKmdfVersionFromRegistry(
166     __in PDRIVER_OBJECT   DriverObject
167     );
168 
169 typedef struct _DRV_EXTENSION {
170     UNICODE_STRING ParametersRegistryPath;
171 } DRV_EXTENSION, *PDRV_EXTENSION;
172 
173 //-----------------------------------------------------------------------------
174 // Library registeration information
175 //-----------------------------------------------------------------------------
176 extern "C" {
177 #pragma prefast(suppress:__WARNING_ENCODE_MEMBER_FUNCTION_POINTER, "kernel component.");
178 WDF_LIBRARY_INFO  WdfLibraryInfo = {
179     sizeof(WDF_LIBRARY_INFO),
180     (PFNLIBRARYCOMMISSION)        WDF_LIBRARY_COMMISSION,
181     (PFNLIBRARYDECOMMISSION)      WDF_LIBRARY_DECOMMISSION,
182     (PFNLIBRARYREGISTERCLIENT)    WDF_LIBRARY_REGISTER_CLIENT,
183     (PFNLIBRARYUNREGISTERCLIENT)  WDF_LIBRARY_UNREGISTER_CLIENT,
184     { __WDF_MAJOR_VERSION, __WDF_MINOR_VERSION, __WDF_BUILD_NUMBER }
185 };
186 
187 } // extern "C" end
188 
189 extern "C"
190 NTSTATUS
191 FxLibraryDispatch (
192     __in struct _DEVICE_OBJECT * DeviceObject,
193     __in PIRP Irp
194     )
195 {
196     NTSTATUS status;
197 
198     UNREFERENCED_PARAMETER(DeviceObject);
199     ASSERT(FxLibraryGlobals.LibraryDeviceObject == DeviceObject);
200 
201     status = STATUS_INVALID_DEVICE_REQUEST;
202 
203     switch (IoGetCurrentIrpStackLocation(Irp)->MajorFunction) {
204     case IRP_MJ_CREATE:
205         //
206         // To limit our exposure for this device object, only allow kernel mode
207         // creates.
208         //
209         if (Irp->RequestorMode == KernelMode) {
210             status = STATUS_SUCCESS;
211         }
212         break;
213 
214     case IRP_MJ_CLEANUP:
215     case IRP_MJ_CLOSE:
216         //
217         // Since we allowed a create to succeed, succeed the cleanup and close
218         //
219         status = STATUS_SUCCESS;
220         break;
221     }
222 
223     Irp->IoStatus.Status = status;
224     Irp->IoStatus.Information = 0x0;
225     IoCompleteRequest(Irp, IO_NO_INCREMENT);
226 
227     return status;
228 }
229 
230 //-----------------------------------------------------------------------------
231 //
232 //-----------------------------------------------------------------------------
233 
234 #define KMDF_DEVICE_NAME L"\\Device\\KMDF"
235 
236 _Must_inspect_result_
237 NTSTATUS
238 FxLibraryCreateDevice(
239     __in PUNICODE_STRING DeviceName
240     )
241 {
242     NTSTATUS status;
243     ULONG i;
244 
245     i = 0;
246 
247     //
248     // Repeatedly try to create a named device object until we run out of buffer
249     // space or we succeed.
250     //
251     do {
252         status = RtlUnicodeStringPrintf(DeviceName, L"%s%d", KMDF_DEVICE_NAME, i++);
253         if (!NT_SUCCESS(status)) {
254             return status;
255         }
256 
257         //
258         // Create a device with no device extension
259         //
260         status = IoCreateDevice(
261             FxLibraryGlobals.DriverObject,
262             0,
263             DeviceName,
264             FILE_DEVICE_UNKNOWN,
265             0,
266             FALSE,
267             &FxLibraryGlobals.LibraryDeviceObject
268             );
269     } while (STATUS_OBJECT_NAME_COLLISION == status);
270 
271     if (NT_SUCCESS(status)) {
272         //
273         // Clear the initializing bit now because the loader will attempt to
274         // open the device before we return from DriverEntry
275         //
276         ASSERT(FxLibraryGlobals.LibraryDeviceObject != NULL);
277         FxLibraryGlobals.LibraryDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
278     }
279 
280     return status;
281 }
282 
283 extern "C"
284 VOID
285 FxLibraryDeleteDevice(
286     VOID
287     )
288 {
289     FxLibraryCleanup();
290 }
291 
292 VOID
293 FxLibraryCleanup(
294     VOID
295     )
296 {
297     if (FxLibraryGlobals.LibraryDeviceObject != NULL) {
298         IoDeleteDevice(FxLibraryGlobals.LibraryDeviceObject);
299         FxLibraryGlobals.LibraryDeviceObject = NULL;
300     }
301 }
302 
303 extern "C"
304 NTSTATUS
305 DriverEntry(
306     __in PDRIVER_OBJECT   DriverObject,
307     __in PUNICODE_STRING  RegistryPath
308     )
309 {
310     UNICODE_STRING name;
311     UNICODE_STRING string;
312     NTSTATUS status;
313 
314     //
315     // This creates a local buffer which is big enough to hold a copy of the
316     // constant string assigned to it.  It does not point to the constant
317     // string.  As such, it is a writeable buffer.
318     //
319     // NOTE:  KMDF_DEVICE_NAME L"XXXX" creates a concatenated string of
320     //        KMDF_DEVICE_NAME + L"XXXX".  This is done to give us room for
321     //        appending a number up to 4 digits long after KMDF_DEVICE_NAME if
322     //        you want a null terminated string, 5 digits long if the string is
323     //        not null terminated (as is the case for a UNICODE_STRING)
324     //
325     WCHAR buffer[] = KMDF_DEVICE_NAME L"XXXX";
326 
327     //
328     // Initialize global to make NonPagedPool be treated as NxPool on Win8
329     // and NonPagedPool on down-level
330     //
331     ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
332 
333     RtlInitUnicodeString(&string, WDF_REGISTRY_DBGPRINT_ON);
334 
335     //
336     // Determine if debug prints are on.
337     //
338     (void) WdfLdrDiagnosticsValueByNameAsULONG(&string, &WdfLdrDbgPrintOn);
339 
340     __Print(("DriverEntry\n"));
341 
342     DriverObject->DriverUnload = DriverUnload;
343 
344     FxLibraryGlobals.DriverObject = DriverObject;
345 
346     DriverObject->MajorFunction[IRP_MJ_CREATE] = FxLibraryDispatch;
347     DriverObject->MajorFunction[IRP_MJ_CLEANUP] = FxLibraryDispatch;
348     DriverObject->MajorFunction[IRP_MJ_CLOSE] = FxLibraryDispatch;
349 
350     RtlZeroMemory(&name, sizeof(name));
351     name.Buffer = buffer;
352     name.Length = 0x0;
353     name.MaximumLength = sizeof(buffer);
354 
355     //
356     // We use the string when we declare the buffer to get the right sized
357     // buffer.  Now we want to make sure there are no contents before we
358     // use it to create a device object.
359     //
360     RtlZeroMemory(buffer, sizeof(buffer));
361 
362     status = FxLibraryCreateDevice(&name);
363     if (!NT_SUCCESS(status)) {
364         __Print(("ERROR: FxLibraryCreateDevice failed with Status 0x%x\n", status));
365         return status;
366     }
367 
368     //
369     // Register this library with WdfLdr
370     //
371     // NOTE:  Once WdfRegisterLibrary returns NT_SUCCESS() we must return
372     //        NT_SUCCESS from DriverEntry!
373     //
374     status = WdfRegisterLibrary( &WdfLibraryInfo, RegistryPath, &name );
375     if (!NT_SUCCESS(status)) {
376         __Print(("ERROR: WdfRegisterLibrary failed with Status 0x%x\n", status));
377         FxLibraryCleanup();
378         return status;
379     }
380 
381     //
382     // Write KMDF version to registry
383     //
384     WdfWriteKmdfVersionToRegistry(DriverObject, RegistryPath);
385 
386     return STATUS_SUCCESS;
387 }
388 
389 //-----------------------------------------------------------------------------
390 //
391 //-----------------------------------------------------------------------------
392 extern "C"
393 VOID
394 DriverUnload(
395     __in PDRIVER_OBJECT   DriverObject
396     )
397 {
398     __Print(("DriverUnload\n"));
399 
400     //
401     // Delete KMDF version from registry before destroying the Driver Object
402     //
403     WdfDeleteKmdfVersionFromRegistry(DriverObject);
404 
405     //
406     // Make sure everything is deleted.  Since the driver is considered a legacy
407     // driver, it can be unloaded while there are still outstanding device objects.
408     //
409     FxLibraryCleanup();
410 }
411 
412 //-----------------------------------------------------------------------------
413 //
414 //-----------------------------------------------------------------------------
415 extern "C"
416 _Must_inspect_result_
417 NTSTATUS
418 WDF_LIBRARY_COMMISSION(
419     VOID
420     )
421 {
422     return FxLibraryCommonCommission();
423 }
424 
425 //-----------------------------------------------------------------------------
426 //
427 //-----------------------------------------------------------------------------
428 extern "C"
429 _Must_inspect_result_
430 NTSTATUS
431 WDF_LIBRARY_DECOMMISSION(
432     VOID
433     )
434 {
435     return FxLibraryCommonDecommission();
436 }
437 
438 #define EVTLOG_MESSAGE_SIZE 70
439 #define RAW_DATA_SIZE 4
440 
441 extern "C"
442 _Must_inspect_result_
443 NTSTATUS
444 WDF_LIBRARY_REGISTER_CLIENT(
445     __in  PWDF_BIND_INFO        Info,
446     __deref_out   PWDF_DRIVER_GLOBALS * WdfDriverGlobals,
447     __deref_inout PVOID             * Context
448     )
449 {
450     NTSTATUS           status = STATUS_INVALID_PARAMETER;
451     PFX_DRIVER_GLOBALS pFxDriverGlobals;
452     WCHAR              insertString[EVTLOG_MESSAGE_SIZE];
453     ULONG              rawData[RAW_DATA_SIZE];
454     PCLIENT_INFO       clientInfo = NULL;
455 
456     __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) ": enter\n"));
457 
458     clientInfo = (PCLIENT_INFO)*Context;
459     *Context = NULL;
460 
461     ASSERT(Info->Version.Major == WdfLibraryInfo.Version.Major);
462 
463     //
464     // NOTE: If the currently loaded  library < drivers minor version fail the load
465     // instead of binding to a lower minor version. The reason for that if there
466     // is a newer API or new contract change made the driver shouldn't be using older
467     // API than it was compiled with.
468     //
469 
470     if (Info->Version.Minor > WdfLibraryInfo.Version.Minor) {
471         status = RtlStringCchPrintfW(insertString,
472                                      RTL_NUMBER_OF(insertString),
473                                      L"Driver Version: %d.%d Kmdf Lib. Version: %d.%d",
474                                      Info->Version.Major,
475                                      Info->Version.Minor,
476                                      WdfLibraryInfo.Version.Major,
477                                      WdfLibraryInfo.Version.Minor);
478         if (!NT_SUCCESS(status)) {
479             __Print(("ERROR: RtlStringCchPrintfW failed with Status 0x%x\n", status));
480             return status;
481         }
482         rawData[0] = Info->Version.Major;
483         rawData[1] = Info->Version.Minor;
484         rawData[2] = WdfLibraryInfo.Version.Major;
485         rawData[3] = WdfLibraryInfo.Version.Minor;
486 
487         LibraryLogEvent(FxLibraryGlobals.DriverObject,
488                        WDFVER_MINOR_VERSION_NOT_SUPPORTED,
489                        STATUS_OBJECT_TYPE_MISMATCH,
490                        insertString,
491                        rawData,
492                        sizeof(rawData) );
493         //
494         // this looks like the best status to return
495         //
496         return STATUS_OBJECT_TYPE_MISMATCH;
497 
498     }
499 
500     status = FxLibraryCommonRegisterClient(Info,
501                                            WdfDriverGlobals,
502                                            clientInfo);
503 
504     if (NT_SUCCESS(status)) {
505         //
506         // The context will be a pointer to FX_DRIVER_GLOBALS
507         //
508         *Context = GetFxDriverGlobals(*WdfDriverGlobals);
509 
510         //
511         // Set the WDF_BIND_INFO structure pointer in FxDriverGlobals
512         //
513         pFxDriverGlobals = GetFxDriverGlobals(*WdfDriverGlobals);
514         pFxDriverGlobals->WdfBindInfo = Info;
515     }
516 
517     return status;
518 }
519 
520 
521 //-----------------------------------------------------------------------------
522 //
523 //-----------------------------------------------------------------------------
524 extern "C"
525 _Must_inspect_result_
526 NTSTATUS
527 WDF_LIBRARY_UNREGISTER_CLIENT(
528     __in PWDF_BIND_INFO        Info,
529     __in PWDF_DRIVER_GLOBALS   WdfDriverGlobals
530     )
531 {
532     return FxLibraryCommonUnregisterClient(Info, WdfDriverGlobals);
533 }
534 
535 VOID
536 WdfWriteKmdfVersionToRegistry(
537     __in PDRIVER_OBJECT   DriverObject,
538     __in PUNICODE_STRING  RegistryPath
539     )
540 {
541     NTSTATUS status;
542     OBJECT_ATTRIBUTES objectAttributes;
543     HANDLE driverKey;
544     HANDLE parametersKey;
545     UNICODE_STRING valueName;
546     UNICODE_STRING parametersPath;
547     PDRV_EXTENSION driverExtension;
548 
549     driverKey = NULL;
550     parametersKey = NULL;
551     driverExtension = NULL;
552 
553     RtlInitUnicodeString(&parametersPath, DRIVER_PARAMETERS);
554 
555     InitializeObjectAttributes(&objectAttributes,
556                                RegistryPath,
557                                OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
558                                NULL,
559                                NULL);
560 
561     status = ZwOpenKey(&driverKey, KEY_CREATE_SUB_KEY, &objectAttributes);
562     if (!NT_SUCCESS(status)) {
563         __Print(("WdfWriteKmdfVersionToRegistry: Failed to open HKLM\\%S\n",
564                  RegistryPath->Buffer));
565         goto out;
566     }
567 
568     InitializeObjectAttributes(&objectAttributes,
569                                &parametersPath,
570                                OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
571                                driverKey,
572                                NULL);
573 
574     //
575     // Open or create key and get a handle
576     //
577     status = ZwCreateKey(&parametersKey,
578                          KEY_SET_VALUE,
579                          &objectAttributes,
580                          0,
581                          (PUNICODE_STRING) NULL,
582                          REG_OPTION_VOLATILE,
583                          NULL);
584 
585     if (!NT_SUCCESS(status)) {
586         __Print(("WdfWriteKmdfVersionToRegistry: Failed to open HKLM\\%S\\%S\n",
587                  RegistryPath->Buffer, parametersPath.Buffer));
588         goto out;
589     }
590 
591     //
592     // Set Major Version
593     //
594     RtlInitUnicodeString(&valueName, REGISTRY_KMDF_MAJOR_VERSION);
595 
596     status = ZwSetValueKey(parametersKey,
597                            &valueName,
598                            0,
599                            REG_DWORD,
600                            &WdfLibraryInfo.Version.Major,
601                            sizeof(WdfLibraryInfo.Version.Major));
602 
603     if (!NT_SUCCESS(status)) {
604         __Print(("WdfWriteKmdfVersionToRegistry: Failed to set Major Version\n"));
605         goto out;
606     }
607 
608     //
609     // Set Minor Version
610     //
611     RtlInitUnicodeString(&valueName, REGISTRY_KMDF_MINOR_VERSION);
612 
613     status = ZwSetValueKey(parametersKey,
614                            &valueName,
615                            0,
616                            REG_DWORD,
617                            &WdfLibraryInfo.Version.Minor,
618                            sizeof(WdfLibraryInfo.Version.Minor));
619 
620     if (!NT_SUCCESS(status)) {
621         __Print(("WdfWriteKmdfVersionToRegistry: Failed to set Minor Version\n"));
622         goto out;
623     }
624 
625 
626     //
627     // Set Build Number
628     //
629     RtlInitUnicodeString(&valueName, REGISTRY_KMDF_BUILD_NUMBER);
630 
631     status = ZwSetValueKey(parametersKey,
632                            &valueName,
633                            0,
634                            REG_DWORD,
635                            &WdfLibraryInfo.Version.Build,
636                            sizeof(WdfLibraryInfo.Version.Build));
637 
638     if (!NT_SUCCESS(status)) {
639         __Print(("WdfWriteKmdfVersionToRegistry: Failed to set Build Number\n"));
640         goto out;
641     }
642 
643     //
644     // Create a Driver Extension to store the registry path, where we write the
645     // version of the wdf01000.sys that's loaded in memory
646     //
647     status = IoAllocateDriverObjectExtension(DriverObject,
648                                              (PVOID) DRIVER_OBJECT_EXTENSION_IDENTIFIER,
649                                              sizeof(DRV_EXTENSION),
650                                              (PVOID *)&driverExtension);
651 
652     if (!NT_SUCCESS(status) || driverExtension == NULL) {
653         goto out;
654     }
655 
656     driverExtension->ParametersRegistryPath.Buffer = (PWCHAR) ExAllocatePoolWithTag(
657                                                                 PagedPool,
658                                                                 RegistryPath->MaximumLength,
659                                                                 FX_TAG);
660     if (driverExtension->ParametersRegistryPath.Buffer == NULL) {
661         goto out;
662     }
663 
664     driverExtension->ParametersRegistryPath.MaximumLength = RegistryPath->MaximumLength;
665     RtlCopyUnicodeString(&(driverExtension->ParametersRegistryPath), RegistryPath);
666 
667 out:
668     if (driverKey != NULL) {
669         ZwClose(driverKey);
670     }
671 
672     if (parametersKey != NULL) {
673         ZwClose(parametersKey);
674     }
675 
676     return;
677 }
678 
679 VOID
680 WdfDeleteKmdfVersionFromRegistry(
681     __in PDRIVER_OBJECT   DriverObject
682     )
683 {
684     PUNICODE_STRING registryPath;
685     OBJECT_ATTRIBUTES objectAttributes;
686     HANDLE driverKey;
687     HANDLE parametersKey;
688     UNICODE_STRING valueName;
689     NTSTATUS status;
690     UNICODE_STRING parametersPath;
691     PDRV_EXTENSION driverExtension;
692 
693     RtlInitUnicodeString(&parametersPath, DRIVER_PARAMETERS);
694 
695     driverKey = NULL;
696     parametersKey = NULL;
697 
698     driverExtension = (PDRV_EXTENSION)IoGetDriverObjectExtension(DriverObject,
699                                                                  DRIVER_OBJECT_EXTENSION_IDENTIFIER);
700 
701     if (driverExtension == NULL || driverExtension->ParametersRegistryPath.Buffer == NULL) {
702         return;
703     }
704 
705     registryPath = &driverExtension->ParametersRegistryPath;
706 
707     InitializeObjectAttributes(&objectAttributes,
708                                registryPath,
709                                OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
710                                NULL,
711                                NULL);
712 
713     status = ZwOpenKey(&driverKey, KEY_SET_VALUE, &objectAttributes);
714     if (!NT_SUCCESS(status)) {
715         goto out;
716     }
717 
718     InitializeObjectAttributes(&objectAttributes,
719                                &parametersPath,
720                                OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
721                                driverKey,
722                                NULL);
723     //
724     // Open the key for deletion
725     //
726     status = ZwOpenKey(&parametersKey,
727                        DELETE,
728                        &objectAttributes);
729 
730     if (!NT_SUCCESS(status)) {
731         goto out;
732     }
733 
734     RtlInitUnicodeString(&valueName, REGISTRY_KMDF_MAJOR_VERSION);
735     ZwDeleteValueKey(parametersKey, &valueName);
736 
737     RtlInitUnicodeString(&valueName, REGISTRY_KMDF_MINOR_VERSION);
738     ZwDeleteValueKey(parametersKey, &valueName);
739 
740     RtlInitUnicodeString(&valueName, REGISTRY_KMDF_BUILD_NUMBER);
741     ZwDeleteValueKey(parametersKey, &valueName);
742 
743     ZwDeleteKey(parametersKey);
744 
745 out:
746     if (driverExtension->ParametersRegistryPath.Buffer != NULL) {
747         ExFreePool(driverExtension->ParametersRegistryPath.Buffer);
748     }
749 
750     if (driverKey != NULL) {
751         ZwClose(driverKey);
752     }
753 
754     if (parametersKey != NULL) {
755         ZwClose(parametersKey);
756     }
757 
758     return;
759 }
760 
761