QueueCallback.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. // QueueCallback.cpp - I/O Queue 回调实现
  2. #include <ntddk.h>
  3. #include <wdf.h>
  4. #include <initguid.h>
  5. #include <wdmsec.h>
  6. #include "QueueCallback.h"
  7. #include "ClientConnection.h"
  8. #include "DeviceContext.h"
  9. #include "../common/CommKitIoctl.h"
  10. namespace commkit_driver {
  11. // SDDL: System+Admins full access, Authenticated Users+Everyone read/write
  12. // 控制设备 \\.\CommModifyKit 需要允许非 elevated 进程也能打开
  13. static const UNICODE_STRING SddlSysAdminFullAccess =
  14. RTL_CONSTANT_STRING(L"D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GRGW;;;AU)(A;;GRGW;;;WD)");
  15. // 专用 Parallel 队列句柄:用于 READ_EVENTS 转发
  16. // WdfDeviceConfigureRequestDispatching 只能按请求类型路由(如 WdfRequestTypeDeviceControl),
  17. // 不能按具体 IOCTL 码路由。改为在 EvtIoDeviceControl 中用 WdfRequestForwardToIoQueue 转发。
  18. static WDFQUEUE g_read_events_queue = nullptr;
  19. NTSTATUS CreateControlDevice(WDFDRIVER driver) {
  20. NTSTATUS status;
  21. PWDFDEVICE_INIT init = WdfControlDeviceInitAllocate(
  22. driver, (PCUNICODE_STRING)&SddlSysAdminFullAccess);
  23. if (!init) {
  24. return STATUS_INSUFFICIENT_RESOURCES;
  25. }
  26. // 设置设备名
  27. DECLARE_UNICODE_STRING_SIZE(device_name, 64);
  28. RtlInitUnicodeString(&device_name, COMMKIT_DEVICE_NAME);
  29. status = WdfDeviceInitAssignName(init, &device_name);
  30. if (!NT_SUCCESS(status)) {
  31. WdfDeviceInitFree(init);
  32. return status;
  33. }
  34. // 创建设备
  35. WDFDEVICE control_device;
  36. WDF_OBJECT_ATTRIBUTES attrs;
  37. WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attrs, DEVICE_CONTEXT);
  38. status = WdfDeviceCreate(&init, &attrs, &control_device);
  39. if (!NT_SUCCESS(status)) {
  40. WdfDeviceInitFree(init);
  41. return status;
  42. }
  43. // 创建符号链接 \\DosDevices\\CommModifyKit → \\.\CommModifyKit
  44. DECLARE_UNICODE_STRING_SIZE(symbolic_link, 64);
  45. RtlInitUnicodeString(&symbolic_link, COMMKIT_DEVICE_DOS_NAME);
  46. status = WdfDeviceCreateSymbolicLink(control_device, &symbolic_link);
  47. if (!NT_SUCCESS(status)) {
  48. return status;
  49. }
  50. // 配置 I/O Queue 处理 IOCTL
  51. // 主队列:Sequential 派发,处理除 READ_EVENTS 外的所有 IOCTL
  52. // (ATTACH/DETACH/WRITE_PORT/READ_PORT/FREE_ALL 需要串行化避免竞争)
  53. WDF_IO_QUEUE_CONFIG queue_config;
  54. WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queue_config, WdfIoQueueDispatchSequential);
  55. queue_config.EvtIoDeviceControl = EvtIoDeviceControl;
  56. queue_config.EvtIoDefault = EvtIoDefault;
  57. WDFQUEUE queue;
  58. status = WdfIoQueueCreate(control_device, &queue_config,
  59. WDF_NO_OBJECT_ATTRIBUTES, &queue);
  60. if (!NT_SUCCESS(status)) {
  61. return status;
  62. }
  63. // 专用队列:Parallel 派发,仅处理 IOCTL_COMMKIT_READ_EVENTS
  64. // 独立于主队列,避免 WRITE_PORT/READ_PORT 同步阻塞时 EventLoop 无法读取事件
  65. // (否则高流量场景下环形缓冲溢出覆盖旧事件)
  66. WDF_IO_QUEUE_CONFIG read_events_config;
  67. WDF_IO_QUEUE_CONFIG_INIT(&read_events_config, WdfIoQueueDispatchParallel);
  68. read_events_config.EvtIoDeviceControl = EvtIoReadEvents;
  69. WDFQUEUE read_events_queue;
  70. status = WdfIoQueueCreate(control_device, &read_events_config,
  71. WDF_NO_OBJECT_ATTRIBUTES, &read_events_queue);
  72. if (!NT_SUCCESS(status)) {
  73. return status;
  74. }
  75. // 保存队列句柄供 EvtIoDeviceControl 转发 READ_EVENTS 请求
  76. g_read_events_queue = read_events_queue;
  77. // 标记控制设备已就绪
  78. WdfControlFinishInitializing(control_device);
  79. return STATUS_SUCCESS;
  80. }
  81. VOID EvtIoDeviceControl(WDFQUEUE queue, WDFREQUEST request,
  82. size_t output_buffer_length, size_t input_buffer_length,
  83. ULONG io_control_code) {
  84. UNREFERENCED_PARAMETER(queue);
  85. UNREFERENCED_PARAMETER(input_buffer_length);
  86. UNREFERENCED_PARAMETER(output_buffer_length);
  87. NTSTATUS status = STATUS_SUCCESS;
  88. ULONG info = 0;
  89. auto& conn = GetClientConnection();
  90. switch (io_control_code) {
  91. case IOCTL_COMMKIT_REGISTER_CALLBACK:
  92. status = conn.HandleRegisterCallback();
  93. break;
  94. case IOCTL_COMMKIT_ATTACH_PORT: {
  95. COMMKIT_PORT_REQUEST* req = nullptr;
  96. size_t buf_len = 0;
  97. status = WdfRequestRetrieveInputBuffer(request, sizeof(*req),
  98. (PVOID*)&req, &buf_len);
  99. if (NT_SUCCESS(status) && req) {
  100. status = conn.HandleAttachPort(req->ComNumber);
  101. }
  102. break;
  103. }
  104. case IOCTL_COMMKIT_DETACH_PORT: {
  105. COMMKIT_PORT_REQUEST* req = nullptr;
  106. size_t buf_len = 0;
  107. status = WdfRequestRetrieveInputBuffer(request, sizeof(*req),
  108. (PVOID*)&req, &buf_len);
  109. if (NT_SUCCESS(status) && req) {
  110. status = conn.HandleDetachPort(req->ComNumber);
  111. }
  112. break;
  113. }
  114. case IOCTL_COMMKIT_WRITE_PORT: {
  115. COMMKIT_DATA_REQUEST* req = nullptr;
  116. size_t buf_len = 0;
  117. status = WdfRequestRetrieveInputBuffer(request, sizeof(*req),
  118. (PVOID*)&req, &buf_len);
  119. if (NT_SUCCESS(status) && req) {
  120. // 校验 DataLen 不超过实际缓冲区容量,防止越界读取
  121. ULONG header_size = FIELD_OFFSET(COMMKIT_DATA_REQUEST, Data);
  122. ULONG data_capacity = (buf_len > header_size)
  123. ? (ULONG)(buf_len - header_size) : 0;
  124. if (req->DataLen > data_capacity) {
  125. status = STATUS_INVALID_PARAMETER;
  126. } else {
  127. PVOID data = req->Data;
  128. ULONG bytes_written = 0;
  129. status = conn.HandleWritePort(req->ComNumber, data, req->DataLen,
  130. &bytes_written);
  131. // 更新 DataLen 为实际写入字节数,用户态 DLL 可直接读取
  132. req->DataLen = bytes_written;
  133. // METHOD_BUFFERED: info = 从 SystemBuffer 拷贝回用户缓冲的字节数
  134. // = 头部(ComNumber+DataLen) + 实际数据
  135. info = header_size + bytes_written;
  136. }
  137. }
  138. break;
  139. }
  140. case IOCTL_COMMKIT_READ_PORT: {
  141. COMMKIT_DATA_REQUEST* req = nullptr;
  142. size_t buf_len = 0;
  143. status = WdfRequestRetrieveInputBuffer(request, sizeof(*req),
  144. (PVOID*)&req, &buf_len);
  145. if (NT_SUCCESS(status) && req) {
  146. ULONG header_size = FIELD_OFFSET(COMMKIT_DATA_REQUEST, Data);
  147. ULONG data_capacity = (buf_len > header_size)
  148. ? (ULONG)(buf_len - header_size) : 0;
  149. if (req->DataLen > data_capacity) {
  150. status = STATUS_INVALID_PARAMETER;
  151. } else {
  152. PVOID data = req->Data;
  153. ULONG bytes_read = 0;
  154. status = conn.HandleReadPort(req->ComNumber, data, req->DataLen,
  155. &bytes_read);
  156. // 更新 DataLen 为实际读取字节数,用户态 DLL 可直接读取
  157. req->DataLen = bytes_read;
  158. // METHOD_BUFFERED: info = 从 SystemBuffer 拷贝回用户缓冲的字节数
  159. // = 头部(ComNumber+DataLen) + 实际数据
  160. info = header_size + bytes_read;
  161. }
  162. }
  163. break;
  164. }
  165. case IOCTL_COMMKIT_READ_EVENTS:
  166. // 转发到专用 Parallel 队列,避免被 WRITE_PORT/READ_PORT 的同步阻塞拖慢
  167. if (g_read_events_queue) {
  168. NTSTATUS fwd = WdfRequestForwardToIoQueue(request, g_read_events_queue);
  169. if (NT_SUCCESS(fwd)) {
  170. return; // 转发成功,请求已移至专用队列,不再完成
  171. }
  172. // 转发失败,按错误完成
  173. }
  174. status = STATUS_INVALID_DEVICE_REQUEST;
  175. break;
  176. case IOCTL_COMMKIT_FREE_ALL:
  177. status = conn.HandleFreeAll();
  178. break;
  179. default:
  180. status = STATUS_INVALID_DEVICE_REQUEST;
  181. break;
  182. }
  183. WdfRequestCompleteWithInformation(request, status, info);
  184. }
  185. // 专用队列回调:处理 IOCTL_COMMKIT_READ_EVENTS
  186. // 独立于主队列,即使 WRITE_PORT/READ_PORT 阻塞,EventLoop 仍可读取事件
  187. VOID EvtIoReadEvents(WDFQUEUE queue, WDFREQUEST request,
  188. size_t output_buffer_length, size_t input_buffer_length,
  189. ULONG io_control_code) {
  190. UNREFERENCED_PARAMETER(queue);
  191. UNREFERENCED_PARAMETER(input_buffer_length);
  192. UNREFERENCED_PARAMETER(output_buffer_length);
  193. if (io_control_code != IOCTL_COMMKIT_READ_EVENTS) {
  194. WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST);
  195. return;
  196. }
  197. PVOID out_buf = nullptr;
  198. size_t out_len = 0;
  199. NTSTATUS status = WdfRequestRetrieveOutputBuffer(request, 0,
  200. (PVOID*)&out_buf, &out_len);
  201. if (NT_SUCCESS(status) && out_buf) {
  202. ULONG returned = 0;
  203. status = GetClientConnection().HandleReadEvents(out_buf, (ULONG)out_len, &returned);
  204. WdfRequestCompleteWithInformation(request, status, returned);
  205. } else {
  206. WdfRequestComplete(request, STATUS_INVALID_PARAMETER);
  207. }
  208. }
  209. VOID EvtIoDefault(WDFQUEUE queue, WDFREQUEST request) {
  210. UNREFERENCED_PARAMETER(queue);
  211. WdfRequestComplete(request, STATUS_INVALID_DEVICE_REQUEST);
  212. }
  213. } // namespace commkit_driver