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(¶metersPath, 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 ¶metersPath, 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(¶metersKey, 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(¶metersPath, 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 ¶metersPath, 720 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, 721 driverKey, 722 NULL); 723 // 724 // Open the key for deletion 725 // 726 status = ZwOpenKey(¶metersKey, 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