VirtualBox

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

Last change on this file was 98650, checked in by vboxsync, 15 months ago

VMM,SUPLib: Adjustments for running tstPDMQueue in driverless mode on hardened windows builds. This adds a fFlags parameter to VMR3Create and defines VMCREATE_F_DRIVERLESS, allowing it to switch between default and driverless suplib initialization. The default CFGM config constructor was amended to enable the IEM fallback option by default (only relevant to amd64/x86). [fix]

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

© 2023 Oracle
ContactPrivacy policyTerms of Use