VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuestLib/HGCMInternal.cpp@ 4056

Last change on this file since 4056 was 3466, checked in by vboxsync, 18 years ago

Wrong locking for read-only memory in Windows guests.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.8 KB
Line 
1/** @file
2 *
3 * VBoxGuestLib - A support library for VirtualBox guest additions:
4 * Host-Guest Communication Manager internal functions, implemented by VBoxGuest
5 */
6
7/*
8 * Copyright (C) 2006-2007 innotek GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
21 */
22
23/* Entire file is ifdef'ed with VBGL_VBOXGUEST */
24#ifdef VBGL_VBOXGUEST
25
26#include <VBox/VBoxGuestLib.h>
27#include "VBGLInternal.h"
28#include <iprt/string.h>
29#include <iprt/assert.h>
30
31/* These functions can be only used by VBoxGuest. */
32
33DECLVBGL(int) VbglHGCMConnect (VBoxGuestHGCMConnectInfo *pConnectInfo,
34 VBGLHGCMCALLBACK *pAsyncCallback, void *pvAsyncData,
35 uint32_t u32AsyncData)
36{
37 VMMDevHGCMConnect *pHGCMConnect;
38 int rc;
39
40 if (!pConnectInfo || !pAsyncCallback)
41 return VERR_INVALID_PARAMETER;
42
43 pHGCMConnect = NULL;
44
45 /* Allocate request */
46 rc = VbglGRAlloc ((VMMDevRequestHeader **)&pHGCMConnect, sizeof (VMMDevHGCMConnect), VMMDevReq_HGCMConnect);
47
48 if (VBOX_SUCCESS(rc))
49 {
50 /* Initialize request memory */
51 pHGCMConnect->header.fu32Flags = 0;
52
53 memcpy (&pHGCMConnect->loc, &pConnectInfo->Loc, sizeof (HGCMServiceLocation));
54 pHGCMConnect->u32ClientID = 0;
55
56 /* Issue request */
57 rc = VbglGRPerform (&pHGCMConnect->header.header);
58
59 if (VBOX_SUCCESS(rc))
60 {
61 /* Check if host decides to process the request asynchronously. */
62 if (rc == VINF_HGCM_ASYNC_EXECUTE)
63 {
64 /* Wait for request completion interrupt notification from host */
65 pAsyncCallback (&pHGCMConnect->header, pvAsyncData, u32AsyncData);
66 }
67
68 pConnectInfo->result = pHGCMConnect->header.result;
69
70 if (VBOX_SUCCESS (pConnectInfo->result))
71 pConnectInfo->u32ClientID = pHGCMConnect->u32ClientID;
72 }
73
74 VbglGRFree (&pHGCMConnect->header.header);
75 }
76
77 return rc;
78}
79
80
81DECLVBGL(int) VbglHGCMDisconnect (VBoxGuestHGCMDisconnectInfo *pDisconnectInfo,
82 VBGLHGCMCALLBACK *pAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData)
83{
84 VMMDevHGCMDisconnect *pHGCMDisconnect;
85 int rc;
86
87 if (!pDisconnectInfo || !pAsyncCallback)
88 return VERR_INVALID_PARAMETER;
89
90 pHGCMDisconnect = NULL;
91
92 /* Allocate request */
93 rc = VbglGRAlloc ((VMMDevRequestHeader **)&pHGCMDisconnect, sizeof (VMMDevHGCMDisconnect), VMMDevReq_HGCMDisconnect);
94
95 if (VBOX_SUCCESS(rc))
96 {
97 /* Initialize request memory */
98 pHGCMDisconnect->header.fu32Flags = 0;
99
100 pHGCMDisconnect->u32ClientID = pDisconnectInfo->u32ClientID;
101
102 /* Issue request */
103 rc = VbglGRPerform (&pHGCMDisconnect->header.header);
104
105 if (VBOX_SUCCESS(rc))
106 {
107 /* Check if host decides to process the request asynchronously. */
108 if (rc == VINF_HGCM_ASYNC_EXECUTE)
109 {
110 /* Wait for request completion interrupt notification from host */
111 pAsyncCallback (&pHGCMDisconnect->header, pvAsyncData, u32AsyncData);
112 }
113
114 pDisconnectInfo->result = pHGCMDisconnect->header.result;
115 }
116
117 VbglGRFree (&pHGCMDisconnect->header.header);
118 }
119
120 return rc;
121}
122
123
124DECLVBGL(int) VbglHGCMCall (VBoxGuestHGCMCallInfo *pCallInfo,
125 VBGLHGCMCALLBACK *pAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData)
126{
127 VMMDevHGCMCall *pHGCMCall;
128 uint32_t cbParms;
129 HGCMFunctionParameter *pParm;
130 unsigned iParm;
131 int rc;
132
133 if (!pCallInfo || !pAsyncCallback || pCallInfo->cParms > VBOX_HGCM_MAX_PARMS)
134 return VERR_INVALID_PARAMETER;
135
136 dprintf (("VbglHGCMCall: pCallInfo->cParms = %d, pHGCMCall->u32Function = %d\n", pCallInfo->cParms, pCallInfo->u32Function));
137
138 pHGCMCall = NULL;
139
140 cbParms = pCallInfo->cParms * sizeof (HGCMFunctionParameter);
141
142 /* Allocate request */
143 rc = VbglGRAlloc ((VMMDevRequestHeader **)&pHGCMCall, sizeof (VMMDevHGCMCall) + cbParms, VMMDevReq_HGCMCall);
144
145 dprintf (("VbglHGCMCall Allocated gr %p, rc = %Vrc, cbParms = %d\n", pHGCMCall, rc, cbParms));
146
147 if (VBOX_SUCCESS(rc))
148 {
149 void *apvCtx[VBOX_HGCM_MAX_PARMS];
150 memset (apvCtx, 0, sizeof (apvCtx));
151
152 /* Initialize request memory */
153 pHGCMCall->header.fu32Flags = 0;
154 pHGCMCall->header.result = VINF_SUCCESS;
155
156 pHGCMCall->u32ClientID = pCallInfo->u32ClientID;
157 pHGCMCall->u32Function = pCallInfo->u32Function;
158 pHGCMCall->cParms = pCallInfo->cParms;
159
160 if (cbParms)
161 {
162 memcpy (VMMDEV_HGCM_CALL_PARMS(pHGCMCall), VBOXGUEST_HGCM_CALL_PARMS(pCallInfo), cbParms);
163
164 /* Lock user buffers. */
165 pParm = VBOXGUEST_HGCM_CALL_PARMS(pCallInfo);
166
167 for (iParm = 0; iParm < pCallInfo->cParms; iParm++, pParm++)
168 {
169 if ( pParm->type == VMMDevHGCMParmType_LinAddr_In
170 || pParm->type == VMMDevHGCMParmType_LinAddr_Out
171 || pParm->type == VMMDevHGCMParmType_LinAddr)
172 {
173 /* PORTME: When porting this to Darwin and other systems where the entire kernel isn't mapped
174 into every process, all linear address will have to be converted to physical SG lists at
175 this point. Care must also be taken on these guests to not mix kernel and user addresses
176 in HGCM calls, or we'll end up locking the wrong memory. If VMMDev/HGCM gets a linear address
177 it will assume that it's in the current memory context (i.e. use CR3 to translate it).
178
179 These kind of problems actually applies to some patched linux kernels too, including older
180 fedora releases. (The patch is the infamous 4G/4G patch, aka 4g4g, by Ingo Molnar.) */
181 rc = vbglLockLinear (&apvCtx[iParm], (void *)pParm->u.Pointer.u.linearAddr, pParm->u.Pointer.size, (pParm->type == VMMDevHGCMParmType_LinAddr_In) ? false : true /* write access */);
182
183 if (VBOX_FAILURE (rc))
184 {
185 break;
186 }
187 }
188 }
189 }
190
191 /* Check that the parameter locking was ok. */
192 if (VBOX_SUCCESS(rc))
193 {
194 dprintf (("calling VbglGRPerform\n"));
195
196 /* Issue request */
197 rc = VbglGRPerform (&pHGCMCall->header.header);
198
199 dprintf (("VbglGRPerform rc = %Vrc (header rc=%d)\n", rc, pHGCMCall->header.result));
200
201 /** If the call failed, but as a result of the request itself, then pretend success
202 * Upper layers will interpret the result code in the packet.
203 */
204 if (VBOX_FAILURE(rc) && rc == pHGCMCall->header.result)
205 {
206 Assert(pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_DONE);
207 rc = VINF_SUCCESS;
208 }
209
210 if (VBOX_SUCCESS(rc))
211 {
212 /* Check if host decides to process the request asynchronously. */
213 if (rc == VINF_HGCM_ASYNC_EXECUTE)
214 {
215 /* Wait for request completion interrupt notification from host */
216 pAsyncCallback (&pHGCMCall->header, pvAsyncData, u32AsyncData);
217 }
218
219 if (pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_DONE)
220 {
221 if (cbParms)
222 {
223 memcpy (VBOXGUEST_HGCM_CALL_PARMS(pCallInfo), VMMDEV_HGCM_CALL_PARMS(pHGCMCall), cbParms);
224 }
225 pCallInfo->result = pHGCMCall->header.result;
226 }
227 else
228 {
229 /* The callback returns without completing the request,
230 * that means the wait was interrrupted. That can happen
231 * if system reboots or the VBoxService ended abnormally.
232 * In both cases it is OK to just leave the allocated memory
233 * in the physical heap. The memory leak does not affect normal
234 * operations.
235 * @todo VbglGRCancel (&pHGCMCall->header.header) need to be implemented.
236 * The host will not write to the cancelled memory.
237 */
238 pHGCMCall->header.fu32Flags |= VBOX_HGCM_REQ_CANCELLED;
239 }
240 }
241 }
242
243 /* Unlock user buffers. */
244 pParm = VBOXGUEST_HGCM_CALL_PARMS(pCallInfo);
245
246 for (iParm = 0; iParm < pCallInfo->cParms; iParm++, pParm++)
247 {
248 if ( pParm->type == VMMDevHGCMParmType_LinAddr_In
249 || pParm->type == VMMDevHGCMParmType_LinAddr_Out
250 || pParm->type == VMMDevHGCMParmType_LinAddr)
251 {
252 if (apvCtx[iParm] != NULL)
253 {
254 vbglUnlockLinear (apvCtx[iParm], (void *)pParm->u.Pointer.u.linearAddr, pParm->u.Pointer.size);
255 }
256 }
257 }
258
259 if ((pHGCMCall->header.fu32Flags & VBOX_HGCM_REQ_CANCELLED) == 0)
260 VbglGRFree (&pHGCMCall->header.header);
261 else
262 rc = VERR_INTERRUPTED;
263 }
264
265 return rc;
266}
267
268#endif /* VBGL_VBOXGUEST */
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