From 3a6e0d4b6526eccfd91347b70d9df6011dfd49ce Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Tue, 29 Jul 2025 00:48:53 +0300 Subject: [PATCH] [BATTC] Fix IOCTL_BATTERY_QUERY_STATUS Previously the function waited for the conditions *after* querying the status, and then returned the old status. Also, if querying failed, it waited and when the wait timed out it returned STATUS_SUCCESS without returning any data. If the call to SetStatusNotify failed and there was no timeout, it would wait forever. This is all fixed now. --- drivers/battery/battc/battc.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/drivers/battery/battc/battc.c b/drivers/battery/battc/battc.c index e724f720b5f..33cbc438475 100644 --- a/drivers/battery/battc/battc.c +++ b/drivers/battery/battc/battc.c @@ -281,25 +281,20 @@ BatteryClassIoctl(PVOID ClassData, BattWait = *(PBATTERY_WAIT_STATUS)Irp->AssociatedIrp.SystemBuffer; - Timeout.QuadPart = Int32x32To64(BattWait.Timeout, -10000); - - BattStatus = Irp->AssociatedIrp.SystemBuffer; - Status = BattClass->MiniportInfo.QueryStatus(BattClass->MiniportInfo.Context, - BattWait.BatteryTag, - BattStatus); - - if (!NT_SUCCESS(Status) || - (BattWait.PowerState == BattStatus->PowerState && - BattWait.HighCapacity >= BattStatus->Capacity && - BattWait.LowCapacity <= BattStatus->Capacity)) + if (BattWait.Timeout != 0) { BattNotify.PowerState = BattWait.PowerState; BattNotify.HighCapacity = BattWait.HighCapacity; BattNotify.LowCapacity = BattWait.LowCapacity; - BattClass->MiniportInfo.SetStatusNotify(BattClass->MiniportInfo.Context, - BattWait.BatteryTag, - &BattNotify); + Status = BattClass->MiniportInfo.SetStatusNotify(BattClass->MiniportInfo.Context, + BattWait.BatteryTag, + &BattNotify); + if (!NT_SUCCESS(Status)) + { + DPRINT1("SetStatusNotify failed (0x%x)\n", Status); + break; + } ExAcquireFastMutex(&BattClass->Mutex); BattClass->EventTrigger = EVENT_BATTERY_STATUS; @@ -307,6 +302,7 @@ BatteryClassIoctl(PVOID ClassData, BattClass->Waiting = TRUE; ExReleaseFastMutex(&BattClass->Mutex); + Timeout.QuadPart = Int32x32To64(BattWait.Timeout, -10000); Status = KeWaitForSingleObject(&BattClass->WaitEvent, Executive, KernelMode, @@ -321,7 +317,15 @@ BatteryClassIoctl(PVOID ClassData, BattClass->MiniportInfo.DisableStatusNotify(BattClass->MiniportInfo.Context); } - else + + /* Zero the output buffer to prevent leakage of kernel data */ + BattStatus = Irp->AssociatedIrp.SystemBuffer; + RtlZeroMemory(BattStatus, sizeof(BATTERY_STATUS)); + + Status = BattClass->MiniportInfo.QueryStatus(BattClass->MiniportInfo.Context, + BattWait.BatteryTag, + BattStatus); + if (NT_SUCCESS(Status)) { Irp->IoStatus.Information = sizeof(BATTERY_STATUS); }