VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxUSB/win/mon/VBoxUsbMon.cpp@ 80207

Last change on this file since 80207 was 80207, checked in by vboxsync, 5 years ago

VBoxUSBMon: Log semi-undocumented PnP IRPs that we may see.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 53.4 KB
Line 
1/* $Id: VBoxUsbMon.cpp 80207 2019-08-09 10:54:29Z vboxsync $ */
2/** @file
3 * VBox USB Monitor
4 */
5
6/*
7 * Copyright (C) 2011-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include "VBoxUsbMon.h"
32#include "../cmn/VBoxUsbIdc.h"
33#include <iprt/errcore.h>
34#include <VBox/usblib.h>
35#include <excpt.h>
36
37
38/*********************************************************************************************************************************
39* Defined Constants And Macros *
40*********************************************************************************************************************************/
41/*
42 * Note: Must match the VID & PID in the USB driver .inf file!!
43 */
44/*
45 BusQueryDeviceID USB\Vid_80EE&Pid_CAFE
46 BusQueryInstanceID 2
47 BusQueryHardwareIDs USB\Vid_80EE&Pid_CAFE&Rev_0100
48 BusQueryHardwareIDs USB\Vid_80EE&Pid_CAFE
49 BusQueryCompatibleIDs USB\Class_ff&SubClass_00&Prot_00
50 BusQueryCompatibleIDs USB\Class_ff&SubClass_00
51 BusQueryCompatibleIDs USB\Class_ff
52*/
53
54#define szBusQueryDeviceId L"USB\\Vid_80EE&Pid_CAFE"
55#define szBusQueryHardwareIDs L"USB\\Vid_80EE&Pid_CAFE&Rev_0100\0USB\\Vid_80EE&Pid_CAFE\0\0"
56#define szBusQueryCompatibleIDs L"USB\\Class_ff&SubClass_00&Prot_00\0USB\\Class_ff&SubClass_00\0USB\\Class_ff\0\0"
57
58#define szDeviceTextDescription L"VirtualBox USB"
59
60
61#define VBOXUSBMON_MEMTAG 'MUBV'
62
63
64/*********************************************************************************************************************************
65* Structures and Typedefs *
66*********************************************************************************************************************************/
67typedef struct VBOXUSBMONINS
68{
69 void * pvDummy;
70} VBOXUSBMONINS, *PVBOXUSBMONINS;
71
72typedef struct VBOXUSBMONCTX
73{
74 VBOXUSBFLTCTX FltCtx;
75} VBOXUSBMONCTX, *PVBOXUSBMONCTX;
76
77typedef struct VBOXUSBHUB_PNPHOOK
78{
79 VBOXUSBHOOK_ENTRY Hook;
80 bool fUninitFailed;
81} VBOXUSBHUB_PNPHOOK, *PVBOXUSBHUB_PNPHOOK;
82
83typedef struct VBOXUSBHUB_PNPHOOK_COMPLETION
84{
85 VBOXUSBHOOK_REQUEST Rq;
86} VBOXUSBHUB_PNPHOOK_COMPLETION, *PVBOXUSBHUB_PNPHOOK_COMPLETION;
87
88#define VBOXUSBMON_MAXDRIVERS 5
89typedef struct VBOXUSB_PNPDRIVER
90{
91 PDRIVER_OBJECT DriverObject;
92 VBOXUSBHUB_PNPHOOK UsbHubPnPHook;
93 PDRIVER_DISPATCH pfnHookStub;
94} VBOXUSB_PNPDRIVER, *PVBOXUSB_PNPDRIVER;
95
96typedef struct VBOXUSBMONGLOBALS
97{
98 PDEVICE_OBJECT pDevObj;
99 VBOXUSB_PNPDRIVER pDrivers[VBOXUSBMON_MAXDRIVERS];
100 KEVENT OpenSynchEvent;
101 IO_REMOVE_LOCK RmLock;
102 uint32_t cOpens;
103 volatile LONG ulPreventUnloadOn;
104 PFILE_OBJECT pPreventUnloadFileObj;
105} VBOXUSBMONGLOBALS, *PVBOXUSBMONGLOBALS;
106
107
108/*********************************************************************************************************************************
109* Global Variables *
110*********************************************************************************************************************************/
111static VBOXUSBMONGLOBALS g_VBoxUsbMonGlobals;
112
113
114
115PVOID VBoxUsbMonMemAlloc(SIZE_T cbBytes)
116{
117 PVOID pvMem = ExAllocatePoolWithTag(NonPagedPool, cbBytes, VBOXUSBMON_MEMTAG);
118 Assert(pvMem);
119 return pvMem;
120}
121
122PVOID VBoxUsbMonMemAllocZ(SIZE_T cbBytes)
123{
124 PVOID pvMem = VBoxUsbMonMemAlloc(cbBytes);
125 if (pvMem)
126 {
127 RtlZeroMemory(pvMem, cbBytes);
128 }
129 return pvMem;
130}
131
132VOID VBoxUsbMonMemFree(PVOID pvMem)
133{
134 ExFreePoolWithTag(pvMem, VBOXUSBMON_MEMTAG);
135}
136
137#define VBOXUSBDBG_STRCASE(_t) \
138 case _t: return #_t
139#define VBOXUSBDBG_STRCASE_UNKNOWN(_v) \
140 default: LOG((__FUNCTION__": Unknown Value (0n%d), (0x%x)", _v, _v)); return "Unknown"
141
142/* These minor code are semi-undocumented. */
143#ifndef IRP_MN_QUERY_LEGACY_BUS_INFORMATION
144#define IRP_MN_QUERY_LEGACY_BUS_INFORMATION 0x18
145#endif
146#ifndef IRP_MN_DEVICE_ENUMERATED
147#define IRP_MN_DEVICE_ENUMERATED 0x19
148#endif
149
150static const char* vboxUsbDbgStrPnPMn(UCHAR uMn)
151{
152 switch (uMn)
153 {
154 VBOXUSBDBG_STRCASE(IRP_MN_START_DEVICE);
155 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_REMOVE_DEVICE);
156 VBOXUSBDBG_STRCASE(IRP_MN_REMOVE_DEVICE);
157 VBOXUSBDBG_STRCASE(IRP_MN_CANCEL_REMOVE_DEVICE);
158 VBOXUSBDBG_STRCASE(IRP_MN_STOP_DEVICE);
159 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_STOP_DEVICE);
160 VBOXUSBDBG_STRCASE(IRP_MN_CANCEL_STOP_DEVICE);
161 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_DEVICE_RELATIONS);
162 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_INTERFACE);
163 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_CAPABILITIES);
164 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_RESOURCES);
165 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_RESOURCE_REQUIREMENTS);
166 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_DEVICE_TEXT);
167 VBOXUSBDBG_STRCASE(IRP_MN_FILTER_RESOURCE_REQUIREMENTS);
168 VBOXUSBDBG_STRCASE(IRP_MN_READ_CONFIG);
169 VBOXUSBDBG_STRCASE(IRP_MN_WRITE_CONFIG);
170 VBOXUSBDBG_STRCASE(IRP_MN_EJECT);
171 VBOXUSBDBG_STRCASE(IRP_MN_SET_LOCK);
172 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_ID);
173 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_PNP_DEVICE_STATE);
174 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_BUS_INFORMATION);
175 VBOXUSBDBG_STRCASE(IRP_MN_DEVICE_USAGE_NOTIFICATION);
176 VBOXUSBDBG_STRCASE(IRP_MN_SURPRISE_REMOVAL);
177 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_LEGACY_BUS_INFORMATION);
178 VBOXUSBDBG_STRCASE(IRP_MN_DEVICE_ENUMERATED);
179 VBOXUSBDBG_STRCASE_UNKNOWN(uMn);
180 }
181}
182
183/**
184 * Send IRP_MN_QUERY_DEVICE_RELATIONS
185 *
186 * @returns NT Status
187 * @param pDevObj USB device pointer
188 * @param pFileObj Valid file object pointer
189 * @param pDevRelations Pointer to DEVICE_RELATIONS pointer (out)
190 */
191NTSTATUS VBoxUsbMonQueryBusRelations(PDEVICE_OBJECT pDevObj, PFILE_OBJECT pFileObj, PDEVICE_RELATIONS *pDevRelations)
192{
193 IO_STATUS_BLOCK IoStatus;
194 KEVENT Event;
195 NTSTATUS Status;
196 PIRP pIrp;
197 PIO_STACK_LOCATION pSl;
198
199 KeInitializeEvent(&Event, NotificationEvent, FALSE);
200
201 Assert(pDevRelations);
202 *pDevRelations = NULL;
203
204 pIrp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, pDevObj, NULL, 0, NULL, &Event, &IoStatus);
205 if (!pIrp)
206 {
207 WARN(("IoBuildDeviceIoControlRequest failed!!"));
208 return STATUS_INSUFFICIENT_RESOURCES;
209 }
210 pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
211
212 pSl = IoGetNextIrpStackLocation(pIrp);
213 pSl->MajorFunction = IRP_MJ_PNP;
214 pSl->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
215 pSl->Parameters.QueryDeviceRelations.Type = BusRelations;
216 pSl->FileObject = pFileObj;
217
218 Status = IoCallDriver(pDevObj, pIrp);
219 if (Status == STATUS_PENDING)
220 {
221 LOG(("IoCallDriver returned STATUS_PENDING!!"));
222 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
223 Status = IoStatus.Status;
224 }
225
226 if (Status == STATUS_SUCCESS)
227 {
228 PDEVICE_RELATIONS pRel = (PDEVICE_RELATIONS)IoStatus.Information;
229 LOG(("pRel = %p", pRel));
230 if (VALID_PTR(pRel))
231 {
232 *pDevRelations = pRel;
233 }
234 else
235 {
236 WARN(("Invalid pointer %p", pRel));
237 }
238 }
239 else
240 {
241 WARN(("IRP_MN_QUERY_DEVICE_RELATIONS failed Status(0x%x)", Status));
242 }
243
244 LOG(("IoCallDriver returned %x", Status));
245 return Status;
246}
247
248VOID vboxUsbMonHubDevWalk(PFNVBOXUSBMONDEVWALKER pfnWalker, PVOID pvWalker, ULONG fFlags)
249{
250 NTSTATUS Status = STATUS_UNSUCCESSFUL;
251 RT_NOREF1(fFlags);
252 PWSTR szwHubList;
253 Status = IoGetDeviceInterfaces(&GUID_DEVINTERFACE_USB_HUB, NULL, 0, &szwHubList);
254 if (Status != STATUS_SUCCESS)
255 {
256 LOG(("IoGetDeviceInterfaces failed with %d\n", Status));
257 return;
258 }
259 if (szwHubList)
260 {
261 UNICODE_STRING UnicodeName;
262 PDEVICE_OBJECT pHubDevObj;
263 PFILE_OBJECT pHubFileObj;
264 PWSTR szwHubName = szwHubList;
265 while (*szwHubName != UNICODE_NULL)
266 {
267 RtlInitUnicodeString(&UnicodeName, szwHubName);
268 Status = IoGetDeviceObjectPointer(&UnicodeName, FILE_READ_DATA, &pHubFileObj, &pHubDevObj);
269 if (Status == STATUS_SUCCESS)
270 {
271 /* We could not log hub name here.
272 * It is the paged memory and we cannot use it in logger cause it increases the IRQL
273 */
274 LOG(("IoGetDeviceObjectPointer returned %p %p", pHubDevObj, pHubFileObj));
275 if (!pfnWalker(pHubFileObj, pHubDevObj, pHubDevObj, pvWalker))
276 {
277 LOG(("the walker said to stop"));
278 ObDereferenceObject(pHubFileObj);
279 break;
280 }
281
282 LOG(("going forward.."));
283 ObDereferenceObject(pHubFileObj);
284 }
285 szwHubName += wcslen(szwHubName) + 1;
286 }
287 ExFreePool(szwHubList);
288 }
289}
290
291/* NOTE: the stack location data is not the "actual" IRP stack location,
292 * but a copy being preserved on the IRP way down.
293 * See the note in VBoxUsbPnPCompletion for detail */
294static NTSTATUS vboxUsbMonHandlePnPIoctl(PDEVICE_OBJECT pDevObj, PIO_STACK_LOCATION pSl, PIO_STATUS_BLOCK pIoStatus)
295{
296 LOG(("IRQL = %d", KeGetCurrentIrql()));
297 switch(pSl->MinorFunction)
298 {
299 case IRP_MN_QUERY_DEVICE_TEXT:
300 {
301 LOG(("IRP_MN_QUERY_DEVICE_TEXT: pIoStatus->Status = %x", pIoStatus->Status));
302 if (pIoStatus->Status == STATUS_SUCCESS)
303 {
304 WCHAR *pId = (WCHAR *)pIoStatus->Information;
305 if (VALID_PTR(pId))
306 {
307 KIRQL Iqrl = KeGetCurrentIrql();
308 /* IRQL should be always passive here */
309 ASSERT_WARN(Iqrl == PASSIVE_LEVEL, ("irql is not PASSIVE"));
310 switch(pSl->Parameters.QueryDeviceText.DeviceTextType)
311 {
312 case DeviceTextLocationInformation:
313 LOG(("DeviceTextLocationInformation"));
314 LOG_STRW(pId);
315 break;
316
317 case DeviceTextDescription:
318 LOG(("DeviceTextDescription"));
319 LOG_STRW(pId);
320 if (VBoxUsbFltPdoIsFiltered(pDevObj))
321 {
322 LOG(("PDO (0x%p) is filtered", pDevObj));
323 WCHAR *pId = (WCHAR *)ExAllocatePool(PagedPool, sizeof(szDeviceTextDescription));
324 if (!pId)
325 {
326 AssertFailed();
327 break;
328 }
329 memcpy(pId, szDeviceTextDescription, sizeof(szDeviceTextDescription));
330 LOG(("NEW szDeviceTextDescription"));
331 LOG_STRW(pId);
332 ExFreePool((PVOID)pIoStatus->Information);
333 pIoStatus->Information = (ULONG_PTR)pId;
334 }
335 else
336 {
337 LOG(("PDO (0x%p) is NOT filtered", pDevObj));
338 }
339 break;
340 default:
341 LOG(("DeviceText %d", pSl->Parameters.QueryDeviceText.DeviceTextType));
342 break;
343 }
344 }
345 else
346 LOG(("Invalid pointer %p", pId));
347 }
348 break;
349 }
350
351 case IRP_MN_QUERY_ID:
352 {
353 LOG(("IRP_MN_QUERY_ID: Irp->pIoStatus->Status = %x", pIoStatus->Status));
354 if (pIoStatus->Status == STATUS_SUCCESS && pDevObj)
355 {
356 WCHAR *pId = (WCHAR *)pIoStatus->Information;
357#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
358 WCHAR *pTmp;
359#endif
360 if (VALID_PTR(pId))
361 {
362 KIRQL Iqrl = KeGetCurrentIrql();
363 /* IRQL should be always passive here */
364 ASSERT_WARN(Iqrl == PASSIVE_LEVEL, ("irql is not PASSIVE"));
365
366 switch (pSl->Parameters.QueryId.IdType)
367 {
368 case BusQueryInstanceID:
369 LOG(("BusQueryInstanceID"));
370 LOG_STRW(pId);
371 break;
372
373 case BusQueryDeviceID:
374 {
375 LOG(("BusQueryDeviceID"));
376 pId = (WCHAR *)ExAllocatePool(PagedPool, sizeof(szBusQueryDeviceId));
377 if (!pId)
378 {
379 WARN(("ExAllocatePool failed"));
380 break;
381 }
382
383 BOOLEAN bFiltered = FALSE;
384 NTSTATUS Status = VBoxUsbFltPdoAdd(pDevObj, &bFiltered);
385 if (Status != STATUS_SUCCESS || !bFiltered)
386 {
387 if (Status == STATUS_SUCCESS)
388 {
389 LOG(("PDO (0x%p) is NOT filtered", pDevObj));
390 }
391 else
392 {
393 WARN(("VBoxUsbFltPdoAdd for PDO (0x%p) failed Status 0x%x", pDevObj, Status));
394 }
395 ExFreePool(pId);
396 break;
397 }
398
399 LOG(("PDO (0x%p) is filtered", pDevObj));
400 ExFreePool((PVOID)pIoStatus->Information);
401 memcpy(pId, szBusQueryDeviceId, sizeof(szBusQueryDeviceId));
402 pIoStatus->Information = (ULONG_PTR)pId;
403 break;
404 }
405 case BusQueryHardwareIDs:
406 {
407 LOG(("BusQueryHardwareIDs"));
408#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
409 while (*pId) //MULTI_SZ
410 {
411 LOG_STRW(pId);
412 while (*pId) pId++;
413 pId++;
414 }
415#endif
416 pId = (WCHAR *)ExAllocatePool(PagedPool, sizeof(szBusQueryHardwareIDs));
417 if (!pId)
418 {
419 WARN(("ExAllocatePool failed"));
420 break;
421 }
422
423 BOOLEAN bFiltered = FALSE;
424 NTSTATUS Status = VBoxUsbFltPdoAdd(pDevObj, &bFiltered);
425 if (Status != STATUS_SUCCESS || !bFiltered)
426 {
427 if (Status == STATUS_SUCCESS)
428 {
429 LOG(("PDO (0x%p) is NOT filtered", pDevObj));
430 }
431 else
432 {
433 WARN(("VBoxUsbFltPdoAdd for PDO (0x%p) failed Status 0x%x", pDevObj, Status));
434 }
435 ExFreePool(pId);
436 break;
437 }
438
439 LOG(("PDO (0x%p) is filtered", pDevObj));
440
441 memcpy(pId, szBusQueryHardwareIDs, sizeof(szBusQueryHardwareIDs));
442#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
443 LOG(("NEW BusQueryHardwareIDs"));
444 pTmp = pId;
445 while (*pTmp) //MULTI_SZ
446 {
447
448 LOG_STRW(pTmp);
449 while (*pTmp) pTmp++;
450 pTmp++;
451 }
452#endif
453 ExFreePool((PVOID)pIoStatus->Information);
454 pIoStatus->Information = (ULONG_PTR)pId;
455 break;
456 }
457 case BusQueryCompatibleIDs:
458 LOG(("BusQueryCompatibleIDs"));
459#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
460 while (*pId) //MULTI_SZ
461 {
462 LOG_STRW(pId);
463 while (*pId) pId++;
464 pId++;
465 }
466#endif
467 if (VBoxUsbFltPdoIsFiltered(pDevObj))
468 {
469 LOG(("PDO (0x%p) is filtered", pDevObj));
470 pId = (WCHAR *)ExAllocatePool(PagedPool, sizeof(szBusQueryCompatibleIDs));
471 if (!pId)
472 {
473 WARN(("ExAllocatePool failed"));
474 break;
475 }
476 memcpy(pId, szBusQueryCompatibleIDs, sizeof(szBusQueryCompatibleIDs));
477#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
478 LOG(("NEW BusQueryCompatibleIDs"));
479 pTmp = pId;
480 while (*pTmp) //MULTI_SZ
481 {
482 LOG_STRW(pTmp);
483 while (*pTmp) pTmp++;
484 pTmp++;
485 }
486#endif
487 ExFreePool((PVOID)pIoStatus->Information);
488 pIoStatus->Information = (ULONG_PTR)pId;
489 }
490 else
491 {
492 LOG(("PDO (0x%p) is NOT filtered", pDevObj));
493 }
494 break;
495
496 default:
497 /** @todo r=bird: handle BusQueryContainerID and whatever else we might see */
498 break;
499 }
500 }
501 else
502 {
503 LOG(("Invalid pointer %p", pId));
504 }
505 }
506 break;
507 }
508
509#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
510 case IRP_MN_QUERY_DEVICE_RELATIONS:
511 {
512 switch(pSl->Parameters.QueryDeviceRelations.Type)
513 {
514 case BusRelations:
515 LOG(("BusRelations"));
516
517 if (pIoStatus->Status == STATUS_SUCCESS)
518 {
519 PDEVICE_RELATIONS pRel = (PDEVICE_RELATIONS)pIoStatus->Information;
520 LOG(("pRel = %p", pRel));
521 if (VALID_PTR(pRel))
522 {
523 for (unsigned i=0;i<pRel->Count;i++)
524 {
525 if (VBoxUsbFltPdoIsFiltered(pDevObj))
526 LOG(("New PDO %p", pRel->Objects[i]));
527 }
528 }
529 else
530 LOG(("Invalid pointer %p", pRel));
531 }
532 break;
533 case TargetDeviceRelation:
534 LOG(("TargetDeviceRelation"));
535 break;
536 case RemovalRelations:
537 LOG(("RemovalRelations"));
538 break;
539 case EjectionRelations:
540 LOG(("EjectionRelations"));
541 break;
542 default:
543 LOG(("QueryDeviceRelations.Type=%d", pSl->Parameters.QueryDeviceRelations.Type));
544 }
545 break;
546 }
547
548 case IRP_MN_QUERY_CAPABILITIES:
549 {
550 LOG(("IRP_MN_QUERY_CAPABILITIES: pIoStatus->Status = %x", pIoStatus->Status));
551 if (pIoStatus->Status == STATUS_SUCCESS)
552 {
553 PDEVICE_CAPABILITIES pCaps = pSl->Parameters.DeviceCapabilities.Capabilities;
554 if (VALID_PTR(pCaps))
555 {
556 LOG(("Caps.SilentInstall = %d", pCaps->SilentInstall));
557 LOG(("Caps.UniqueID = %d", pCaps->UniqueID ));
558 LOG(("Caps.Address = %d", pCaps->Address ));
559 LOG(("Caps.UINumber = %d", pCaps->UINumber ));
560 }
561 else
562 LOG(("Invalid pointer %p", pCaps));
563 }
564 break;
565 }
566
567 default:
568 break;
569#endif
570 } /*switch */
571
572 LOG(("Done returns %x (IRQL = %d)", pIoStatus->Status, KeGetCurrentIrql()));
573 return pIoStatus->Status;
574}
575
576NTSTATUS _stdcall VBoxUsbPnPCompletion(DEVICE_OBJECT *pDevObj, IRP *pIrp, void *pvContext)
577{
578 LOG(("Completion PDO(0x%p), IRP(0x%p), Status(0x%x)", pDevObj, pIrp, pIrp->IoStatus.Status));
579 ASSERT_WARN(pvContext, ("zero context"));
580
581 PVBOXUSBHOOK_REQUEST pRequest = (PVBOXUSBHOOK_REQUEST)pvContext;
582 /* NOTE: despite a regular IRP processing the stack location in our completion
583 * differs from those of the PnP hook since the hook is invoked in the "context" of the calle,
584 * while the completion is in the "coller" context in terms of IRP,
585 * so the completion stack location is one level "up" here.
586 *
587 * Moreover we CAN NOT access irp stack location in the completion because we might not have one at all
588 * in case the hooked driver is at the top of the irp call stack
589 *
590 * This is why we use the stack location we saved on IRP way down.
591 * */
592 PIO_STACK_LOCATION pSl = &pRequest->OldLocation;
593 ASSERT_WARN(pIrp == pRequest->pIrp, ("completed IRP(0x%x) not match request IRP(0x%x)", pIrp, pRequest->pIrp));
594 /* NOTE: we can not rely on pDevObj passed in IoCompletion since it may be zero
595 * in case IRP was created with extra stack locations and the caller did not initialize
596 * the IO_STACK_LOCATION::DeviceObject */
597 DEVICE_OBJECT *pRealDevObj = pRequest->pDevObj;
598// Assert(!pDevObj || pDevObj == pRealDevObj);
599// Assert(pSl->DeviceObject == pDevObj);
600
601 switch(pSl->MinorFunction)
602 {
603 case IRP_MN_QUERY_DEVICE_TEXT:
604 case IRP_MN_QUERY_ID:
605#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
606 case IRP_MN_QUERY_DEVICE_RELATIONS:
607 case IRP_MN_QUERY_CAPABILITIES:
608#endif
609 if (NT_SUCCESS(pIrp->IoStatus.Status))
610 {
611 vboxUsbMonHandlePnPIoctl(pRealDevObj, pSl, &pIrp->IoStatus);
612 }
613 else
614 {
615 ASSERT_WARN(pIrp->IoStatus.Status == STATUS_NOT_SUPPORTED, ("Irp failed with status(0x%x)", pIrp->IoStatus.Status));
616 }
617 break;
618
619 case IRP_MN_SURPRISE_REMOVAL:
620 case IRP_MN_REMOVE_DEVICE:
621 if (NT_SUCCESS(pIrp->IoStatus.Status))
622 {
623 VBoxUsbFltPdoRemove(pRealDevObj);
624 }
625 else
626 {
627 AssertFailed();
628 }
629 break;
630
631 /* These two IRPs are received when the PnP subsystem has determined the id of the newly arrived device */
632 /* IRP_MN_START_DEVICE only arrives if it's a USB device of a known class or with a present host driver */
633 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
634 case IRP_MN_QUERY_RESOURCES:
635 if (NT_SUCCESS(pIrp->IoStatus.Status) || pIrp->IoStatus.Status == STATUS_NOT_SUPPORTED)
636 {
637 VBoxUsbFltPdoAddCompleted(pRealDevObj);
638 }
639 else
640 {
641 AssertFailed();
642 }
643 break;
644
645 default:
646 break;
647 }
648
649 LOG(("<==PnP: Mn(%s), PDO(0x%p), IRP(0x%p), Status(0x%x), Sl PDO(0x%p), Compl PDO(0x%p)",
650 vboxUsbDbgStrPnPMn(pSl->MinorFunction),
651 pRealDevObj, pIrp, pIrp->IoStatus.Status,
652 pSl->DeviceObject, pDevObj));
653#ifdef DEBUG_misha
654 NTSTATUS tmpStatus = pIrp->IoStatus.Status;
655#endif
656 PVBOXUSBHOOK_ENTRY pHook = pRequest->pHook;
657 NTSTATUS Status = VBoxUsbHookRequestComplete(pHook, pDevObj, pIrp, pRequest);
658 VBoxUsbMonMemFree(pRequest);
659#ifdef DEBUG_misha
660 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
661 {
662 Assert(pIrp->IoStatus.Status == tmpStatus);
663 }
664#endif
665 VBoxUsbHookRelease(pHook);
666 return Status;
667}
668
669/**
670 * Device PnP hook
671 *
672 * @param pDevObj Device object.
673 * @param pIrp Request packet.
674 */
675static NTSTATUS vboxUsbMonPnPHook(IN PVBOXUSBHOOK_ENTRY pHook, IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
676{
677 LOG(("==>PnP: Mn(%s), PDO(0x%p), IRP(0x%p), Status(0x%x)", vboxUsbDbgStrPnPMn(IoGetCurrentIrpStackLocation(pIrp)->MinorFunction), pDevObj, pIrp, pIrp->IoStatus.Status));
678
679 if (!VBoxUsbHookRetain(pHook))
680 {
681 WARN(("VBoxUsbHookRetain failed"));
682 return VBoxUsbHookRequestPassDownHookSkip(pHook, pDevObj, pIrp);
683 }
684
685 PVBOXUSBHUB_PNPHOOK_COMPLETION pCompletion = (PVBOXUSBHUB_PNPHOOK_COMPLETION)VBoxUsbMonMemAlloc(sizeof (*pCompletion));
686 if (!pCompletion)
687 {
688 WARN(("VBoxUsbMonMemAlloc failed"));
689 VBoxUsbHookRelease(pHook);
690 pIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
691 pIrp->IoStatus.Information = 0;
692 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
693 return STATUS_INSUFFICIENT_RESOURCES;
694 }
695
696 NTSTATUS Status = VBoxUsbHookRequestPassDownHookCompletion(pHook, pDevObj, pIrp, VBoxUsbPnPCompletion, &pCompletion->Rq);
697#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
698 if (Status != STATUS_PENDING)
699 {
700 LOG(("Request completed, Status(0x%x)", Status));
701 VBoxUsbHookVerifyCompletion(pHook, &pCompletion->Rq, pIrp);
702 }
703 else
704 {
705 LOG(("Request pending"));
706 }
707#endif
708 return Status;
709}
710
711/**
712 * Device PnP hook stubs.
713 *
714 * @param pDevObj Device object.
715 * @param pIrp Request packet.
716 */
717#define VBOX_PNPHOOKSTUB(n) NTSTATUS _stdcall VBoxUsbMonPnPHook##n(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) \
718{ \
719 return vboxUsbMonPnPHook(&g_VBoxUsbMonGlobals.pDrivers[n].UsbHubPnPHook.Hook, pDevObj, pIrp); \
720}
721
722#define VBOX_PNPHOOKSTUB_INIT(n) g_VBoxUsbMonGlobals.pDrivers[n].pfnHookStub = VBoxUsbMonPnPHook##n
723
724VBOX_PNPHOOKSTUB(0)
725VBOX_PNPHOOKSTUB(1)
726VBOX_PNPHOOKSTUB(2)
727VBOX_PNPHOOKSTUB(3)
728VBOX_PNPHOOKSTUB(4)
729AssertCompile(VBOXUSBMON_MAXDRIVERS == 5);
730
731typedef struct VBOXUSBMONHOOKDRIVERWALKER
732{
733 PDRIVER_OBJECT pDrvObj;
734} VBOXUSBMONHOOKDRIVERWALKER, *PVBOXUSBMONHOOKDRIVERWALKER;
735
736/**
737 * Logs an error to the system event log.
738 *
739 * @param ErrCode Error to report to event log.
740 * @param ReturnedStatus Error that was reported by the driver to the caller.
741 * @param uErrId Unique error id representing the location in the driver.
742 * @param cbDumpData Number of bytes at pDumpData.
743 * @param pDumpData Pointer to data that will be added to the message (see 'details' tab).
744 */
745static void vboxUsbMonLogError(NTSTATUS ErrCode, NTSTATUS ReturnedStatus, ULONG uErrId, USHORT cbDumpData, PVOID pDumpData)
746{
747 PIO_ERROR_LOG_PACKET pErrEntry;
748
749
750 /* Truncate dumps that do not fit into IO_ERROR_LOG_PACKET. */
751 if (FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData) + cbDumpData > ERROR_LOG_MAXIMUM_SIZE)
752 cbDumpData = ERROR_LOG_MAXIMUM_SIZE - FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData);
753
754 pErrEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(g_VBoxUsbMonGlobals.pDevObj,
755 FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData) + cbDumpData);
756 if (pErrEntry)
757 {
758 uint8_t *pDump = (uint8_t *)pErrEntry->DumpData;
759 if (cbDumpData)
760 memcpy(pDump, pDumpData, cbDumpData);
761 pErrEntry->MajorFunctionCode = 0;
762 pErrEntry->RetryCount = 0;
763 pErrEntry->DumpDataSize = cbDumpData;
764 pErrEntry->NumberOfStrings = 0;
765 pErrEntry->StringOffset = 0;
766 pErrEntry->ErrorCode = ErrCode;
767 pErrEntry->UniqueErrorValue = uErrId;
768 pErrEntry->FinalStatus = ReturnedStatus;
769 pErrEntry->IoControlCode = 0;
770 IoWriteErrorLogEntry(pErrEntry);
771 }
772 else
773 {
774 LOG(("Failed to allocate error log entry (cb=%d)\n", FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData) + cbDumpData));
775 }
776}
777
778static DECLCALLBACK(BOOLEAN) vboxUsbMonHookDrvObjWalker(PFILE_OBJECT pFile, PDEVICE_OBJECT pTopDo, PDEVICE_OBJECT pHubDo, PVOID pvContext)
779{
780 RT_NOREF3(pFile, pTopDo, pvContext);
781 PDRIVER_OBJECT pDrvObj = pHubDo->DriverObject;
782
783 /* First we try to figure out if we are already hooked to this driver. */
784 for (int i = 0; i < VBOXUSBMON_MAXDRIVERS; i++)
785 if (pDrvObj == g_VBoxUsbMonGlobals.pDrivers[i].DriverObject)
786 {
787 LOG(("Found %p at pDrivers[%d]\n", pDrvObj, i));
788 /* We've already hooked to this one -- nothing to do. */
789 return TRUE;
790 }
791 /* We are not hooked yet, find an empty slot. */
792 for (int i = 0; i < VBOXUSBMON_MAXDRIVERS; i++)
793 {
794 if (!g_VBoxUsbMonGlobals.pDrivers[i].DriverObject)
795 {
796 /* Found an emtpy slot, use it. */
797 g_VBoxUsbMonGlobals.pDrivers[i].DriverObject = pDrvObj;
798 ObReferenceObject(pDrvObj);
799 LOG(("pDrivers[%d] = %p, installing the hook...\n", i, pDrvObj));
800 VBoxUsbHookInit(&g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.Hook,
801 pDrvObj,
802 IRP_MJ_PNP,
803 g_VBoxUsbMonGlobals.pDrivers[i].pfnHookStub);
804 VBoxUsbHookInstall(&g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.Hook);
805 return TRUE; /* Must continue to find all drivers. */
806 }
807 if (pDrvObj == g_VBoxUsbMonGlobals.pDrivers[i].DriverObject)
808 {
809 LOG(("Found %p at pDrivers[%d]\n", pDrvObj, i));
810 /* We've already hooked to this one -- nothing to do. */
811 return TRUE;
812 }
813 }
814 /* No empty slots! No reason to continue. */
815 LOG(("No empty slots!\n"));
816 ANSI_STRING ansiDrvName;
817 NTSTATUS Status = RtlUnicodeStringToAnsiString(&ansiDrvName, &pDrvObj->DriverName, true);
818 if (Status != STATUS_SUCCESS)
819 {
820 ansiDrvName.Length = 0;
821 LOG(("RtlUnicodeStringToAnsiString failed with 0x%x", Status));
822 }
823 vboxUsbMonLogError(IO_ERR_INSUFFICIENT_RESOURCES, STATUS_SUCCESS, 1, ansiDrvName.Length, ansiDrvName.Buffer);
824 if (Status == STATUS_SUCCESS)
825 RtlFreeAnsiString(&ansiDrvName);
826 return FALSE;
827}
828
829/**
830 * Finds all USB drivers in the system and installs hooks if haven't done already.
831 */
832static NTSTATUS vboxUsbMonInstallAllHooks()
833{
834 vboxUsbMonHubDevWalk(vboxUsbMonHookDrvObjWalker, NULL, VBOXUSBMONHUBWALK_F_ALL);
835 return STATUS_SUCCESS;
836}
837
838static NTSTATUS vboxUsbMonHookCheckInit()
839{
840 static bool fIsHookInited = false;
841 if (fIsHookInited)
842 {
843 LOG(("hook inited already, success"));
844 return STATUS_SUCCESS;
845 }
846 return vboxUsbMonInstallAllHooks();
847}
848
849static NTSTATUS vboxUsbMonHookInstall()
850{
851 /* Nothing to do here as we have already installed all hooks in vboxUsbMonHookCheckInit(). */
852 return STATUS_SUCCESS;
853}
854
855static NTSTATUS vboxUsbMonHookUninstall()
856{
857#ifdef VBOXUSBMON_DBG_NO_PNPHOOK
858 return STATUS_SUCCESS;
859#else
860 NTSTATUS Status = STATUS_SUCCESS;
861 for (int i = 0; i < VBOXUSBMON_MAXDRIVERS; i++)
862 {
863 if (g_VBoxUsbMonGlobals.pDrivers[i].DriverObject)
864 {
865 Assert(g_VBoxUsbMonGlobals.pDrivers[i].DriverObject == g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.Hook.pDrvObj);
866 LOG(("Unhooking from %p...\n", g_VBoxUsbMonGlobals.pDrivers[i].DriverObject));
867 Status = VBoxUsbHookUninstall(&g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.Hook);
868 if (!NT_SUCCESS(Status))
869 {
870 /*
871 * We failed to uninstall the hook, so we keep the reference to the driver
872 * in order to prevent another driver re-using this slot because we are
873 * going to mark this hook as fUninitFailed.
874 */
875 //AssertMsgFailed(("usbhub pnp unhook failed, setting the fUninitFailed flag, the current value of fUninitFailed (%d)", g_VBoxUsbMonGlobals.UsbHubPnPHook.fUninitFailed));
876 LOG(("usbhub pnp unhook failed, setting the fUninitFailed flag, the current value of fUninitFailed (%d)", g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.fUninitFailed));
877 g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.fUninitFailed = true;
878 }
879 else
880 {
881 /* The hook was removed successfully, now we can forget about this driver. */
882 ObDereferenceObject(g_VBoxUsbMonGlobals.pDrivers[i].DriverObject);
883 g_VBoxUsbMonGlobals.pDrivers[i].DriverObject = NULL;
884 }
885 }
886 }
887 return Status;
888#endif
889}
890
891
892static NTSTATUS vboxUsbMonCheckTermStuff()
893{
894 NTSTATUS Status = KeWaitForSingleObject(&g_VBoxUsbMonGlobals.OpenSynchEvent,
895 Executive, KernelMode,
896 FALSE, /* BOOLEAN Alertable */
897 NULL /* IN PLARGE_INTEGER Timeout */
898 );
899 AssertRelease(Status == STATUS_SUCCESS);
900
901 do
902 {
903 if (--g_VBoxUsbMonGlobals.cOpens)
904 break;
905
906 Status = vboxUsbMonHookUninstall();
907
908 NTSTATUS tmpStatus = VBoxUsbFltTerm();
909 if (!NT_SUCCESS(tmpStatus))
910 {
911 /* this means a driver state is screwed up, KeBugCheckEx here ? */
912 AssertReleaseFailed();
913 }
914 } while (0);
915
916 KeSetEvent(&g_VBoxUsbMonGlobals.OpenSynchEvent, 0, FALSE);
917
918 return Status;
919}
920
921static NTSTATUS vboxUsbMonCheckInitStuff()
922{
923 NTSTATUS Status = KeWaitForSingleObject(&g_VBoxUsbMonGlobals.OpenSynchEvent,
924 Executive, KernelMode,
925 FALSE, /* BOOLEAN Alertable */
926 NULL /* IN PLARGE_INTEGER Timeout */
927 );
928 if (Status == STATUS_SUCCESS)
929 {
930 do
931 {
932 if (g_VBoxUsbMonGlobals.cOpens++)
933 {
934 LOG(("opens: %d, success", g_VBoxUsbMonGlobals.cOpens));
935 break;
936 }
937
938 Status = VBoxUsbFltInit();
939 if (NT_SUCCESS(Status))
940 {
941 Status = vboxUsbMonHookCheckInit();
942 if (NT_SUCCESS(Status))
943 {
944 Status = vboxUsbMonHookInstall();
945 if (NT_SUCCESS(Status))
946 {
947 Status = STATUS_SUCCESS;
948 LOG(("succeded!!"));
949 break;
950 }
951 else
952 {
953 WARN(("vboxUsbMonHookInstall failed, Status (0x%x)", Status));
954 }
955 }
956 else
957 {
958 WARN(("vboxUsbMonHookCheckInit failed, Status (0x%x)", Status));
959 }
960 VBoxUsbFltTerm();
961 }
962 else
963 {
964 WARN(("VBoxUsbFltInit failed, Status (0x%x)", Status));
965 }
966
967 --g_VBoxUsbMonGlobals.cOpens;
968 Assert(!g_VBoxUsbMonGlobals.cOpens);
969 } while (0);
970
971 KeSetEvent(&g_VBoxUsbMonGlobals.OpenSynchEvent, 0, FALSE);
972 }
973 else
974 {
975 WARN(("KeWaitForSingleObject failed, Status (0x%x)", Status));
976 }
977 return Status;
978}
979
980static NTSTATUS vboxUsbMonContextCreate(PVBOXUSBMONCTX *ppCtx)
981{
982 NTSTATUS Status;
983 *ppCtx = NULL;
984 PVBOXUSBMONCTX pFileCtx = (PVBOXUSBMONCTX)VBoxUsbMonMemAllocZ(sizeof (*pFileCtx));
985 if (pFileCtx)
986 {
987 Status = vboxUsbMonCheckInitStuff();
988 if (Status == STATUS_SUCCESS)
989 {
990 Status = VBoxUsbFltCreate(&pFileCtx->FltCtx);
991 if (Status == STATUS_SUCCESS)
992 {
993 *ppCtx = pFileCtx;
994 LOG(("succeeded!!"));
995 return STATUS_SUCCESS;
996 }
997 else
998 {
999 WARN(("VBoxUsbFltCreate failed"));
1000 }
1001 vboxUsbMonCheckTermStuff();
1002 }
1003 else
1004 {
1005 WARN(("vboxUsbMonCheckInitStuff failed"));
1006 }
1007 VBoxUsbMonMemFree(pFileCtx);
1008 }
1009 else
1010 {
1011 WARN(("VBoxUsbMonMemAllocZ failed"));
1012 Status = STATUS_NO_MEMORY;
1013 }
1014
1015 return Status;
1016}
1017
1018static NTSTATUS vboxUsbMonContextClose(PVBOXUSBMONCTX pCtx)
1019{
1020 NTSTATUS Status = VBoxUsbFltClose(&pCtx->FltCtx);
1021 if (Status == STATUS_SUCCESS)
1022 {
1023 Status = vboxUsbMonCheckTermStuff();
1024 Assert(Status == STATUS_SUCCESS);
1025 /* ignore the failure */
1026 VBoxUsbMonMemFree(pCtx);
1027 }
1028
1029 return Status;
1030}
1031
1032static NTSTATUS _stdcall VBoxUsbMonClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1033{
1034 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1035 PFILE_OBJECT pFileObj = pStack->FileObject;
1036 Assert(pFileObj->FsContext);
1037 PVBOXUSBMONCTX pCtx = (PVBOXUSBMONCTX)pFileObj->FsContext;
1038
1039 LOG(("VBoxUsbMonClose"));
1040
1041 NTSTATUS Status = vboxUsbMonContextClose(pCtx);
1042 if (Status != STATUS_SUCCESS)
1043 {
1044 WARN(("vboxUsbMonContextClose failed, Status (0x%x), prefent unload", Status));
1045 if (!InterlockedExchange(&g_VBoxUsbMonGlobals.ulPreventUnloadOn, 1))
1046 {
1047 LOGREL(("ulPreventUnloadOn not set, preventing unload"));
1048 UNICODE_STRING UniName;
1049 PDEVICE_OBJECT pTmpDevObj;
1050 RtlInitUnicodeString(&UniName, USBMON_DEVICE_NAME_NT);
1051 NTSTATUS tmpStatus = IoGetDeviceObjectPointer(&UniName, FILE_ALL_ACCESS, &g_VBoxUsbMonGlobals.pPreventUnloadFileObj, &pTmpDevObj);
1052 AssertRelease(NT_SUCCESS(tmpStatus));
1053 AssertRelease(pTmpDevObj == pDevObj);
1054 }
1055 else
1056 {
1057 WARN(("ulPreventUnloadOn already set"));
1058 }
1059 LOG(("success!!"));
1060 Status = STATUS_SUCCESS;
1061 }
1062 pFileObj->FsContext = NULL;
1063 pIrp->IoStatus.Status = Status;
1064 pIrp->IoStatus.Information = 0;
1065 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1066 return Status;
1067}
1068
1069
1070static NTSTATUS _stdcall VBoxUsbMonCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1071{
1072 RT_NOREF1(pDevObj);
1073 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1074 PFILE_OBJECT pFileObj = pStack->FileObject;
1075 NTSTATUS Status;
1076
1077 LOG(("VBoxUSBMonCreate"));
1078
1079 if (pStack->Parameters.Create.Options & FILE_DIRECTORY_FILE)
1080 {
1081 WARN(("trying to open as a directory"));
1082 pIrp->IoStatus.Status = STATUS_NOT_A_DIRECTORY;
1083 pIrp->IoStatus.Information = 0;
1084 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1085 return STATUS_NOT_A_DIRECTORY;
1086 }
1087
1088 pFileObj->FsContext = NULL;
1089 PVBOXUSBMONCTX pCtx = NULL;
1090 Status = vboxUsbMonContextCreate(&pCtx);
1091 if (Status == STATUS_SUCCESS)
1092 {
1093 Assert(pCtx);
1094 pFileObj->FsContext = pCtx;
1095 }
1096 else
1097 {
1098 WARN(("vboxUsbMonContextCreate failed Status (0x%x)", Status));
1099 }
1100
1101 pIrp->IoStatus.Status = Status;
1102 pIrp->IoStatus.Information = 0;
1103 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1104 return Status;
1105}
1106
1107static int VBoxUsbMonSetNotifyEvent(PVBOXUSBMONCTX pContext, HANDLE hEvent)
1108{
1109 int rc = VBoxUsbFltSetNotifyEvent(&pContext->FltCtx, hEvent);
1110 return rc;
1111}
1112
1113static int VBoxUsbMonFltAdd(PVBOXUSBMONCTX pContext, PUSBFILTER pFilter, uintptr_t *pId)
1114{
1115#ifdef VBOXUSBMON_DBG_NO_FILTERS
1116 static uintptr_t idDummy = 1;
1117 *pId = idDummy;
1118 ++idDummy;
1119 return VINF_SUCCESS;
1120#else
1121 int rc = VBoxUsbFltAdd(&pContext->FltCtx, pFilter, pId);
1122 return rc;
1123#endif
1124}
1125
1126static int VBoxUsbMonFltRemove(PVBOXUSBMONCTX pContext, uintptr_t uId)
1127{
1128#ifdef VBOXUSBMON_DBG_NO_FILTERS
1129 return VINF_SUCCESS;
1130#else
1131 int rc = VBoxUsbFltRemove(&pContext->FltCtx, uId);
1132 return rc;
1133#endif
1134}
1135
1136static NTSTATUS VBoxUsbMonRunFilters(PVBOXUSBMONCTX pContext)
1137{
1138 NTSTATUS Status = VBoxUsbFltFilterCheck(&pContext->FltCtx);
1139 return Status;
1140}
1141
1142static NTSTATUS VBoxUsbMonGetDevice(PVBOXUSBMONCTX pContext, HVBOXUSBDEVUSR hDevice, PUSBSUP_GETDEV_MON pInfo)
1143{
1144 NTSTATUS Status = VBoxUsbFltGetDevice(&pContext->FltCtx, hDevice, pInfo);
1145 return Status;
1146}
1147
1148static NTSTATUS vboxUsbMonIoctlDispatch(PVBOXUSBMONCTX pContext, ULONG Ctl, PVOID pvBuffer, ULONG cbInBuffer,
1149 ULONG cbOutBuffer, ULONG_PTR *pInfo)
1150{
1151 NTSTATUS Status = STATUS_SUCCESS;
1152 ULONG_PTR Info = 0;
1153 switch (Ctl)
1154 {
1155 case SUPUSBFLT_IOCTL_GET_VERSION:
1156 {
1157 PUSBSUP_VERSION pOut = (PUSBSUP_VERSION)pvBuffer;
1158
1159 LOG(("SUPUSBFLT_IOCTL_GET_VERSION"));
1160 if (!pvBuffer || cbOutBuffer != sizeof(*pOut) || cbInBuffer != 0)
1161 {
1162 WARN(("SUPUSBFLT_IOCTL_GET_VERSION: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.",
1163 cbInBuffer, 0, cbOutBuffer, sizeof (*pOut)));
1164 Status = STATUS_INVALID_PARAMETER;
1165 break;
1166 }
1167 pOut->u32Major = USBMON_MAJOR_VERSION;
1168 pOut->u32Minor = USBMON_MINOR_VERSION;
1169 Info = sizeof (*pOut);
1170 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1171 break;
1172 }
1173
1174 case SUPUSBFLT_IOCTL_ADD_FILTER:
1175 {
1176 PUSBFILTER pFilter = (PUSBFILTER)pvBuffer;
1177 PUSBSUP_FLTADDOUT pOut = (PUSBSUP_FLTADDOUT)pvBuffer;
1178 uintptr_t uId = 0;
1179 int rc;
1180 if (RT_UNLIKELY(!pvBuffer || cbInBuffer != sizeof (*pFilter) || cbOutBuffer != sizeof (*pOut)))
1181 {
1182 WARN(("SUPUSBFLT_IOCTL_ADD_FILTER: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.",
1183 cbInBuffer, sizeof (*pFilter), cbOutBuffer, sizeof (*pOut)));
1184 Status = STATUS_INVALID_PARAMETER;
1185 break;
1186 }
1187
1188 rc = VBoxUsbMonFltAdd(pContext, pFilter, &uId);
1189 pOut->rc = rc;
1190 pOut->uId = uId;
1191 Info = sizeof (*pOut);
1192 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1193 break;
1194 }
1195
1196 case SUPUSBFLT_IOCTL_REMOVE_FILTER:
1197 {
1198 uintptr_t *pIn = (uintptr_t *)pvBuffer;
1199 int *pRc = (int *)pvBuffer;
1200
1201 if (!pvBuffer || cbInBuffer != sizeof (*pIn) || (cbOutBuffer && cbOutBuffer != sizeof (*pRc)))
1202 {
1203 WARN(("SUPUSBFLT_IOCTL_REMOVE_FILTER: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.",
1204 cbInBuffer, sizeof (*pIn), cbOutBuffer, 0));
1205 Status = STATUS_INVALID_PARAMETER;
1206 break;
1207 }
1208 LOG(("SUPUSBFLT_IOCTL_REMOVE_FILTER %x", *pIn));
1209 int rc = VBoxUsbMonFltRemove(pContext, *pIn);
1210 if (cbOutBuffer)
1211 {
1212 /* we've validated that already */
1213 Assert(cbOutBuffer == (ULONG)*pRc);
1214 *pRc = rc;
1215 Info = sizeof (*pRc);
1216 }
1217 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1218 break;
1219 }
1220
1221 case SUPUSBFLT_IOCTL_RUN_FILTERS:
1222 {
1223 if (pvBuffer || cbInBuffer || cbOutBuffer)
1224 {
1225 WARN(("SUPUSBFLT_IOCTL_RUN_FILTERS: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.",
1226 cbInBuffer, 0, cbOutBuffer, 0));
1227 Status = STATUS_INVALID_PARAMETER;
1228 break;
1229 }
1230 LOG(("SUPUSBFLT_IOCTL_RUN_FILTERS "));
1231 Status = VBoxUsbMonRunFilters(pContext);
1232 ASSERT_WARN(Status != STATUS_PENDING, ("status pending!"));
1233 break;
1234 }
1235
1236 case SUPUSBFLT_IOCTL_GET_DEVICE:
1237 {
1238 HVBOXUSBDEVUSR hDevice = *((HVBOXUSBDEVUSR*)pvBuffer);
1239 PUSBSUP_GETDEV_MON pOut = (PUSBSUP_GETDEV_MON)pvBuffer;
1240 if (!pvBuffer || cbInBuffer != sizeof (hDevice) || cbOutBuffer < sizeof (*pOut))
1241 {
1242 WARN(("SUPUSBFLT_IOCTL_GET_DEVICE: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected >= %d.",
1243 cbInBuffer, sizeof (hDevice), cbOutBuffer, sizeof (*pOut)));
1244 Status = STATUS_INVALID_PARAMETER;
1245 break;
1246 }
1247
1248 Status = VBoxUsbMonGetDevice(pContext, hDevice, pOut);
1249
1250 if (NT_SUCCESS(Status))
1251 {
1252 Info = sizeof (*pOut);
1253 }
1254 else
1255 {
1256 WARN(("VBoxUsbMonGetDevice fail 0x%x", Status));
1257 }
1258 break;
1259 }
1260
1261 case SUPUSBFLT_IOCTL_SET_NOTIFY_EVENT:
1262 {
1263 PUSBSUP_SET_NOTIFY_EVENT pSne = (PUSBSUP_SET_NOTIFY_EVENT)pvBuffer;
1264 if (!pvBuffer || cbInBuffer != sizeof (*pSne) || cbOutBuffer != sizeof (*pSne))
1265 {
1266 WARN(("SUPUSBFLT_IOCTL_SET_NOTIFY_EVENT: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.",
1267 cbInBuffer, sizeof (*pSne), cbOutBuffer, sizeof (*pSne)));
1268 Status = STATUS_INVALID_PARAMETER;
1269 break;
1270 }
1271
1272 pSne->u.rc = VBoxUsbMonSetNotifyEvent(pContext, pSne->u.hEvent);
1273 Info = sizeof (*pSne);
1274 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1275 break;
1276 }
1277
1278 default:
1279 WARN(("Unknown code 0x%x", Ctl));
1280 Status = STATUS_INVALID_PARAMETER;
1281 break;
1282 }
1283
1284 ASSERT_WARN(Status != STATUS_PENDING, ("Status pending!"));
1285
1286 *pInfo = Info;
1287 return Status;
1288}
1289
1290static NTSTATUS _stdcall VBoxUsbMonDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1291{
1292 ULONG_PTR Info = 0;
1293 NTSTATUS Status = IoAcquireRemoveLock(&g_VBoxUsbMonGlobals.RmLock, pDevObj);
1294 if (NT_SUCCESS(Status))
1295 {
1296 PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
1297 PFILE_OBJECT pFileObj = pSl->FileObject;
1298 Assert(pFileObj);
1299 Assert(pFileObj->FsContext);
1300 PVBOXUSBMONCTX pCtx = (PVBOXUSBMONCTX)pFileObj->FsContext;
1301 Assert(pCtx);
1302 Status = vboxUsbMonIoctlDispatch(pCtx,
1303 pSl->Parameters.DeviceIoControl.IoControlCode,
1304 pIrp->AssociatedIrp.SystemBuffer,
1305 pSl->Parameters.DeviceIoControl.InputBufferLength,
1306 pSl->Parameters.DeviceIoControl.OutputBufferLength,
1307 &Info);
1308 ASSERT_WARN(Status != STATUS_PENDING, ("Status pending"));
1309
1310 IoReleaseRemoveLock(&g_VBoxUsbMonGlobals.RmLock, pDevObj);
1311 }
1312 else
1313 {
1314 WARN(("IoAcquireRemoveLock failed Status (0x%x)", Status));
1315 }
1316
1317 pIrp->IoStatus.Information = Info;
1318 pIrp->IoStatus.Status = Status;
1319 IoCompleteRequest (pIrp, IO_NO_INCREMENT);
1320 return Status;
1321}
1322
1323static NTSTATUS vboxUsbMonInternalIoctlDispatch(ULONG Ctl, PVOID pvBuffer, ULONG_PTR *pInfo)
1324{
1325 NTSTATUS Status = STATUS_SUCCESS;
1326 *pInfo = 0;
1327 switch (Ctl)
1328 {
1329 case VBOXUSBIDC_INTERNAL_IOCTL_GET_VERSION:
1330 {
1331 PVBOXUSBIDC_VERSION pOut = (PVBOXUSBIDC_VERSION)pvBuffer;
1332
1333 LOG(("VBOXUSBIDC_INTERNAL_IOCTL_GET_VERSION"));
1334 if (!pvBuffer)
1335 {
1336 WARN(("VBOXUSBIDC_INTERNAL_IOCTL_GET_VERSION: Buffer is NULL"));
1337 Status = STATUS_INVALID_PARAMETER;
1338 break;
1339 }
1340 pOut->u32Major = VBOXUSBIDC_VERSION_MAJOR;
1341 pOut->u32Minor = VBOXUSBIDC_VERSION_MINOR;
1342 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1343 break;
1344 }
1345
1346 case VBOXUSBIDC_INTERNAL_IOCTL_PROXY_STARTUP:
1347 {
1348 PVBOXUSBIDC_PROXY_STARTUP pOut = (PVBOXUSBIDC_PROXY_STARTUP)pvBuffer;
1349
1350 LOG(("VBOXUSBIDC_INTERNAL_IOCTL_PROXY_STARTUP"));
1351 if (!pvBuffer)
1352 {
1353 WARN(("VBOXUSBIDC_INTERNAL_IOCTL_PROXY_STARTUP: Buffer is NULL"));
1354 Status = STATUS_INVALID_PARAMETER;
1355 break;
1356 }
1357
1358 pOut->u.hDev = VBoxUsbFltProxyStarted(pOut->u.pPDO);
1359 ASSERT_WARN(pOut->u.hDev, ("zero hDev"));
1360 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1361 break;
1362 }
1363
1364 case VBOXUSBIDC_INTERNAL_IOCTL_PROXY_TEARDOWN:
1365 {
1366 PVBOXUSBIDC_PROXY_TEARDOWN pOut = (PVBOXUSBIDC_PROXY_TEARDOWN)pvBuffer;
1367
1368 LOG(("VBOXUSBIDC_INTERNAL_IOCTL_PROXY_TEARDOWN"));
1369 if (!pvBuffer)
1370 {
1371 WARN(("VBOXUSBIDC_INTERNAL_IOCTL_PROXY_TEARDOWN: Buffer is NULL"));
1372 Status = STATUS_INVALID_PARAMETER;
1373 break;
1374 }
1375
1376 ASSERT_WARN(pOut->hDev, ("zero hDev"));
1377 VBoxUsbFltProxyStopped(pOut->hDev);
1378 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1379 break;
1380 }
1381
1382 default:
1383 {
1384 WARN(("Unknown code 0x%x", Ctl));
1385 Status = STATUS_INVALID_PARAMETER;
1386 break;
1387 }
1388 }
1389
1390 return Status;
1391}
1392
1393static NTSTATUS _stdcall VBoxUsbMonInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1394{
1395 ULONG_PTR Info = 0;
1396 NTSTATUS Status = IoAcquireRemoveLock(&g_VBoxUsbMonGlobals.RmLock, pDevObj);
1397 if (NT_SUCCESS(Status))
1398 {
1399 PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
1400 Status = vboxUsbMonInternalIoctlDispatch(pSl->Parameters.DeviceIoControl.IoControlCode,
1401 pSl->Parameters.Others.Argument1,
1402 &Info);
1403 Assert(Status != STATUS_PENDING);
1404
1405 IoReleaseRemoveLock(&g_VBoxUsbMonGlobals.RmLock, pDevObj);
1406 }
1407
1408 pIrp->IoStatus.Information = Info;
1409 pIrp->IoStatus.Status = Status;
1410 IoCompleteRequest (pIrp, IO_NO_INCREMENT);
1411 return Status;
1412}
1413
1414/**
1415 * Unload the driver.
1416 *
1417 * @param pDrvObj Driver object.
1418 */
1419static void _stdcall VBoxUsbMonUnload(PDRIVER_OBJECT pDrvObj)
1420{
1421 RT_NOREF1(pDrvObj);
1422 LOG(("VBoxUSBMonUnload pDrvObj (0x%p)", pDrvObj));
1423
1424 IoReleaseRemoveLockAndWait(&g_VBoxUsbMonGlobals.RmLock, &g_VBoxUsbMonGlobals);
1425
1426 Assert(!g_VBoxUsbMonGlobals.cOpens);
1427
1428 UNICODE_STRING DosName;
1429 RtlInitUnicodeString(&DosName, USBMON_DEVICE_NAME_DOS);
1430 IoDeleteSymbolicLink(&DosName);
1431
1432 IoDeleteDevice(g_VBoxUsbMonGlobals.pDevObj);
1433
1434 /* cleanup the logger */
1435 PRTLOGGER pLogger = RTLogRelSetDefaultInstance(NULL);
1436 if (pLogger)
1437 RTLogDestroy(pLogger);
1438 pLogger = RTLogSetDefaultInstance(NULL);
1439 if (pLogger)
1440 RTLogDestroy(pLogger);
1441}
1442
1443RT_C_DECLS_BEGIN
1444NTSTATUS _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath);
1445RT_C_DECLS_END
1446
1447/**
1448 * Driver entry point.
1449 *
1450 * @returns appropriate status code.
1451 * @param pDrvObj Pointer to driver object.
1452 * @param pRegPath Registry base path.
1453 */
1454NTSTATUS _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
1455{
1456 RT_NOREF1(pRegPath);
1457#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
1458 RTLogGroupSettings(0, "+default.e.l.f.l2.l3");
1459 RTLogDestinations(0, "debugger");
1460#endif
1461
1462 LOGREL(("Built %s %s", __DATE__, __TIME__));
1463
1464 memset (&g_VBoxUsbMonGlobals, 0, sizeof (g_VBoxUsbMonGlobals));
1465
1466 VBOX_PNPHOOKSTUB_INIT(0);
1467 VBOX_PNPHOOKSTUB_INIT(1);
1468 VBOX_PNPHOOKSTUB_INIT(2);
1469 VBOX_PNPHOOKSTUB_INIT(3);
1470 VBOX_PNPHOOKSTUB_INIT(4);
1471 AssertCompile(VBOXUSBMON_MAXDRIVERS == 5);
1472
1473 KeInitializeEvent(&g_VBoxUsbMonGlobals.OpenSynchEvent, SynchronizationEvent, TRUE /* signaled */);
1474 IoInitializeRemoveLock(&g_VBoxUsbMonGlobals.RmLock, VBOXUSBMON_MEMTAG, 1, 100);
1475 UNICODE_STRING DevName;
1476 PDEVICE_OBJECT pDevObj;
1477 /* create the device */
1478 RtlInitUnicodeString(&DevName, USBMON_DEVICE_NAME_NT);
1479 NTSTATUS Status = IoAcquireRemoveLock(&g_VBoxUsbMonGlobals.RmLock, &g_VBoxUsbMonGlobals);
1480 if (NT_SUCCESS(Status))
1481 {
1482 Status = IoCreateDevice(pDrvObj, sizeof (VBOXUSBMONINS), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDevObj);
1483 if (NT_SUCCESS(Status))
1484 {
1485 UNICODE_STRING DosName;
1486 RtlInitUnicodeString(&DosName, USBMON_DEVICE_NAME_DOS);
1487 Status = IoCreateSymbolicLink(&DosName, &DevName);
1488 if (NT_SUCCESS(Status))
1489 {
1490 PVBOXUSBMONINS pDevExt = (PVBOXUSBMONINS)pDevObj->DeviceExtension;
1491 memset(pDevExt, 0, sizeof(*pDevExt));
1492
1493 pDrvObj->DriverUnload = VBoxUsbMonUnload;
1494 pDrvObj->MajorFunction[IRP_MJ_CREATE] = VBoxUsbMonCreate;
1495 pDrvObj->MajorFunction[IRP_MJ_CLOSE] = VBoxUsbMonClose;
1496 pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VBoxUsbMonDeviceControl;
1497 pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = VBoxUsbMonInternalDeviceControl;
1498
1499 g_VBoxUsbMonGlobals.pDevObj = pDevObj;
1500 LOG(("VBoxUSBMon::DriverEntry returning STATUS_SUCCESS"));
1501 return STATUS_SUCCESS;
1502 }
1503 IoDeleteDevice(pDevObj);
1504 }
1505 IoReleaseRemoveLockAndWait(&g_VBoxUsbMonGlobals.RmLock, &g_VBoxUsbMonGlobals);
1506 }
1507
1508 return Status;
1509}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette