VirtualBox

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

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

iprt/asm-amd64-x86.h: Split out some non-assembly functions that related more to x86.h than to asm.h, changing the function prefix from ASM to RTX86. bugref:9898

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.7 KB
Line 
1/* $Id: SUPLib-win.cpp 93515 2022-01-31 22:17:19Z vboxsync $ */
2/** @file
3 * VirtualBox Support Library - Windows NT specific parts.
4 */
5
6/*
7 * Copyright (C) 2006-2022 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 "VBoxSup"
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, uint32_t fFlags, 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) * (fFlags & SUPR3INIT_F_UNRESTRICTED ? 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 = RT_BOOL(fFlags & SUPR3INIT_F_UNRESTRICTED);
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("\\VBoxSup.sys"));
317 if (RT_SUCCESS(rc))
318 {
319 strcat(szDriver, "\\VBoxSup.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 int rcRet = VINF_SUCCESS;
434 SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_CHANGE_CONFIG);
435 DWORD dwErr = GetLastError();
436 AssertMsg(hSMgr, ("OpenSCManager(,,delete) failed rc=%d\n", dwErr));
437 if (hSMgr)
438 {
439 /*
440 * Old service name.
441 */
442 SC_HANDLE hService = OpenService(hSMgr, "VBoxDrv", DELETE);
443 if (hService)
444 {
445 if (!DeleteService(hService))
446 {
447 dwErr = GetLastError();
448 AssertMsgFailed(("DeleteService failed for VBoxDrv dwErr=%Rwa\n", dwErr));
449 rcRet = RTErrConvertFromWin32(dwErr);
450 }
451 CloseServiceHandle(hService);
452 }
453 else
454 {
455 dwErr = GetLastError();
456 if (dwErr != ERROR_SERVICE_DOES_NOT_EXIST)
457 {
458 AssertMsgFailed(("OpenService failed for VBoxDrv dwErr=%Rwa\n", dwErr));
459 rcRet = RTErrConvertFromWin32(dwErr);
460 }
461 }
462
463 /*
464 * The new service.
465 */
466 hService = OpenService(hSMgr, SERVICE_NAME, DELETE);
467 if (hService)
468 {
469 if (!DeleteService(hService))
470 {
471 dwErr = GetLastError();
472 AssertMsgFailed(("DeleteService for " SERVICE_NAME " failed dwErr=%Rwa\n", dwErr));
473 rcRet = RTErrConvertFromWin32(dwErr);
474 }
475 CloseServiceHandle(hService);
476 }
477 else
478 {
479 dwErr = GetLastError();
480 if (dwErr != ERROR_SERVICE_DOES_NOT_EXIST)
481 {
482 AssertMsgFailed(("OpenService failed for " SERVICE_NAME " dwErr=%Rwa\n", dwErr));
483 rcRet = RTErrConvertFromWin32(dwErr);
484 }
485 }
486 CloseServiceHandle(hSMgr);
487 }
488 else
489 rcRet = RTErrConvertFromWin32(dwErr);
490 return rcRet;
491}
492
493#if 0
494/**
495 * Creates the service.
496 *
497 * @returns 0 on success.
498 * @returns -1 on failure.
499 */
500static int suplibOsUpdateService(void)
501{
502 /*
503 * Assume it didn't exist, so we'll create the service.
504 */
505 SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_CHANGE_CONFIG);
506 DWORD LastError = GetLastError(); NOREF(LastError);
507 AssertMsg(hSMgr, ("OpenSCManager(,,delete) failed LastError=%Rwa\n", LastError));
508 if (hSMgr)
509 {
510 SC_HANDLE hService = OpenService(hSMgr, SERVICE_NAME, SERVICE_CHANGE_CONFIG);
511 if (hService)
512 {
513 char szDriver[RTPATH_MAX];
514 int rc = RTPathExecDir(szDriver, sizeof(szDriver) - sizeof("\\VBoxSup.sys"));
515 if (RT_SUCCESS(rc))
516 {
517 strcat(szDriver, "\\VBoxSup.sys");
518
519 SC_LOCK hLock = LockServiceDatabase(hSMgr);
520 if (ChangeServiceConfig(hService,
521 SERVICE_KERNEL_DRIVER,
522 SERVICE_DEMAND_START,
523 SERVICE_ERROR_NORMAL,
524 szDriver,
525 NULL, NULL, NULL, NULL, NULL, NULL))
526 {
527
528 UnlockServiceDatabase(hLock);
529 CloseServiceHandle(hService);
530 CloseServiceHandle(hSMgr);
531 return 0;
532 }
533 else
534 {
535 DWORD LastError = GetLastError(); NOREF(LastError);
536 AssertMsgFailed(("ChangeServiceConfig failed LastError=%Rwa\n", LastError));
537 }
538 }
539 UnlockServiceDatabase(hLock);
540 CloseServiceHandle(hService);
541 }
542 else
543 {
544 DWORD LastError = GetLastError(); NOREF(LastError);
545 AssertMsgFailed(("OpenService failed LastError=%Rwa\n", LastError));
546 }
547 CloseServiceHandle(hSMgr);
548 }
549 return -1;
550}
551#endif
552
553
554/**
555 * Attempts to start the service, creating it if necessary.
556 *
557 * @returns VBox status code.
558 */
559static int suplibOsStartService(void)
560{
561 /*
562 * Check if the driver service is there.
563 */
564 SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_QUERY_STATUS | SERVICE_START);
565 if (hSMgr == NULL)
566 {
567 DWORD dwErr = GetLastError();
568 AssertMsgFailed(("couldn't open service manager in SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS mode! (dwErr=%d)\n", dwErr));
569 return RTErrConvertFromWin32(dwErr);
570 }
571
572 /*
573 * Try open our service to check it's status.
574 */
575 SC_HANDLE hService = OpenService(hSMgr, SERVICE_NAME, SERVICE_QUERY_STATUS | SERVICE_START);
576 if (!hService)
577 {
578 /*
579 * Create the service.
580 */
581 int rc = suplibOsCreateService();
582 if (RT_FAILURE(rc))
583 return rc;
584
585 /*
586 * Try open the service.
587 */
588 hService = OpenService(hSMgr, SERVICE_NAME, SERVICE_QUERY_STATUS | SERVICE_START);
589 }
590
591 /*
592 * Check if open and on demand create succeeded.
593 */
594 int rc;
595 if (hService)
596 {
597
598 /*
599 * Query service status to see if we need to start it or not.
600 */
601 SERVICE_STATUS Status;
602 BOOL fRc = QueryServiceStatus(hService, &Status);
603 Assert(fRc); NOREF(fRc);
604 if (Status.dwCurrentState == SERVICE_RUNNING)
605 rc = VINF_ALREADY_INITIALIZED;
606 else
607 {
608 if (Status.dwCurrentState == SERVICE_START_PENDING)
609 rc = VINF_SUCCESS;
610 else
611 {
612 /*
613 * Start it.
614 */
615 if (StartService(hService, 0, NULL))
616 rc = VINF_SUCCESS;
617 else
618 {
619 DWORD dwErr = GetLastError();
620 AssertMsg(fRc, ("StartService failed with dwErr=%Rwa\n", dwErr));
621 rc = RTErrConvertFromWin32(dwErr);
622 }
623 }
624
625 /*
626 * Wait for the service to finish starting.
627 * We'll wait for 10 seconds then we'll give up.
628 */
629 QueryServiceStatus(hService, &Status);
630 if (Status.dwCurrentState == SERVICE_START_PENDING)
631 {
632 int iWait;
633 for (iWait = 100; iWait > 0 && Status.dwCurrentState == SERVICE_START_PENDING; iWait--)
634 {
635 Sleep(100);
636 QueryServiceStatus(hService, &Status);
637 }
638 DWORD dwErr = GetLastError(); NOREF(dwErr);
639 AssertMsg(Status.dwCurrentState != SERVICE_RUNNING,
640 ("Failed to start. dwErr=%Rwa iWait=%d status=%d\n", dwErr, iWait, Status.dwCurrentState));
641 }
642
643 if (Status.dwCurrentState == SERVICE_RUNNING)
644 rc = VINF_SUCCESS;
645 else if (RT_SUCCESS_NP(rc))
646 rc = VERR_GENERAL_FAILURE;
647 }
648
649 /*
650 * Close open handles.
651 */
652 CloseServiceHandle(hService);
653 }
654 else
655 {
656 DWORD dwErr = GetLastError();
657 AssertMsgFailed(("OpenService failed! LastError=%Rwa\n", dwErr));
658 rc = RTErrConvertFromWin32(dwErr);
659 }
660 if (!CloseServiceHandle(hSMgr))
661 AssertFailed();
662
663 return rc;
664}
665
666#endif /* !IN_SUP_HARDENED_R3 */
667
668DECLHIDDEN(int) suplibOsTerm(PSUPLIBDATA pThis)
669{
670 /*
671 * Check if we're inited at all.
672 */
673 if (pThis->hDevice != NULL)
674 {
675 NTSTATUS rcNt = NtClose((HANDLE)pThis->hDevice);
676 Assert(NT_SUCCESS(rcNt)); RT_NOREF(rcNt);
677 pThis->hDevice = NIL_RTFILE; /* yes, that's right */
678 }
679
680 return VINF_SUCCESS;
681}
682
683#ifndef IN_SUP_HARDENED_R3
684
685DECLHIDDEN(int) suplibOsIOCtl(PSUPLIBDATA pThis, uintptr_t uFunction, void *pvReq, size_t cbReq)
686{
687 RT_NOREF1(cbReq);
688
689 /*
690 * Issue the device I/O control.
691 */
692 PSUPREQHDR pHdr = (PSUPREQHDR)pvReq;
693 Assert(cbReq == RT_MAX(pHdr->cbIn, pHdr->cbOut));
694# ifdef USE_NT_DEVICE_IO_CONTROL_FILE
695 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
696 NTSTATUS rcNt = NtDeviceIoControlFile((HANDLE)pThis->hDevice, NULL /*hEvent*/, NULL /*pfnApc*/, NULL /*pvApcCtx*/, &Ios,
697 (ULONG)uFunction,
698 pvReq /*pvInput */, pHdr->cbIn /* cbInput */,
699 pvReq /*pvOutput*/, pHdr->cbOut /* cbOutput */);
700 if (NT_SUCCESS(rcNt))
701 {
702 if (NT_SUCCESS(Ios.Status))
703 return VINF_SUCCESS;
704 rcNt = Ios.Status;
705 }
706 return suplibConvertNtStatus(rcNt);
707
708# else
709 DWORD cbReturned = (ULONG)pHdr->cbOut;
710 if (DeviceIoControl((HANDLE)pThis->hDevice, uFunction, pvReq, pHdr->cbIn, pvReq, cbReturned, &cbReturned, NULL))
711 return 0;
712 return suplibConvertWin32Err(GetLastError());
713# endif
714}
715
716
717DECLHIDDEN(int) suplibOsIOCtlFast(PSUPLIBDATA pThis, uintptr_t uFunction, uintptr_t idCpu)
718{
719 /*
720 * Issue device I/O control.
721 */
722# ifdef USE_NT_DEVICE_IO_CONTROL_FILE
723 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
724 NTSTATUS rcNt = NtDeviceIoControlFile((HANDLE)pThis->hDevice, NULL /*hEvent*/, NULL /*pfnApc*/, NULL /*pvApcCtx*/, &Ios,
725 (ULONG)uFunction,
726 NULL /*pvInput */, 0 /* cbInput */,
727 (PVOID)idCpu /*pvOutput*/, 0 /* cbOutput */);
728 if (NT_SUCCESS(rcNt))
729 {
730 if (NT_SUCCESS(Ios.Status))
731 return VINF_SUCCESS;
732 rcNt = Ios.Status;
733 }
734 return suplibConvertNtStatus(rcNt);
735# else
736 DWORD cbReturned = 0;
737 if (DeviceIoControl((HANDLE)pThis->hDevice, uFunction, NULL, 0, (LPVOID)idCpu, 0, &cbReturned, NULL))
738 return VINF_SUCCESS;
739 return suplibConvertWin32Err(GetLastError());
740# endif
741}
742
743
744DECLHIDDEN(int) suplibOsPageAlloc(PSUPLIBDATA pThis, size_t cPages, uint32_t fFlags, void **ppvPages)
745{
746 RT_NOREF(pThis, fFlags);
747
748 /*
749 * Do some one-time init here wrt large pages.
750 *
751 * Large pages requires the SeLockMemoryPrivilege, which by default (Win10,
752 * Win11) isn't even enabled and must be gpedit'ed to be adjustable here.
753 */
754 if (!(cPages & 511) && (fFlags & SUP_PAGE_ALLOC_F_LARGE_PAGES))
755 {
756 static int volatile s_fCanDoLargePages = -1;
757 int fCanDoLargePages = s_fCanDoLargePages;
758 if (s_fCanDoLargePages != -1)
759 { /* likely */ }
760 else if (RTEnvExistsUtf8("VBOX_DO_NOT_USE_LARGE_PAGES")) /** @todo add flag for this instead? */
761 s_fCanDoLargePages = fCanDoLargePages = 0;
762 else
763 {
764 HANDLE hToken = NULL;
765 if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken))
766 {
767 union
768 {
769 TOKEN_PRIVILEGES s;
770 uint8_t abPadding[RT_UOFFSETOF(TOKEN_PRIVILEGES, Privileges) + sizeof(LUID_AND_ATTRIBUTES)];
771 } Privileges;
772 RT_ZERO(Privileges);
773 Privileges.s.PrivilegeCount = 1;
774 Privileges.s.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
775 if (LookupPrivilegeValueW(NULL, L"SeLockMemoryPrivilege", &Privileges.s.Privileges[0].Luid))
776 AdjustTokenPrivileges(hToken, FALSE, &Privileges.s, 0, NULL, NULL);
777 else
778 AssertFailed();
779 CloseHandle(hToken);
780 }
781 else
782 AssertFailed();
783 s_fCanDoLargePages = fCanDoLargePages = -2;
784 }
785
786 /*
787 * Try allocate with large pages.
788 */
789 if (fCanDoLargePages != 0)
790 {
791 *ppvPages = VirtualAlloc(NULL, (size_t)cPages << PAGE_SHIFT, MEM_COMMIT | MEM_LARGE_PAGES, PAGE_EXECUTE_READWRITE);
792 if (*ppvPages)
793 {
794 if (fCanDoLargePages == -2)
795 {
796 s_fCanDoLargePages = 1;
797 LogRel(("SUPLib: MEM_LARGE_PAGES works!\n"));
798 }
799 LogRel2(("SUPLib: MEM_LARGE_PAGES for %p LB %p\n", *ppvPages, (size_t)cPages << PAGE_SHIFT));
800 return VINF_SUCCESS;
801 }
802
803 /* This can happen if the above AdjustTokenPrivileges failed (non-admin
804 user), or if the privilege isn't present in the token (need gpedit). */
805 if (GetLastError() == ERROR_PRIVILEGE_NOT_HELD)
806 {
807 LogRel(("SUPLib: MEM_LARGE_PAGES privilege not held.\n"));
808 s_fCanDoLargePages = 0;
809 }
810 else
811 LogRel2(("SUPLib: MEM_LARGE_PAGES allocation failed with odd status: %u\n", GetLastError()));
812 }
813 }
814
815 /*
816 * Do a regular allocation w/o large pages.
817 */
818 *ppvPages = VirtualAlloc(NULL, (size_t)cPages << PAGE_SHIFT, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
819 if (*ppvPages)
820 return VINF_SUCCESS;
821 return RTErrConvertFromWin32(GetLastError());
822}
823
824
825DECLHIDDEN(int) suplibOsPageFree(PSUPLIBDATA pThis, void *pvPages, size_t /* cPages */)
826{
827 NOREF(pThis);
828 if (VirtualFree(pvPages, 0, MEM_RELEASE))
829 return VINF_SUCCESS;
830 return RTErrConvertFromWin32(GetLastError());
831}
832
833
834DECLHIDDEN(bool) suplibOsIsNemSupportedWhenNoVtxOrAmdV(void)
835{
836# if ARCH_BITS == 64
837 /*
838 * Check that we're in a VM.
839 */
840 if (!ASMHasCpuId())
841 return false;
842 if (!RTX86IsValidStdRange(ASMCpuId_EAX(0)))
843 return false;
844 if (!(ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_HVP))
845 return false;
846
847 /*
848 * Try load WinHvPlatform and resolve API for checking.
849 * Note! The two size_t arguments and the ssize_t one are all too big, but who cares.
850 */
851 RTLDRMOD hLdrMod = NIL_RTLDRMOD;
852 int rc = RTLdrLoadSystem("WinHvPlatform.dll", false, &hLdrMod);
853 if (RT_FAILURE(rc))
854 return false;
855
856 bool fRet = false;
857 typedef HRESULT (WINAPI *PFNWHVGETCAPABILITY)(ssize_t, void *, size_t, size_t *);
858 PFNWHVGETCAPABILITY pfnWHvGetCapability = (PFNWHVGETCAPABILITY)RTLdrGetFunction(hLdrMod, "WHvGetCapability");
859 if (pfnWHvGetCapability)
860 {
861 /*
862 * Query the API.
863 */
864 union
865 {
866 BOOL fHypervisorPresent;
867 uint64_t u64Padding;
868 } Caps;
869 RT_ZERO(Caps);
870 size_t cbRetIgn = 0;
871 HRESULT hrc = pfnWHvGetCapability(0 /*WHvCapabilityCodeHypervisorPresent*/, &Caps, sizeof(Caps), &cbRetIgn);
872 if (SUCCEEDED(hrc) && Caps.fHypervisorPresent)
873 fRet = true;
874 }
875
876 RTLdrClose(hLdrMod);
877 return fRet;
878# else
879 return false;
880#endif
881}
882
883
884# ifndef USE_NT_DEVICE_IO_CONTROL_FILE
885/**
886 * Converts a supdrv win32 error code to an IPRT status code.
887 *
888 * @returns corresponding IPRT error code.
889 * @param rc Win32 error code.
890 */
891static int suplibConvertWin32Err(int rc)
892{
893 /* Conversion program (link with ntdll.lib from ddk):
894 #define _WIN32_WINNT 0x0501
895 #include <iprt/win/windows.h>
896 #include <ntstatus.h>
897 #include <winternl.h>
898 #include <stdio.h>
899
900 int main()
901 {
902 #define CONVERT(a) printf(#a " %#x -> %d\n", a, RtlNtStatusToDosError((a)))
903 CONVERT(STATUS_SUCCESS);
904 CONVERT(STATUS_NOT_SUPPORTED);
905 CONVERT(STATUS_INVALID_PARAMETER);
906 CONVERT(STATUS_UNKNOWN_REVISION);
907 CONVERT(STATUS_INVALID_HANDLE);
908 CONVERT(STATUS_INVALID_ADDRESS);
909 CONVERT(STATUS_NOT_LOCKED);
910 CONVERT(STATUS_IMAGE_ALREADY_LOADED);
911 CONVERT(STATUS_ACCESS_DENIED);
912 CONVERT(STATUS_REVISION_MISMATCH);
913
914 return 0;
915 }
916 */
917
918 switch (rc)
919 {
920 //case 0: return STATUS_SUCCESS;
921 case 0: return VINF_SUCCESS;
922 case ERROR_NOT_SUPPORTED: return VERR_GENERAL_FAILURE;
923 case ERROR_INVALID_PARAMETER: return VERR_INVALID_PARAMETER;
924 case ERROR_UNKNOWN_REVISION: return VERR_INVALID_MAGIC;
925 case ERROR_INVALID_HANDLE: return VERR_INVALID_HANDLE;
926 case ERROR_UNEXP_NET_ERR: return VERR_INVALID_POINTER;
927 case ERROR_NOT_LOCKED: return VERR_LOCK_FAILED;
928 case ERROR_SERVICE_ALREADY_RUNNING: return VERR_ALREADY_LOADED;
929 case ERROR_ACCESS_DENIED: return VERR_PERMISSION_DENIED;
930 case ERROR_REVISION_MISMATCH: return VERR_VERSION_MISMATCH;
931 }
932
933 /* fall back on the default conversion. */
934 return RTErrConvertFromWin32(rc);
935}
936# else
937/**
938 * Reverse of VBoxDrvNtErr2NtStatus
939 * returns VBox status code.
940 * @param rcNt NT status code.
941 */
942static int suplibConvertNtStatus(NTSTATUS rcNt)
943{
944 switch (rcNt)
945 {
946 case STATUS_SUCCESS: return VINF_SUCCESS;
947 case STATUS_NOT_SUPPORTED: return VERR_GENERAL_FAILURE;
948 case STATUS_INVALID_PARAMETER: return VERR_INVALID_PARAMETER;
949 case STATUS_UNKNOWN_REVISION: return VERR_INVALID_MAGIC;
950 case STATUS_INVALID_HANDLE: return VERR_INVALID_HANDLE;
951 case STATUS_INVALID_ADDRESS: return VERR_INVALID_POINTER;
952 case STATUS_NOT_LOCKED: return VERR_LOCK_FAILED;
953 case STATUS_IMAGE_ALREADY_LOADED: return VERR_ALREADY_LOADED;
954 case STATUS_ACCESS_DENIED: return VERR_PERMISSION_DENIED;
955 case STATUS_REVISION_MISMATCH: return VERR_VERSION_MISMATCH;
956 }
957
958 /* See VBoxDrvNtErr2NtStatus. */
959 if (SUP_NT_STATUS_IS_VBOX(rcNt))
960 return SUP_NT_STATUS_TO_VBOX(rcNt);
961
962 /* Fall back on IPRT for the rest. */
963 return RTErrConvertFromNtStatus(rcNt);
964}
965# endif
966
967#endif /* !IN_SUP_HARDENED_R3 */
968
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