VirtualBox

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

Last change on this file since 79392 was 79334, checked in by vboxsync, 6 years ago

VBoxUSBMon.sys: Removed unused code.

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

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