From 37cc98b05c33438e2f4e970e542e8805054a5656 Mon Sep 17 00:00:00 2001 From: Dylan Deverill Date: Sat, 20 Jun 2026 23:08:46 -0700 Subject: [PATCH] Fix CancelIo OVERLAPPED drain bug in ReadInputReport Same latent use-after-free as WriteOutputReport: after CancelIo, the kernel can still complete the IRP and write into the stack OVERLAPPED after the function returns. Block with GetOverlappedResult(..., TRUE) to drain before ov goes out of scope. Co-Authored-By: Dylan Deverill --- src/hid/HidDevice.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hid/HidDevice.cpp b/src/hid/HidDevice.cpp index e5a8dad..faf3934 100644 --- a/src/hid/HidDevice.cpp +++ b/src/hid/HidDevice.cpp @@ -242,7 +242,9 @@ size_t HidDevice::ReadInputReport(uint8_t* buffer, size_t size, uint32_t timeout DWORD wait = WaitForSingleObject(m_event, timeoutMs); if (wait != WAIT_OBJECT_0) { + // CancelIo is asynchronous — drain before ov leaves scope. CancelIo(m_handle); + GetOverlappedResult(m_handle, &ov, &bytesRead, TRUE); return 0; } if (!GetOverlappedResult(m_handle, &ov, &bytesRead, FALSE))