[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.
This commit is contained in:
Timo Kreuzer
2025-07-29 00:48:53 +03:00
parent ae23b4dc8f
commit 3a6e0d4b65

View File

@@ -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);
}