VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/win/SUPLib-win.cpp@ 92434

Last change on this file since 92434 was 92434, checked in by vboxsync, 3 years ago

VMM/NEM-win,SUPLib-win: Allocate large pages in SUPPageAlloc when we're allowed. bugref:10122

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.9 KB
Line 
1/* $Id: SUPLib-win.cpp 92434 2021-11-15 17:12:43Z vboxsync $ */
2/** @file
3 * VirtualBox Support Library - Windows NT specific parts.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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#define LOG_GROUP LOG_GROUP_SUP
32#ifdef IN_SUP_HARDENED_R3
33# undef DEBUG /* Warning: disables RT_STRICT */
34# undef LOG_DISABLED
35# define LOG_DISABLED
36 /** @todo RTLOGREL_DISABLED */
37# include <iprt/log.h>
38# undef LogRelIt
39# define LogRelIt(pvInst, fFlags, iGroup, fmtargs) do { } while (0)
40#endif
41
42#define USE_NT_DEVICE_IO_CONTROL_FILE
43#include <iprt/nt/nt-and-windows.h>
44
45#include <VBox/sup.h>
46#include <VBox/types.h>
47#include <VBox/err.h>
48#include <VBox/param.h>
49#include <VBox/log.h>
50#include <iprt/assert.h>
51#ifndef IN_SUP_HARDENED_R3
52# include <iprt/env.h>
53# include <iprt/x86.h>
54# include <iprt/ldr.h>
55#endif
56#include <iprt/path.h>
57#include <iprt/string.h>
58#include "../SUPLibInternal.h"
59#include "../SUPDrvIOC.h"
60#ifdef VBOX_WITH_HARDENING
61# include "win/SUPHardenedVerify-win.h"
62#endif
63
64
65/*********************************************************************************************************************************
66* Defined Constants And Macros *
67*********************************************************************************************************************************/
68/** The support service name. */
69#define SERVICE_NAME "VBoxDrv"
70
71
72/*********************************************************************************************************************************
73* Internal Functions *
74*********************************************************************************************************************************/
75#ifndef IN_SUP_HARDENED_R3
76static int suplibOsCreateService(void);
77//unused: static int suplibOsUpdateService(void);
78static int suplibOsDeleteService(void);
79static int suplibOsStartService(void);
80static int suplibOsStopService(void);
81#endif
82#ifdef USE_NT_DEVICE_IO_CONTROL_FILE
83static int suplibConvertNtStatus(NTSTATUS rcNt);
84#else
85static int suplibConvertWin32Err(int);
86#endif
87
88
89/*********************************************************************************************************************************
90* Global Variables *
91*********************************************************************************************************************************/
92static bool g_fHardenedVerifyInited = false;
93
94
95DECLHIDDEN(int) suplibOsHardenedVerifyInit(void)
96{
97 if (!g_fHardenedVerifyInited)
98 {
99#if defined(VBOX_WITH_HARDENING) && !defined(IN_SUP_HARDENED_R3) && !defined(IN_SUP_R3_STATIC)
100 supR3HardenedWinInitVersion(false /*fEarly*/);
101 int rc = supHardenedWinInitImageVerifier(NULL);
102 if (RT_FAILURE(rc))
103 return rc;
104 supR3HardenedWinResolveVerifyTrustApiAndHookThreadCreation(NULL);
105#endif
106 g_fHardenedVerifyInited = true;
107 }
108 return VINF_SUCCESS;
109}
110
111
112DECLHIDDEN(int) suplibOsHardenedVerifyTerm(void)
113{
114 /** @todo free resources... */
115 return VINF_SUCCESS;
116}
117
118
119DECLHIDDEN(int) suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, bool fUnrestricted, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
120{
121 /*
122 * Make sure the image verifier is fully initialized.
123 */
124 int rc = suplibOsHardenedVerifyInit();
125 if (RT_FAILURE(rc))
126 return RTErrInfoSetF(pErrInfo, rc, "suplibOsHardenedVerifyInit failed: %Rrc", rc);
127
128 /*
129 * Done if of pre-inited.
130 */
131 if (fPreInited)
132 {
133#if defined(VBOX_WITH_HARDENING) && !defined(IN_SUP_HARDENED_R3)
134# ifdef IN_SUP_R3_STATIC
135 return VERR_NOT_SUPPORTED;
136# else
137 return VINF_SUCCESS;
138# endif
139#else
140 return VINF_SUCCESS;
141#endif
142 }
143
144 /*
145 * Try open the device.
146 */
147#ifndef IN_SUP_HARDENED_R3
148 uint32_t cTry = 0;
149#endif
150 HANDLE hDevice;
151 for (;;)
152 {
153 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
154
155 static const WCHAR s_wszName[] = L"\\Device\\VBoxDrvU";
156 UNICODE_STRING NtName;
157 NtName.Buffer = (PWSTR)s_wszName;
158 NtName.Length = sizeof(s_wszName) - sizeof(WCHAR) * (fUnrestricted ? 2 : 1);
159 NtName.MaximumLength = NtName.Length;
160
161 OBJECT_ATTRIBUTES ObjAttr;
162 InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
163
164 hDevice = RTNT_INVALID_HANDLE_VALUE;
165
166 NTSTATUS rcNt = NtCreateFile(&hDevice,
167 GENERIC_READ | GENERIC_WRITE, /* No SYNCHRONIZE. */
168 &ObjAttr,
169 &Ios,
170 NULL /* Allocation Size*/,
171 FILE_ATTRIBUTE_NORMAL,
172 FILE_SHARE_READ | FILE_SHARE_WRITE,
173 FILE_OPEN,
174 FILE_NON_DIRECTORY_FILE, /* No FILE_SYNCHRONOUS_IO_NONALERT! */
175 NULL /*EaBuffer*/,
176 0 /*EaLength*/);
177 if (NT_SUCCESS(rcNt))
178 rcNt = Ios.Status;
179 if (NT_SUCCESS(rcNt))
180 {
181 /*
182 * We're good.
183 */
184 pThis->hDevice = hDevice;
185 pThis->fUnrestricted = fUnrestricted;
186 return VINF_SUCCESS;
187 }
188
189#ifndef IN_SUP_HARDENED_R3
190 /*
191 * Failed to open, try starting the service and reopen the device
192 * exactly once.
193 */
194 if (cTry == 0 && !NT_SUCCESS(rcNt))
195 {
196 cTry++;
197 suplibOsStartService();
198 continue;
199 }
200#endif
201
202 /*
203 * Translate the error code.
204 */
205 switch (rcNt)
206 {
207 /** @todo someone must test what is actually returned. */
208 case STATUS_DEVICE_DOES_NOT_EXIST:
209 case STATUS_DEVICE_NOT_CONNECTED:
210 //case ERROR_BAD_DEVICE:
211 case STATUS_DEVICE_REMOVED:
212 //case ERROR_DEVICE_NOT_AVAILABLE:
213 rc = VERR_VM_DRIVER_LOAD_ERROR;
214 break;
215 case STATUS_OBJECT_PATH_NOT_FOUND:
216 case STATUS_NO_SUCH_DEVICE:
217 case STATUS_NO_SUCH_FILE:
218 case STATUS_OBJECT_NAME_NOT_FOUND:
219 rc = VERR_VM_DRIVER_NOT_INSTALLED;
220 break;
221 case STATUS_ACCESS_DENIED:
222 case STATUS_SHARING_VIOLATION:
223 rc = VERR_VM_DRIVER_NOT_ACCESSIBLE;
224 break;
225 case STATUS_UNSUCCESSFUL:
226 rc = VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0;
227 break;
228 case STATUS_TRUST_FAILURE:
229 rc = VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1;
230 break;
231 case STATUS_TOO_LATE:
232 rc = VERR_SUPDRV_HARDENING_EVIL_HANDLE;
233 break;
234 default:
235 if (SUP_NT_STATUS_IS_VBOX(rcNt)) /* See VBoxDrvNtErr2NtStatus. */
236 rc = SUP_NT_STATUS_TO_VBOX(rcNt);
237 else
238 rc = VERR_VM_DRIVER_OPEN_ERROR;
239 break;
240 }
241
242#ifdef IN_SUP_HARDENED_R3
243 /*
244 * Get more details from VBoxDrvErrorInfo if present.
245 */
246 if (pErrInfo && pErrInfo->cbMsg > 32)
247 {
248 /* Prefix. */
249 size_t cchPrefix;
250 if (RTErrIsKnown(rc))
251 cchPrefix = RTStrPrintf(pErrInfo->pszMsg, pErrInfo->cbMsg / 2, "Integrity error (%#x/%Rrc): ", rcNt, rc);
252 else
253 cchPrefix = RTStrPrintf(pErrInfo->pszMsg, pErrInfo->cbMsg / 2, "Integrity error (%#x/%d): ", rcNt, rc);
254
255 /* Get error info. */
256 supR3HardenedWinReadErrorInfoDevice(pErrInfo->pszMsg + cchPrefix, pErrInfo->cbMsg - cchPrefix, "");
257 if (pErrInfo->pszMsg[cchPrefix] != '\0')
258 {
259 pErrInfo->fFlags |= RTERRINFO_FLAGS_SET;
260 pErrInfo->rc = rc;
261 *penmWhat = kSupInitOp_Integrity;
262 }
263 else
264 pErrInfo->pszMsg[0] = '\0';
265 }
266#else
267 RT_NOREF1(penmWhat);
268#endif
269 return rc;
270 }
271}
272
273
274#ifndef IN_SUP_HARDENED_R3
275
276DECLHIDDEN(int) suplibOsInstall(void)
277{
278 int rc = suplibOsCreateService();
279 if (RT_SUCCESS(rc))
280 {
281 int rc2 = suplibOsStartService();
282 if (rc2 != VINF_SUCCESS)
283 rc = rc2;
284 }
285 return rc;
286}
287
288
289DECLHIDDEN(int) suplibOsUninstall(void)
290{
291 int rc = suplibOsStopService();
292 if (RT_SUCCESS(rc))
293 rc = suplibOsDeleteService();
294 return rc;
295}
296
297
298/**
299 * Creates the service.
300 *
301 * @returns VBox status code.
302 * @retval VWRN_ALREADY_EXISTS if it already exists.
303 */
304static int suplibOsCreateService(void)
305{
306 /*
307 * Assume it didn't exist, so we'll create the service.
308 */
309 int rc;
310 SC_HANDLE hSMgrCreate = OpenSCManager(NULL, NULL, SERVICE_CHANGE_CONFIG);
311 DWORD dwErr = GetLastError();
312 AssertMsg(hSMgrCreate, ("OpenSCManager(,,create) failed dwErr=%d\n", dwErr));
313 if (hSMgrCreate != NULL)
314 {
315 char szDriver[RTPATH_MAX];
316 rc = RTPathExecDir(szDriver, sizeof(szDriver) - sizeof("\\VBoxDrv.sys"));
317 if (RT_SUCCESS(rc))
318 {
319 strcat(szDriver, "\\VBoxDrv.sys");
320 SC_HANDLE hService = CreateService(hSMgrCreate,
321 SERVICE_NAME,
322 "VBox Support Driver",
323 SERVICE_QUERY_STATUS,
324 SERVICE_KERNEL_DRIVER,
325 SERVICE_DEMAND_START,
326 SERVICE_ERROR_NORMAL,
327 szDriver,
328 NULL, NULL, NULL, NULL, NULL);
329 dwErr = GetLastError();
330 if (hService)
331 {
332 CloseServiceHandle(hService);
333 rc = VINF_SUCCESS;
334 }
335 else if (dwErr == ERROR_SERVICE_EXISTS)
336 rc = VWRN_ALREADY_EXISTS;
337 else
338 {
339 AssertMsgFailed(("CreateService failed! dwErr=%Rwa szDriver=%s\n", dwErr, szDriver));
340 rc = RTErrConvertFromWin32(dwErr);
341 }
342 }
343 CloseServiceHandle(hSMgrCreate);
344 }
345 else
346 rc = RTErrConvertFromWin32(GetLastError());
347 return rc;
348}
349
350
351/**
352 * Stops a possibly running service.
353 *
354 * @returns VBox status code.
355 */
356static int suplibOsStopService(void)
357{
358 /*
359 * Assume it didn't exist, so we'll create the service.
360 */
361 int rc;
362 SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_STOP | SERVICE_QUERY_STATUS);
363 DWORD dwErr = GetLastError();
364 AssertMsg(hSMgr, ("OpenSCManager(,,delete) failed dwErr=%d\n", dwErr));
365 if (hSMgr)
366 {
367 SC_HANDLE hService = OpenService(hSMgr, SERVICE_NAME, SERVICE_STOP | SERVICE_QUERY_STATUS);
368 if (hService)
369 {
370 /*
371 * Stop the service.
372 */
373 SERVICE_STATUS Status;
374 QueryServiceStatus(hService, &Status);
375 if (Status.dwCurrentState == SERVICE_STOPPED)
376 rc = VINF_SUCCESS;
377 else if (ControlService(hService, SERVICE_CONTROL_STOP, &Status))
378 {
379 int iWait = 100;
380 while (Status.dwCurrentState == SERVICE_STOP_PENDING && iWait-- > 0)
381 {
382 Sleep(100);
383 QueryServiceStatus(hService, &Status);
384 }
385 if (Status.dwCurrentState == SERVICE_STOPPED)
386 rc = VINF_SUCCESS;
387 else
388 {
389 AssertMsgFailed(("Failed to stop service. status=%d\n", Status.dwCurrentState));
390 rc = VERR_GENERAL_FAILURE;
391 }
392 }
393 else
394 {
395 dwErr = GetLastError();
396 if ( Status.dwCurrentState == SERVICE_STOP_PENDING
397 && dwErr == ERROR_SERVICE_CANNOT_ACCEPT_CTRL)
398 rc = VERR_RESOURCE_BUSY; /* better than VERR_GENERAL_FAILURE */
399 else
400 {
401 AssertMsgFailed(("ControlService failed with dwErr=%Rwa. status=%d\n", dwErr, Status.dwCurrentState));
402 rc = RTErrConvertFromWin32(dwErr);
403 }
404 }
405 CloseServiceHandle(hService);
406 }
407 else
408 {
409 dwErr = GetLastError();
410 if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST)
411 rc = VINF_SUCCESS;
412 else
413 {
414 AssertMsgFailed(("OpenService failed dwErr=%Rwa\n", dwErr));
415 rc = RTErrConvertFromWin32(dwErr);
416 }
417 }
418 CloseServiceHandle(hSMgr);
419 }
420 else
421 rc = RTErrConvertFromWin32(dwErr);
422 return rc;
423}
424
425
426/**
427 * Deletes the service.
428 *
429 * @returns VBox status code.
430 */
431int suplibOsDeleteService(void)
432{
433 /*
434 * Assume it didn't exist, so we'll create the service.
435 */
436 int rc;
437 SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_CHANGE_CONFIG);
438 DWORD dwErr = GetLastError();
439 AssertMsg(hSMgr, ("OpenSCManager(,,delete) failed rc=%d\n", dwErr));
440 if (hSMgr)
441 {
442 SC_HANDLE hService = OpenService(hSMgr, SERVICE_NAME, DELETE);
443 if (hService)
444 {
445 /*
446 * Delete the service.
447 */
448 if (DeleteService(hService))
449 rc = VINF_SUCCESS;
450 else
451 {
452 dwErr = GetLastError();
453 AssertMsgFailed(("DeleteService failed dwErr=%Rwa\n", dwErr));
454 rc = RTErrConvertFromWin32(dwErr);
455 }
456 CloseServiceHandle(hService);
457 }
458 else
459 {
460 dwErr = GetLastError();
461 if (dwErr == ERROR_SERVICE_DOES_NOT_EXIST)
462 rc = VINF_SUCCESS;
463 else
464 {
465 AssertMsgFailed(("OpenService failed dwErr=%Rwa\n", dwErr));
466 rc = RTErrConvertFromWin32(dwErr);
467 }
468 }
469 CloseServiceHandle(hSMgr);
470 }
471 else
472 rc = RTErrConvertFromWin32(dwErr);
473 return rc;
474}
475
476#if 0
477/**
478 * Creates the service.
479 *
480 * @returns 0 on success.
481 * @returns -1 on failure.
482 */
483static int suplibOsUpdateService(void)
484{
485 /*
486 * Assume it didn't exist, so we'll create the service.
487 */
488 SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_CHANGE_CONFIG);
489 DWORD LastError = GetLastError(); NOREF(LastError);
490 AssertMsg(hSMgr, ("OpenSCManager(,,delete) failed LastError=%Rwa\n", LastError));
491 if (hSMgr)
492 {
493 SC_HANDLE hService = OpenService(hSMgr, SERVICE_NAME, SERVICE_CHANGE_CONFIG);
494 if (hService)
495 {
496 char szDriver[RTPATH_MAX];
497 int rc = RTPathExecDir(szDriver, sizeof(szDriver) - sizeof("\\VBoxDrv.sys"));
498 if (RT_SUCCESS(rc))
499 {
500 strcat(szDriver, "\\VBoxDrv.sys");
501
502 SC_LOCK hLock = LockServiceDatabase(hSMgr);
503 if (ChangeServiceConfig(hService,
504 SERVICE_KERNEL_DRIVER,
505 SERVICE_DEMAND_START,
506 SERVICE_ERROR_NORMAL,
507 szDriver,
508 NULL, NULL, NULL, NULL, NULL, NULL))
509 {
510
511 UnlockServiceDatabase(hLock);
512 CloseServiceHandle(hService);
513 CloseServiceHandle(hSMgr);
514 return 0;
515 }
516 else
517 {
518 DWORD LastError = GetLastError(); NOREF(LastError);
519 AssertMsgFailed(("ChangeServiceConfig failed LastError=%Rwa\n", LastError));
520 }
521 }
522 UnlockServiceDatabase(hLock);
523 CloseServiceHandle(hService);
524 }
525 else
526 {
527 DWORD LastError = GetLastError(); NOREF(LastError);
528 AssertMsgFailed(("OpenService failed LastError=%Rwa\n", LastError));
529 }
530 CloseServiceHandle(hSMgr);
531 }
532 return -1;
533}
534#endif
535
536
537/**
538 * Attempts to start the service, creating it if necessary.
539 *
540 * @returns VBox status code.
541 */
542static int suplibOsStartService(void)
543{
544 /*
545 * Check if the driver service is there.
546 */
547 SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_QUERY_STATUS | SERVICE_START);
548 if (hSMgr == NULL)
549 {
550 DWORD dwErr = GetLastError();
551 AssertMsgFailed(("couldn't open service manager in SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS mode! (dwErr=%d)\n", dwErr));
552 return RTErrConvertFromWin32(dwErr);
553 }
554
555 /*
556 * Try open our service to check it's status.
557 */
558 SC_HANDLE hService = OpenService(hSMgr, SERVICE_NAME, SERVICE_QUERY_STATUS | SERVICE_START);
559 if (!hService)
560 {
561 /*
562 * Create the service.
563 */
564 int rc = suplibOsCreateService();
565 if (RT_FAILURE(rc))
566 return rc;
567
568 /*
569 * Try open the service.
570 */
571 hService = OpenService(hSMgr, SERVICE_NAME, SERVICE_QUERY_STATUS | SERVICE_START);
572 }
573
574 /*
575 * Check if open and on demand create succeeded.
576 */
577 int rc;
578 if (hService)
579 {
580
581 /*
582 * Query service status to see if we need to start it or not.
583 */
584 SERVICE_STATUS Status;
585 BOOL fRc = QueryServiceStatus(hService, &Status);
586 Assert(fRc); NOREF(fRc);
587 if (Status.dwCurrentState == SERVICE_RUNNING)
588 rc = VINF_ALREADY_INITIALIZED;
589 else
590 {
591 if (Status.dwCurrentState == SERVICE_START_PENDING)
592 rc = VINF_SUCCESS;
593 else
594 {
595 /*
596 * Start it.
597 */
598 if (StartService(hService, 0, NULL))
599 rc = VINF_SUCCESS;
600 else
601 {
602 DWORD dwErr = GetLastError();
603 AssertMsg(fRc, ("StartService failed with dwErr=%Rwa\n", dwErr));
604 rc = RTErrConvertFromWin32(dwErr);
605 }
606 }
607
608 /*
609 * Wait for the service to finish starting.
610 * We'll wait for 10 seconds then we'll give up.
611 */
612 QueryServiceStatus(hService, &Status);
613 if (Status.dwCurrentState == SERVICE_START_PENDING)
614 {
615 int iWait;
616 for (iWait = 100; iWait > 0 && Status.dwCurrentState == SERVICE_START_PENDING; iWait--)
617 {
618 Sleep(100);
619 QueryServiceStatus(hService, &Status);
620 }
621 DWORD dwErr = GetLastError(); NOREF(dwErr);
622 AssertMsg(Status.dwCurrentState != SERVICE_RUNNING,
623 ("Failed to start. dwErr=%Rwa iWait=%d status=%d\n", dwErr, iWait, Status.dwCurrentState));
624 }
625
626 if (Status.dwCurrentState == SERVICE_RUNNING)
627 rc = VINF_SUCCESS;
628 else if (RT_SUCCESS_NP(rc))
629 rc = VERR_GENERAL_FAILURE;
630 }
631
632 /*
633 * Close open handles.
634 */
635 CloseServiceHandle(hService);
636 }
637 else
638 {
639 DWORD dwErr = GetLastError();
640 AssertMsgFailed(("OpenService failed! LastError=%Rwa\n", dwErr));
641 rc = RTErrConvertFromWin32(dwErr);
642 }
643 if (!CloseServiceHandle(hSMgr))
644 AssertFailed();
645
646 return rc;
647}
648
649#endif /* !IN_SUP_HARDENED_R3 */
650
651DECLHIDDEN(int) suplibOsTerm(PSUPLIBDATA pThis)
652{
653 /*
654 * Check if we're inited at all.
655 */
656 if (pThis->hDevice != NULL)
657 {
658 NTSTATUS rcNt = NtClose((HANDLE)pThis->hDevice);
659 Assert(NT_SUCCESS(rcNt)); RT_NOREF(rcNt);
660 pThis->hDevice = NIL_RTFILE; /* yes, that's right */
661 }
662
663 return VINF_SUCCESS;
664}
665
666#ifndef IN_SUP_HARDENED_R3
667
668DECLHIDDEN(int) suplibOsIOCtl(PSUPLIBDATA pThis, uintptr_t uFunction, void *pvReq, size_t cbReq)
669{
670 RT_NOREF1(cbReq);
671
672 /*
673 * Issue the device I/O control.
674 */
675 PSUPREQHDR pHdr = (PSUPREQHDR)pvReq;
676 Assert(cbReq == RT_MAX(pHdr->cbIn, pHdr->cbOut));
677# ifdef USE_NT_DEVICE_IO_CONTROL_FILE
678 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
679 NTSTATUS rcNt = NtDeviceIoControlFile((HANDLE)pThis->hDevice, NULL /*hEvent*/, NULL /*pfnApc*/, NULL /*pvApcCtx*/, &Ios,
680 (ULONG)uFunction,
681 pvReq /*pvInput */, pHdr->cbIn /* cbInput */,
682 pvReq /*pvOutput*/, pHdr->cbOut /* cbOutput */);
683 if (NT_SUCCESS(rcNt))
684 {
685 if (NT_SUCCESS(Ios.Status))
686 return VINF_SUCCESS;
687 rcNt = Ios.Status;
688 }
689 return suplibConvertNtStatus(rcNt);
690
691# else
692 DWORD cbReturned = (ULONG)pHdr->cbOut;
693 if (DeviceIoControl((HANDLE)pThis->hDevice, uFunction, pvReq, pHdr->cbIn, pvReq, cbReturned, &cbReturned, NULL))
694 return 0;
695 return suplibConvertWin32Err(GetLastError());
696# endif
697}
698
699
700DECLHIDDEN(int) suplibOsIOCtlFast(PSUPLIBDATA pThis, uintptr_t uFunction, uintptr_t idCpu)
701{
702 /*
703 * Issue device I/O control.
704 */
705# ifdef USE_NT_DEVICE_IO_CONTROL_FILE
706 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
707 NTSTATUS rcNt = NtDeviceIoControlFile((HANDLE)pThis->hDevice, NULL /*hEvent*/, NULL /*pfnApc*/, NULL /*pvApcCtx*/, &Ios,
708 (ULONG)uFunction,
709 NULL /*pvInput */, 0 /* cbInput */,
710 (PVOID)idCpu /*pvOutput*/, 0 /* cbOutput */);
711 if (NT_SUCCESS(rcNt))
712 {
713 if (NT_SUCCESS(Ios.Status))
714 return VINF_SUCCESS;
715 rcNt = Ios.Status;
716 }
717 return suplibConvertNtStatus(rcNt);
718# else
719 DWORD cbReturned = 0;
720 if (DeviceIoControl((HANDLE)pThis->hDevice, uFunction, NULL, 0, (LPVOID)idCpu, 0, &cbReturned, NULL))
721 return VINF_SUCCESS;
722 return suplibConvertWin32Err(GetLastError());
723# endif
724}
725
726
727DECLHIDDEN(int) suplibOsPageAlloc(PSUPLIBDATA pThis, size_t cPages, void **ppvPages)
728{
729 NOREF(pThis);
730
731 /*
732 * Do some one-time init here wrt large pages.
733 *
734 * Large pages requires the SeLockMemoryPrivilege, which by default (Win10,
735 * Win11) isn't even enabled and must be gpedit'ed to be adjustable here.
736 */
737 if (!(cPages & 511))
738 {
739 static int volatile s_fCanDoLargePages = -1;
740 int fCanDoLargePages = s_fCanDoLargePages;
741 if (s_fCanDoLargePages != -1)
742 { /* likely */ }
743 else if (RTEnvExistsUtf8("VBOX_DO_NOT_USE_LARGE_PAGES")) /** @todo add flag for this instead? */
744 s_fCanDoLargePages = fCanDoLargePages = 0;
745 else
746 {
747 HANDLE hToken = NULL;
748 if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken))
749 {
750 union
751 {
752 TOKEN_PRIVILEGES s;
753 uint8_t abPadding[RT_UOFFSETOF(TOKEN_PRIVILEGES, Privileges) + sizeof(LUID_AND_ATTRIBUTES)];
754 } Privileges;
755 RT_ZERO(Privileges);
756 Privileges.s.PrivilegeCount = 1;
757 Privileges.s.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
758 if (LookupPrivilegeValueW(NULL, L"SeLockMemoryPrivilege", &Privileges.s.Privileges[0].Luid))
759 AdjustTokenPrivileges(hToken, FALSE, &Privileges.s, 0, NULL, NULL);
760 else
761 AssertFailed();
762 CloseHandle(hToken);
763 }
764 else
765 AssertFailed();
766 s_fCanDoLargePages = fCanDoLargePages = -2;
767 }
768
769 /*
770 * Try allocate with large pages.
771 */
772 if (fCanDoLargePages != 0)
773 {
774 *ppvPages = VirtualAlloc(NULL, (size_t)cPages << PAGE_SHIFT, MEM_COMMIT | MEM_LARGE_PAGES, PAGE_EXECUTE_READWRITE);
775 if (*ppvPages)
776 {
777 if (fCanDoLargePages == -2)
778 {
779 s_fCanDoLargePages = 1;
780 LogRel(("SUPLib: MEM_LARGE_PAGES works!\n"));
781 }
782 LogRel2(("SUPLib: MEM_LARGE_PAGES for %p LB %p\n", *ppvPages, (size_t)cPages << PAGE_SHIFT));
783 return VINF_SUCCESS;
784 }
785
786 /* This can happen if the above AdjustTokenPrivileges failed (non-admin
787 user), or if the privilege isn't present in the token (need gpedit). */
788 if (GetLastError() == ERROR_PRIVILEGE_NOT_HELD)
789 {
790 LogRel(("SUPLib: MEM_LARGE_PAGES privilege not held.\n"));
791 s_fCanDoLargePages = 0;
792 }
793 else
794 LogRel2(("SUPLib: MEM_LARGE_PAGES allocation failed with odd status: %u\n", GetLastError()));
795 }
796 }
797
798 /*
799 * Do a regular allocation w/o large pages.
800 */
801 *ppvPages = VirtualAlloc(NULL, (size_t)cPages << PAGE_SHIFT, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
802 if (*ppvPages)
803 return VINF_SUCCESS;
804 return RTErrConvertFromWin32(GetLastError());
805}
806
807
808DECLHIDDEN(int) suplibOsPageFree(PSUPLIBDATA pThis, void *pvPages, size_t /* cPages */)
809{
810 NOREF(pThis);
811 if (VirtualFree(pvPages, 0, MEM_RELEASE))
812 return VINF_SUCCESS;
813 return RTErrConvertFromWin32(GetLastError());
814}
815
816
817DECLHIDDEN(bool) suplibOsIsNemSupportedWhenNoVtxOrAmdV(void)
818{
819# if ARCH_BITS == 64
820 /*
821 * Check that we're in a VM.
822 */
823 if (!ASMHasCpuId())
824 return false;
825 if (!ASMIsValidStdRange(ASMCpuId_EAX(0)))
826 return false;
827 if (!(ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_HVP))
828 return false;
829
830 /*
831 * Try load WinHvPlatform and resolve API for checking.
832 * Note! The two size_t arguments and the ssize_t one are all too big, but who cares.
833 */
834 RTLDRMOD hLdrMod = NIL_RTLDRMOD;
835 int rc = RTLdrLoadSystem("WinHvPlatform.dll", false, &hLdrMod);
836 if (RT_FAILURE(rc))
837 return false;
838
839 bool fRet = false;
840 typedef HRESULT (WINAPI *PFNWHVGETCAPABILITY)(ssize_t, void *, size_t, size_t *);
841 PFNWHVGETCAPABILITY pfnWHvGetCapability = (PFNWHVGETCAPABILITY)RTLdrGetFunction(hLdrMod, "WHvGetCapability");
842 if (pfnWHvGetCapability)
843 {
844 /*
845 * Query the API.
846 */
847 union
848 {
849 BOOL fHypervisorPresent;
850 uint64_t u64Padding;
851 } Caps;
852 RT_ZERO(Caps);
853 size_t cbRetIgn = 0;
854 HRESULT hrc = pfnWHvGetCapability(0 /*WHvCapabilityCodeHypervisorPresent*/, &Caps, sizeof(Caps), &cbRetIgn);
855 if (SUCCEEDED(hrc) && Caps.fHypervisorPresent)
856 fRet = true;
857 }
858
859 RTLdrClose(hLdrMod);
860 return fRet;
861# else
862 return false;
863#endif
864}
865
866
867# ifndef USE_NT_DEVICE_IO_CONTROL_FILE
868/**
869 * Converts a supdrv win32 error code to an IPRT status code.
870 *
871 * @returns corresponding IPRT error code.
872 * @param rc Win32 error code.
873 */
874static int suplibConvertWin32Err(int rc)
875{
876 /* Conversion program (link with ntdll.lib from ddk):
877 #define _WIN32_WINNT 0x0501
878 #include <iprt/win/windows.h>
879 #include <ntstatus.h>
880 #include <winternl.h>
881 #include <stdio.h>
882
883 int main()
884 {
885 #define CONVERT(a) printf(#a " %#x -> %d\n", a, RtlNtStatusToDosError((a)))
886 CONVERT(STATUS_SUCCESS);
887 CONVERT(STATUS_NOT_SUPPORTED);
888 CONVERT(STATUS_INVALID_PARAMETER);
889 CONVERT(STATUS_UNKNOWN_REVISION);
890 CONVERT(STATUS_INVALID_HANDLE);
891 CONVERT(STATUS_INVALID_ADDRESS);
892 CONVERT(STATUS_NOT_LOCKED);
893 CONVERT(STATUS_IMAGE_ALREADY_LOADED);
894 CONVERT(STATUS_ACCESS_DENIED);
895 CONVERT(STATUS_REVISION_MISMATCH);
896
897 return 0;
898 }
899 */
900
901 switch (rc)
902 {
903 //case 0: return STATUS_SUCCESS;
904 case 0: return VINF_SUCCESS;
905 case ERROR_NOT_SUPPORTED: return VERR_GENERAL_FAILURE;
906 case ERROR_INVALID_PARAMETER: return VERR_INVALID_PARAMETER;
907 case ERROR_UNKNOWN_REVISION: return VERR_INVALID_MAGIC;
908 case ERROR_INVALID_HANDLE: return VERR_INVALID_HANDLE;
909 case ERROR_UNEXP_NET_ERR: return VERR_INVALID_POINTER;
910 case ERROR_NOT_LOCKED: return VERR_LOCK_FAILED;
911 case ERROR_SERVICE_ALREADY_RUNNING: return VERR_ALREADY_LOADED;
912 case ERROR_ACCESS_DENIED: return VERR_PERMISSION_DENIED;
913 case ERROR_REVISION_MISMATCH: return VERR_VERSION_MISMATCH;
914 }
915
916 /* fall back on the default conversion. */
917 return RTErrConvertFromWin32(rc);
918}
919# else
920/**
921 * Reverse of VBoxDrvNtErr2NtStatus
922 * returns VBox status code.
923 * @param rcNt NT status code.
924 */
925static int suplibConvertNtStatus(NTSTATUS rcNt)
926{
927 switch (rcNt)
928 {
929 case STATUS_SUCCESS: return VINF_SUCCESS;
930 case STATUS_NOT_SUPPORTED: return VERR_GENERAL_FAILURE;
931 case STATUS_INVALID_PARAMETER: return VERR_INVALID_PARAMETER;
932 case STATUS_UNKNOWN_REVISION: return VERR_INVALID_MAGIC;
933 case STATUS_INVALID_HANDLE: return VERR_INVALID_HANDLE;
934 case STATUS_INVALID_ADDRESS: return VERR_INVALID_POINTER;
935 case STATUS_NOT_LOCKED: return VERR_LOCK_FAILED;
936 case STATUS_IMAGE_ALREADY_LOADED: return VERR_ALREADY_LOADED;
937 case STATUS_ACCESS_DENIED: return VERR_PERMISSION_DENIED;
938 case STATUS_REVISION_MISMATCH: return VERR_VERSION_MISMATCH;
939 }
940
941 /* See VBoxDrvNtErr2NtStatus. */
942 if (SUP_NT_STATUS_IS_VBOX(rcNt))
943 return SUP_NT_STATUS_TO_VBOX(rcNt);
944
945 /* Fall back on IPRT for the rest. */
946 return RTErrConvertFromNtStatus(rcNt);
947}
948# endif
949
950#endif /* !IN_SUP_HARDENED_R3 */
951
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