VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxUSB/win/mon/VBoxUsbHook.cpp@ 97405

Last change on this file since 97405 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.1 KB
Line 
1/* $Id: VBoxUsbHook.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * Driver Dispatch Table Hooking API
4 */
5
6/*
7 * Copyright (C) 2011-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include "VBoxUsbMon.h"
42
43
44/*********************************************************************************************************************************
45* Defined Constants And Macros *
46*********************************************************************************************************************************/
47#define VBOXUSBHOOK_MEMTAG 'HUBV'
48
49
50NTSTATUS VBoxUsbHookInstall(PVBOXUSBHOOK_ENTRY pHook)
51{
52 KIRQL Irql;
53 KeAcquireSpinLock(&pHook->Lock, &Irql);
54 if (pHook->fIsInstalled)
55 {
56 WARN(("hook is marked installed, returning failure"));
57 KeReleaseSpinLock(&pHook->Lock, Irql);
58 return STATUS_UNSUCCESSFUL;
59 }
60
61 pHook->pfnOldHandler = (PDRIVER_DISPATCH)InterlockedExchangePointer((PVOID*)&pHook->pDrvObj->MajorFunction[pHook->iMjFunction], pHook->pfnHook);
62 Assert(pHook->pfnOldHandler);
63 Assert(pHook->pfnHook != pHook->pfnOldHandler);
64 pHook->fIsInstalled = TRUE;
65 KeReleaseSpinLock(&pHook->Lock, Irql);
66 return STATUS_SUCCESS;
67
68}
69NTSTATUS VBoxUsbHookUninstall(PVBOXUSBHOOK_ENTRY pHook)
70{
71 KIRQL Irql;
72 KeAcquireSpinLock(&pHook->Lock, &Irql);
73 if (!pHook->fIsInstalled)
74 {
75 KeReleaseSpinLock(&pHook->Lock, Irql);
76 return STATUS_SUCCESS;
77 }
78
79 PDRIVER_DISPATCH pfnOldVal = (PDRIVER_DISPATCH)InterlockedCompareExchangePointer((PVOID*)&pHook->pDrvObj->MajorFunction[pHook->iMjFunction], pHook->pfnOldHandler, pHook->pfnHook);
80 Assert(pfnOldVal == pHook->pfnHook);
81 if (pfnOldVal != pHook->pfnHook)
82 {
83 AssertMsgFailed(("unhook failed!!!\n"));
84 /* this is bad! this could happen if someone else has chained another hook,
85 * or (which is even worse) restored the "initial" entry value it saved when doing a hooking before us
86 * return the failure and don't do anything else
87 * the best thing to do if this happens is to leave everything as is
88 * and to prevent the driver from being unloaded to ensure no one references our unloaded hook routine */
89 KeReleaseSpinLock(&pHook->Lock, Irql);
90 return STATUS_UNSUCCESSFUL;
91 }
92
93 pHook->fIsInstalled = FALSE;
94 KeReleaseSpinLock(&pHook->Lock, Irql);
95
96 /* wait for the current handlers to exit */
97 VBoxDrvToolRefWaitEqual(&pHook->HookRef, 1);
98
99 return STATUS_SUCCESS;
100}
101
102BOOLEAN VBoxUsbHookIsInstalled(PVBOXUSBHOOK_ENTRY pHook)
103{
104 KIRQL Irql;
105 BOOLEAN fIsInstalled;
106 KeAcquireSpinLock(&pHook->Lock, &Irql);
107 fIsInstalled = pHook->fIsInstalled;
108 KeReleaseSpinLock(&pHook->Lock, Irql);
109 return fIsInstalled;
110}
111
112VOID VBoxUsbHookInit(PVBOXUSBHOOK_ENTRY pHook, PDRIVER_OBJECT pDrvObj, UCHAR iMjFunction, PDRIVER_DISPATCH pfnHook)
113{
114 Assert(pDrvObj);
115 Assert(iMjFunction <= IRP_MJ_MAXIMUM_FUNCTION);
116 Assert(pfnHook);
117 memset(pHook, 0, sizeof (*pHook));
118 InitializeListHead(&pHook->RequestList);
119 KeInitializeSpinLock(&pHook->Lock);
120 VBoxDrvToolRefInit(&pHook->HookRef);
121 pHook->pDrvObj = pDrvObj;
122 pHook->iMjFunction = iMjFunction;
123 pHook->pfnHook = pfnHook;
124 Assert(!pHook->pfnOldHandler);
125 Assert(!pHook->fIsInstalled);
126
127}
128
129static void vboxUsbHookRequestRegisterCompletion(PVBOXUSBHOOK_ENTRY pHook, PDEVICE_OBJECT pDevObj, PIRP pIrp, PIO_COMPLETION_ROUTINE pfnCompletion, PVBOXUSBHOOK_REQUEST pRequest)
130{
131 Assert(pfnCompletion);
132 Assert(pRequest);
133 Assert(pDevObj);
134 Assert(pIrp);
135 PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
136 memset(pRequest, 0, sizeof (*pRequest));
137 pRequest->pHook = pHook;
138 pRequest->OldLocation = *pSl;
139 pRequest->pDevObj = pDevObj;
140 pRequest->pIrp = pIrp;
141 pRequest->bCompletionStopped = FALSE;
142 pSl->CompletionRoutine = pfnCompletion;
143 pSl->Context = pRequest;
144 pSl->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL;
145
146 KIRQL oldIrql;
147 KeAcquireSpinLock(&pHook->Lock, &oldIrql);
148 InsertTailList(&pHook->RequestList, &pRequest->ListEntry);
149 KeReleaseSpinLock(&pHook->Lock, oldIrql);
150}
151
152NTSTATUS VBoxUsbHookRequestPassDownHookCompletion(PVBOXUSBHOOK_ENTRY pHook, PDEVICE_OBJECT pDevObj, PIRP pIrp, PIO_COMPLETION_ROUTINE pfnCompletion, PVBOXUSBHOOK_REQUEST pRequest)
153{
154 Assert(pfnCompletion);
155 vboxUsbHookRequestRegisterCompletion(pHook, pDevObj, pIrp, pfnCompletion, pRequest);
156 return pHook->pfnOldHandler(pDevObj, pIrp);
157}
158
159NTSTATUS VBoxUsbHookRequestPassDownHookSkip(PVBOXUSBHOOK_ENTRY pHook, PDEVICE_OBJECT pDevObj, PIRP pIrp)
160{
161 return pHook->pfnOldHandler(pDevObj, pIrp);
162}
163
164NTSTATUS VBoxUsbHookRequestMoreProcessingRequired(PVBOXUSBHOOK_ENTRY pHook, PDEVICE_OBJECT pDevObj, PIRP pIrp,
165 PVBOXUSBHOOK_REQUEST pRequest)
166{
167 RT_NOREF3(pHook, pDevObj, pIrp);
168 Assert(!pRequest->bCompletionStopped);
169 pRequest->bCompletionStopped = TRUE;
170 return STATUS_MORE_PROCESSING_REQUIRED;
171}
172
173NTSTATUS VBoxUsbHookRequestComplete(PVBOXUSBHOOK_ENTRY pHook, PDEVICE_OBJECT pDevObj, PIRP pIrp, PVBOXUSBHOOK_REQUEST pRequest)
174{
175 NTSTATUS Status = STATUS_SUCCESS;
176
177 if (pRequest->OldLocation.CompletionRoutine && pRequest->OldLocation.Control)
178 {
179 Status = pRequest->OldLocation.CompletionRoutine(pDevObj, pIrp, pRequest->OldLocation.Context);
180 }
181
182 if (Status != STATUS_MORE_PROCESSING_REQUIRED)
183 {
184 if (pRequest->bCompletionStopped)
185 {
186 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
187 }
188 }
189 /*
190 * else - in case driver returned STATUS_MORE_PROCESSING_REQUIRED,
191 * it will call IoCompleteRequest itself
192 */
193
194 KIRQL oldIrql;
195 KeAcquireSpinLock(&pHook->Lock, &oldIrql);
196 RemoveEntryList(&pRequest->ListEntry);
197 KeReleaseSpinLock(&pHook->Lock, oldIrql);
198 return Status;
199}
200
201#define PVBOXUSBHOOK_REQUEST_FROM_LE(_pLe) ( (PVBOXUSBHOOK_REQUEST)( ((uint8_t*)(_pLe)) - RT_OFFSETOF(VBOXUSBHOOK_REQUEST, ListEntry) ) )
202
203VOID VBoxUsbHookVerifyCompletion(PVBOXUSBHOOK_ENTRY pHook, PVBOXUSBHOOK_REQUEST pRequest, PIRP pIrp)
204{
205 KIRQL oldIrql;
206 KeAcquireSpinLock(&pHook->Lock, &oldIrql);
207 for (PLIST_ENTRY pLe = pHook->RequestList.Flink; pLe != &pHook->RequestList; pLe = pLe->Flink)
208 {
209 PVBOXUSBHOOK_REQUEST pCur = PVBOXUSBHOOK_REQUEST_FROM_LE(pLe);
210 if (pCur != pRequest)
211 continue;
212 if (pCur->pIrp != pIrp)
213 continue;
214 WARN(("found pending IRP(0x%p) when it should not be", pIrp));
215 }
216 KeReleaseSpinLock(&pHook->Lock, oldIrql);
217
218}
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