CVE-2024-45383
A mishandling of IRP requests vulnerability exists in the HDAudBus_DMA interface of Microsoft High Definition Audio Bus Driver 10.0.19041.3636 (WinBuild.160101.0800). A specially crafted application can issue multiple IRP Complete requests which leads to a local denial-of-service. An attacker can execute malicious script/application to trigger this vulnerability.
The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.
Microsoft HDAudBus.sys 10.0.19041.3636 (WinBuild.160101.0800)
HDAudBus.sys - https://www.microsoft.com
5.0 - CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:N/I:N/A:H
CWE-664 - Improper Control of a Resource Through its Lifetime
The High Definition Audio Bus Driver (hdaudbus.sys) is a Microsoft system driver responsible for managing and facilitating communication between the operating system and audio hardware that conforms to the Intel High Definition Audio (HD Audio) specification. This driver plays a crucial role in ensuring the proper functioning of audio devices on Windows systems, particularly those integrated into motherboards or connected via HD Audio interfaces.
There is a “multiple irp complete requests” vulnerability in HDAudBus.sys driver related to HDAudBus_DMA interface.
Any user trying to obtain a handle via WmiOpenBlock
to WMI HDAudBus_DMA
block (represented by {AEF818D8-0878-4FB2-A776-536883B37AA1}
GUID) with WMIGUID_NOTIFICATION
flag set will cause a BSOD due to the invalid handling of the IRP package by the HDAudBus
driver.
When we try to obtain an handle to the HDAudBus_DMA
interface we land in the following function in HDAudBus.sys
driver.
Line 1 __int64 __fastcall HDAudBusWmiSystemControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
Line 2 {
Line 3 int Status; // edi
Line 4 WDFDEVICE v5; // rbp
Line 5 struct _IO_STACK_LOCATION *CurrentStackLocation; // rax
Line 6 UCHAR MinorFunction; // cl
Line 7 struct _DEVICE_OBJECT *v8; // rax
Line 8 int v9; // edx
Line 9 PVOID userData; // rax
Line 10 struct _WMILIB_CONTEXT *wmilibContext; // rcx
Line 11 int error_code; // eax
Line 12 enum _SYSCTL_IRP_DISPOSITION IrpDisposition; // [rsp+40h] [rbp+8h] BYREF
Line 13
Line 14 IrpDisposition = IrpProcessed;
Line 15 Status = Irp->IoStatus.Status;
Line 16 v5 = WdfFunctions->pfnWdfWdmDeviceGetWdfDeviceHandle(WdfDriverGlobals, DeviceObject);
Line 17 CurrentStackLocation = Irp->Tail.Overlay.CurrentStackLocation;
Line 18 MinorFunction = CurrentStackLocation->MinorFunction;
Line 19 if ( MinorFunction <= (unsigned int)IRP_MN_EXECUTE_METHOD || MinorFunction == IRP_MN_REGINFO_EX )
Line 20 {
Line 21 userData = WdfFunctions->pfnWdfObjectGetTypedContextWorker(WdfDriverGlobals, v5, off_FFFFF80131CF7090);
Line 22 if ( userData )
Line 23 {
Line 24 wmilibContext = (struct _WMILIB_CONTEXT *)*((_QWORD *)userData + 21);
Line 25 if ( wmilibContext )
Line 26 {
Line 27 error_code = WmiSystemControl(wmilibContext, DeviceObject, Irp, &IrpDisposition);
Line 28 Status = error_code;
Line 29 if ( error_code >= 0 )
Line 30 {
Line 31 if ( IrpDisposition == IrpProcessed )
Line 32 goto LABEL_16;
Line 33 if ( IrpDisposition != IrpNotCompleted )
Line 34 {
Line 35 ++Irp->CurrentLocation;
Line 36 ++Irp->Tail.Overlay.CurrentStackLocation;
Line 37 goto LABEL_6;
Line 38 }
Line 39 Irp->IoStatus.Status = error_code;
Line 40 }
Line 41 LABEL_15:
Line 42 IofCompleteRequest(Irp, 0);
Line 43 goto LABEL_16;
Line 44 }
Line 45 }
Line 46 LABEL_14:
Line 47 Irp->IoStatus.Status = Status;
Line 48 goto LABEL_15;
Line 49 }
Line 50
Line 51 LABEL_6:
Line 52 v8 = WdfFunctions->pfnWdfDeviceWdmGetAttachedDevice(WdfDriverGlobals, v5);
Line 53 Status = IofCallDriver(v8, Irp);
Line 54 LABEL_16:
Line 55
Line 56 return (unsigned int)Status;
Line 57 }
Entering this function MinorFunction is set to:
IRP_MN_ENABLE_EVENTS - 0x04
Reaching line 27
, WmiSystemControl
is called and execution flow is redirect to HDAudBusWmiFunctionControl
.
Line 1 NTSTATUS __fastcall HDAudBusWmiFunctionControl(
Line 2 PDEVICE_OBJECT DeviceObject,
Line 3 PIRP Irp,
Line 4 int GuidIndex,
Line 5 enum _WMIENABLEDISABLECONTROL Function,
Line 6 unsigned __int8 Enable)
Line 7 {
Line 8 struct _IO_STACK_LOCATION *CurrentStackLocation; // rax
Line 9 NTSTATUS error_status; // r8d
Line 10 _QWORD *buffer; // rdx
Line 11
Line 12 CurrentStackLocation = Irp->Tail.Overlay.CurrentStackLocation;
Line 13 error_status = 0;
Line 14 if ( CurrentStackLocation->Parameters.WMI.BufferSize >= 0x30 )
Line 15 {
Line 16 buffer = CurrentStackLocation->Parameters.WMI.Buffer;
Line 17 if ( Function )
Line 18 {
Line 19 error_status = 0xC0000010;
Line 20 }
Line 21 else if ( GuidIndex )
Line 22 {
Line 23 error_status = 0xC0000295;
Line 24 }
Line 25 }
Line 26 else
Line 27 {
Line 28 error_status = 0xC0000023;
Line 29 }
Line 30 Irp->IoStatus.Status = error_status;
Line 31 return WmiCompleteRequest(DeviceObject, Irp, error_status, 0, 0);
Line 32 }
Here, a few arguments are important :
Function
is set to 0, so condition at line 17
is false
GuidIndex
is equal 2 becase when we dump WMILIB_CONTEXT structure
Dump of WMILIB_CONTEXT
2: kd> dd rcx L1
ffffdd0f`511f4990 00000003
We can see that there are 3 GUIDs entries. Dumping informations about each entry of WMIGUIDREGINFO :
2: kd> dq fffff800`39bd5110
fffff800`39bd5110 fffff800`39bd3060 00081000`00000000
fffff800`39bd5120 fffff800`39bd2370 00000040`00000001
fffff800`39bd5130 fffff800`39bd2360 00000040`00000001
2: kd> dt nt!_GUID fffff800`39bd3060
{9502cbc6-aa74-4eff-ba91-d9329bcce758}
+0x000 Data1 : 0x9502cbc6
+0x004 Data2 : 0xaa74
+0x006 Data3 : 0x4eff
+0x008 Data4 : [8] "???"
2: kd> dt nt!_GUID fffff800`39bd2370
{e7ad130f-d1e6-4969-ab89-7d78bce3a3fe}
+0x000 Data1 : 0xe7ad130f
+0x004 Data2 : 0xd1e6
+0x006 Data3 : 0x4969
+0x008 Data4 : [8] "???"
2: kd> dt nt!_GUID fffff800`39bd2360
{aef818d8-0878-4fb2-a776-536883b37aa1}
+0x000 Data1 : 0xaef818d8
+0x004 Data2 : 0x878
+0x006 Data3 : 0x4fb2
+0x008 Data4 : [8] "???"
We can see previously mentioned GUID : {aef818d8-0878-4fb2-a776-536883b37aa1} is at index 2.
As we can see at lines 21-23
if GuidIndex
is different than 0, error_status
is set to 0xC0000295
// The guid passed was not recognized as valid by a WMI data provider.
//
#define STATUS_WMI_GUID_NOT_FOUND ((NTSTATUS)0xC0000295L)
and what is the most imporant , at the end of this function, WmiCompleteRequest
is called. After that we return to HDAudBusWmiSystemControl
.
Doing signed comparison operation at line 29
Line 29 if ( error_code >= 0 )
We do not meet the requirment, because 0xC0000295 ( 32bit) is below zero and code at line 42
is executed:
Line 42 IofCompleteRequest(Irp, 0);
Executing IofCompleteRequest
is root cause of further problems with multiple irp complete requests, because according to the documentation IofCompleteRequest
function should be called only when :
Line 27 error_code = WmiSystemControl(wmilibContext, DeviceObject, Irp, &IrpDisposition);
IrpDisposition
after call to WmiSystemControl
is set to IrpNotCompleted
, in our case is set to IrpProcessed
.
MSDN documentation
IrpNotCompleted
The IRP was processed but not completed, either because WMI detected an error and set up the IRP with an appropriate error code, or processed an IRP_MN_REGINFO or IRP_MN_REGINFO_EX request.
The driver must complete the IRP by calling IoCompleteRequest.
Finishing execution of HDAudBusWmiSystemControl
returns control back to the kernel, where there is a call attempting to free resources related to this IRP:
IoFreeIrp(Irp);
This function detects that there are multiple irp complete requests which in turn results in Blue Screen of Death and denial of service.
For analysis of this file, run !analyze -v
nt!KeBugCheckEx:
fffff800`48ffcd70 48894c2408 mov qword ptr [rsp+8],rcx ss:0018:ffffc882`d1e84240=0000000000000044
13: kd> !analyze -v
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************
MULTIPLE_IRP_COMPLETE_REQUESTS (44)
A driver has requested that an IRP be completed (IoCompleteRequest()), but
the packet has already been completed. This is a tough bug to find because
the easiest case, a driver actually attempted to complete its own packet
twice, is generally not what happened. Rather, two separate drivers each
believe that they own the packet, and each attempts to complete it. The
first actually works, and the second fails. Tracking down which drivers
in the system actually did this is difficult, generally because the trails
of the first driver have been covered by the second. However, the driver
stack for the current request can be found by examining the DeviceObject
fields in each of the stack locations.
Arguments:
Arg1: ffffcd81648605e0, Address of the IRP
Arg2: 0000000000002980
Arg3: 0000000000000000
Arg4: 0000000000000000
Debugging Details:
------------------
KEY_VALUES_STRING: 1
Key : Analysis.CPU.mSec
Value: 3592
Key : Analysis.Elapsed.mSec
Value: 3638
Key : Analysis.IO.Other.Mb
Value: 0
Key : Analysis.IO.Read.Mb
Value: 0
Key : Analysis.IO.Write.Mb
Value: 0
Key : Analysis.Init.CPU.mSec
Value: 1546
Key : Analysis.Init.Elapsed.mSec
Value: 10737
Key : Analysis.Memory.CommitPeak.Mb
Value: 105
Key : Bugcheck.Code.KiBugCheckData
Value: 0x44
Key : Bugcheck.Code.LegacyAPI
Value: 0x44
Key : Bugcheck.Code.TargetModel
Value: 0x44
Key : Failure.Bucket
Value: 0x44_nt!WmipSendWmiIrp
Key : Failure.Hash
Value: {48cfcddd-a58b-91ab-1333-f9836e1f36ce}
Key : Hypervisor.Enlightenments.Value
Value: 68673420
Key : Hypervisor.Enlightenments.ValueHex
Value: 417df8c
Key : Hypervisor.Flags.AnyHypervisorPresent
Value: 1
Key : Hypervisor.Flags.ApicEnlightened
Value: 0
Key : Hypervisor.Flags.ApicVirtualizationAvailable
Value: 1
Key : Hypervisor.Flags.AsyncMemoryHint
Value: 0
Key : Hypervisor.Flags.CoreSchedulerRequested
Value: 0
Key : Hypervisor.Flags.CpuManager
Value: 1
Key : Hypervisor.Flags.DeprecateAutoEoi
Value: 1
Key : Hypervisor.Flags.DynamicCpuDisabled
Value: 1
Key : Hypervisor.Flags.Epf
Value: 0
Key : Hypervisor.Flags.ExtendedProcessorMasks
Value: 1
Key : Hypervisor.Flags.HardwareMbecAvailable
Value: 0
Key : Hypervisor.Flags.MaxBankNumber
Value: 0
Key : Hypervisor.Flags.MemoryZeroingControl
Value: 0
Key : Hypervisor.Flags.NoExtendedRangeFlush
Value: 0
Key : Hypervisor.Flags.NoNonArchCoreSharing
Value: 1
Key : Hypervisor.Flags.Phase0InitDone
Value: 1
Key : Hypervisor.Flags.PowerSchedulerQos
Value: 0
Key : Hypervisor.Flags.RootScheduler
Value: 0
Key : Hypervisor.Flags.SynicAvailable
Value: 1
Key : Hypervisor.Flags.UseQpcBias
Value: 0
Key : Hypervisor.Flags.Value
Value: 21500158
Key : Hypervisor.Flags.ValueHex
Value: 14810fe
Key : Hypervisor.Flags.VpAssistPage
Value: 1
Key : Hypervisor.Flags.VsmAvailable
Value: 1
Key : Hypervisor.RootFlags.AccessStats
Value: 1
Key : Hypervisor.RootFlags.CrashdumpEnlightened
Value: 1
Key : Hypervisor.RootFlags.CreateVirtualProcessor
Value: 1
Key : Hypervisor.RootFlags.DisableHyperthreading
Value: 0
Key : Hypervisor.RootFlags.HostTimelineSync
Value: 1
Key : Hypervisor.RootFlags.HypervisorDebuggingEnabled
Value: 0
Key : Hypervisor.RootFlags.IsHyperV
Value: 1
Key : Hypervisor.RootFlags.LivedumpEnlightened
Value: 1
Key : Hypervisor.RootFlags.MapDeviceInterrupt
Value: 1
Key : Hypervisor.RootFlags.MceEnlightened
Value: 1
Key : Hypervisor.RootFlags.Nested
Value: 0
Key : Hypervisor.RootFlags.StartLogicalProcessor
Value: 1
Key : Hypervisor.RootFlags.Value
Value: 1015
Key : Hypervisor.RootFlags.ValueHex
Value: 3f7
Key : SecureKernel.HalpHvciEnabled
Value: 0
Key : WER.OS.Branch
Value: vb_release
Key : WER.OS.Version
Value: 10.0.19041.1
BUGCHECK_CODE: 44
BUGCHECK_P1: ffffcd81648605e0
BUGCHECK_P2: 2980
BUGCHECK_P3: 0
BUGCHECK_P4: 0
FILE_IN_CAB: MEMORY.DMP
IRP_ADDRESS: ffffcd81648605e0
PROCESS_NAME: TestWMI.exe
STACK_TEXT:
ffffc882`d1e84238 fffff800`4902446e : 00000000`00000044 ffffcd81`648605e0 00000000`00002980 00000000`00000000 : nt!KeBugCheckEx
ffffc882`d1e84240 fffff800`48e18233 : 00000000`0000004a ffffc882`d1e84370 ffffc882`d1e84348 00000000`00000004 : nt!IopFreeIrp+0x20c21e
ffffc882`d1e84280 fffff800`49336b82 : ffffcd81`648605e0 00000000`00000030 ffffc882`d1e84358 ffffc882`d1e84410 : nt!IoFreeIrp+0x13
ffffc882`d1e842b0 fffff800`4937bfe7 : ffff8e0d`f8629120 ffffc882`d1e84410 ffffc882`d1e84390 fffff800`491fdc1a : nt!WmipSendWmiIrp+0xb6
ffffc882`d1e84310 fffff800`492ddfaf : fffff800`49819ea0 ffffcd81`8f27be10 ffff8e0d`f8609810 ffffcd81`8f27bd70 : nt!WmipSendEnableDisableRequest+0x187
ffffc882`d1e845e0 fffff800`492ddf18 : ffffcd81`8f27bd70 ffff8e0d`f8609810 00000000`00224101 ffffcd81`8f27be10 : nt!WmipSendEnableRequest+0x6f
ffffc882`d1e84610 fffff800`49241773 : ffffcd81`8f27bd70 ffffc882`d1e84701 00000000`00224140 0000005a`a73af300 : nt!WmipEnableCollectOrEvent+0xcc
ffffc882`d1e84650 fffff800`492ea9bc : 00000000`00000000 ffffc882`d1e847b0 00000000`00000018 ffffcd81`35c02ec0 : nt!WmipOpenBlock+0x11b
ffffc882`d1e846b0 fffff800`48e10665 : 00000000`00000002 ffffcd81`97727f60 00000000`00000000 ffffcd81`845925e0 : nt!WmipIoControl+0x22c
ffffc882`d1e84800 fffff800`49200fec : 00000000`00000002 00000000`00000000 ffffcd81`8145a430 ffffcd81`977f3080 : nt!IofCallDriver+0x55
ffffc882`d1e84840 fffff800`49200c41 : ffffcd81`84592f20 ffffc882`d1e84b80 00000000`00040005 ffffcd81`84592f20 : nt!IopSynchronousServiceTail+0x34c
ffffc882`d1e848e0 fffff800`491fffb6 : 00000000`00000001 00000000`00000160 00000000`00000000 00000000`00000000 : nt!IopXxxControlFile+0xc71
ffffc882`d1e84a20 fffff800`490105f8 : ffffcd81`789fb080 0000005a`a73af1b8 ffffc882`d1e84aa8 00000000`00000000 : nt!NtDeviceIoControlFile+0x56
ffffc882`d1e84a90 00007fff`be5acf34 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : nt!KiSystemServiceCopyEnd+0x28
0000005a`a73af228 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : 0x00007fff`be5acf34
SYMBOL_NAME: nt!WmipSendWmiIrp+b6
MODULE_NAME: nt
IMAGE_NAME: ntkrnlmp.exe
IMAGE_VERSION: 10.0.19041.3448
STACK_COMMAND: .cxr; .ecxr ; kb
BUCKET_ID_FUNC_OFFSET: b6
FAILURE_BUCKET_ID: 0x44_nt!WmipSendWmiIrp
OS_VERSION: 10.0.19041.1
BUILDLAB_STR: vb_release
OSPLATFORM_TYPE: x64
OSNAME: Windows 10
FAILURE_ID_HASH: {48cfcddd-a58b-91ab-1333-f9836e1f36ce}
Followup: MachineOwner
---------
13: kd> kb
# RetAddr : Args to Child : Call Site
00 fffff800`4902446e : 00000000`00000044 ffffcd81`648605e0 00000000`00002980 00000000`00000000 : nt!KeBugCheckEx
01 fffff800`48e18233 : 00000000`0000004a ffffc882`d1e84370 ffffc882`d1e84348 00000000`00000004 : nt!IopFreeIrp+0x20c21e
02 fffff800`49336b82 : ffffcd81`648605e0 00000000`00000030 ffffc882`d1e84358 ffffc882`d1e84410 : nt!IoFreeIrp+0x13
03 fffff800`4937bfe7 : ffff8e0d`f8629120 ffffc882`d1e84410 ffffc882`d1e84390 fffff800`491fdc1a : nt!WmipSendWmiIrp+0xb6
04 fffff800`492ddfaf : fffff800`49819ea0 ffffcd81`8f27be10 ffff8e0d`f8609810 ffffcd81`8f27bd70 : nt!WmipSendEnableDisableRequest+0x187
05 fffff800`492ddf18 : ffffcd81`8f27bd70 ffff8e0d`f8609810 00000000`00224101 ffffcd81`8f27be10 : nt!WmipSendEnableRequest+0x6f
06 fffff800`49241773 : ffffcd81`8f27bd70 ffffc882`d1e84701 00000000`00224140 0000005a`a73af300 : nt!WmipEnableCollectOrEvent+0xcc
07 fffff800`492ea9bc : 00000000`00000000 ffffc882`d1e847b0 00000000`00000018 ffffcd81`35c02ec0 : nt!WmipOpenBlock+0x11b
08 fffff800`48e10665 : 00000000`00000002 ffffcd81`97727f60 00000000`00000000 ffffcd81`845925e0 : nt!WmipIoControl+0x22c
09 fffff800`49200fec : 00000000`00000002 00000000`00000000 ffffcd81`8145a430 ffffcd81`977f3080 : nt!IofCallDriver+0x55
0a fffff800`49200c41 : ffffcd81`84592f20 ffffc882`d1e84b80 00000000`00040005 ffffcd81`84592f20 : nt!IopSynchronousServiceTail+0x34c
0b fffff800`491fffb6 : 00000000`00000001 00000000`00000160 00000000`00000000 00000000`00000000 : nt!IopXxxControlFile+0xc71
0c fffff800`490105f8 : ffffcd81`789fb080 0000005a`a73af1b8 ffffc882`d1e84aa8 00000000`00000000 : nt!NtDeviceIoControlFile+0x56
0d 00007fff`be5acf34 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : nt!KiSystemServiceCopyEnd+0x28
0e 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : 0x00007fff`be5acf34
2024-06-24 - Vendor Disclosure
2024-08-26 - Vendor response that moderate DoS do not meet their bug bar
2024-08-27 - Talos request for CVE
2024-08-28 - Vendor said they do not assign CVEs to moderate severity issues
2024-09-12 - Public release
Discovered by Marcin 'Icewall' Noga of Cisco Talos.