[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; BattWait = *(PBATTERY_WAIT_STATUS)Irp->AssociatedIrp.SystemBuffer;
Timeout.QuadPart = Int32x32To64(BattWait.Timeout, -10000); if (BattWait.Timeout != 0)
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))
{ {
BattNotify.PowerState = BattWait.PowerState; BattNotify.PowerState = BattWait.PowerState;
BattNotify.HighCapacity = BattWait.HighCapacity; BattNotify.HighCapacity = BattWait.HighCapacity;
BattNotify.LowCapacity = BattWait.LowCapacity; BattNotify.LowCapacity = BattWait.LowCapacity;
BattClass->MiniportInfo.SetStatusNotify(BattClass->MiniportInfo.Context, Status = BattClass->MiniportInfo.SetStatusNotify(BattClass->MiniportInfo.Context,
BattWait.BatteryTag, BattWait.BatteryTag,
&BattNotify); &BattNotify);
if (!NT_SUCCESS(Status))
{
DPRINT1("SetStatusNotify failed (0x%x)\n", Status);
break;
}
ExAcquireFastMutex(&BattClass->Mutex); ExAcquireFastMutex(&BattClass->Mutex);
BattClass->EventTrigger = EVENT_BATTERY_STATUS; BattClass->EventTrigger = EVENT_BATTERY_STATUS;
@@ -307,6 +302,7 @@ BatteryClassIoctl(PVOID ClassData,
BattClass->Waiting = TRUE; BattClass->Waiting = TRUE;
ExReleaseFastMutex(&BattClass->Mutex); ExReleaseFastMutex(&BattClass->Mutex);
Timeout.QuadPart = Int32x32To64(BattWait.Timeout, -10000);
Status = KeWaitForSingleObject(&BattClass->WaitEvent, Status = KeWaitForSingleObject(&BattClass->WaitEvent,
Executive, Executive,
KernelMode, KernelMode,
@@ -321,7 +317,15 @@ BatteryClassIoctl(PVOID ClassData,
BattClass->MiniportInfo.DisableStatusNotify(BattClass->MiniportInfo.Context); 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); Irp->IoStatus.Information = sizeof(BATTERY_STATUS);
} }