VirtualBox

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

Last change on this file since 61556 was 60639, checked in by vboxsync, 9 years ago

HostDrivers/win: coding style

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 66.7 KB
Line 
1/* $Id: VBoxUsbMon.cpp 60639 2016-04-22 07:37:54Z vboxsync $ */
2/** @file
3 * VBox USB Monitor
4 */
5/*
6 * Copyright (C) 2011-2015 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 */
16
17#include "VBoxUsbMon.h"
18#include "../cmn/VBoxUsbIdc.h"
19#include <vbox/err.h>
20#include <VBox/usblib.h>
21#include <excpt.h>
22#include <stdio.h>
23
24/*
25 * Note: Must match the VID & PID in the USB driver .inf file!!
26 */
27/*
28 BusQueryDeviceID USB\Vid_80EE&Pid_CAFE
29 BusQueryInstanceID 2
30 BusQueryHardwareIDs USB\Vid_80EE&Pid_CAFE&Rev_0100
31 BusQueryHardwareIDs USB\Vid_80EE&Pid_CAFE
32 BusQueryCompatibleIDs USB\Class_ff&SubClass_00&Prot_00
33 BusQueryCompatibleIDs USB\Class_ff&SubClass_00
34 BusQueryCompatibleIDs USB\Class_ff
35*/
36
37#define szBusQueryDeviceId L"USB\\Vid_80EE&Pid_CAFE"
38#define szBusQueryHardwareIDs L"USB\\Vid_80EE&Pid_CAFE&Rev_0100\0USB\\Vid_80EE&Pid_CAFE\0\0"
39#define szBusQueryCompatibleIDs L"USB\\Class_ff&SubClass_00&Prot_00\0USB\\Class_ff&SubClass_00\0USB\\Class_ff\0\0"
40
41#define szDeviceTextDescription L"VirtualBox USB"
42
43typedef struct VBOXUSBMONINS
44{
45 void * pvDummy;
46} VBOXUSBMONINS, *PVBOXUSBMONINS;
47
48typedef struct VBOXUSBMONCTX
49{
50 VBOXUSBFLTCTX FltCtx;
51} VBOXUSBMONCTX, *PVBOXUSBMONCTX;
52
53typedef struct VBOXUSBHUB_PNPHOOK
54{
55 VBOXUSBHOOK_ENTRY Hook;
56 bool fUninitFailed;
57} VBOXUSBHUB_PNPHOOK, *PVBOXUSBHUB_PNPHOOK;
58
59typedef struct VBOXUSBHUB_PNPHOOK_COMPLETION
60{
61 VBOXUSBHOOK_REQUEST Rq;
62} VBOXUSBHUB_PNPHOOK_COMPLETION, *PVBOXUSBHUB_PNPHOOK_COMPLETION;
63
64/*
65 * Comment out VBOX_USB3PORT definition to disable hooking to multiple drivers (#6509)
66 */
67#define VBOX_USB3PORT
68
69#ifdef VBOX_USB3PORT
70#define VBOXUSBMON_MAXDRIVERS 5
71typedef struct VBOXUSB_PNPDRIVER
72{
73 PDRIVER_OBJECT DriverObject;
74 VBOXUSBHUB_PNPHOOK UsbHubPnPHook;
75 PDRIVER_DISPATCH pfnHookStub;
76} VBOXUSB_PNPDRIVER, *PVBOXUSB_PNPDRIVER;
77#endif /* !VBOX_USB3PORT */
78
79typedef struct VBOXUSBMONGLOBALS
80{
81 PDEVICE_OBJECT pDevObj;
82#ifdef VBOX_USB3PORT
83 VBOXUSB_PNPDRIVER pDrivers[VBOXUSBMON_MAXDRIVERS];
84#else /* !VBOX_USB3PORT */
85 VBOXUSBHUB_PNPHOOK UsbHubPnPHook;
86#endif /* !VBOX_USB3PORT */
87 KEVENT OpenSynchEvent;
88 IO_REMOVE_LOCK RmLock;
89 uint32_t cOpens;
90 volatile LONG ulPreventUnloadOn;
91 PFILE_OBJECT pPreventUnloadFileObj;
92} VBOXUSBMONGLOBALS, *PVBOXUSBMONGLOBALS;
93
94static VBOXUSBMONGLOBALS g_VBoxUsbMonGlobals;
95
96#define VBOXUSBMON_MEMTAG 'MUBV'
97
98PVOID VBoxUsbMonMemAlloc(SIZE_T cbBytes)
99{
100 PVOID pvMem = ExAllocatePoolWithTag(NonPagedPool, cbBytes, VBOXUSBMON_MEMTAG);
101 Assert(pvMem);
102 return pvMem;
103}
104
105PVOID VBoxUsbMonMemAllocZ(SIZE_T cbBytes)
106{
107 PVOID pvMem = VBoxUsbMonMemAlloc(cbBytes);
108 if (pvMem)
109 {
110 RtlZeroMemory(pvMem, cbBytes);
111 }
112 return pvMem;
113}
114
115VOID VBoxUsbMonMemFree(PVOID pvMem)
116{
117 ExFreePoolWithTag(pvMem, VBOXUSBMON_MEMTAG);
118}
119
120#define VBOXUSBDBG_STRCASE(_t) \
121 case _t: return #_t
122#define VBOXUSBDBG_STRCASE_UNKNOWN(_v) \
123 default: LOG((__FUNCTION__": Unknown Value (0n%d), (0x%x)", _v, _v)); return "Unknown"
124
125static const char* vboxUsbDbgStrPnPMn(UCHAR uMn)
126{
127 switch (uMn)
128 {
129 VBOXUSBDBG_STRCASE(IRP_MN_START_DEVICE);
130 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_REMOVE_DEVICE);
131 VBOXUSBDBG_STRCASE(IRP_MN_REMOVE_DEVICE);
132 VBOXUSBDBG_STRCASE(IRP_MN_CANCEL_REMOVE_DEVICE);
133 VBOXUSBDBG_STRCASE(IRP_MN_STOP_DEVICE);
134 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_STOP_DEVICE);
135 VBOXUSBDBG_STRCASE(IRP_MN_CANCEL_STOP_DEVICE);
136 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_DEVICE_RELATIONS);
137 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_INTERFACE);
138 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_CAPABILITIES);
139 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_RESOURCES);
140 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_RESOURCE_REQUIREMENTS);
141 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_DEVICE_TEXT);
142 VBOXUSBDBG_STRCASE(IRP_MN_FILTER_RESOURCE_REQUIREMENTS);
143 VBOXUSBDBG_STRCASE(IRP_MN_READ_CONFIG);
144 VBOXUSBDBG_STRCASE(IRP_MN_WRITE_CONFIG);
145 VBOXUSBDBG_STRCASE(IRP_MN_EJECT);
146 VBOXUSBDBG_STRCASE(IRP_MN_SET_LOCK);
147 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_ID);
148 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_PNP_DEVICE_STATE);
149 VBOXUSBDBG_STRCASE(IRP_MN_QUERY_BUS_INFORMATION);
150 VBOXUSBDBG_STRCASE(IRP_MN_DEVICE_USAGE_NOTIFICATION);
151 VBOXUSBDBG_STRCASE(IRP_MN_SURPRISE_REMOVAL);
152 VBOXUSBDBG_STRCASE_UNKNOWN(uMn);
153 }
154}
155
156void vboxUsbDbgPrintUnicodeString(PUNICODE_STRING pUnicodeString)
157{
158 PWSTR pStr = pUnicodeString->Buffer;
159 for (int i = 0; i < pUnicodeString->Length/2; ++i)
160 {
161 LOG(("%c", *pStr++));
162 }
163}
164
165/**
166 * Send IRP_MN_QUERY_DEVICE_RELATIONS
167 *
168 * @returns NT Status
169 * @param pDevObj USB device pointer
170 * @param pFileObj Valid file object pointer
171 * @param pDevRelations Pointer to DEVICE_RELATIONS pointer (out)
172 */
173NTSTATUS VBoxUsbMonQueryBusRelations(PDEVICE_OBJECT pDevObj, PFILE_OBJECT pFileObj, PDEVICE_RELATIONS *pDevRelations)
174{
175 IO_STATUS_BLOCK IoStatus;
176 KEVENT Event;
177 NTSTATUS Status;
178 PIRP pIrp;
179 PIO_STACK_LOCATION pSl;
180
181 KeInitializeEvent(&Event, NotificationEvent, FALSE);
182
183 Assert(pDevRelations);
184 *pDevRelations = NULL;
185
186 pIrp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, pDevObj, NULL, 0, NULL, &Event, &IoStatus);
187 if (!pIrp)
188 {
189 WARN(("IoBuildDeviceIoControlRequest failed!!"));
190 return STATUS_INSUFFICIENT_RESOURCES;
191 }
192 pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
193
194 pSl = IoGetNextIrpStackLocation(pIrp);
195 pSl->MajorFunction = IRP_MJ_PNP;
196 pSl->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS;
197 pSl->Parameters.QueryDeviceRelations.Type = BusRelations;
198 pSl->FileObject = pFileObj;
199
200 Status = IoCallDriver(pDevObj, pIrp);
201 if (Status == STATUS_PENDING)
202 {
203 LOG(("IoCallDriver returned STATUS_PENDING!!"));
204 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
205 Status = IoStatus.Status;
206 }
207
208 if (Status == STATUS_SUCCESS)
209 {
210 PDEVICE_RELATIONS pRel = (PDEVICE_RELATIONS)IoStatus.Information;
211 LOG(("pRel = %p", pRel));
212 if (VALID_PTR(pRel))
213 {
214 *pDevRelations = pRel;
215 }
216 else
217 {
218 WARN(("Invalid pointer %p", pRel));
219 }
220 }
221 else
222 {
223 WARN(("IRP_MN_QUERY_DEVICE_RELATIONS failed Status(0x%x)", Status));
224 }
225
226 LOG(("IoCallDriver returned %x", Status));
227 return Status;
228}
229
230RT_C_DECLS_BEGIN
231/* these two come from IFS Kit, which is not included in 2K DDK we use,
232 * although they are documented and exported in ntoskrnl,
233 * and both should be present for >= XP according to MSDN */
234NTKERNELAPI
235NTSTATUS
236ObQueryNameString(
237 __in PVOID Object,
238 __out_bcount_opt(Length) POBJECT_NAME_INFORMATION ObjectNameInfo,
239 __in ULONG Length,
240 __out PULONG ReturnLength
241 );
242
243NTKERNELAPI
244PDEVICE_OBJECT
245IoGetLowerDeviceObject(
246 __in PDEVICE_OBJECT DeviceObject
247 );
248
249RT_C_DECLS_END
250
251typedef DECLCALLBACK(VOID) FNVBOXUSBDEVNAMEMATCHER(PDEVICE_OBJECT pDo, PUNICODE_STRING pName, PVOID pvMatcher);
252typedef FNVBOXUSBDEVNAMEMATCHER *PFNVBOXUSBDEVNAMEMATCHER;
253
254static NTSTATUS vboxUsbObjCheckName(PDEVICE_OBJECT pDo, PFNVBOXUSBDEVNAMEMATCHER pfnMatcher, PVOID pvMatcher)
255{
256 union
257 {
258 OBJECT_NAME_INFORMATION Info;
259 char buf[1024];
260 } buf;
261 ULONG cbLength = 0;
262
263 POBJECT_NAME_INFORMATION pInfo = &buf.Info;
264 NTSTATUS Status = ObQueryNameString(pDo, &buf.Info, sizeof (buf), &cbLength);
265 if (!NT_SUCCESS(Status))
266 {
267 if (STATUS_INFO_LENGTH_MISMATCH != Status)
268 {
269 WARN(("ObQueryNameString failed 0x%x", Status));
270 return Status;
271 }
272
273 LOG(("ObQueryNameString returned STATUS_INFO_LENGTH_MISMATCH, required size %d", cbLength));
274
275 pInfo = (POBJECT_NAME_INFORMATION)VBoxUsbMonMemAlloc(cbLength);
276 if (!pInfo)
277 {
278 WARN(("VBoxUsbMonMemAlloc failed"));
279 return STATUS_NO_MEMORY;
280 }
281 Status = ObQueryNameString(pDo, pInfo, cbLength, &cbLength);
282 if (!NT_SUCCESS(Status))
283 {
284 WARN(("ObQueryNameString second try failed 0x%x", Status));
285 VBoxUsbMonMemFree(pInfo);
286 return Status;
287 }
288 }
289
290 /* we've got the name! */
291 LOG(("got the name:"));
292 LOG_USTR(&pInfo->Name);
293 pfnMatcher(pDo, &pInfo->Name, pvMatcher);
294
295 if (&buf.Info != pInfo)
296 {
297 LOG(("freeing allocated pInfo(0x%p)", pInfo));
298 VBoxUsbMonMemFree(pInfo);
299 }
300 else
301 {
302 LOG(("no freeing info needed"));
303 }
304
305 return STATUS_SUCCESS;
306}
307
308
309typedef DECLCALLBACK(BOOLEAN) FNVBOXUSBDEVSTACKWALKER(PDEVICE_OBJECT pTopDo, PDEVICE_OBJECT pCurDo, PVOID pvContext);
310typedef FNVBOXUSBDEVSTACKWALKER *PFNVBOXUSBDEVSTACKWALKER;
311
312VOID vboxUsbObjDevStackWalk(PDEVICE_OBJECT pDo, PFNVBOXUSBDEVSTACKWALKER pfnWalker, PVOID pvWalker)
313{
314 LOG(("==>tree walk for Do 0x%p", pDo));
315 PDEVICE_OBJECT pCurDo = pDo;
316 ObReferenceObject(pCurDo); /* <- to make sure the dereferencing logic below works correctly */
317 do
318 {
319 LOG(("==Do 0x%p", pCurDo));
320#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
321 {
322 union
323 {
324 OBJECT_NAME_INFORMATION Info;
325 char buf[1024];
326 } buf;
327 ULONG cbLength = 0;
328
329 NTSTATUS tmpStatus = ObQueryNameString(pCurDo, &buf.Info, sizeof (buf), &cbLength);
330 if (NT_SUCCESS(tmpStatus))
331 {
332 LOG((" Obj name:"));
333 LOG_USTR(&buf.Info.Name);
334 }
335 else
336 {
337 if (STATUS_INFO_LENGTH_MISMATCH != tmpStatus)
338 {
339 WARN(("ObQueryNameString failed 0x%x", tmpStatus));
340 }
341 else
342 {
343 WARN(("ObQueryNameString STATUS_INFO_LENGTH_MISMATCH, required %d", cbLength));
344 }
345 }
346
347 if (pCurDo->DriverObject
348 && pCurDo->DriverObject->DriverName.Buffer
349 && pCurDo->DriverObject->DriverName.Length)
350 {
351 LOG((" Drv Obj(0x%p), name:", pCurDo->DriverObject));
352 LOG_USTR(&pCurDo->DriverObject->DriverName);
353 }
354 else
355 {
356 LOG((" No Drv Name, Drv Obj(0x%p)", pCurDo->DriverObject));
357 if (pCurDo->DriverObject)
358 {
359 LOG((" driver name is zero, Length(%d), Buffer(0x%p)",
360 pCurDo->DriverObject->DriverName.Length, pCurDo->DriverObject->DriverName.Buffer));
361 }
362 else
363 {
364 LOG((" driver object is NULL"));
365 }
366 }
367 }
368#endif
369 if (!pfnWalker(pDo, pCurDo, pvWalker))
370 {
371 LOG(("the walker said to stop"));
372 ObDereferenceObject(pCurDo);
373 break;
374 }
375
376 PDEVICE_OBJECT pLowerDo = IoGetLowerDeviceObject(pCurDo);
377 ObDereferenceObject(pCurDo);
378 if (!pLowerDo)
379 {
380 LOG(("IoGetLowerDeviceObject returnned NULL, stop"));
381 break;
382 }
383 pCurDo = pLowerDo;
384 } while (1);
385
386 LOG(("<==tree walk"));
387}
388
389static DECLCALLBACK(BOOLEAN) vboxUsbObjNamePrefixMatch(PUNICODE_STRING pName, PUNICODE_STRING pNamePrefix, BOOLEAN fCaseInSensitive)
390{
391 LOG(("Matching prefix:"));
392 LOG_USTR(pNamePrefix);
393 if (pNamePrefix->Length > pName->Length)
394 {
395 LOG(("Pregix Length(%d) > Name Length(%d)", pNamePrefix->Length, pName->Length));
396 return FALSE;
397 }
398
399 LOG(("Pregix Length(%d) <= Name Length(%d)", pNamePrefix->Length, pName->Length));
400
401 UNICODE_STRING NamePrefix = *pName;
402 NamePrefix.Length = pNamePrefix->Length;
403 LONG rc = RtlCompareUnicodeString(&NamePrefix, pNamePrefix, fCaseInSensitive);
404
405 if (!rc)
406 {
407 LOG(("prefix MATCHED!"));
408 return TRUE;
409 }
410
411 LOG(("prefix NOT matched!"));
412 return FALSE;
413}
414
415typedef struct VBOXUSBOBJNAMEPREFIXMATCHER
416{
417 PUNICODE_STRING pNamePrefix;
418 BOOLEAN fMatched;
419} VBOXUSBOBJNAMEPREFIXMATCHER, *PVBOXUSBOBJNAMEPREFIXMATCHER;
420
421static DECLCALLBACK(VOID) vboxUsbObjDevNamePrefixMatcher(PDEVICE_OBJECT pDo, PUNICODE_STRING pName, PVOID pvMatcher)
422{
423 PVBOXUSBOBJNAMEPREFIXMATCHER pData = (PVBOXUSBOBJNAMEPREFIXMATCHER)pvMatcher;
424 PUNICODE_STRING pNamePrefix = pData->pNamePrefix;
425 ASSERT_WARN(!pData->fMatched, ("match flag already set!"));
426 pData->fMatched = vboxUsbObjNamePrefixMatch(pName, pNamePrefix, TRUE /* fCaseInSensitive */);
427 LOG(("match result (%d)", (int)pData->fMatched));
428}
429
430typedef struct VBOXUSBOBJDRVOBJSEARCHER
431{
432 PDEVICE_OBJECT pDevObj;
433 PUNICODE_STRING pDrvName;
434 PUNICODE_STRING pPdoNamePrefix;
435 ULONG fFlags;
436} VBOXUSBOBJDRVOBJSEARCHER, *PVBOXUSBOBJDRVOBJSEARCHER;
437
438static DECLCALLBACK(BOOLEAN) vboxUsbObjDevObjSearcherWalker(PDEVICE_OBJECT pTopDo, PDEVICE_OBJECT pCurDo, PVOID pvContext)
439{
440 PVBOXUSBOBJDRVOBJSEARCHER pData = (PVBOXUSBOBJDRVOBJSEARCHER)pvContext;
441 ASSERT_WARN(!pData->pDevObj, ("non-null dev object (0x%p) on enter", pData->pDevObj));
442 pData->pDevObj = NULL;
443 if (pCurDo->DriverObject
444 && pCurDo->DriverObject->DriverName.Buffer
445 && pCurDo->DriverObject->DriverName.Length
446 && !RtlCompareUnicodeString(pData->pDrvName, &pCurDo->DriverObject->DriverName, TRUE /* case insensitive */))
447 {
448 LOG(("MATCHED driver:"));
449 LOG_USTR(&pCurDo->DriverObject->DriverName);
450 if ((pData->fFlags & VBOXUSBMONHUBWALK_F_ALL) != VBOXUSBMONHUBWALK_F_ALL)
451 {
452 VBOXUSBOBJNAMEPREFIXMATCHER Data = {0};
453 Data.pNamePrefix = pData->pPdoNamePrefix;
454 NTSTATUS Status = vboxUsbObjCheckName(pCurDo, vboxUsbObjDevNamePrefixMatcher, &Data);
455 if (!NT_SUCCESS(Status))
456 {
457 WARN(("vboxUsbObjCheckName failed Status (0x%x)", Status));
458 return TRUE;
459 }
460
461
462 LOG(("prefix match result (%d)", Data.fMatched));
463 if ((pData->fFlags & VBOXUSBMONHUBWALK_F_FDO) == VBOXUSBMONHUBWALK_F_FDO)
464 {
465 LOG(("VBOXUSBMONHUBWALK_F_FDO"));
466 if (Data.fMatched)
467 {
468 LOG(("this is a PDO object, skip it and stop search"));
469 /* stop search as we will not find FDO here */
470 return FALSE;
471 }
472
473 LOG(("this is a FDO object, MATCHED!!"));
474 }
475 else if ((pData->fFlags & VBOXUSBMONHUBWALK_F_PDO) == VBOXUSBMONHUBWALK_F_PDO)
476 {
477 LOG(("VBOXUSBMONHUBWALK_F_PDO"));
478 if (!Data.fMatched)
479 {
480 LOG(("this is a FDO object, skip it and continue search"));
481 /* continue seach since since this could be a nested hub that would have a usbhub-originated PDO */
482 return TRUE;
483 }
484
485 LOG(("this is a PDO object, MATCHED!!"));
486 }
487
488 }
489 else
490 {
491 LOG(("VBOXUSBMONHUBWALK_F_ALL"));
492 LOG(("either PDO or FDO, MATCHED!!"));
493 }
494
495 /* ensure the dev object is not destroyed */
496 ObReferenceObject(pCurDo);
497 pData->pDevObj = pCurDo;
498 /* we are done */
499 return FALSE;
500 }
501 else
502 {
503 LOG(("driver object (0x%p) no match", pCurDo->DriverObject));
504 if (pCurDo->DriverObject)
505 {
506 if ( pCurDo->DriverObject->DriverName.Buffer
507 && pCurDo->DriverObject->DriverName.Length)
508 {
509 LOG(("driver name not match, was:"));
510 LOG_USTR(&pCurDo->DriverObject->DriverName);
511 LOG(("but expected:"));
512 LOG_USTR(pData->pDrvName);
513 }
514 else
515 {
516 LOG(("driver name is zero, Length(%d), Buffer(0x%p)",
517 pCurDo->DriverObject->DriverName.Length, pCurDo->DriverObject->DriverName.Buffer));
518 }
519 }
520 else
521 {
522 LOG(("driver object is NULL"));
523 }
524 }
525 return TRUE;
526}
527
528VOID vboxUsbMonHubDevWalk(PFNVBOXUSBMONDEVWALKER pfnWalker, PVOID pvWalker, ULONG fFlags)
529{
530 NTSTATUS Status = STATUS_UNSUCCESSFUL;
531#ifndef VBOX_USB3PORT
532 UNICODE_STRING szStandardHubName;
533 PDRIVER_OBJECT pDrvObj = NULL;
534 szStandardHubName.Length = 0;
535 szStandardHubName.MaximumLength = 0;
536 szStandardHubName.Buffer = 0;
537 RtlInitUnicodeString(&szStandardHubName, L"\\Driver\\usbhub");
538 UNICODE_STRING szStandardHubPdoNamePrefix;
539 szStandardHubPdoNamePrefix.Length = 0;
540 szStandardHubPdoNamePrefix.MaximumLength = 0;
541 szStandardHubPdoNamePrefix.Buffer = 0;
542 RtlInitUnicodeString(&szStandardHubPdoNamePrefix, L"\\Device\\USBPDO-");
543
544 for (int i = 0; i < 16; i++)
545 {
546 WCHAR szwHubName[32] = {0};
547 char szHubName[32] = {0};
548 ANSI_STRING AnsiName;
549 UNICODE_STRING UnicodeName;
550 PDEVICE_OBJECT pHubDevObj;
551 PFILE_OBJECT pHubFileObj;
552
553 sprintf(szHubName, "\\Device\\USBPDO-%d", i);
554
555 RtlInitAnsiString(&AnsiName, szHubName);
556
557 UnicodeName.Length = 0;
558 UnicodeName.MaximumLength = sizeof (szwHubName);
559 UnicodeName.Buffer = szwHubName;
560
561 RtlInitAnsiString(&AnsiName, szHubName);
562 Status = RtlAnsiStringToUnicodeString(&UnicodeName, &AnsiName, FALSE);
563 if (Status == STATUS_SUCCESS)
564 {
565 Status = IoGetDeviceObjectPointer(&UnicodeName, FILE_READ_DATA, &pHubFileObj, &pHubDevObj);
566 if (Status == STATUS_SUCCESS)
567 {
568 LOG(("IoGetDeviceObjectPointer for \\Device\\USBPDO-%d returned %p %p", i, pHubDevObj, pHubFileObj));
569
570 VBOXUSBOBJDRVOBJSEARCHER Data = {0};
571 Data.pDrvName = &szStandardHubName;
572 Data.pPdoNamePrefix = &szStandardHubPdoNamePrefix;
573 Data.fFlags = fFlags;
574
575 vboxUsbObjDevStackWalk(pHubDevObj, vboxUsbObjDevObjSearcherWalker, &Data);
576 if (Data.pDevObj)
577 {
578 LOG(("found hub dev obj (0x%p)", Data.pDevObj));
579 if (!pfnWalker(pHubFileObj, pHubDevObj, Data.pDevObj, pvWalker))
580 {
581 LOG(("the walker said to stop"));
582 ObDereferenceObject(Data.pDevObj);
583 ObDereferenceObject(pHubFileObj);
584 break;
585 }
586
587 LOG(("going forward.."));
588 ObDereferenceObject(Data.pDevObj);
589 }
590 else
591 {
592 LOG(("no hub driver obj found"));
593 ASSERT_WARN(!Data.pDevObj, ("non-null dev obj poiter returned (0x%p)", Data.pDevObj));
594 }
595
596 /* this will dereference both file and dev obj */
597 ObDereferenceObject(pHubFileObj);
598 }
599 else
600 {
601 LOG(("IoGetDeviceObjectPointer returned Status (0x%x) for (\\Device\\USBPDO-%d)", Status, i));
602 }
603 }
604 else
605 {
606 WARN(("RtlAnsiStringToUnicodeString failed, Status (0x%x) for Ansu name (\\Device\\USBPDO-%d)", Status, i));
607 }
608 }
609#else /* VBOX_USB3PORT */
610 PWSTR szwHubList;
611 Status = IoGetDeviceInterfaces(&GUID_DEVINTERFACE_USB_HUB, NULL, 0, &szwHubList);
612 if (Status != STATUS_SUCCESS)
613 {
614 LOG(("IoGetDeviceInterfaces failed with %d\n", Status));
615 return;
616 }
617 if (szwHubList)
618 {
619 UNICODE_STRING UnicodeName;
620 PDEVICE_OBJECT pHubDevObj;
621 PFILE_OBJECT pHubFileObj;
622 PWSTR szwHubName = szwHubList;
623 while (*szwHubName != UNICODE_NULL)
624 {
625 RtlInitUnicodeString(&UnicodeName, szwHubName);
626 Status = IoGetDeviceObjectPointer(&UnicodeName, FILE_READ_DATA, &pHubFileObj, &pHubDevObj);
627 if (Status == STATUS_SUCCESS)
628 {
629 /* We could not log hub name here.
630 * It is the paged memory and we cannot use it in logger cause it increases the IRQL
631 */
632 LOG(("IoGetDeviceObjectPointer returned %p %p", pHubDevObj, pHubFileObj));
633 if (!pfnWalker(pHubFileObj, pHubDevObj, pHubDevObj, pvWalker))
634 {
635 LOG(("the walker said to stop"));
636 ObDereferenceObject(pHubFileObj);
637 break;
638 }
639
640 LOG(("going forward.."));
641 ObDereferenceObject(pHubFileObj);
642 }
643 szwHubName += wcslen(szwHubName) + 1;
644 }
645 ExFreePool(szwHubList);
646 }
647#endif /* VBOX_USB3PORT */
648}
649
650typedef struct VBOXUSBMONFINDHUBWALKER
651{
652 PDRIVER_OBJECT pDrvObj;
653} VBOXUSBMONFINDHUBWALKER, *PVBOXUSBMONFINDHUBWALKER;
654
655static DECLCALLBACK(BOOLEAN) vboxUsbMonFindHubDrvObjWalker(PFILE_OBJECT pFile, PDEVICE_OBJECT pTopDo, PDEVICE_OBJECT pHubDo, PVOID pvContext)
656{
657 PVBOXUSBMONFINDHUBWALKER pData = (PVBOXUSBMONFINDHUBWALKER)pvContext;
658 PDRIVER_OBJECT pDrvObj = pHubDo->DriverObject;
659
660 ASSERT_WARN(!pData->pDrvObj, ("pDrvObj expected null on enter, but was(0x%p)", pData->pDrvObj));
661 if (pDrvObj)
662 {
663 LOG(("found driver object 0x%p", pDrvObj));
664 ObReferenceObject(pDrvObj);
665 pData->pDrvObj = pDrvObj;
666 return FALSE;
667 }
668
669 WARN(("null pDrvObj!"));
670 return TRUE;
671}
672
673static PDRIVER_OBJECT vboxUsbMonHookFindHubDrvObj()
674{
675 NTSTATUS Status = STATUS_UNSUCCESSFUL;
676 UNICODE_STRING szStandardHubName;
677 PDRIVER_OBJECT pDrvObj = NULL;
678 szStandardHubName.Length = 0;
679 szStandardHubName.MaximumLength = 0;
680 szStandardHubName.Buffer = 0;
681 RtlInitUnicodeString(&szStandardHubName, L"\\Driver\\usbhub");
682
683 LOG(("Search USB hub"));
684 VBOXUSBMONFINDHUBWALKER Data = {0};
685 vboxUsbMonHubDevWalk(vboxUsbMonFindHubDrvObjWalker, &Data, VBOXUSBMONHUBWALK_F_ALL);
686 if (Data.pDrvObj)
687 {
688 LOG(("returning driver object 0x%p", Data.pDrvObj));
689 }
690 else
691 {
692 WARN(("no hub driver object found!"));
693 }
694 return Data.pDrvObj;
695}
696
697/* NOTE: the stack location data is not the "actual" IRP stack location,
698 * but a copy being preserved on the IRP way down.
699 * See the note in VBoxUsbPnPCompletion for detail */
700static NTSTATUS vboxUsbMonHandlePnPIoctl(PDEVICE_OBJECT pDevObj, PIO_STACK_LOCATION pSl, PIO_STATUS_BLOCK pIoStatus)
701{
702 LOG(("IRQL = %d", KeGetCurrentIrql()));
703 switch(pSl->MinorFunction)
704 {
705 case IRP_MN_QUERY_DEVICE_TEXT:
706 {
707 LOG(("IRP_MN_QUERY_DEVICE_TEXT: pIoStatus->Status = %x", pIoStatus->Status));
708 if (pIoStatus->Status == STATUS_SUCCESS)
709 {
710 WCHAR *pId = (WCHAR *)pIoStatus->Information;
711 if (VALID_PTR(pId))
712 {
713 KIRQL Iqrl = KeGetCurrentIrql();
714 /* IRQL should be always passive here */
715 ASSERT_WARN(Iqrl == PASSIVE_LEVEL, ("irql is not PASSIVE"));
716 switch(pSl->Parameters.QueryDeviceText.DeviceTextType)
717 {
718 case DeviceTextLocationInformation:
719 LOG(("DeviceTextLocationInformation"));
720 LOG_STRW(pId);
721 break;
722
723 case DeviceTextDescription:
724 LOG(("DeviceTextDescription"));
725 LOG_STRW(pId);
726 if (VBoxUsbFltPdoIsFiltered(pDevObj))
727 {
728 LOG(("PDO (0x%p) is filtered", pDevObj));
729 WCHAR *pId = (WCHAR *)ExAllocatePool(PagedPool, sizeof(szDeviceTextDescription));
730 if (!pId)
731 {
732 AssertFailed();
733 break;
734 }
735 memcpy(pId, szDeviceTextDescription, sizeof(szDeviceTextDescription));
736 LOG(("NEW szDeviceTextDescription"));
737 LOG_STRW(pId);
738 ExFreePool((PVOID)pIoStatus->Information);
739 pIoStatus->Information = (ULONG_PTR)pId;
740 }
741 else
742 {
743 LOG(("PDO (0x%p) is NOT filtered", pDevObj));
744 }
745 break;
746 default:
747 LOG(("DeviceText %d", pSl->Parameters.QueryDeviceText.DeviceTextType));
748 break;
749 }
750 }
751 else
752 LOG(("Invalid pointer %p", pId));
753 }
754 break;
755 }
756
757 case IRP_MN_QUERY_ID:
758 {
759 LOG(("IRP_MN_QUERY_ID: Irp->pIoStatus->Status = %x", pIoStatus->Status));
760 if (pIoStatus->Status == STATUS_SUCCESS && pDevObj)
761 {
762 WCHAR *pId = (WCHAR *)pIoStatus->Information;
763#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
764 WCHAR *pTmp;
765#endif
766 if (VALID_PTR(pId))
767 {
768 KIRQL Iqrl = KeGetCurrentIrql();
769 /* IRQL should be always passive here */
770 ASSERT_WARN(Iqrl == PASSIVE_LEVEL, ("irql is not PASSIVE"));
771
772 switch (pSl->Parameters.QueryDeviceRelations.Type)
773 {
774 case BusQueryInstanceID:
775 LOG(("BusQueryInstanceID"));
776 LOG_STRW(pId);
777 break;
778
779 case BusQueryDeviceID:
780 {
781 LOG(("BusQueryDeviceID"));
782 pId = (WCHAR *)ExAllocatePool(PagedPool, sizeof(szBusQueryDeviceId));
783 if (!pId)
784 {
785 WARN(("ExAllocatePool failed"));
786 break;
787 }
788
789 BOOLEAN bFiltered = FALSE;
790 NTSTATUS Status = VBoxUsbFltPdoAdd(pDevObj, &bFiltered);
791 if (Status != STATUS_SUCCESS || !bFiltered)
792 {
793 if (Status == STATUS_SUCCESS)
794 {
795 LOG(("PDO (0x%p) is NOT filtered", pDevObj));
796 }
797 else
798 {
799 WARN(("VBoxUsbFltPdoAdd for PDO (0x%p) failed Status 0x%x", pDevObj, Status));
800 }
801 ExFreePool(pId);
802 break;
803 }
804
805 LOG(("PDO (0x%p) is filtered", pDevObj));
806 ExFreePool((PVOID)pIoStatus->Information);
807 memcpy(pId, szBusQueryDeviceId, sizeof(szBusQueryDeviceId));
808 pIoStatus->Information = (ULONG_PTR)pId;
809 break;
810 }
811 case BusQueryHardwareIDs:
812 {
813 LOG(("BusQueryHardwareIDs"));
814#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
815 while (*pId) //MULTI_SZ
816 {
817 LOG_STRW(pId);
818 while (*pId) pId++;
819 pId++;
820 }
821#endif
822 pId = (WCHAR *)ExAllocatePool(PagedPool, sizeof(szBusQueryHardwareIDs));
823 if (!pId)
824 {
825 WARN(("ExAllocatePool failed"));
826 break;
827 }
828
829 BOOLEAN bFiltered = FALSE;
830 NTSTATUS Status = VBoxUsbFltPdoAdd(pDevObj, &bFiltered);
831 if (Status != STATUS_SUCCESS || !bFiltered)
832 {
833 if (Status == STATUS_SUCCESS)
834 {
835 LOG(("PDO (0x%p) is NOT filtered", pDevObj));
836 }
837 else
838 {
839 WARN(("VBoxUsbFltPdoAdd for PDO (0x%p) failed Status 0x%x", pDevObj, Status));
840 }
841 ExFreePool(pId);
842 break;
843 }
844
845 LOG(("PDO (0x%p) is filtered", pDevObj));
846
847 memcpy(pId, szBusQueryHardwareIDs, sizeof(szBusQueryHardwareIDs));
848#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
849 LOG(("NEW BusQueryHardwareIDs"));
850 pTmp = pId;
851 while (*pTmp) //MULTI_SZ
852 {
853
854 LOG_STRW(pTmp);
855 while (*pTmp) pTmp++;
856 pTmp++;
857 }
858#endif
859 ExFreePool((PVOID)pIoStatus->Information);
860 pIoStatus->Information = (ULONG_PTR)pId;
861 break;
862 }
863 case BusQueryCompatibleIDs:
864 LOG(("BusQueryCompatibleIDs"));
865#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
866 while (*pId) //MULTI_SZ
867 {
868 LOG_STRW(pId);
869 while (*pId) pId++;
870 pId++;
871 }
872#endif
873 if (VBoxUsbFltPdoIsFiltered(pDevObj))
874 {
875 LOG(("PDO (0x%p) is filtered", pDevObj));
876 pId = (WCHAR *)ExAllocatePool(PagedPool, sizeof(szBusQueryCompatibleIDs));
877 if (!pId)
878 {
879 WARN(("ExAllocatePool failed"));
880 break;
881 }
882 memcpy(pId, szBusQueryCompatibleIDs, sizeof(szBusQueryCompatibleIDs));
883#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
884 LOG(("NEW BusQueryCompatibleIDs"));
885 pTmp = pId;
886 while (*pTmp) //MULTI_SZ
887 {
888 LOG_STRW(pTmp);
889 while (*pTmp) pTmp++;
890 pTmp++;
891 }
892#endif
893 ExFreePool((PVOID)pIoStatus->Information);
894 pIoStatus->Information = (ULONG_PTR)pId;
895 }
896 else
897 {
898 LOG(("PDO (0x%p) is NOT filtered", pDevObj));
899 }
900 break;
901 }
902 }
903 else
904 {
905 LOG(("Invalid pointer %p", pId));
906 }
907 }
908 break;
909 }
910
911#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
912 case IRP_MN_QUERY_DEVICE_RELATIONS:
913 {
914 switch(pSl->Parameters.QueryDeviceRelations.Type)
915 {
916 case BusRelations:
917 {
918 LOG(("BusRelations"));
919
920 if (pIoStatus->Status == STATUS_SUCCESS)
921 {
922 PDEVICE_RELATIONS pRel = (PDEVICE_RELATIONS)pIoStatus->Information;
923 LOG(("pRel = %p", pRel));
924 if (VALID_PTR(pRel))
925 {
926 for (unsigned i=0;i<pRel->Count;i++)
927 {
928 if (VBoxUsbFltPdoIsFiltered(pDevObj))
929 LOG(("New PDO %p", pRel->Objects[i]));
930 }
931 }
932 else
933 LOG(("Invalid pointer %p", pRel));
934 }
935 break;
936 }
937 case TargetDeviceRelation:
938 LOG(("TargetDeviceRelation"));
939 break;
940 case RemovalRelations:
941 LOG(("RemovalRelations"));
942 break;
943 case EjectionRelations:
944 LOG(("EjectionRelations"));
945 break;
946 }
947 break;
948 }
949
950 case IRP_MN_QUERY_CAPABILITIES:
951 {
952 LOG(("IRP_MN_QUERY_CAPABILITIES: pIoStatus->Status = %x", pIoStatus->Status));
953 if (pIoStatus->Status == STATUS_SUCCESS)
954 {
955 PDEVICE_CAPABILITIES pCaps = pSl->Parameters.DeviceCapabilities.Capabilities;
956 if (VALID_PTR(pCaps))
957 {
958 LOG(("Caps.SilentInstall = %d", pCaps->SilentInstall));
959 LOG(("Caps.UniqueID = %d", pCaps->UniqueID ));
960 LOG(("Caps.Address = %d", pCaps->Address ));
961 LOG(("Caps.UINumber = %d", pCaps->UINumber ));
962 }
963 else
964 LOG(("Invalid pointer %p", pCaps));
965 }
966 break;
967 }
968
969 default:
970 break;
971#endif
972 } /*switch */
973
974 LOG(("Done returns %x (IRQL = %d)", pIoStatus->Status, KeGetCurrentIrql()));
975 return pIoStatus->Status;
976}
977
978NTSTATUS _stdcall VBoxUsbPnPCompletion(DEVICE_OBJECT *pDevObj, IRP *pIrp, void *pvContext)
979{
980 LOG(("Completion PDO(0x%p), IRP(0x%p), Status(0x%x)", pDevObj, pIrp, pIrp->IoStatus.Status));
981 ASSERT_WARN(pvContext, ("zero context"));
982
983 PVBOXUSBHOOK_REQUEST pRequest = (PVBOXUSBHOOK_REQUEST)pvContext;
984 /* NOTE: despite a regular IRP processing the stack location in our completion
985 * differs from those of the PnP hook since the hook is invoked in the "context" of the calle,
986 * while the completion is in the "coller" context in terms of IRP,
987 * so the completion stack location is one level "up" here.
988 *
989 * Moreover we CAN NOT access irp stack location in the completion because we might not have one at all
990 * in case the hooked driver is at the top of the irp call stack
991 *
992 * This is why we use the stack location we saved on IRP way down.
993 * */
994 PIO_STACK_LOCATION pSl = &pRequest->OldLocation;
995 ASSERT_WARN(pIrp == pRequest->pIrp, ("completed IRP(0x%x) not match request IRP(0x%x)", pIrp, pRequest->pIrp));
996 /* NOTE: we can not rely on pDevObj passed in IoCompletion since it may be zero
997 * in case IRP was created with extra stack locations and the caller did not initialize
998 * the IO_STACK_LOCATION::DeviceObject */
999 DEVICE_OBJECT *pRealDevObj = pRequest->pDevObj;
1000// Assert(!pDevObj || pDevObj == pRealDevObj);
1001// Assert(pSl->DeviceObject == pDevObj);
1002
1003 switch(pSl->MinorFunction)
1004 {
1005 case IRP_MN_QUERY_DEVICE_TEXT:
1006 case IRP_MN_QUERY_ID:
1007#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
1008 case IRP_MN_QUERY_DEVICE_RELATIONS:
1009 case IRP_MN_QUERY_CAPABILITIES:
1010#endif
1011 if (NT_SUCCESS(pIrp->IoStatus.Status))
1012 {
1013 vboxUsbMonHandlePnPIoctl(pRealDevObj, pSl, &pIrp->IoStatus);
1014 }
1015 else
1016 {
1017 ASSERT_WARN(pIrp->IoStatus.Status == STATUS_NOT_SUPPORTED, ("Irp failed with status(0x%x)", pIrp->IoStatus.Status));
1018 }
1019 break;
1020
1021 case IRP_MN_SURPRISE_REMOVAL:
1022 case IRP_MN_REMOVE_DEVICE:
1023 if (NT_SUCCESS(pIrp->IoStatus.Status))
1024 {
1025 VBoxUsbFltPdoRemove(pRealDevObj);
1026 }
1027 else
1028 {
1029 AssertFailed();
1030 }
1031 break;
1032
1033 /* These two IRPs are received when the PnP subsystem has determined the id of the newly arrived device */
1034 /* IRP_MN_START_DEVICE only arrives if it's a USB device of a known class or with a present host driver */
1035 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
1036 case IRP_MN_QUERY_RESOURCES:
1037 if (NT_SUCCESS(pIrp->IoStatus.Status) || pIrp->IoStatus.Status == STATUS_NOT_SUPPORTED)
1038 {
1039 VBoxUsbFltPdoAddCompleted(pRealDevObj);
1040 }
1041 else
1042 {
1043 AssertFailed();
1044 }
1045 break;
1046
1047 default:
1048 break;
1049 }
1050
1051 LOG(("<==PnP: Mn(%s), PDO(0x%p), IRP(0x%p), Status(0x%x), Sl PDO(0x%p), Compl PDO(0x%p)",
1052 vboxUsbDbgStrPnPMn(pSl->MinorFunction),
1053 pRealDevObj, pIrp, pIrp->IoStatus.Status,
1054 pSl->DeviceObject, pDevObj));
1055#ifdef DEBUG_misha
1056 NTSTATUS tmpStatus = pIrp->IoStatus.Status;
1057#endif
1058#ifdef VBOX_USB3PORT
1059 PVBOXUSBHOOK_ENTRY pHook = pRequest->pHook;
1060#else /* !VBOX_USB3PORT */
1061 PVBOXUSBHOOK_ENTRY pHook = &g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook;
1062#endif /* !VBOX_USB3PORT */
1063 NTSTATUS Status = VBoxUsbHookRequestComplete(pHook, pDevObj, pIrp, pRequest);
1064 VBoxUsbMonMemFree(pRequest);
1065#ifdef DEBUG_misha
1066 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
1067 {
1068 Assert(pIrp->IoStatus.Status == tmpStatus);
1069 }
1070#endif
1071 VBoxUsbHookRelease(pHook);
1072 return Status;
1073}
1074
1075/**
1076 * Device PnP hook
1077 *
1078 * @param pDevObj Device object.
1079 * @param pIrp Request packet.
1080 */
1081#ifdef VBOX_USB3PORT
1082static NTSTATUS vboxUsbMonPnPHook(IN PVBOXUSBHOOK_ENTRY pHook, IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
1083#else /* !VBOX_USB3PORT */
1084NTSTATUS _stdcall VBoxUsbMonPnPHook(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
1085#endif /* !VBOX_USB3PORT */
1086{
1087#ifndef VBOX_USB3PORT
1088 PVBOXUSBHOOK_ENTRY pHook = &g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook;
1089#endif /* !VBOX_USB3PORT */
1090 LOG(("==>PnP: Mn(%s), PDO(0x%p), IRP(0x%p), Status(0x%x)", vboxUsbDbgStrPnPMn(IoGetCurrentIrpStackLocation(pIrp)->MinorFunction), pDevObj, pIrp, pIrp->IoStatus.Status));
1091
1092 if (!VBoxUsbHookRetain(pHook))
1093 {
1094 WARN(("VBoxUsbHookRetain failed"));
1095 return VBoxUsbHookRequestPassDownHookSkip(pHook, pDevObj, pIrp);
1096 }
1097
1098 PVBOXUSBHUB_PNPHOOK_COMPLETION pCompletion = (PVBOXUSBHUB_PNPHOOK_COMPLETION)VBoxUsbMonMemAlloc(sizeof (*pCompletion));
1099 if (!pCompletion)
1100 {
1101 WARN(("VBoxUsbMonMemAlloc failed"));
1102 VBoxUsbHookRelease(pHook);
1103 pIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1104 pIrp->IoStatus.Information = 0;
1105 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1106 return STATUS_INSUFFICIENT_RESOURCES;
1107 }
1108
1109 NTSTATUS Status = VBoxUsbHookRequestPassDownHookCompletion(pHook, pDevObj, pIrp, VBoxUsbPnPCompletion, &pCompletion->Rq);
1110#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
1111 if (Status != STATUS_PENDING)
1112 {
1113 LOG(("Request completed, Status(0x%x)", Status));
1114 VBoxUsbHookVerifyCompletion(pHook, &pCompletion->Rq, pIrp);
1115 }
1116 else
1117 {
1118 LOG(("Request pending"));
1119 }
1120#endif
1121 return Status;
1122}
1123
1124#ifdef VBOX_USB3PORT
1125/**
1126 * Device PnP hook stubs.
1127 *
1128 * @param pDevObj Device object.
1129 * @param pIrp Request packet.
1130 */
1131#define VBOX_PNPHOOKSTUB(n) NTSTATUS _stdcall VBoxUsbMonPnPHook##n(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) \
1132{ \
1133 return vboxUsbMonPnPHook(&g_VBoxUsbMonGlobals.pDrivers[n].UsbHubPnPHook.Hook, pDevObj, pIrp); \
1134}
1135
1136#define VBOX_PNPHOOKSTUB_INIT(n) g_VBoxUsbMonGlobals.pDrivers[n].pfnHookStub = VBoxUsbMonPnPHook##n
1137
1138VBOX_PNPHOOKSTUB(0)
1139VBOX_PNPHOOKSTUB(1)
1140VBOX_PNPHOOKSTUB(2)
1141VBOX_PNPHOOKSTUB(3)
1142VBOX_PNPHOOKSTUB(4)
1143AssertCompile(VBOXUSBMON_MAXDRIVERS == 5);
1144
1145typedef struct VBOXUSBMONHOOKDRIVERWALKER
1146{
1147 PDRIVER_OBJECT pDrvObj;
1148} VBOXUSBMONHOOKDRIVERWALKER, *PVBOXUSBMONHOOKDRIVERWALKER;
1149
1150/**
1151 * Logs an error to the system event log.
1152 *
1153 * @param ErrCode Error to report to event log.
1154 * @param ReturnedStatus Error that was reported by the driver to the caller.
1155 * @param uErrId Unique error id representing the location in the driver.
1156 * @param cbDumpData Number of bytes at pDumpData.
1157 * @param pDumpData Pointer to data that will be added to the message (see 'details' tab).
1158 */
1159static void vboxUsbMonLogError(NTSTATUS ErrCode, NTSTATUS ReturnedStatus, ULONG uErrId, USHORT cbDumpData, PVOID pDumpData)
1160{
1161 PIO_ERROR_LOG_PACKET pErrEntry;
1162
1163
1164 /* Truncate dumps that do not fit into IO_ERROR_LOG_PACKET. */
1165 if (FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData) + cbDumpData > ERROR_LOG_MAXIMUM_SIZE)
1166 cbDumpData = ERROR_LOG_MAXIMUM_SIZE - FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData);
1167
1168 pErrEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(g_VBoxUsbMonGlobals.pDevObj,
1169 FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData) + cbDumpData);
1170 if (pErrEntry)
1171 {
1172 uint8_t *pDump = (uint8_t *)pErrEntry->DumpData;
1173 if (cbDumpData)
1174 memcpy(pDump, pDumpData, cbDumpData);
1175 pErrEntry->MajorFunctionCode = 0;
1176 pErrEntry->RetryCount = 0;
1177 pErrEntry->DumpDataSize = cbDumpData;
1178 pErrEntry->NumberOfStrings = 0;
1179 pErrEntry->StringOffset = 0;
1180 pErrEntry->ErrorCode = ErrCode;
1181 pErrEntry->UniqueErrorValue = uErrId;
1182 pErrEntry->FinalStatus = ReturnedStatus;
1183 pErrEntry->IoControlCode = 0;
1184 IoWriteErrorLogEntry(pErrEntry);
1185 }
1186 else
1187 {
1188 LOG(("Failed to allocate error log entry (cb=%d)\n", FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData) + cbDumpData));
1189 }
1190}
1191
1192static DECLCALLBACK(BOOLEAN) vboxUsbMonHookDrvObjWalker(PFILE_OBJECT pFile, PDEVICE_OBJECT pTopDo, PDEVICE_OBJECT pHubDo, PVOID pvContext)
1193{
1194 PDRIVER_OBJECT pDrvObj = pHubDo->DriverObject;
1195
1196 /* First we try to figure out if we are already hooked to this driver. */
1197 for (int i = 0; i < VBOXUSBMON_MAXDRIVERS; i++)
1198 if (pDrvObj == g_VBoxUsbMonGlobals.pDrivers[i].DriverObject)
1199 {
1200 LOG(("Found %p at pDrivers[%d]\n", pDrvObj, i));
1201 /* We've already hooked to this one -- nothing to do. */
1202 return TRUE;
1203 }
1204 /* We are not hooked yet, find an empty slot. */
1205 for (int i = 0; i < VBOXUSBMON_MAXDRIVERS; i++)
1206 {
1207 if (!g_VBoxUsbMonGlobals.pDrivers[i].DriverObject)
1208 {
1209 /* Found an emtpy slot, use it. */
1210 g_VBoxUsbMonGlobals.pDrivers[i].DriverObject = pDrvObj;
1211 ObReferenceObject(pDrvObj);
1212 LOG(("pDrivers[%d] = %p, installing the hook...\n", i, pDrvObj));
1213 VBoxUsbHookInit(&g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.Hook,
1214 pDrvObj,
1215 IRP_MJ_PNP,
1216 g_VBoxUsbMonGlobals.pDrivers[i].pfnHookStub);
1217 VBoxUsbHookInstall(&g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.Hook);
1218 return TRUE; /* Must continue to find all drivers. */
1219 }
1220 if (pDrvObj == g_VBoxUsbMonGlobals.pDrivers[i].DriverObject)
1221 {
1222 LOG(("Found %p at pDrivers[%d]\n", pDrvObj, i));
1223 /* We've already hooked to this one -- nothing to do. */
1224 return TRUE;
1225 }
1226 }
1227 /* No empty slots! No reason to continue. */
1228 LOG(("No empty slots!\n"));
1229 ANSI_STRING ansiDrvName;
1230 NTSTATUS Status = RtlUnicodeStringToAnsiString(&ansiDrvName, &pDrvObj->DriverName, true);
1231 if (Status != STATUS_SUCCESS)
1232 {
1233 ansiDrvName.Length = 0;
1234 LOG(("RtlUnicodeStringToAnsiString failed with 0x%x", Status));
1235 }
1236 vboxUsbMonLogError(IO_ERR_INSUFFICIENT_RESOURCES, STATUS_SUCCESS, 1, ansiDrvName.Length, ansiDrvName.Buffer);
1237 if (Status == STATUS_SUCCESS)
1238 RtlFreeAnsiString(&ansiDrvName);
1239 return FALSE;
1240}
1241
1242/**
1243 * Finds all USB drivers in the system and installs hooks if haven't done already.
1244 */
1245static NTSTATUS vboxUsbMonInstallAllHooks()
1246{
1247 vboxUsbMonHubDevWalk(vboxUsbMonHookDrvObjWalker, NULL, VBOXUSBMONHUBWALK_F_ALL);
1248 return STATUS_SUCCESS;
1249}
1250#endif /* VBOX_USB3PORT */
1251
1252static NTSTATUS vboxUsbMonHookCheckInit()
1253{
1254 static bool fIsHookInited = false;
1255 if (fIsHookInited)
1256 {
1257 LOG(("hook inited already, success"));
1258 return STATUS_SUCCESS;
1259 }
1260#ifdef VBOX_USB3PORT
1261 return vboxUsbMonInstallAllHooks();
1262#else /* !VBOX_USB3PORT */
1263 PDRIVER_OBJECT pDrvObj = vboxUsbMonHookFindHubDrvObj();
1264 if (pDrvObj)
1265 {
1266 VBoxUsbHookInit(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook, pDrvObj, IRP_MJ_PNP, VBoxUsbMonPnPHook);
1267 fIsHookInited = true;
1268 LOG(("SUCCESS"));
1269 return STATUS_SUCCESS;
1270 }
1271 WARN(("hub drv obj not found, fail"));
1272 return STATUS_UNSUCCESSFUL;
1273#endif /* !VBOX_USB3PORT */
1274}
1275
1276static NTSTATUS vboxUsbMonHookInstall()
1277{
1278#ifdef VBOX_USB3PORT
1279 /* Nothing to do here as we have already installed all hooks in vboxUsbMonHookCheckInit(). */
1280 return STATUS_SUCCESS;
1281#else /* !VBOX_USB3PORT */
1282#ifdef VBOXUSBMON_DBG_NO_PNPHOOK
1283 return STATUS_SUCCESS;
1284#else
1285 if (g_VBoxUsbMonGlobals.UsbHubPnPHook.fUninitFailed)
1286 {
1287 WARN(("trying to hook usbhub pnp after the unhook failed, do nothing & pretend success"));
1288 return STATUS_SUCCESS;
1289 }
1290 return VBoxUsbHookInstall(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook);
1291#endif
1292#endif /* !VBOX_USB3PORT */
1293}
1294
1295static NTSTATUS vboxUsbMonHookUninstall()
1296{
1297#ifdef VBOXUSBMON_DBG_NO_PNPHOOK
1298 return STATUS_SUCCESS;
1299#else
1300#ifdef VBOX_USB3PORT
1301 NTSTATUS Status = STATUS_SUCCESS;
1302 for (int i = 0; i < VBOXUSBMON_MAXDRIVERS; i++)
1303 {
1304 if (g_VBoxUsbMonGlobals.pDrivers[i].DriverObject)
1305 {
1306 Assert(g_VBoxUsbMonGlobals.pDrivers[i].DriverObject == g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.Hook.pDrvObj);
1307 LOG(("Unhooking from %p...\n", g_VBoxUsbMonGlobals.pDrivers[i].DriverObject));
1308 Status = VBoxUsbHookUninstall(&g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.Hook);
1309 if (!NT_SUCCESS(Status))
1310 {
1311 /*
1312 * We failed to uninstall the hook, so we keep the reference to the driver
1313 * in order to prevent another driver re-using this slot because we are
1314 * going to mark this hook as fUninitFailed.
1315 */
1316 //AssertMsgFailed(("usbhub pnp unhook failed, setting the fUninitFailed flag, the current value of fUninitFailed (%d)", g_VBoxUsbMonGlobals.UsbHubPnPHook.fUninitFailed));
1317 LOG(("usbhub pnp unhook failed, setting the fUninitFailed flag, the current value of fUninitFailed (%d)", g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.fUninitFailed));
1318 g_VBoxUsbMonGlobals.pDrivers[i].UsbHubPnPHook.fUninitFailed = true;
1319 }
1320 else
1321 {
1322 /* The hook was removed successfully, now we can forget about this driver. */
1323 ObDereferenceObject(g_VBoxUsbMonGlobals.pDrivers[i].DriverObject);
1324 g_VBoxUsbMonGlobals.pDrivers[i].DriverObject = NULL;
1325 }
1326 }
1327 }
1328#else /* !VBOX_USB3PORT */
1329 NTSTATUS Status = VBoxUsbHookUninstall(&g_VBoxUsbMonGlobals.UsbHubPnPHook.Hook);
1330 if (!NT_SUCCESS(Status))
1331 {
1332 AssertMsgFailed(("usbhub pnp unhook failed, setting the fUninitFailed flag, the current value of fUninitFailed (%d)", g_VBoxUsbMonGlobals.UsbHubPnPHook.fUninitFailed));
1333 g_VBoxUsbMonGlobals.UsbHubPnPHook.fUninitFailed = true;
1334 }
1335#endif /* !VBOX_USB3PORT */
1336 return Status;
1337#endif
1338}
1339
1340
1341static NTSTATUS vboxUsbMonCheckTermStuff()
1342{
1343 NTSTATUS Status = KeWaitForSingleObject(&g_VBoxUsbMonGlobals.OpenSynchEvent,
1344 Executive, KernelMode,
1345 FALSE, /* BOOLEAN Alertable */
1346 NULL /* IN PLARGE_INTEGER Timeout */
1347 );
1348 AssertRelease(Status == STATUS_SUCCESS);
1349
1350 do
1351 {
1352 if (--g_VBoxUsbMonGlobals.cOpens)
1353 break;
1354
1355 Status = vboxUsbMonHookUninstall();
1356
1357 NTSTATUS tmpStatus = VBoxUsbFltTerm();
1358 if (!NT_SUCCESS(tmpStatus))
1359 {
1360 /* this means a driver state is screwed up, KeBugCheckEx here ? */
1361 AssertReleaseFailed();
1362 }
1363 } while (0);
1364
1365 KeSetEvent(&g_VBoxUsbMonGlobals.OpenSynchEvent, 0, FALSE);
1366
1367 return Status;
1368}
1369
1370static NTSTATUS vboxUsbMonCheckInitStuff()
1371{
1372 NTSTATUS Status = KeWaitForSingleObject(&g_VBoxUsbMonGlobals.OpenSynchEvent,
1373 Executive, KernelMode,
1374 FALSE, /* BOOLEAN Alertable */
1375 NULL /* IN PLARGE_INTEGER Timeout */
1376 );
1377 if (Status == STATUS_SUCCESS)
1378 {
1379 do
1380 {
1381 if (g_VBoxUsbMonGlobals.cOpens++)
1382 {
1383 LOG(("opens: %d, success", g_VBoxUsbMonGlobals.cOpens));
1384 break;
1385 }
1386
1387 Status = VBoxUsbFltInit();
1388 if (NT_SUCCESS(Status))
1389 {
1390 Status = vboxUsbMonHookCheckInit();
1391 if (NT_SUCCESS(Status))
1392 {
1393 Status = vboxUsbMonHookInstall();
1394 if (NT_SUCCESS(Status))
1395 {
1396 Status = STATUS_SUCCESS;
1397 LOG(("succeded!!"));
1398 break;
1399 }
1400 else
1401 {
1402 WARN(("vboxUsbMonHookInstall failed, Status (0x%x)", Status));
1403 }
1404 }
1405 else
1406 {
1407 WARN(("vboxUsbMonHookCheckInit failed, Status (0x%x)", Status));
1408 }
1409 VBoxUsbFltTerm();
1410 }
1411 else
1412 {
1413 WARN(("VBoxUsbFltInit failed, Status (0x%x)", Status));
1414 }
1415
1416 --g_VBoxUsbMonGlobals.cOpens;
1417 Assert(!g_VBoxUsbMonGlobals.cOpens);
1418 } while (0);
1419
1420 KeSetEvent(&g_VBoxUsbMonGlobals.OpenSynchEvent, 0, FALSE);
1421 }
1422 else
1423 {
1424 WARN(("KeWaitForSingleObject failed, Status (0x%x)", Status));
1425 }
1426 return Status;
1427}
1428
1429static NTSTATUS vboxUsbMonContextCreate(PVBOXUSBMONCTX *ppCtx)
1430{
1431 NTSTATUS Status;
1432 *ppCtx = NULL;
1433 PVBOXUSBMONCTX pFileCtx = (PVBOXUSBMONCTX)VBoxUsbMonMemAllocZ(sizeof (*pFileCtx));
1434 if (pFileCtx)
1435 {
1436 Status = vboxUsbMonCheckInitStuff();
1437 if (Status == STATUS_SUCCESS)
1438 {
1439 Status = VBoxUsbFltCreate(&pFileCtx->FltCtx);
1440 if (Status == STATUS_SUCCESS)
1441 {
1442 *ppCtx = pFileCtx;
1443 LOG(("succeeded!!"));
1444 return STATUS_SUCCESS;
1445 }
1446 else
1447 {
1448 WARN(("VBoxUsbFltCreate failed"));
1449 }
1450 vboxUsbMonCheckTermStuff();
1451 }
1452 else
1453 {
1454 WARN(("vboxUsbMonCheckInitStuff failed"));
1455 }
1456 VBoxUsbMonMemFree(pFileCtx);
1457 }
1458 else
1459 {
1460 WARN(("VBoxUsbMonMemAllocZ failed"));
1461 Status = STATUS_NO_MEMORY;
1462 }
1463
1464 return Status;
1465}
1466
1467static NTSTATUS vboxUsbMonContextClose(PVBOXUSBMONCTX pCtx)
1468{
1469 NTSTATUS Status = VBoxUsbFltClose(&pCtx->FltCtx);
1470 if (Status == STATUS_SUCCESS)
1471 {
1472 Status = vboxUsbMonCheckTermStuff();
1473 Assert(Status == STATUS_SUCCESS);
1474 /* ignore the failure */
1475 VBoxUsbMonMemFree(pCtx);
1476 }
1477
1478 return Status;
1479}
1480
1481static NTSTATUS _stdcall VBoxUsbMonClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1482{
1483 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1484 PFILE_OBJECT pFileObj = pStack->FileObject;
1485 Assert(pFileObj->FsContext);
1486 PVBOXUSBMONCTX pCtx = (PVBOXUSBMONCTX)pFileObj->FsContext;
1487
1488 LOG(("VBoxUsbMonClose"));
1489
1490 NTSTATUS Status = vboxUsbMonContextClose(pCtx);
1491 if (Status != STATUS_SUCCESS)
1492 {
1493 WARN(("vboxUsbMonContextClose failed, Status (0x%x), prefent unload", Status));
1494 if (!InterlockedExchange(&g_VBoxUsbMonGlobals.ulPreventUnloadOn, 1))
1495 {
1496 LOGREL(("ulPreventUnloadOn not set, preventing unload"));
1497 UNICODE_STRING UniName;
1498 PDEVICE_OBJECT pTmpDevObj;
1499 RtlInitUnicodeString(&UniName, USBMON_DEVICE_NAME_NT);
1500 NTSTATUS tmpStatus = IoGetDeviceObjectPointer(&UniName, FILE_ALL_ACCESS, &g_VBoxUsbMonGlobals.pPreventUnloadFileObj, &pTmpDevObj);
1501 AssertRelease(NT_SUCCESS(tmpStatus));
1502 AssertRelease(pTmpDevObj == pDevObj);
1503 }
1504 else
1505 {
1506 WARN(("ulPreventUnloadOn already set"));
1507 }
1508 LOG(("success!!"));
1509 Status = STATUS_SUCCESS;
1510 }
1511 pFileObj->FsContext = NULL;
1512 pIrp->IoStatus.Status = Status;
1513 pIrp->IoStatus.Information = 0;
1514 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1515 return Status;
1516}
1517
1518
1519static NTSTATUS _stdcall VBoxUsbMonCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1520{
1521 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1522 PFILE_OBJECT pFileObj = pStack->FileObject;
1523 NTSTATUS Status;
1524
1525 LOG(("VBoxUSBMonCreate"));
1526
1527 if (pStack->Parameters.Create.Options & FILE_DIRECTORY_FILE)
1528 {
1529 WARN(("trying to open as a directory"));
1530 pIrp->IoStatus.Status = STATUS_NOT_A_DIRECTORY;
1531 pIrp->IoStatus.Information = 0;
1532 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1533 return STATUS_NOT_A_DIRECTORY;
1534 }
1535
1536 pFileObj->FsContext = NULL;
1537 PVBOXUSBMONCTX pCtx = NULL;
1538 Status = vboxUsbMonContextCreate(&pCtx);
1539 if (Status == STATUS_SUCCESS)
1540 {
1541 Assert(pCtx);
1542 pFileObj->FsContext = pCtx;
1543 }
1544 else
1545 {
1546 WARN(("vboxUsbMonContextCreate failed Status (0x%x)", Status));
1547 }
1548
1549 pIrp->IoStatus.Status = Status;
1550 pIrp->IoStatus.Information = 0;
1551 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1552 return Status;
1553}
1554
1555static int VBoxUsbMonSetNotifyEvent(PVBOXUSBMONCTX pContext, HANDLE hEvent)
1556{
1557 int rc = VBoxUsbFltSetNotifyEvent(&pContext->FltCtx, hEvent);
1558 return rc;
1559}
1560
1561static int VBoxUsbMonFltAdd(PVBOXUSBMONCTX pContext, PUSBFILTER pFilter, uintptr_t *pId)
1562{
1563#ifdef VBOXUSBMON_DBG_NO_FILTERS
1564 static uintptr_t idDummy = 1;
1565 *pId = idDummy;
1566 ++idDummy;
1567 return VINF_SUCCESS;
1568#else
1569 int rc = VBoxUsbFltAdd(&pContext->FltCtx, pFilter, pId);
1570 return rc;
1571#endif
1572}
1573
1574static int VBoxUsbMonFltRemove(PVBOXUSBMONCTX pContext, uintptr_t uId)
1575{
1576#ifdef VBOXUSBMON_DBG_NO_FILTERS
1577 return VINF_SUCCESS;
1578#else
1579 int rc = VBoxUsbFltRemove(&pContext->FltCtx, uId);
1580 return rc;
1581#endif
1582}
1583
1584static NTSTATUS VBoxUsbMonRunFilters(PVBOXUSBMONCTX pContext)
1585{
1586 NTSTATUS Status = VBoxUsbFltFilterCheck(&pContext->FltCtx);
1587 return Status;
1588}
1589
1590static NTSTATUS VBoxUsbMonGetDevice(PVBOXUSBMONCTX pContext, HVBOXUSBDEVUSR hDevice, PUSBSUP_GETDEV_MON pInfo)
1591{
1592 NTSTATUS Status = VBoxUsbFltGetDevice(&pContext->FltCtx, hDevice, pInfo);
1593 return Status;
1594}
1595
1596static NTSTATUS vboxUsbMonIoctlDispatch(PVBOXUSBMONCTX pContext, ULONG Ctl, PVOID pvBuffer, ULONG cbInBuffer, ULONG cbOutBuffer, ULONG_PTR* pInfo)
1597{
1598 NTSTATUS Status = STATUS_SUCCESS;
1599 ULONG_PTR Info = 0;
1600 switch (Ctl)
1601 {
1602 case SUPUSBFLT_IOCTL_GET_VERSION:
1603 {
1604 PUSBSUP_VERSION pOut = (PUSBSUP_VERSION)pvBuffer;
1605
1606 LOG(("SUPUSBFLT_IOCTL_GET_VERSION"));
1607 if (!pvBuffer || cbOutBuffer != sizeof(*pOut) || cbInBuffer != 0)
1608 {
1609 WARN(("SUPUSBFLT_IOCTL_GET_VERSION: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.",
1610 cbInBuffer, 0, cbOutBuffer, sizeof (*pOut)));
1611 Status = STATUS_INVALID_PARAMETER;
1612 break;
1613 }
1614 pOut->u32Major = USBMON_MAJOR_VERSION;
1615 pOut->u32Minor = USBMON_MINOR_VERSION;
1616 Info = sizeof (*pOut);
1617 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1618 break;
1619 }
1620
1621 case SUPUSBFLT_IOCTL_ADD_FILTER:
1622 {
1623 PUSBFILTER pFilter = (PUSBFILTER)pvBuffer;
1624 PUSBSUP_FLTADDOUT pOut = (PUSBSUP_FLTADDOUT)pvBuffer;
1625 uintptr_t uId = 0;
1626 int rc;
1627 if (RT_UNLIKELY(!pvBuffer || cbInBuffer != sizeof (*pFilter) || cbOutBuffer != sizeof (*pOut)))
1628 {
1629 WARN(("SUPUSBFLT_IOCTL_ADD_FILTER: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.",
1630 cbInBuffer, sizeof (*pFilter), cbOutBuffer, sizeof (*pOut)));
1631 Status = STATUS_INVALID_PARAMETER;
1632 break;
1633 }
1634
1635 rc = VBoxUsbMonFltAdd(pContext, pFilter, &uId);
1636 pOut->rc = rc;
1637 pOut->uId = uId;
1638 Info = sizeof (*pOut);
1639 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1640 break;
1641 }
1642
1643 case SUPUSBFLT_IOCTL_REMOVE_FILTER:
1644 {
1645 uintptr_t *pIn = (uintptr_t *)pvBuffer;
1646 int *pRc = (int *)pvBuffer;
1647
1648 if (!pvBuffer || cbInBuffer != sizeof (*pIn) || (cbOutBuffer && cbOutBuffer != sizeof (*pRc)))
1649 {
1650 WARN(("SUPUSBFLT_IOCTL_REMOVE_FILTER: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.",
1651 cbInBuffer, sizeof (*pIn), cbOutBuffer, 0));
1652 Status = STATUS_INVALID_PARAMETER;
1653 break;
1654 }
1655 LOG(("SUPUSBFLT_IOCTL_REMOVE_FILTER %x", *pIn));
1656 int rc = VBoxUsbMonFltRemove(pContext, *pIn);
1657 if (cbOutBuffer)
1658 {
1659 /* we've validated that already */
1660 Assert(cbOutBuffer == *pRc);
1661 *pRc = rc;
1662 Info = sizeof (*pRc);
1663 }
1664 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1665 break;
1666 }
1667
1668 case SUPUSBFLT_IOCTL_RUN_FILTERS:
1669 {
1670 if (pvBuffer || cbInBuffer || cbOutBuffer)
1671 {
1672 WARN(("SUPUSBFLT_IOCTL_RUN_FILTERS: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.",
1673 cbInBuffer, 0, cbOutBuffer, 0));
1674 Status = STATUS_INVALID_PARAMETER;
1675 break;
1676 }
1677 LOG(("SUPUSBFLT_IOCTL_RUN_FILTERS "));
1678 Status = VBoxUsbMonRunFilters(pContext);
1679 ASSERT_WARN(Status != STATUS_PENDING, ("status pending!"));
1680 break;
1681 }
1682
1683 case SUPUSBFLT_IOCTL_GET_DEVICE:
1684 {
1685 HVBOXUSBDEVUSR hDevice = *((HVBOXUSBDEVUSR*)pvBuffer);
1686 PUSBSUP_GETDEV_MON pOut = (PUSBSUP_GETDEV_MON)pvBuffer;
1687 if (!pvBuffer || cbInBuffer != sizeof (hDevice) || cbOutBuffer < sizeof (*pOut))
1688 {
1689 WARN(("SUPUSBFLT_IOCTL_GET_DEVICE: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected >= %d.",
1690 cbInBuffer, sizeof (hDevice), cbOutBuffer, sizeof (*pOut)));
1691 Status = STATUS_INVALID_PARAMETER;
1692 break;
1693 }
1694
1695 Status = VBoxUsbMonGetDevice(pContext, hDevice, pOut);
1696
1697 if (NT_SUCCESS(Status))
1698 {
1699 Info = sizeof (*pOut);
1700 }
1701 else
1702 {
1703 WARN(("VBoxUsbMonGetDevice fail 0x%x", Status));
1704 }
1705 break;
1706 }
1707
1708 case SUPUSBFLT_IOCTL_SET_NOTIFY_EVENT:
1709 {
1710 PUSBSUP_SET_NOTIFY_EVENT pSne = (PUSBSUP_SET_NOTIFY_EVENT)pvBuffer;
1711 if (!pvBuffer || cbInBuffer != sizeof (*pSne) || cbOutBuffer != sizeof (*pSne))
1712 {
1713 WARN(("SUPUSBFLT_IOCTL_SET_NOTIFY_EVENT: Invalid input/output sizes. cbIn=%d expected %d. cbOut=%d expected %d.",
1714 cbInBuffer, sizeof (*pSne), cbOutBuffer, sizeof (*pSne)));
1715 Status = STATUS_INVALID_PARAMETER;
1716 break;
1717 }
1718
1719 pSne->u.rc = VBoxUsbMonSetNotifyEvent(pContext, pSne->u.hEvent);
1720 Info = sizeof (*pSne);
1721 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1722 break;
1723 }
1724
1725 default:
1726 WARN(("Unknown code 0x%x", Ctl));
1727 Status = STATUS_INVALID_PARAMETER;
1728 break;
1729 }
1730
1731 ASSERT_WARN(Status != STATUS_PENDING, ("Status pending!"));
1732
1733 *pInfo = Info;
1734 return Status;
1735}
1736
1737static NTSTATUS _stdcall VBoxUsbMonDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1738{
1739 ULONG_PTR Info = 0;
1740 NTSTATUS Status = IoAcquireRemoveLock(&g_VBoxUsbMonGlobals.RmLock, pDevObj);
1741 if (NT_SUCCESS(Status))
1742 {
1743 PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
1744 PFILE_OBJECT pFileObj = pSl->FileObject;
1745 Assert(pFileObj);
1746 Assert(pFileObj->FsContext);
1747 PVBOXUSBMONCTX pCtx = (PVBOXUSBMONCTX)pFileObj->FsContext;
1748 Assert(pCtx);
1749 Status = vboxUsbMonIoctlDispatch(pCtx,
1750 pSl->Parameters.DeviceIoControl.IoControlCode,
1751 pIrp->AssociatedIrp.SystemBuffer,
1752 pSl->Parameters.DeviceIoControl.InputBufferLength,
1753 pSl->Parameters.DeviceIoControl.OutputBufferLength,
1754 &Info);
1755 ASSERT_WARN(Status != STATUS_PENDING, ("Status pending"));
1756
1757 IoReleaseRemoveLock(&g_VBoxUsbMonGlobals.RmLock, pDevObj);
1758 }
1759 else
1760 {
1761 WARN(("IoAcquireRemoveLock failed Status (0x%x)", Status));
1762 }
1763
1764 pIrp->IoStatus.Information = Info;
1765 pIrp->IoStatus.Status = Status;
1766 IoCompleteRequest (pIrp, IO_NO_INCREMENT);
1767 return Status;
1768}
1769
1770static NTSTATUS vboxUsbMonInternalIoctlDispatch(ULONG Ctl, PVOID pvBuffer, ULONG_PTR *pInfo)
1771{
1772 NTSTATUS Status = STATUS_SUCCESS;
1773 *pInfo = 0;
1774 switch (Ctl)
1775 {
1776 case VBOXUSBIDC_INTERNAL_IOCTL_GET_VERSION:
1777 {
1778 PVBOXUSBIDC_VERSION pOut = (PVBOXUSBIDC_VERSION)pvBuffer;
1779
1780 LOG(("VBOXUSBIDC_INTERNAL_IOCTL_GET_VERSION"));
1781 if (!pvBuffer)
1782 {
1783 WARN(("VBOXUSBIDC_INTERNAL_IOCTL_GET_VERSION: Buffer is NULL"));
1784 Status = STATUS_INVALID_PARAMETER;
1785 break;
1786 }
1787 pOut->u32Major = VBOXUSBIDC_VERSION_MAJOR;
1788 pOut->u32Minor = VBOXUSBIDC_VERSION_MINOR;
1789 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1790 break;
1791 }
1792
1793 case VBOXUSBIDC_INTERNAL_IOCTL_PROXY_STARTUP:
1794 {
1795 PVBOXUSBIDC_PROXY_STARTUP pOut = (PVBOXUSBIDC_PROXY_STARTUP)pvBuffer;
1796
1797 LOG(("VBOXUSBIDC_INTERNAL_IOCTL_PROXY_STARTUP"));
1798 if (!pvBuffer)
1799 {
1800 WARN(("VBOXUSBIDC_INTERNAL_IOCTL_PROXY_STARTUP: Buffer is NULL"));
1801 Status = STATUS_INVALID_PARAMETER;
1802 break;
1803 }
1804
1805 pOut->u.hDev = VBoxUsbFltProxyStarted(pOut->u.pPDO);
1806 ASSERT_WARN(pOut->u.hDev, ("zero hDev"));
1807 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1808 break;
1809 }
1810
1811 case VBOXUSBIDC_INTERNAL_IOCTL_PROXY_TEARDOWN:
1812 {
1813 PVBOXUSBIDC_PROXY_TEARDOWN pOut = (PVBOXUSBIDC_PROXY_TEARDOWN)pvBuffer;
1814
1815 LOG(("VBOXUSBIDC_INTERNAL_IOCTL_PROXY_TEARDOWN"));
1816 if (!pvBuffer)
1817 {
1818 WARN(("VBOXUSBIDC_INTERNAL_IOCTL_PROXY_TEARDOWN: Buffer is NULL"));
1819 Status = STATUS_INVALID_PARAMETER;
1820 break;
1821 }
1822
1823 ASSERT_WARN(pOut->hDev, ("zero hDev"));
1824 VBoxUsbFltProxyStopped(pOut->hDev);
1825 ASSERT_WARN(Status == STATUS_SUCCESS, ("unexpected status, 0x%x", Status));
1826 break;
1827 }
1828
1829 default:
1830 {
1831 WARN(("Unknown code 0x%x", Ctl));
1832 Status = STATUS_INVALID_PARAMETER;
1833 break;
1834 }
1835 }
1836
1837 return Status;
1838}
1839
1840static NTSTATUS _stdcall VBoxUsbMonInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1841{
1842 ULONG_PTR Info = 0;
1843 NTSTATUS Status = IoAcquireRemoveLock(&g_VBoxUsbMonGlobals.RmLock, pDevObj);
1844 if (NT_SUCCESS(Status))
1845 {
1846 PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
1847 Status = vboxUsbMonInternalIoctlDispatch(pSl->Parameters.DeviceIoControl.IoControlCode,
1848 pSl->Parameters.Others.Argument1,
1849 &Info);
1850 Assert(Status != STATUS_PENDING);
1851
1852 IoReleaseRemoveLock(&g_VBoxUsbMonGlobals.RmLock, pDevObj);
1853 }
1854
1855 pIrp->IoStatus.Information = Info;
1856 pIrp->IoStatus.Status = Status;
1857 IoCompleteRequest (pIrp, IO_NO_INCREMENT);
1858 return Status;
1859}
1860
1861/**
1862 * Unload the driver.
1863 *
1864 * @param pDrvObj Driver object.
1865 */
1866static void _stdcall VBoxUsbMonUnload(PDRIVER_OBJECT pDrvObj)
1867{
1868 LOG(("VBoxUSBMonUnload pDrvObj (0x%p)", pDrvObj));
1869
1870 IoReleaseRemoveLockAndWait(&g_VBoxUsbMonGlobals.RmLock, &g_VBoxUsbMonGlobals);
1871
1872 Assert(!g_VBoxUsbMonGlobals.cOpens);
1873
1874 UNICODE_STRING DosName;
1875 RtlInitUnicodeString(&DosName, USBMON_DEVICE_NAME_DOS);
1876 NTSTATUS rc = IoDeleteSymbolicLink(&DosName);
1877
1878 IoDeleteDevice(g_VBoxUsbMonGlobals.pDevObj);
1879
1880 /* cleanup the logger */
1881 PRTLOGGER pLogger = RTLogRelSetDefaultInstance(NULL);
1882 if (pLogger)
1883 {
1884 RTLogDestroy(pLogger);
1885 }
1886 pLogger = RTLogSetDefaultInstance(NULL);
1887 if (pLogger)
1888 {
1889 RTLogDestroy(pLogger);
1890 }
1891}
1892
1893RT_C_DECLS_BEGIN
1894NTSTATUS _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath);
1895RT_C_DECLS_END
1896
1897/**
1898 * Driver entry point.
1899 *
1900 * @returns appropriate status code.
1901 * @param pDrvObj Pointer to driver object.
1902 * @param pRegPath Registry base path.
1903 */
1904NTSTATUS _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
1905{
1906#ifdef VBOX_USB_WITH_VERBOSE_LOGGING
1907 RTLogGroupSettings(0, "+default.e.l.f.l2.l3");
1908 RTLogDestinations(0, "debugger");
1909#endif
1910
1911 LOGREL(("Built %s %s", __DATE__, __TIME__));
1912
1913 memset (&g_VBoxUsbMonGlobals, 0, sizeof (g_VBoxUsbMonGlobals));
1914#ifdef VBOX_USB3PORT
1915 VBOX_PNPHOOKSTUB_INIT(0);
1916 VBOX_PNPHOOKSTUB_INIT(1);
1917 VBOX_PNPHOOKSTUB_INIT(2);
1918 VBOX_PNPHOOKSTUB_INIT(3);
1919 VBOX_PNPHOOKSTUB_INIT(4);
1920 AssertCompile(VBOXUSBMON_MAXDRIVERS == 5);
1921#endif /* VBOX_USB3PORT */
1922 KeInitializeEvent(&g_VBoxUsbMonGlobals.OpenSynchEvent, SynchronizationEvent, TRUE /* signaled */);
1923 IoInitializeRemoveLock(&g_VBoxUsbMonGlobals.RmLock, VBOXUSBMON_MEMTAG, 1, 100);
1924 UNICODE_STRING DevName;
1925 PDEVICE_OBJECT pDevObj;
1926 /* create the device */
1927 RtlInitUnicodeString(&DevName, USBMON_DEVICE_NAME_NT);
1928 NTSTATUS Status = IoAcquireRemoveLock(&g_VBoxUsbMonGlobals.RmLock, &g_VBoxUsbMonGlobals);
1929 if (NT_SUCCESS(Status))
1930 {
1931 Status = IoCreateDevice(pDrvObj, sizeof (VBOXUSBMONINS), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDevObj);
1932 if (NT_SUCCESS(Status))
1933 {
1934 UNICODE_STRING DosName;
1935 RtlInitUnicodeString(&DosName, USBMON_DEVICE_NAME_DOS);
1936 Status = IoCreateSymbolicLink(&DosName, &DevName);
1937 if (NT_SUCCESS(Status))
1938 {
1939 PVBOXUSBMONINS pDevExt = (PVBOXUSBMONINS)pDevObj->DeviceExtension;
1940 memset(pDevExt, 0, sizeof(*pDevExt));
1941
1942 pDrvObj->DriverUnload = VBoxUsbMonUnload;
1943 pDrvObj->MajorFunction[IRP_MJ_CREATE] = VBoxUsbMonCreate;
1944 pDrvObj->MajorFunction[IRP_MJ_CLOSE] = VBoxUsbMonClose;
1945 pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VBoxUsbMonDeviceControl;
1946 pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = VBoxUsbMonInternalDeviceControl;
1947
1948 g_VBoxUsbMonGlobals.pDevObj = pDevObj;
1949 LOG(("VBoxUSBMon::DriverEntry returning STATUS_SUCCESS"));
1950 return STATUS_SUCCESS;
1951 }
1952 IoDeleteDevice(pDevObj);
1953 }
1954 IoReleaseRemoveLockAndWait(&g_VBoxUsbMonGlobals.RmLock, &g_VBoxUsbMonGlobals);
1955 }
1956
1957 return Status;
1958}
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