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
RevLine 
[11725]1/* $Id: SUPLib-win.cpp 98650 2023-02-20 13:00:56Z vboxsync $ */
[1]2/** @file
[3542]3 * VirtualBox Support Library - Windows NT specific parts.
[1]4 */
5
6/*
[98103]7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[1]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
[5999]11 *
[96407]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 *
[5999]25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
[96407]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
[5999]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.
[96407]33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
[1]35 */
36
[57358]37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
[1]41#define LOG_GROUP LOG_GROUP_SUP
[11725]42#ifdef IN_SUP_HARDENED_R3
43# undef DEBUG /* Warning: disables RT_STRICT */
[51770]44# undef LOG_DISABLED
[11725]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
[49150]52#define USE_NT_DEVICE_IO_CONTROL_FILE
[51770]53#include <iprt/nt/nt-and-windows.h>
[1]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>
[72334]61#ifndef IN_SUP_HARDENED_R3
[92434]62# include <iprt/env.h>
[72326]63# include <iprt/x86.h>
64# include <iprt/ldr.h>
65#endif
[1]66#include <iprt/path.h>
67#include <iprt/string.h>
[10256]68#include "../SUPLibInternal.h"
69#include "../SUPDrvIOC.h"
[51770]70#ifdef VBOX_WITH_HARDENING
71# include "win/SUPHardenedVerify-win.h"
72#endif
[1]73
74
[57358]75/*********************************************************************************************************************************
76* Defined Constants And Macros *
77*********************************************************************************************************************************/
[1]78/** The support service name. */
[93239]79#define SERVICE_NAME "VBoxSup"
[1]80
81
[57358]82/*********************************************************************************************************************************
83* Internal Functions *
84*********************************************************************************************************************************/
[51770]85#ifndef IN_SUP_HARDENED_R3
[1]86static int suplibOsCreateService(void);
[11725]87//unused: static int suplibOsUpdateService(void);
[1]88static int suplibOsDeleteService(void);
89static int suplibOsStartService(void);
90static int suplibOsStopService(void);
[51770]91#endif
[49150]92#ifdef USE_NT_DEVICE_IO_CONTROL_FILE
93static int suplibConvertNtStatus(NTSTATUS rcNt);
94#else
[1]95static int suplibConvertWin32Err(int);
[49150]96#endif
[1]97
[57358]98
99/*********************************************************************************************************************************
100* Global Variables *
101*********************************************************************************************************************************/
[51978]102static bool g_fHardenedVerifyInited = false;
[1]103
[51978]104
[85129]105DECLHIDDEN(int) suplibOsHardenedVerifyInit(void)
[51978]106{
107 if (!g_fHardenedVerifyInited)
108 {
109#if defined(VBOX_WITH_HARDENING) && !defined(IN_SUP_HARDENED_R3) && !defined(IN_SUP_R3_STATIC)
[59810]110 supR3HardenedWinInitVersion(false /*fEarly*/);
[51978]111 int rc = supHardenedWinInitImageVerifier(NULL);
112 if (RT_FAILURE(rc))
113 return rc;
[52356]114 supR3HardenedWinResolveVerifyTrustApiAndHookThreadCreation(NULL);
[51978]115#endif
116 g_fHardenedVerifyInited = true;
117 }
118 return VINF_SUCCESS;
119}
120
121
[85129]122DECLHIDDEN(int) suplibOsHardenedVerifyTerm(void)
[51978]123{
124 /** @todo free resources... */
125 return VINF_SUCCESS;
126}
127
128
[92613]129DECLHIDDEN(int) suplibOsInit(PSUPLIBDATA pThis, bool fPreInited, uint32_t fFlags, SUPINITOP *penmWhat, PRTERRINFO pErrInfo)
[1]130{
131 /*
[51969]132 * Make sure the image verifier is fully initialized.
[1]133 */
[51978]134 int rc = suplibOsHardenedVerifyInit();
[51969]135 if (RT_FAILURE(rc))
[53002]136 return RTErrInfoSetF(pErrInfo, rc, "suplibOsHardenedVerifyInit failed: %Rrc", rc);
[51969]137
138 /*
139 * Done if of pre-inited.
140 */
[11725]141 if (fPreInited)
[51770]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
[51969]147 return VINF_SUCCESS;
[51770]148# endif
149#else
[11725]150 return VINF_SUCCESS;
[51770]151#endif
152 }
[1]153
[98644]154#if !defined(IN_SUP_HARDENED_R3)
[1]155 /*
[98644]156 * Driverless?
157 */
158 if (fFlags & SUPR3INIT_F_DRIVERLESS)
159 {
160 pThis->fDriverless = true;
161 return VINF_SUCCESS;
162 }
163#endif
164
165 /*
[1]166 * Try open the device.
167 */
[51770]168#ifndef IN_SUP_HARDENED_R3
169 uint32_t cTry = 0;
170#endif
171 HANDLE hDevice;
172 for (;;)
[1]173 {
[51770]174 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
[11725]175
[51770]176 static const WCHAR s_wszName[] = L"\\Device\\VBoxDrvU";
177 UNICODE_STRING NtName;
178 NtName.Buffer = (PWSTR)s_wszName;
[92613]179 NtName.Length = sizeof(s_wszName) - sizeof(WCHAR) * (fFlags & SUPR3INIT_F_UNRESTRICTED ? 2 : 1);
[51770]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,
[53036]188 GENERIC_READ | GENERIC_WRITE, /* No SYNCHRONIZE. */
[51770]189 &ObjAttr,
190 &Ios,
191 NULL /* Allocation Size*/,
192 FILE_ATTRIBUTE_NORMAL,
193 FILE_SHARE_READ | FILE_SHARE_WRITE,
194 FILE_OPEN,
[53036]195 FILE_NON_DIRECTORY_FILE, /* No FILE_SYNCHRONOUS_IO_NONALERT! */
[51770]196 NULL /*EaBuffer*/,
197 0 /*EaLength*/);
198 if (NT_SUCCESS(rcNt))
199 rcNt = Ios.Status;
[53002]200 if (NT_SUCCESS(rcNt))
[1]201 {
[51770]202 /*
[53002]203 * We're good.
[51770]204 */
[53002]205 pThis->hDevice = hDevice;
[92613]206 pThis->fUnrestricted = RT_BOOL(fFlags & SUPR3INIT_F_UNRESTRICTED);
[53002]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 }
[51770]221#endif
[53002]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. */
[84054]270 size_t cchPrefix;
271 if (RTErrIsKnown(rc))
272 cchPrefix = RTStrPrintf(pErrInfo->pszMsg, pErrInfo->cbMsg / 2, "Integrity error (%#x/%Rrc): ", rcNt, rc);
[53002]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')
[51770]279 {
[53002]280 pErrInfo->fFlags |= RTERRINFO_FLAGS_SET;
281 pErrInfo->rc = rc;
282 *penmWhat = kSupInitOp_Integrity;
[1]283 }
[53002]284 else
285 pErrInfo->pszMsg[0] = '\0';
[1]286 }
[98644]287
[98650]288#else
289 RT_NOREF1(penmWhat);
290
[98644]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 }
[53002]302#endif
303 return rc;
[1]304 }
305}
306
[51978]307
[11725]308#ifndef IN_SUP_HARDENED_R3
309
[85129]310DECLHIDDEN(int) suplibOsInstall(void)
[1]311{
[52000]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;
[1]320}
321
322
[85129]323DECLHIDDEN(int) suplibOsUninstall(void)
[1]324{
325 int rc = suplibOsStopService();
[52000]326 if (RT_SUCCESS(rc))
[1]327 rc = suplibOsDeleteService();
328 return rc;
329}
330
331
332/**
333 * Creates the service.
334 *
[52000]335 * @returns VBox status code.
336 * @retval VWRN_ALREADY_EXISTS if it already exists.
[1]337 */
[11725]338static int suplibOsCreateService(void)
[1]339{
340 /*
341 * Assume it didn't exist, so we'll create the service.
342 */
[52000]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)
[1]348 {
349 char szDriver[RTPATH_MAX];
[93239]350 rc = RTPathExecDir(szDriver, sizeof(szDriver) - sizeof("\\VBoxSup.sys"));
[13835]351 if (RT_SUCCESS(rc))
[1]352 {
[93239]353 strcat(szDriver, "\\VBoxSup.sys");
[1]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);
[52000]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 }
[1]376 }
377 CloseServiceHandle(hSMgrCreate);
378 }
[52000]379 else
380 rc = RTErrConvertFromWin32(GetLastError());
381 return rc;
[1]382}
383
[11725]384
[1]385/**
386 * Stops a possibly running service.
387 *
[52000]388 * @returns VBox status code.
[1]389 */
[11725]390static int suplibOsStopService(void)
[1]391{
392 /*
393 * Assume it didn't exist, so we'll create the service.
394 */
[52000]395 int rc;
[1]396 SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_STOP | SERVICE_QUERY_STATUS);
[52000]397 DWORD dwErr = GetLastError();
398 AssertMsg(hSMgr, ("OpenSCManager(,,delete) failed dwErr=%d\n", dwErr));
[1]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)
[52000]410 rc = VINF_SUCCESS;
[1]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)
[52000]420 rc = VINF_SUCCESS;
[1]421 else
[52000]422 {
423 AssertMsgFailed(("Failed to stop service. status=%d\n", Status.dwCurrentState));
424 rc = VERR_GENERAL_FAILURE;
425 }
[1]426 }
427 else
428 {
[52000]429 dwErr = GetLastError();
[67493]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 }
[1]438 }
439 CloseServiceHandle(hService);
440 }
441 else
442 {
[52000]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 }
[1]451 }
452 CloseServiceHandle(hSMgr);
453 }
[52844]454 else
455 rc = RTErrConvertFromWin32(dwErr);
[1]456 return rc;
457}
458
459
460/**
461 * Deletes the service.
462 *
[52000]463 * @returns VBox status code.
[1]464 */
465int suplibOsDeleteService(void)
466{
[93239]467 int rcRet = VINF_SUCCESS;
[1]468 SC_HANDLE hSMgr = OpenSCManager(NULL, NULL, SERVICE_CHANGE_CONFIG);
[52000]469 DWORD dwErr = GetLastError();
470 AssertMsg(hSMgr, ("OpenSCManager(,,delete) failed rc=%d\n", dwErr));
[1]471 if (hSMgr)
472 {
[93239]473 /*
474 * Old service name.
475 */
476 SC_HANDLE hService = OpenService(hSMgr, "VBoxDrv", DELETE);
[1]477 if (hService)
478 {
[93239]479 if (!DeleteService(hService))
[1]480 {
[52000]481 dwErr = GetLastError();
[93239]482 AssertMsgFailed(("DeleteService failed for VBoxDrv dwErr=%Rwa\n", dwErr));
483 rcRet = RTErrConvertFromWin32(dwErr);
[1]484 }
485 CloseServiceHandle(hService);
486 }
487 else
488 {
[52000]489 dwErr = GetLastError();
[93239]490 if (dwErr != ERROR_SERVICE_DOES_NOT_EXIST)
[52000]491 {
[93239]492 AssertMsgFailed(("OpenService failed for VBoxDrv dwErr=%Rwa\n", dwErr));
493 rcRet = RTErrConvertFromWin32(dwErr);
[52000]494 }
[1]495 }
[93239]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 }
[1]520 CloseServiceHandle(hSMgr);
521 }
[62675]522 else
[93239]523 rcRet = RTErrConvertFromWin32(dwErr);
524 return rcRet;
[1]525}
526
527#if 0
528/**
529 * Creates the service.
530 *
531 * @returns 0 on success.
532 * @returns -1 on failure.
533 */
[11725]534static int suplibOsUpdateService(void)
[1]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];
[93239]548 int rc = RTPathExecDir(szDriver, sizeof(szDriver) - sizeof("\\VBoxSup.sys"));
[13835]549 if (RT_SUCCESS(rc))
[1]550 {
[93239]551 strcat(szDriver, "\\VBoxSup.sys");
[1]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
[11725]587
[1]588/**
589 * Attempts to start the service, creating it if necessary.
590 *
[52000]591 * @returns VBox status code.
[1]592 */
[11725]593static int suplibOsStartService(void)
[1]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 {
[52000]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);
[1]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();
[52000]616 if (RT_FAILURE(rc))
[1]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 */
[52000]628 int rc;
[1]629 if (hService)
630 {
631
632 /*
633 * Query service status to see if we need to start it or not.
634 */
[52000]635 SERVICE_STATUS Status;
[1]636 BOOL fRc = QueryServiceStatus(hService, &Status);
[62675]637 Assert(fRc); NOREF(fRc);
[52000]638 if (Status.dwCurrentState == SERVICE_RUNNING)
639 rc = VINF_ALREADY_INITIALIZED;
640 else
[1]641 {
[52000]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
[1]659 /*
[52000]660 * Wait for the service to finish starting.
661 * We'll wait for 10 seconds then we'll give up.
[1]662 */
[52000]663 QueryServiceStatus(hService, &Status);
664 if (Status.dwCurrentState == SERVICE_START_PENDING)
[1]665 {
[52000]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));
[1]675 }
[52000]676
677 if (Status.dwCurrentState == SERVICE_RUNNING)
678 rc = VINF_SUCCESS;
679 else if (RT_SUCCESS_NP(rc))
680 rc = VERR_GENERAL_FAILURE;
[1]681 }
682
683 /*
684 * Close open handles.
685 */
686 CloseServiceHandle(hService);
687 }
688 else
689 {
[52000]690 DWORD dwErr = GetLastError();
691 AssertMsgFailed(("OpenService failed! LastError=%Rwa\n", dwErr));
692 rc = RTErrConvertFromWin32(dwErr);
[1]693 }
694 if (!CloseServiceHandle(hSMgr))
695 AssertFailed();
696
697 return rc;
698}
[92434]699
[66573]700#endif /* !IN_SUP_HARDENED_R3 */
[1]701
[85129]702DECLHIDDEN(int) suplibOsTerm(PSUPLIBDATA pThis)
[1]703{
704 /*
[33540]705 * Check if we're inited at all.
[1]706 */
[37596]707 if (pThis->hDevice != NULL)
[1]708 {
[66654]709 NTSTATUS rcNt = NtClose((HANDLE)pThis->hDevice);
[66655]710 Assert(NT_SUCCESS(rcNt)); RT_NOREF(rcNt);
[37596]711 pThis->hDevice = NIL_RTFILE; /* yes, that's right */
[1]712 }
713
[11725]714 return VINF_SUCCESS;
[1]715}
716
[66573]717#ifndef IN_SUP_HARDENED_R3
718
[85129]719DECLHIDDEN(int) suplibOsIOCtl(PSUPLIBDATA pThis, uintptr_t uFunction, void *pvReq, size_t cbReq)
[1]720{
[62675]721 RT_NOREF1(cbReq);
722
[1]723 /*
[4800]724 * Issue the device I/O control.
[1]725 */
[4800]726 PSUPREQHDR pHdr = (PSUPREQHDR)pvReq;
727 Assert(cbReq == RT_MAX(pHdr->cbIn, pHdr->cbOut));
[49150]728# ifdef USE_NT_DEVICE_IO_CONTROL_FILE
[71198]729 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
[49150]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
[4800]743 DWORD cbReturned = (ULONG)pHdr->cbOut;
[11725]744 if (DeviceIoControl((HANDLE)pThis->hDevice, uFunction, pvReq, pHdr->cbIn, pvReq, cbReturned, &cbReturned, NULL))
[1]745 return 0;
746 return suplibConvertWin32Err(GetLastError());
[49150]747# endif
[1]748}
749
750
[85129]751DECLHIDDEN(int) suplibOsIOCtlFast(PSUPLIBDATA pThis, uintptr_t uFunction, uintptr_t idCpu)
[2515]752{
753 /*
754 * Issue device I/O control.
755 */
[49150]756# ifdef USE_NT_DEVICE_IO_CONTROL_FILE
[71198]757 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
[49150]758 NTSTATUS rcNt = NtDeviceIoControlFile((HANDLE)pThis->hDevice, NULL /*hEvent*/, NULL /*pfnApc*/, NULL /*pvApcCtx*/, &Ios,
759 (ULONG)uFunction,
[49213]760 NULL /*pvInput */, 0 /* cbInput */,
761 (PVOID)idCpu /*pvOutput*/, 0 /* cbOutput */);
[49150]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
[10736]770 DWORD cbReturned = 0;
[13858]771 if (DeviceIoControl((HANDLE)pThis->hDevice, uFunction, NULL, 0, (LPVOID)idCpu, 0, &cbReturned, NULL))
[10736]772 return VINF_SUCCESS;
[2515]773 return suplibConvertWin32Err(GetLastError());
[49150]774# endif
[2515]775}
776
777
[92556]778DECLHIDDEN(int) suplibOsPageAlloc(PSUPLIBDATA pThis, size_t cPages, uint32_t fFlags, void **ppvPages)
[1]779{
[92556]780 RT_NOREF(pThis, fFlags);
[92434]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 */
[92556]788 if (!(cPages & 511) && (fFlags & SUP_PAGE_ALLOC_F_LARGE_PAGES))
[92434]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 */
[1]852 *ppvPages = VirtualAlloc(NULL, (size_t)cPages << PAGE_SHIFT, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
853 if (*ppvPages)
854 return VINF_SUCCESS;
[49150]855 return RTErrConvertFromWin32(GetLastError());
[1]856}
857
858
[85129]859DECLHIDDEN(int) suplibOsPageFree(PSUPLIBDATA pThis, void *pvPages, size_t /* cPages */)
[1]860{
[11725]861 NOREF(pThis);
[1]862 if (VirtualFree(pvPages, 0, MEM_RELEASE))
863 return VINF_SUCCESS;
[49150]864 return RTErrConvertFromWin32(GetLastError());
[1]865}
866
867
[85129]868DECLHIDDEN(bool) suplibOsIsNemSupportedWhenNoVtxOrAmdV(void)
[72326]869{
870# if ARCH_BITS == 64
871 /*
872 * Check that we're in a VM.
873 */
874 if (!ASMHasCpuId())
875 return false;
[93515]876 if (!RTX86IsValidStdRange(ASMCpuId_EAX(0)))
[72326]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
[49150]918# ifndef USE_NT_DEVICE_IO_CONTROL_FILE
[1]919/**
[25465]920 * Converts a supdrv win32 error code to an IPRT status code.
[1]921 *
[25465]922 * @returns corresponding IPRT error code.
[1]923 * @param rc Win32 error code.
924 */
[11725]925static int suplibConvertWin32Err(int rc)
[1]926{
927 /* Conversion program (link with ntdll.lib from ddk):
928 #define _WIN32_WINNT 0x0501
[62679]929 #include <iprt/win/windows.h>
[1]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}
[49150]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 }
[1]991
[51770]992 /* See VBoxDrvNtErr2NtStatus. */
[51907]993 if (SUP_NT_STATUS_IS_VBOX(rcNt))
994 return SUP_NT_STATUS_TO_VBOX(rcNt);
[51770]995
[49150]996 /* Fall back on IPRT for the rest. */
997 return RTErrConvertFromNtStatus(rcNt);
998}
999# endif
1000
[11725]1001#endif /* !IN_SUP_HARDENED_R3 */
[1]1002
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use