VirtualBox

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

Last change on this file since 98103 was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use