VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp@ 107881

最後變更 在這個檔案從107881是 106945,由 vboxsync 提交於 5 月 前

SUPDrv,/Config.kmk,/Makefile.kmk: Implemented the simplified process validation for the VBOX_WITH_MINIMAL_HARDENING mode. jiraref:VBP-1449

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 235.3 KB
 
1/* $Id: SUPDrv-win.cpp 106945 2024-11-12 02:41:36Z vboxsync $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - Windows NT specifics.
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.alldomusa.eu.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#ifndef IPRT_NT_MAP_TO_ZW
42# define IPRT_NT_MAP_TO_ZW
43#endif
44#define LOG_GROUP LOG_GROUP_SUP_DRV
45#include "../SUPDrvInternal.h"
46#include <excpt.h>
47#include <ntimage.h>
48
49#include <iprt/assert.h>
50#include <iprt/avl.h>
51#include <iprt/ctype.h>
52#include <iprt/initterm.h>
53#include <iprt/mem.h>
54#include <iprt/process.h>
55#include <iprt/power.h>
56#include <iprt/rand.h>
57#include <iprt/semaphore.h>
58#include <iprt/spinlock.h>
59#include <iprt/string.h>
60#include <iprt/utf16.h>
61#include <iprt/x86.h>
62#include <VBox/log.h>
63#include <VBox/err.h>
64
65#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
66# include <iprt/asm-amd64-x86.h>
67#elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)
68# include <iprt/asm-arm.h>
69#else
70# error "Port me!"
71#endif
72
73#if defined(VBOX_WITH_HARDENING) || defined(VBOX_WITH_MINIMAL_HARDENING)
74# include "SUPHardenedVerify-win.h"
75#endif
76
77
78/*********************************************************************************************************************************
79* Defined Constants And Macros *
80*********************************************************************************************************************************/
81/** The support service name. */
82#define SERVICE_NAME "VBoxDrv"
83/** The Pool tag (VBox). */
84#define SUPDRV_NT_POOL_TAG 'xoBV'
85
86/** NT device name for user access. */
87#define DEVICE_NAME_NT_USR L"\\Device\\VBoxDrvU"
88#ifdef VBOX_WITH_HARDENING
89/** Macro for checking for deflecting calls to the stub device. */
90# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(a_pDevObj, a_pIrp) \
91 do { if ((a_pDevObj) == g_pDevObjStub) \
92 return supdrvNtCompleteRequest(STATUS_ACCESS_DENIED, a_pIrp); \
93 } while (0)
94/** Macro for checking for deflecting calls to the stub and error info
95 * devices. */
96# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(a_pDevObj, a_pIrp) \
97 do { if ((a_pDevObj) == g_pDevObjStub || (a_pDevObj) == g_pDevObjErrorInfo) \
98 return supdrvNtCompleteRequest(STATUS_ACCESS_DENIED, a_pIrp); \
99 } while (0)
100#else
101# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_DEV(a_pDevObj, a_pIrp) do {} while (0)
102# define VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(a_pDevObj, a_pIrp) do {} while (0)
103#endif
104
105/** Enables the fast I/O control code path. */
106#define VBOXDRV_WITH_FAST_IO
107
108/** Enables generating UID from NT SIDs so the GMM can share free memory
109 * among VMs running as the same user. */
110#define VBOXDRV_WITH_SID_TO_UID_MAPPING
111
112/* Missing if we're compiling against older WDKs. */
113#ifndef NonPagedPoolNx
114# define NonPagedPoolNx ((POOL_TYPE)512)
115#endif
116
117
118/*********************************************************************************************************************************
119* Structures and Typedefs *
120*********************************************************************************************************************************/
121#ifdef VBOXDRV_WITH_SID_TO_UID_MAPPING
122/**
123 * SID to User ID mapping.
124 *
125 * This is used to generate a RTUID value for a NT security identifier.
126 * Normally, the UID is the hash of the SID string, but due to collisions it may
127 * differ. See g_NtUserIdHashTree and g_NtUserIdUidTree.
128 */
129typedef struct SUPDRVNTUSERID
130{
131 /** Hash tree node, key: RTStrHash1 of szSid. */
132 AVLLU32NODECORE HashCore;
133 /** UID three node, key: The UID. */
134 AVLU32NODECORE UidCore;
135 /** Reference counter. */
136 uint32_t volatile cRefs;
137 /** The length of the SID string. */
138 uint16_t cchSid;
139 /** The SID string for the user. */
140 char szSid[RT_FLEXIBLE_ARRAY];
141} SUPDRVNTUSERID;
142/** Pointer to a SID to UID mapping. */
143typedef SUPDRVNTUSERID *PSUPDRVNTUSERID;
144#endif
145
146/**
147 * Device extension used by VBoxDrvU.
148 */
149typedef struct SUPDRVDEVEXTUSR
150{
151 /** Global cookie (same location as in SUPDRVDEVEXT, different value). */
152 uint32_t u32Cookie;
153 /** Pointer to the main driver extension. */
154 PSUPDRVDEVEXT pMainDrvExt;
155} SUPDRVDEVEXTUSR;
156AssertCompileMembersAtSameOffset(SUPDRVDEVEXT, u32Cookie, SUPDRVDEVEXTUSR, u32Cookie);
157/** Pointer to the VBoxDrvU device extension. */
158typedef SUPDRVDEVEXTUSR *PSUPDRVDEVEXTUSR;
159/** Value of SUPDRVDEVEXTUSR::u32Cookie. */
160#define SUPDRVDEVEXTUSR_COOKIE UINT32_C(0x12345678)
161
162/** Get the main device extension. */
163#define SUPDRVNT_GET_DEVEXT(pDevObj) \
164 ( pDevObj != g_pDevObjUsr \
165 ? (PSUPDRVDEVEXT)pDevObj->DeviceExtension \
166 : ((PSUPDRVDEVEXTUSR)pDevObj->DeviceExtension)->pMainDrvExt )
167
168#ifdef VBOX_WITH_HARDENING
169
170/**
171 * Device extension used by VBoxDrvStub.
172 */
173typedef struct SUPDRVDEVEXTSTUB
174{
175 /** Common header. */
176 SUPDRVDEVEXTUSR Common;
177} SUPDRVDEVEXTSTUB;
178/** Pointer to the VBoxDrvStub device extension. */
179typedef SUPDRVDEVEXTSTUB *PSUPDRVDEVEXTSTUB;
180/** Value of SUPDRVDEVEXTSTUB::Common.u32Cookie. */
181#define SUPDRVDEVEXTSTUB_COOKIE UINT32_C(0x90abcdef)
182
183
184/**
185 * Device extension used by VBoxDrvErrorInfo.
186 */
187typedef struct SUPDRVDEVEXTERRORINFO
188{
189 /** Common header. */
190 SUPDRVDEVEXTUSR Common;
191} SUPDRVDEVEXTERRORINFO;
192/** Pointer to the VBoxDrvErrorInfo device extension. */
193typedef SUPDRVDEVEXTERRORINFO *PSUPDRVDEVEXTERRORINFO;
194/** Value of SUPDRVDEVEXTERRORINFO::Common.u32Cookie. */
195#define SUPDRVDEVEXTERRORINFO_COOKIE UINT32_C(0xBadC0ca0)
196
197/**
198 * Error info for a failed VBoxDrv or VBoxDrvStub open attempt.
199 */
200typedef struct SUPDRVNTERRORINFO
201{
202 /** The list entry (in g_ErrorInfoHead). */
203 RTLISTNODE ListEntry;
204 /** The ID of the process this error info belongs to. */
205 HANDLE hProcessId;
206 /** The ID of the thread owning this info. */
207 HANDLE hThreadId;
208 /** Milliseconds createion timestamp (for cleaning up). */
209 uint64_t uCreatedMsTs;
210 /** Number of bytes of valid info. */
211 uint32_t cchErrorInfo;
212 /** The error info. */
213 char szErrorInfo[16384 - sizeof(RTLISTNODE) - sizeof(HANDLE)*2 - sizeof(uint64_t) - sizeof(uint32_t) - 0x20];
214} SUPDRVNTERRORINFO;
215/** Pointer to error info. */
216typedef SUPDRVNTERRORINFO *PSUPDRVNTERRORINFO;
217
218
219/**
220 * The kind of process we're protecting.
221 */
222typedef enum SUPDRVNTPROTECTKIND
223{
224 kSupDrvNtProtectKind_Invalid = 0,
225
226 /** Stub process protection while performing process verification.
227 * Next: StubSpawning (or free) */
228 kSupDrvNtProtectKind_StubUnverified,
229 /** Stub process protection before it creates the VM process.
230 * Next: StubParent, StubDead. */
231 kSupDrvNtProtectKind_StubSpawning,
232 /** Stub process protection while having a VM process as child.
233 * Next: StubDead */
234 kSupDrvNtProtectKind_StubParent,
235 /** Dead stub process. */
236 kSupDrvNtProtectKind_StubDead,
237
238 /** Potential VM process.
239 * Next: VmProcessConfirmed, VmProcessDead. */
240 kSupDrvNtProtectKind_VmProcessUnconfirmed,
241 /** Confirmed VM process.
242 * Next: VmProcessDead. */
243 kSupDrvNtProtectKind_VmProcessConfirmed,
244 /** Dead VM process. */
245 kSupDrvNtProtectKind_VmProcessDead,
246
247 /** End of valid protection kinds. */
248 kSupDrvNtProtectKind_End
249} SUPDRVNTPROTECTKIND;
250
251/**
252 * A NT process protection structure.
253 */
254typedef struct SUPDRVNTPROTECT
255{
256 /** The AVL node core structure. The process ID is the pid. */
257 AVLPVNODECORE AvlCore;
258 /** Magic value (SUPDRVNTPROTECT_MAGIC). */
259 uint32_t volatile u32Magic;
260 /** Reference counter. */
261 uint32_t volatile cRefs;
262 /** The kind of process we're protecting. */
263 SUPDRVNTPROTECTKIND volatile enmProcessKind;
264 /** Whether this structure is in the tree. */
265 bool fInTree : 1;
266 /** 7,: Hack to allow the supid themes service duplicate handle privileges to
267 * our process. */
268 bool fThemesFirstProcessCreateHandle : 1;
269 /** Vista, 7 & 8: Hack to allow more rights to the handle returned by
270 * NtCreateUserProcess. Only applicable to VmProcessUnconfirmed. */
271 bool fFirstProcessCreateHandle : 1;
272 /** Vista, 7 & 8: Hack to allow more rights to the handle returned by
273 * NtCreateUserProcess. Only applicable to VmProcessUnconfirmed. */
274 bool fFirstThreadCreateHandle : 1;
275 /** 8.1: Hack to allow more rights to the handle returned by
276 * NtCreateUserProcess. Only applicable to VmProcessUnconfirmed. */
277 bool fCsrssFirstProcessCreateHandle : 1;
278 /** Vista, 7 & 8: Hack to allow more rights to the handle duplicated by CSRSS
279 * during process creation. Only applicable to VmProcessUnconfirmed. On
280 * 32-bit systems we allow two as ZoneAlarm's system call hooks has been
281 * observed to do some seemingly unnecessary duplication work. */
282 int32_t volatile cCsrssFirstProcessDuplicateHandle;
283
284 /** The parent PID for VM processes, otherwise NULL. */
285 HANDLE hParentPid;
286 /** The TID of the thread opening VBoxDrv or VBoxDrvStub, NULL if not opened. */
287 HANDLE hOpenTid;
288 /** The PID of the CSRSS process associated with this process. */
289 HANDLE hCsrssPid;
290 /** Pointer to the CSRSS process structure (referenced). */
291 PEPROCESS pCsrssProcess;
292 /** State dependent data. */
293 union
294 {
295 /** A stub process in the StubParent state will keep a reference to a child
296 * while it's in the VmProcessUnconfirmed state so that it can be cleaned up
297 * correctly if things doesn't work out. */
298 struct SUPDRVNTPROTECT *pChild;
299 /** A process in the VmProcessUnconfirmed state will keep a weak
300 * reference to the parent's protection structure so it can clean up the pChild
301 * reference the parent has to it. */
302 struct SUPDRVNTPROTECT *pParent;
303 } u;
304} SUPDRVNTPROTECT;
305/** Pointer to a NT process protection record. */
306typedef SUPDRVNTPROTECT *PSUPDRVNTPROTECT;
307/** The SUPDRVNTPROTECT::u32Magic value (Robert A. Heinlein). */
308# define SUPDRVNTPROTECT_MAGIC UINT32_C(0x19070707)
309/** The SUPDRVNTPROTECT::u32Magic value of a dead structure. */
310# define SUPDRVNTPROTECT_MAGIC_DEAD UINT32_C(0x19880508)
311
312/** Pointer to ObGetObjectType. */
313typedef POBJECT_TYPE (NTAPI *PFNOBGETOBJECTTYPE)(PVOID);
314/** Pointer to ObRegisterCallbacks. */
315typedef NTSTATUS (NTAPI *PFNOBREGISTERCALLBACKS)(POB_CALLBACK_REGISTRATION, PVOID *);
316/** Pointer to ObUnregisterCallbacks. */
317typedef VOID (NTAPI *PFNOBUNREGISTERCALLBACKS)(PVOID);
318/** Pointer to PsSetCreateProcessNotifyRoutineEx. */
319typedef NTSTATUS (NTAPI *PFNPSSETCREATEPROCESSNOTIFYROUTINEEX)(PCREATE_PROCESS_NOTIFY_ROUTINE_EX, BOOLEAN);
320/** Pointer to PsReferenceProcessFilePointer. */
321typedef NTSTATUS (NTAPI *PFNPSREFERENCEPROCESSFILEPOINTER)(PEPROCESS, PFILE_OBJECT *);
322/** Pointer to PsIsProtectedProcessLight. */
323typedef BOOLEAN (NTAPI *PFNPSISPROTECTEDPROCESSLIGHT)(PEPROCESS);
324/** Pointer to ZwAlpcCreatePort. */
325typedef NTSTATUS (NTAPI *PFNZWALPCCREATEPORT)(PHANDLE, POBJECT_ATTRIBUTES, struct _ALPC_PORT_ATTRIBUTES *);
326
327#endif /* VBOX_WITH_HARDENINIG */
328
329
330/*********************************************************************************************************************************
331* Internal Functions *
332*********************************************************************************************************************************/
333static void _stdcall VBoxDrvNtUnload(PDRIVER_OBJECT pDrvObj);
334static NTSTATUS _stdcall VBoxDrvNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp);
335static NTSTATUS _stdcall VBoxDrvNtCleanup(PDEVICE_OBJECT pDevObj, PIRP pIrp);
336static NTSTATUS _stdcall VBoxDrvNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp);
337#ifdef VBOXDRV_WITH_FAST_IO
338static BOOLEAN _stdcall VBoxDrvNtFastIoDeviceControl(PFILE_OBJECT pFileObj, BOOLEAN fWait, PVOID pvInput, ULONG cbInput,
339 PVOID pvOutput, ULONG cbOutput, ULONG uCmd,
340 PIO_STATUS_BLOCK pIoStatus, PDEVICE_OBJECT pDevObj);
341#endif
342static NTSTATUS _stdcall VBoxDrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
343static int VBoxDrvNtDeviceControlSlow(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PIRP pIrp, PIO_STACK_LOCATION pStack);
344static NTSTATUS _stdcall VBoxDrvNtInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
345static VOID _stdcall VBoxPowerDispatchCallback(PVOID pCallbackContext, PVOID pArgument1, PVOID pArgument2);
346static NTSTATUS _stdcall VBoxDrvNtRead(PDEVICE_OBJECT pDevObj, PIRP pIrp);
347static NTSTATUS _stdcall VBoxDrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp);
348static NTSTATUS VBoxDrvNtErr2NtStatus(int rc);
349#if defined(VBOX_WITH_HARDENING) || defined(VBOX_WITH_MINIMAL_HARDENING)
350static NTSTATUS supdrvNtProtectInit(void);
351static void supdrvNtProtectTerm(void);
352#endif
353#ifdef VBOX_WITH_HARDENING
354static int supdrvNtProtectCreate(PSUPDRVNTPROTECT *ppNtProtect, HANDLE hPid,
355 SUPDRVNTPROTECTKIND enmProcessKind, bool fLink);
356static void supdrvNtProtectRelease(PSUPDRVNTPROTECT pNtProtect);
357static PSUPDRVNTPROTECT supdrvNtProtectLookup(HANDLE hPid);
358static int supdrvNtProtectFindAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect);
359static int supdrvNtProtectVerifyProcess(PSUPDRVNTPROTECT pNtProtect);
360
361static bool supdrvNtIsDebuggerAttached(void);
362static void supdrvNtErrorInfoCleanupProcess(HANDLE hProcessId);
363
364#endif
365
366
367/*********************************************************************************************************************************
368* Exported Functions *
369*********************************************************************************************************************************/
370RT_C_DECLS_BEGIN
371NTSTATUS _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath);
372RT_C_DECLS_END
373
374
375/*********************************************************************************************************************************
376* Global Variables *
377*********************************************************************************************************************************/
378/** The non-paged pool type to use, NonPagedPool or NonPagedPoolNx. */
379static POOL_TYPE g_enmNonPagedPoolType = NonPagedPool;
380/** Pointer to the system device instance. */
381static PDEVICE_OBJECT g_pDevObjSys = NULL;
382/** Pointer to the user device instance. */
383static PDEVICE_OBJECT g_pDevObjUsr = NULL;
384#ifdef VBOXDRV_WITH_FAST_IO
385/** Fast I/O dispatch table. */
386static FAST_IO_DISPATCH const g_VBoxDrvFastIoDispatch =
387{
388 /* .SizeOfFastIoDispatch = */ sizeof(g_VBoxDrvFastIoDispatch),
389 /* .FastIoCheckIfPossible = */ NULL,
390 /* .FastIoRead = */ NULL,
391 /* .FastIoWrite = */ NULL,
392 /* .FastIoQueryBasicInfo = */ NULL,
393 /* .FastIoQueryStandardInfo = */ NULL,
394 /* .FastIoLock = */ NULL,
395 /* .FastIoUnlockSingle = */ NULL,
396 /* .FastIoUnlockAll = */ NULL,
397 /* .FastIoUnlockAllByKey = */ NULL,
398 /* .FastIoDeviceControl = */ VBoxDrvNtFastIoDeviceControl,
399 /* .AcquireFileForNtCreateSection = */ NULL,
400 /* .ReleaseFileForNtCreateSection = */ NULL,
401 /* .FastIoDetachDevice = */ NULL,
402 /* .FastIoQueryNetworkOpenInfo = */ NULL,
403 /* .AcquireForModWrite = */ NULL,
404 /* .MdlRead = */ NULL,
405 /* .MdlReadComplete = */ NULL,
406 /* .PrepareMdlWrite = */ NULL,
407 /* .MdlWriteComplete = */ NULL,
408 /* .FastIoReadCompressed = */ NULL,
409 /* .FastIoWriteCompressed = */ NULL,
410 /* .MdlReadCompleteCompressed = */ NULL,
411 /* .MdlWriteCompleteCompressed = */ NULL,
412 /* .FastIoQueryOpen = */ NULL,
413 /* .ReleaseForModWrite = */ NULL,
414 /* .AcquireForCcFlush = */ NULL,
415 /* .ReleaseForCcFlush = */ NULL,
416};
417#endif /* VBOXDRV_WITH_FAST_IO */
418
419/** Default ZERO value. */
420static ULONG g_fOptDefaultZero = 0;
421/** Registry values.
422 * We wrap these in a struct to ensure they are followed by a little zero
423 * padding in order to limit the chance of trouble on unpatched systems. */
424struct
425{
426 /** The ForceAsync registry value. */
427 ULONG fOptForceAsyncTsc;
428 /** Padding. */
429 uint64_t au64Padding[2];
430} g_Options = { FALSE, { 0, 0 } };
431/** Registry query table for RtlQueryRegistryValues. */
432static RTL_QUERY_REGISTRY_TABLE g_aRegValues[] =
433{
434 {
435 /* .QueryRoutine = */ NULL,
436 /* .Flags = */ RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK,
437 /* .Name = */ (PWSTR)L"ForceAsyncTsc",
438 /* .EntryContext = */ &g_Options.fOptForceAsyncTsc,
439 /* .DefaultType = */ (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD,
440 /* .DefaultData = */ &g_fOptDefaultZero,
441 /* .DefaultLength = */ sizeof(g_fOptDefaultZero),
442 },
443 { NULL, 0, NULL, NULL, 0, NULL, 0 } /* terminator entry. */
444};
445
446/** Pointer to KeQueryMaximumGroupCount. */
447static PFNKEQUERYMAXIMUMGROUPCOUNT g_pfnKeQueryMaximumGroupCount = NULL;
448/** Pointer to KeGetProcessorIndexFromNumber. */
449static PFNKEGETPROCESSORINDEXFROMNUMBER g_pfnKeGetProcessorIndexFromNumber = NULL;
450/** Pointer to KeGetProcessorNumberFromIndex. */
451static PFNKEGETPROCESSORNUMBERFROMINDEX g_pfnKeGetProcessorNumberFromIndex = NULL;
452
453#ifdef VBOXDRV_WITH_SID_TO_UID_MAPPING
454/** Spinlock protecting g_NtUserIdHashTree and g_NtUserIdUidTree. */
455static RTSPINLOCK g_hNtUserIdLock = NIL_RTSPINLOCK;
456/** AVL tree of SUPDRVNTUSERID structures by hash value. */
457static PAVLLU32NODECORE g_NtUserIdHashTree = NULL;
458/** AVL tree of SUPDRVNTUSERID structures by UID. */
459static PAVLU32NODECORE g_NtUserIdUidTree = NULL;
460#endif
461
462#if defined(VBOX_WITH_HARDENING) || defined(VBOX_WITH_MINIMAL_HARDENING)
463/** Combined windows NT version number. See SUP_MAKE_NT_VER_COMBINED. */
464uint32_t g_uNtVerCombined = 0;
465#endif
466#ifdef VBOX_WITH_HARDENING
467/** Pointer to the stub device instance. */
468static PDEVICE_OBJECT g_pDevObjStub = NULL;
469/** Spinlock protecting g_NtProtectTree as well as the releasing of protection
470 * structures. */
471static RTSPINLOCK g_hNtProtectLock = NIL_RTSPINLOCK;
472/** AVL tree of SUPDRVNTPROTECT structures. */
473static AVLPVTREE g_NtProtectTree = NULL;
474/** Cookie returned by ObRegisterCallbacks for the callbacks. */
475static PVOID g_pvObCallbacksCookie = NULL;
476/** Pointer to ObGetObjectType if available.. */
477static PFNOBGETOBJECTTYPE g_pfnObGetObjectType = NULL;
478/** Pointer to ObRegisterCallbacks if available.. */
479static PFNOBREGISTERCALLBACKS g_pfnObRegisterCallbacks = NULL;
480/** Pointer to ObUnregisterCallbacks if available.. */
481static PFNOBUNREGISTERCALLBACKS g_pfnObUnRegisterCallbacks = NULL;
482/** Pointer to PsSetCreateProcessNotifyRoutineEx if available.. */
483static PFNPSSETCREATEPROCESSNOTIFYROUTINEEX g_pfnPsSetCreateProcessNotifyRoutineEx = NULL;
484/** Pointer to PsReferenceProcessFilePointer if available. */
485static PFNPSREFERENCEPROCESSFILEPOINTER g_pfnPsReferenceProcessFilePointer = NULL;
486/** Pointer to PsIsProtectedProcessLight. */
487static PFNPSISPROTECTEDPROCESSLIGHT g_pfnPsIsProtectedProcessLight = NULL;
488/** Pointer to ZwAlpcCreatePort. */
489static PFNZWALPCCREATEPORT g_pfnZwAlpcCreatePort = NULL;
490
491# ifdef RT_ARCH_AMD64
492extern "C" {
493/** Pointer to KiServiceLinkage (used to fake missing ZwQueryVirtualMemory on
494 * XP64 / W2K3-64). */
495PFNRT g_pfnKiServiceLinkage = NULL;
496/** Pointer to KiServiceInternal (used to fake missing ZwQueryVirtualMemory on
497 * XP64 / W2K3-64) */
498PFNRT g_pfnKiServiceInternal = NULL;
499}
500# endif
501/** The primary ALPC port object type. (LpcPortObjectType at init time.) */
502static POBJECT_TYPE g_pAlpcPortObjectType1 = NULL;
503/** The secondary ALPC port object type. (Sampled at runtime.) */
504static POBJECT_TYPE volatile g_pAlpcPortObjectType2 = NULL;
505
506/** Pointer to the error information device instance. */
507static PDEVICE_OBJECT g_pDevObjErrorInfo = NULL;
508/** Fast mutex semaphore protecting the error info list. */
509static RTSEMMUTEX g_hErrorInfoLock = NIL_RTSEMMUTEX;
510/** Head of the error info (SUPDRVNTERRORINFO). */
511static RTLISTANCHOR g_ErrorInfoHead;
512
513#endif
514
515
516/**
517 * Takes care of creating the devices and their symbolic links.
518 *
519 * @returns NT status code.
520 * @param pDrvObj Pointer to driver object.
521 */
522static NTSTATUS vboxdrvNtCreateDevices(PDRIVER_OBJECT pDrvObj)
523{
524 /*
525 * System device.
526 */
527 UNICODE_STRING DevName;
528 RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_SYS);
529 NTSTATUS rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXT), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjSys);
530 if (NT_SUCCESS(rcNt))
531 {
532 /*
533 * User device.
534 */
535 RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_USR);
536 rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXTUSR), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjUsr);
537 if (NT_SUCCESS(rcNt))
538 {
539 PSUPDRVDEVEXTUSR pDevExtUsr = (PSUPDRVDEVEXTUSR)g_pDevObjUsr->DeviceExtension;
540 pDevExtUsr->pMainDrvExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
541 pDevExtUsr->u32Cookie = SUPDRVDEVEXTUSR_COOKIE;
542
543#ifdef VBOX_WITH_HARDENING
544 /*
545 * Hardened stub device.
546 */
547 RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_STUB);
548 rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXTSTUB), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &g_pDevObjStub);
549 if (NT_SUCCESS(rcNt))
550 {
551 if (NT_SUCCESS(rcNt))
552 {
553 PSUPDRVDEVEXTSTUB pDevExtStub = (PSUPDRVDEVEXTSTUB)g_pDevObjStub->DeviceExtension;
554 pDevExtStub->Common.pMainDrvExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
555 pDevExtStub->Common.u32Cookie = SUPDRVDEVEXTSTUB_COOKIE;
556
557 /*
558 * Hardened error information device.
559 */
560 RtlInitUnicodeString(&DevName, SUPDRV_NT_DEVICE_NAME_ERROR_INFO);
561 rcNt = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXTERRORINFO), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE,
562 &g_pDevObjErrorInfo);
563 if (NT_SUCCESS(rcNt))
564 {
565 g_pDevObjErrorInfo->Flags |= DO_BUFFERED_IO;
566
567 if (NT_SUCCESS(rcNt))
568 {
569 PSUPDRVDEVEXTERRORINFO pDevExtErrInf = (PSUPDRVDEVEXTERRORINFO)g_pDevObjStub->DeviceExtension;
570 pDevExtErrInf->Common.pMainDrvExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
571 pDevExtErrInf->Common.u32Cookie = SUPDRVDEVEXTERRORINFO_COOKIE;
572
573#endif
574 /* Done. */
575 return rcNt;
576#ifdef VBOX_WITH_HARDENING
577 }
578
579 /* Bail out. */
580 IoDeleteDevice(g_pDevObjErrorInfo);
581 g_pDevObjErrorInfo = NULL;
582 }
583 }
584
585 /* Bail out. */
586 IoDeleteDevice(g_pDevObjStub);
587 g_pDevObjUsr = NULL;
588 }
589 IoDeleteDevice(g_pDevObjUsr);
590 g_pDevObjUsr = NULL;
591#endif
592 }
593 IoDeleteDevice(g_pDevObjSys);
594 g_pDevObjSys = NULL;
595 }
596 return rcNt;
597}
598
599/**
600 * Destroys the devices and links created by vboxdrvNtCreateDevices.
601 */
602static void vboxdrvNtDestroyDevices(void)
603{
604 if (g_pDevObjUsr)
605 {
606 PSUPDRVDEVEXTUSR pDevExtUsr = (PSUPDRVDEVEXTUSR)g_pDevObjUsr->DeviceExtension;
607 pDevExtUsr->pMainDrvExt = NULL;
608 }
609#ifdef VBOX_WITH_HARDENING
610 if (g_pDevObjStub)
611 {
612 PSUPDRVDEVEXTSTUB pDevExtStub = (PSUPDRVDEVEXTSTUB)g_pDevObjStub->DeviceExtension;
613 pDevExtStub->Common.pMainDrvExt = NULL;
614 }
615 if (g_pDevObjErrorInfo)
616 {
617 PSUPDRVDEVEXTERRORINFO pDevExtErrorInfo = (PSUPDRVDEVEXTERRORINFO)g_pDevObjStub->DeviceExtension;
618 pDevExtErrorInfo->Common.pMainDrvExt = NULL;
619 }
620#endif
621
622#ifdef VBOX_WITH_HARDENING
623 IoDeleteDevice(g_pDevObjErrorInfo);
624 g_pDevObjErrorInfo = NULL;
625 IoDeleteDevice(g_pDevObjStub);
626 g_pDevObjStub = NULL;
627#endif
628 IoDeleteDevice(g_pDevObjUsr);
629 g_pDevObjUsr = NULL;
630 IoDeleteDevice(g_pDevObjSys);
631 g_pDevObjSys = NULL;
632}
633
634
635/**
636 * Driver entry point.
637 *
638 * @returns appropriate status code.
639 * @param pDrvObj Pointer to driver object.
640 * @param pRegPath Registry base path.
641 */
642NTSTATUS _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
643{
644 RT_NOREF1(pRegPath);
645
646 /*
647 * Sanity checks.
648 */
649#ifdef VBOXDRV_WITH_FAST_IO
650 if (g_VBoxDrvFastIoDispatch.FastIoDeviceControl != VBoxDrvNtFastIoDeviceControl)
651 {
652 DbgPrint("VBoxDrv: FastIoDeviceControl=%p instead of %p\n",
653 g_VBoxDrvFastIoDispatch.FastIoDeviceControl, VBoxDrvNtFastIoDeviceControl);
654 return STATUS_INTERNAL_ERROR;
655 }
656#endif
657
658 /*
659 * Initialize the Nt version and figure out if we can use NonPagedPoolNx or not.
660 */
661 ULONG ulMajorVersion, ulMinorVersion, ulBuildNumber;
662 PsGetVersion(&ulMajorVersion, &ulMinorVersion, &ulBuildNumber, NULL);
663#if defined(VBOX_WITH_HARDENING) || defined(VBOX_WITH_MINIMAL_HARDENING)
664 g_uNtVerCombined = SUP_MAKE_NT_VER_COMBINED(ulMajorVersion, ulMinorVersion, ulBuildNumber, 0, 0);
665#endif
666 if (ulMajorVersion > 6 || (ulMajorVersion == 6 && ulMinorVersion >= 2)) /* >= 6.2 (W8)*/
667 g_enmNonPagedPoolType = NonPagedPoolNx;
668
669 /*
670 * Query options first so any overflows on unpatched machines will do less
671 * harm (see MS11-011 / 2393802 / 2011-03-18).
672 *
673 * Unfortunately, pRegPath isn't documented as zero terminated, even if it
674 * quite likely always is, so we have to make a copy here.
675 */
676 NTSTATUS rcNt;
677 PWSTR pwszCopy = (PWSTR)ExAllocatePoolWithTag(g_enmNonPagedPoolType, pRegPath->Length + sizeof(WCHAR), 'VBox');
678 if (pwszCopy)
679 {
680 memcpy(pwszCopy, pRegPath->Buffer, pRegPath->Length);
681 pwszCopy[pRegPath->Length / sizeof(WCHAR)] = '\0';
682 rcNt = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, pwszCopy,
683 g_aRegValues, NULL /*pvContext*/, NULL /*pvEnv*/);
684 ExFreePoolWithTag(pwszCopy, 'VBox');
685 /* Probably safe to ignore rcNt here. */
686 }
687
688 /*
689 * Resolve methods we want but isn't available everywhere.
690 */
691 UNICODE_STRING RoutineName;
692 RtlInitUnicodeString(&RoutineName, L"KeQueryMaximumGroupCount");
693 g_pfnKeQueryMaximumGroupCount = (PFNKEQUERYMAXIMUMGROUPCOUNT)MmGetSystemRoutineAddress(&RoutineName);
694
695 RtlInitUnicodeString(&RoutineName, L"KeGetProcessorIndexFromNumber");
696 g_pfnKeGetProcessorIndexFromNumber = (PFNKEGETPROCESSORINDEXFROMNUMBER)MmGetSystemRoutineAddress(&RoutineName);
697
698 RtlInitUnicodeString(&RoutineName, L"KeGetProcessorNumberFromIndex");
699 g_pfnKeGetProcessorNumberFromIndex = (PFNKEGETPROCESSORNUMBERFROMINDEX)MmGetSystemRoutineAddress(&RoutineName);
700
701 Assert( (g_pfnKeGetProcessorNumberFromIndex != NULL) == (g_pfnKeGetProcessorIndexFromNumber != NULL)
702 && (g_pfnKeGetProcessorNumberFromIndex != NULL) == (g_pfnKeQueryMaximumGroupCount != NULL)); /* all or nothing. */
703
704 /*
705 * Initialize the runtime (IPRT).
706 */
707 int vrc = RTR0Init(0);
708 if (RT_SUCCESS(vrc))
709 {
710 Log(("VBoxDrv::DriverEntry\n"));
711
712#if defined(VBOX_WITH_HARDENING) || defined(VBOX_WITH_MINIMAL_HARDENING)
713 /*
714 * Initialize process protection.
715 */
716 rcNt = supdrvNtProtectInit();
717 if (NT_SUCCESS(rcNt))
718#endif
719 {
720#ifdef VBOXDRV_WITH_SID_TO_UID_MAPPING
721 /*
722 * Create the spinlock for the SID -> UID mappings.
723 */
724 vrc = RTSpinlockCreate(&g_hNtUserIdLock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "NtUserId");
725 if (RT_SUCCESS(vrc))
726#endif
727 {
728 /*
729 * Create device.
730 * (That means creating a device object and a symbolic link so the DOS
731 * subsystems (OS/2, win32, ++) can access the device.)
732 */
733 rcNt = vboxdrvNtCreateDevices(pDrvObj);
734 if (NT_SUCCESS(rcNt))
735 {
736 /*
737 * Initialize the device extension.
738 */
739 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
740 memset(pDevExt, 0, sizeof(*pDevExt));
741
742 vrc = supdrvInitDevExt(pDevExt, sizeof(SUPDRVSESSION));
743 if (!vrc)
744 {
745 /*
746 * Setup the driver entry points in pDrvObj.
747 */
748 pDrvObj->DriverUnload = VBoxDrvNtUnload;
749 pDrvObj->MajorFunction[IRP_MJ_CREATE] = VBoxDrvNtCreate;
750 pDrvObj->MajorFunction[IRP_MJ_CLEANUP] = VBoxDrvNtCleanup;
751 pDrvObj->MajorFunction[IRP_MJ_CLOSE] = VBoxDrvNtClose;
752 pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VBoxDrvNtDeviceControl;
753 pDrvObj->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = VBoxDrvNtInternalDeviceControl;
754 pDrvObj->MajorFunction[IRP_MJ_READ] = VBoxDrvNtRead;
755 pDrvObj->MajorFunction[IRP_MJ_WRITE] = VBoxDrvNtNotSupportedStub;
756
757#ifdef VBOXDRV_WITH_FAST_IO
758 /* Fast I/O to speed up guest execution roundtrips. */
759 pDrvObj->FastIoDispatch = (PFAST_IO_DISPATCH)&g_VBoxDrvFastIoDispatch;
760#endif
761
762 /*
763 * Register ourselves for power state changes. We don't
764 * currently care if this fails.
765 */
766 UNICODE_STRING CallbackName;
767 RtlInitUnicodeString(&CallbackName, L"\\Callback\\PowerState");
768
769 OBJECT_ATTRIBUTES Attr;
770 InitializeObjectAttributes(&Attr, &CallbackName, OBJ_CASE_INSENSITIVE, NULL, NULL);
771
772 rcNt = ExCreateCallback(&pDevExt->pObjPowerCallback, &Attr, TRUE, TRUE);
773 if (rcNt == STATUS_SUCCESS)
774 pDevExt->hPowerCallback = ExRegisterCallback(pDevExt->pObjPowerCallback,
775 VBoxPowerDispatchCallback,
776 g_pDevObjSys);
777
778 /*
779 * Done! Returning success!
780 */
781 Log(("VBoxDrv::DriverEntry returning STATUS_SUCCESS\n"));
782 DbgPrint("VBoxSup::DriverEntry: returning STATUS_SUCCESS\n"); /* temp for @bugref{10657} */
783 return STATUS_SUCCESS;
784 }
785
786 /*
787 * Failed. Clean up.
788 */
789 DbgPrint("VBoxSup::DriverEntry: supdrvInitDevExit failed with vrc=%d!\n", vrc);
790 Log(("supdrvInitDevExit failed with vrc=%d!\n", vrc));
791 rcNt = VBoxDrvNtErr2NtStatus(vrc);
792
793 vboxdrvNtDestroyDevices();
794 }
795 else
796 DbgPrint("VBoxSup::DriverEntry: vboxdrvNtCreateDevices failed with rcNt=%#x!\n", rcNt);
797#ifdef VBOXDRV_WITH_SID_TO_UID_MAPPING
798 RTSpinlockDestroy(g_hNtUserIdLock);
799 g_hNtUserIdLock = NIL_RTSPINLOCK;
800#endif
801 }
802#ifdef VBOXDRV_WITH_SID_TO_UID_MAPPING
803 else
804 {
805 DbgPrint("VBoxSup::DriverEntry: RTSpinlockCreate failed with vrc=%d!\n", vrc);
806 rcNt = VBoxDrvNtErr2NtStatus(vrc);
807 }
808#endif
809#if defined(VBOX_WITH_HARDENING) || defined(VBOX_WITH_MINIMAL_HARDENING)
810 supdrvNtProtectTerm();
811#endif
812 }
813#if defined(VBOX_WITH_HARDENING) || defined(VBOX_WITH_MINIMAL_HARDENING)
814 else
815 DbgPrint("VBoxSup::DriverEntry: supdrvNtProtectInit failed with rcNt=%#x!\n", rcNt);
816#endif
817 RTTermRunCallbacks(RTTERMREASON_UNLOAD, 0);
818 RTR0Term();
819 }
820 else
821 {
822 DbgPrint("VBoxSup::DriverEntry: RTR0Init failed with vrc=%d!\n", vrc);
823 Log(("RTR0Init failed with vrc=%d!\n", vrc));
824 rcNt = VBoxDrvNtErr2NtStatus(vrc);
825 }
826 if (NT_SUCCESS(rcNt))
827 rcNt = STATUS_INVALID_PARAMETER;
828 return rcNt;
829}
830
831
832/**
833 * Unload the driver.
834 *
835 * @param pDrvObj Driver object.
836 */
837void _stdcall VBoxDrvNtUnload(PDRIVER_OBJECT pDrvObj)
838{
839 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
840
841 Log(("VBoxDrvNtUnload at irql %d\n", KeGetCurrentIrql()));
842
843 /* Clean up the power callback registration. */
844 if (pDevExt->hPowerCallback)
845 ExUnregisterCallback(pDevExt->hPowerCallback);
846 if (pDevExt->pObjPowerCallback)
847 ObDereferenceObject(pDevExt->pObjPowerCallback);
848
849 /*
850 * We ASSUME that it's not possible to unload a driver with open handles.
851 */
852 supdrvDeleteDevExt(pDevExt);
853#ifdef VBOXDRV_WITH_SID_TO_UID_MAPPING
854 RTSpinlockDestroy(g_hNtUserIdLock);
855 g_hNtUserIdLock = NIL_RTSPINLOCK;
856#endif
857#ifdef VBOX_WITH_HARDENING
858 supdrvNtProtectTerm();
859#endif
860 RTTermRunCallbacks(RTTERMREASON_UNLOAD, 0);
861 RTR0Term();
862 vboxdrvNtDestroyDevices();
863
864 NOREF(pDrvObj);
865}
866
867#ifdef VBOXDRV_WITH_SID_TO_UID_MAPPING
868
869/**
870 * Worker for supdrvNtUserIdMakeForSession.
871 */
872static bool supdrvNtUserIdMakeUid(PSUPDRVNTUSERID pNtUserId)
873{
874 pNtUserId->UidCore.Key = pNtUserId->HashCore.Key;
875 for (uint32_t cTries = 0; cTries < _4K; cTries++)
876 {
877 bool fRc = RTAvlU32Insert(&g_NtUserIdUidTree, &pNtUserId->UidCore);
878 if (fRc)
879 return true;
880 pNtUserId->UidCore.Key += pNtUserId->cchSid | 1;
881 }
882 return false;
883}
884
885
886/**
887 * Try create a RTUID value for the session.
888 *
889 * @returns VBox status code.
890 * @param pSession The session to try set SUPDRVSESSION::Uid for.
891 */
892static int supdrvNtUserIdMakeForSession(PSUPDRVSESSION pSession)
893{
894 /*
895 * Get the current security context and query the User SID for it.
896 */
897 SECURITY_SUBJECT_CONTEXT Ctx = { NULL, SecurityIdentification, NULL, NULL };
898 SeCaptureSubjectContext(&Ctx);
899
900 int rc;
901 TOKEN_USER *pTokenUser = NULL;
902 NTSTATUS rcNt = SeQueryInformationToken(SeQuerySubjectContextToken(&Ctx) /* or always PrimaryToken?*/,
903 TokenUser, (PVOID *)&pTokenUser);
904 if (NT_SUCCESS(rcNt))
905 {
906 /*
907 * Convert the user SID to a string to make it easier to handle, then prepare
908 * a user ID entry for it as that way we can combine lookup and insertion and
909 * avoid needing to deal with races.
910 */
911 UNICODE_STRING UniStr = RTNT_NULL_UNISTR();
912 rcNt = RtlConvertSidToUnicodeString(&UniStr, pTokenUser->User.Sid, TRUE /*AllocateDesitnationString*/);
913 if (NT_SUCCESS(rcNt))
914 {
915 size_t cchSid = 0;
916 rc = RTUtf16CalcUtf8LenEx(UniStr.Buffer, UniStr.Length / sizeof(RTUTF16), &cchSid);
917 if (RT_SUCCESS(rc))
918 {
919 PSUPDRVNTUSERID const pNtUserIdNew = (PSUPDRVNTUSERID)RTMemAlloc(RT_UOFFSETOF_DYN(SUPDRVNTUSERID, szSid[cchSid + 1]));
920 if (pNtUserIdNew)
921 {
922 char *pszSid = pNtUserIdNew->szSid;
923 rc = RTUtf16ToUtf8Ex(UniStr.Buffer, UniStr.Length / sizeof(RTUTF16), &pszSid, cchSid + 1, NULL);
924 if (RT_SUCCESS(rc))
925 {
926 pNtUserIdNew->HashCore.Key = RTStrHash1(pNtUserIdNew->szSid);
927 pNtUserIdNew->cchSid = (uint16_t)cchSid;
928 pNtUserIdNew->cRefs = 1;
929 Log5Func(("pNtUserId=%p cchSid=%u hash=%#x '%s'\n", pNtUserIdNew, cchSid, pNtUserIdNew->HashCore.Key, pszSid));
930
931 /*
932 * Do the lookup / insert.
933 */
934 RTSpinlockAcquire(g_hNtUserIdLock);
935 AssertCompileMemberOffset(SUPDRVNTUSERID, HashCore, 0);
936 PSUPDRVNTUSERID pNtUserId = (PSUPDRVNTUSERID)RTAvllU32Get(&g_NtUserIdHashTree, pNtUserIdNew->HashCore.Key);
937 if (pNtUserId)
938 {
939 /* Match the strings till we reach the end of the collision list. */
940 PSUPDRVNTUSERID const pNtUserIdHead = pNtUserId;
941 while ( pNtUserId
942 && ( pNtUserId->cchSid != cchSid
943 || memcmp(pNtUserId->szSid, pNtUserId->szSid, cchSid) != 0))
944 pNtUserId = (PSUPDRVNTUSERID)pNtUserId->HashCore.pList;
945 if (pNtUserId)
946 {
947 /* Found matching: Retain reference and free the new entry we prepared. */
948 uint32_t const cRefs = ASMAtomicIncU32(&pNtUserId->cRefs);
949 Assert(cRefs < _16K); RT_NOREF(cRefs);
950 RTSpinlockRelease(g_hNtUserIdLock);
951 Log5Func(("Using %p / %#x instead\n", pNtUserId, pNtUserId->UidCore.Key));
952 }
953 else
954 {
955 /* No match: Try insert prepared entry after the head node. */
956 if (supdrvNtUserIdMakeUid(pNtUserIdNew))
957 {
958 pNtUserIdNew->HashCore.pList = pNtUserIdHead->HashCore.pList;
959 pNtUserIdHead->HashCore.pList = &pNtUserIdNew->HashCore;
960 pNtUserId = pNtUserIdNew;
961 }
962 RTSpinlockRelease(g_hNtUserIdLock);
963 if (pNtUserId)
964 Log5Func(("Using %p / %#x (the prepared one)\n", pNtUserId, pNtUserId->UidCore.Key));
965 else
966 LogRelFunc(("supdrvNtUserIdMakeForSession: failed to insert new\n"));
967 }
968 }
969 else
970 {
971 /* No matching hash: Try insert the prepared entry. */
972 pNtUserIdNew->UidCore.Key = pNtUserIdNew->HashCore.Key;
973 if (supdrvNtUserIdMakeUid(pNtUserIdNew))
974 {
975 RTAvllU32Insert(&g_NtUserIdHashTree, &pNtUserIdNew->HashCore);
976 pNtUserId = pNtUserIdNew;
977 }
978 RTSpinlockRelease(g_hNtUserIdLock);
979 if (pNtUserId)
980 Log5Func(("Using %p / %#x (the prepared one, no conflict)\n", pNtUserId, pNtUserId->UidCore.Key));
981 else
982 LogRelFunc(("failed to insert!! WTF!?!\n"));
983 }
984
985 if (pNtUserId != pNtUserIdNew)
986 RTMemFree(pNtUserIdNew);
987
988 /*
989 * Update the session info.
990 */
991 pSession->pNtUserId = pNtUserId;
992 pSession->Uid = pNtUserId ? (RTUID)pNtUserId->UidCore.Key : NIL_RTUID;
993 }
994 else
995 RTMemFree(pNtUserIdNew);
996 }
997 else
998 rc = VERR_NO_MEMORY;
999 }
1000 RtlFreeUnicodeString(&UniStr);
1001 }
1002 else
1003 {
1004 rc = RTErrConvertFromNtStatus(rcNt);
1005 LogFunc(("RtlConvertSidToUnicodeString failed: %#x / %Rrc\n", rcNt, rc));
1006 }
1007 ExFreePool(pTokenUser);
1008 }
1009 else
1010 {
1011 rc = RTErrConvertFromNtStatus(rcNt);
1012 LogFunc(("SeQueryInformationToken failed: %#x / %Rrc\n", rcNt, rc));
1013 }
1014
1015 SeReleaseSubjectContext(&Ctx);
1016 return rc;
1017}
1018
1019
1020/**
1021 * Releases a reference to @a pNtUserId.
1022 *
1023 * @param pNtUserId The NT user ID entry to release.
1024 */
1025static void supdrvNtUserIdRelease(PSUPDRVNTUSERID pNtUserId)
1026{
1027 if (pNtUserId)
1028 {
1029 uint32_t const cRefs = ASMAtomicDecU32(&pNtUserId->cRefs);
1030 Log5Func(("%p / %#x: cRefs=%d\n", pNtUserId, pNtUserId->cRefs));
1031 Assert(cRefs < _8K);
1032 if (cRefs == 0)
1033 {
1034 RTSpinlockAcquire(g_hNtUserIdLock);
1035 if (pNtUserId->cRefs == 0)
1036 {
1037 PAVLLU32NODECORE pAssert1 = RTAvllU32RemoveNode(&g_NtUserIdHashTree, &pNtUserId->HashCore);
1038 PAVLU32NODECORE pAssert2 = RTAvlU32Remove(&g_NtUserIdUidTree, pNtUserId->UidCore.Key);
1039
1040 RTSpinlockRelease(g_hNtUserIdLock);
1041
1042 Assert(pAssert1 == &pNtUserId->HashCore);
1043 Assert(pAssert2 == &pNtUserId->UidCore);
1044 RT_NOREF(pAssert1, pAssert2);
1045
1046 RTMemFree(pNtUserId);
1047 }
1048 else
1049 RTSpinlockRelease(g_hNtUserIdLock);
1050 }
1051 }
1052}
1053
1054#endif /* VBOXDRV_WITH_SID_TO_UID_MAPPING */
1055
1056/**
1057 * For simplifying request completion into a simple return statement, extended
1058 * version.
1059 *
1060 * @returns rcNt
1061 * @param rcNt The status code.
1062 * @param uInfo Extra info value.
1063 * @param pIrp The IRP.
1064 */
1065DECLINLINE(NTSTATUS) supdrvNtCompleteRequestEx(NTSTATUS rcNt, ULONG_PTR uInfo, PIRP pIrp)
1066{
1067 pIrp->IoStatus.Status = rcNt;
1068 pIrp->IoStatus.Information = uInfo;
1069 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1070 return rcNt;
1071}
1072
1073
1074/**
1075 * For simplifying request completion into a simple return statement.
1076 *
1077 * @returns rcNt
1078 * @param rcNt The status code.
1079 * @param pIrp The IRP.
1080 */
1081DECLINLINE(NTSTATUS) supdrvNtCompleteRequest(NTSTATUS rcNt, PIRP pIrp)
1082{
1083 return supdrvNtCompleteRequestEx(rcNt, 0 /*uInfo*/, pIrp);
1084}
1085
1086
1087/**
1088 * Create (i.e. Open) file entry point.
1089 *
1090 * @param pDevObj Device object.
1091 * @param pIrp Request packet.
1092 */
1093NTSTATUS _stdcall VBoxDrvNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1094{
1095 Log(("VBoxDrvNtCreate: RequestorMode=%d\n", pIrp->RequestorMode));
1096 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1097 PFILE_OBJECT pFileObj = pStack->FileObject;
1098 PSUPDRVDEVEXT pDevExt = SUPDRVNT_GET_DEVEXT(pDevObj);
1099
1100 /*
1101 * We are not remotely similar to a directory...
1102 * (But this is possible.)
1103 */
1104 if (pStack->Parameters.Create.Options & FILE_DIRECTORY_FILE)
1105 return supdrvNtCompleteRequest(STATUS_NOT_A_DIRECTORY, pIrp);
1106
1107 /*
1108 * Don't create a session for kernel clients, they'll close the handle
1109 * immediately and work with the file object via
1110 * VBoxDrvNtInternalDeviceControl. The first request will be one to
1111 * create a session.
1112 */
1113 NTSTATUS rcNt;
1114 if (pIrp->RequestorMode == KernelMode)
1115 {
1116 if (pDevObj == g_pDevObjSys)
1117 return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
1118
1119 rcNt = STATUS_ACCESS_DENIED;
1120 }
1121#ifdef VBOX_WITH_HARDENING
1122 /*
1123 * Anyone can open the error device.
1124 */
1125 else if (pDevObj == g_pDevObjErrorInfo)
1126 {
1127 pFileObj->FsContext = NULL;
1128 return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
1129 }
1130#endif
1131 else
1132 {
1133#if defined(VBOX_WITH_HARDENING) && !defined(VBOX_WITHOUT_DEBUGGER_CHECKS)
1134 /*
1135 * Make sure no debuggers are attached to non-user processes.
1136 */
1137 if ( pDevObj != g_pDevObjUsr
1138 && supdrvNtIsDebuggerAttached())
1139 {
1140 LogRel(("vboxdrv: Process %p is being debugged, access to vboxdrv / vboxdrvu declined.\n",
1141 PsGetProcessId(PsGetCurrentProcess())));
1142 rcNt = STATUS_TRUST_FAILURE;
1143 }
1144 else
1145#endif
1146 {
1147 int rc = VINF_SUCCESS;
1148
1149#ifdef VBOX_WITH_HARDENING
1150 /*
1151 * Access to the stub device is only granted to processes which
1152 * passes verification.
1153 *
1154 * Note! The stub device has no need for a SUPDRVSESSION structure,
1155 * so the it uses the SUPDRVNTPROTECT directly instead.
1156 */
1157 if (pDevObj == g_pDevObjStub)
1158 {
1159 PSUPDRVNTPROTECT pNtProtect = NULL;
1160 rc = supdrvNtProtectCreate(&pNtProtect, PsGetProcessId(PsGetCurrentProcess()),
1161 kSupDrvNtProtectKind_StubUnverified, true /*fLink*/);
1162 if (RT_SUCCESS(rc))
1163 {
1164 rc = supdrvNtProtectFindAssociatedCsrss(pNtProtect);
1165 if (RT_SUCCESS(rc))
1166 rc = supdrvNtProtectVerifyProcess(pNtProtect);
1167 if (RT_SUCCESS(rc))
1168 {
1169 pFileObj->FsContext = pNtProtect; /* Keeps reference. */
1170 return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
1171 }
1172
1173 supdrvNtProtectRelease(pNtProtect);
1174 }
1175 LogRel(("vboxdrv: Declined %p access to VBoxDrvStub: rc=%d\n", PsGetProcessId(PsGetCurrentProcess()), rc));
1176 }
1177 /*
1178 * Unrestricted access is only granted to a process in the
1179 * VmProcessUnconfirmed state that checks out correctly and is
1180 * allowed to transition to VmProcessConfirmed. Again, only one
1181 * session per process.
1182 */
1183 else if (pDevObj != g_pDevObjUsr)
1184 {
1185 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(PsGetProcessId(PsGetCurrentProcess()));
1186 if (pNtProtect)
1187 {
1188 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
1189 {
1190 rc = supdrvNtProtectVerifyProcess(pNtProtect);
1191 if (RT_SUCCESS(rc))
1192 {
1193 /* Create a session. */
1194 PSUPDRVSESSION pSession;
1195 rc = supdrvCreateSession(pDevExt, true /*fUser*/, pDevObj == g_pDevObjSys /*fUnrestricted*/,
1196 &pSession);
1197 if (RT_SUCCESS(rc))
1198 {
1199# ifdef VBOXDRV_WITH_SID_TO_UID_MAPPING
1200 rc = supdrvNtUserIdMakeForSession(pSession);
1201 if (RT_SUCCESS(rc))
1202# endif
1203 rc = supdrvSessionHashTabInsert(pDevExt, pSession, (PSUPDRVSESSION *)&pFileObj->FsContext, NULL);
1204 supdrvSessionRelease(pSession);
1205 if (RT_SUCCESS(rc))
1206 {
1207 pSession->pNtProtect = pNtProtect; /* Keeps reference. */
1208 return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
1209 }
1210 }
1211
1212 /* No second attempt. */
1213 RTSpinlockAcquire(g_hNtProtectLock);
1214 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessConfirmed)
1215 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
1216 RTSpinlockRelease(g_hNtProtectLock);
1217
1218 LogRel(("vboxdrv: supdrvCreateSession failed for process %p: rc=%d.\n",
1219 PsGetProcessId(PsGetCurrentProcess()), rc));
1220 }
1221 else
1222 LogRel(("vboxdrv: Process %p failed process verification: rc=%d.\n",
1223 PsGetProcessId(PsGetCurrentProcess()), rc));
1224 }
1225 else
1226 {
1227 LogRel(("vboxdrv: %p is not a budding VM process (enmProcessKind=%d).\n",
1228 PsGetProcessId(PsGetCurrentProcess()), pNtProtect->enmProcessKind));
1229 rc = VERR_SUPDRV_NOT_BUDDING_VM_PROCESS_2;
1230 }
1231 supdrvNtProtectRelease(pNtProtect);
1232 }
1233 else
1234 {
1235 LogRel(("vboxdrv: %p is not a budding VM process.\n", PsGetProcessId(PsGetCurrentProcess())));
1236 rc = VERR_SUPDRV_NOT_BUDDING_VM_PROCESS_1;
1237 }
1238 }
1239 /*
1240 * Call common code to create an unprivileged session.
1241 */
1242 else
1243 {
1244 PSUPDRVSESSION pSession;
1245 rc = supdrvCreateSession(pDevExt, true /*fUser*/, false /*fUnrestricted*/, &pSession);
1246 if (RT_SUCCESS(rc))
1247 {
1248# ifdef VBOXDRV_WITH_SID_TO_UID_MAPPING
1249 rc = supdrvNtUserIdMakeForSession(pSession);
1250 if (RT_SUCCESS(rc))
1251# endif
1252 rc = supdrvSessionHashTabInsert(pDevExt, pSession, (PSUPDRVSESSION *)&pFileObj->FsContext, NULL);
1253 supdrvSessionRelease(pSession);
1254 if (RT_SUCCESS(rc))
1255 {
1256 pFileObj->FsContext = pSession; /* Keeps reference. No race. */
1257 pSession->pNtProtect = NULL;
1258 return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
1259 }
1260 }
1261 }
1262
1263#else /* !VBOX_WITH_HARDENING */
1264# ifdef VBOX_WITH_MINIMAL_HARDENING
1265 /*
1266 * Check that the process is allowed to access the device, i.e. the
1267 * process image is signed with the build certificate.
1268 */
1269 PRTERRINFOSTATIC pErrInfo = (PRTERRINFOSTATIC)RTMemAllocZ(sizeof(*pErrInfo));
1270 rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_VERIFY_ONLY, 0 /*fFlags*/,
1271 NULL, pErrInfo ? RTErrInfoInitStatic(pErrInfo) : NULL);
1272 if (RT_FAILURE(rc))
1273 SUPR0Printf("VBoxDrv: Checking process failed: %Rrc%#RTeim\n", rc, &pErrInfo->Core);
1274 RTMemFree(pErrInfo);
1275
1276 if (RT_SUCCESS(rc))
1277# endif
1278 {
1279 /*
1280 * Call common code to create a session.
1281 */
1282 pFileObj->FsContext = NULL;
1283 PSUPDRVSESSION pSession;
1284 rc = supdrvCreateSession(pDevExt, true /*fUser*/, pDevObj == g_pDevObjSys /*fUnrestricted*/, &pSession);
1285 if (RT_SUCCESS(rc))
1286 {
1287# ifdef VBOXDRV_WITH_SID_TO_UID_MAPPING
1288 rc = supdrvNtUserIdMakeForSession(pSession);
1289 if (RT_SUCCESS(rc))
1290# endif
1291 rc = supdrvSessionHashTabInsert(pDevExt, pSession, (PSUPDRVSESSION *)&pFileObj->FsContext, NULL);
1292 supdrvSessionRelease(pSession);
1293 if (RT_SUCCESS(rc))
1294 return supdrvNtCompleteRequestEx(STATUS_SUCCESS, FILE_OPENED, pIrp);
1295
1296 }
1297 }
1298#endif /* !VBOX_WITH_HARDENING */
1299
1300 /* bail out */
1301 rcNt = VBoxDrvNtErr2NtStatus(rc);
1302 }
1303 }
1304
1305 Assert(!NT_SUCCESS(rcNt));
1306 pFileObj->FsContext = NULL;
1307 return supdrvNtCompleteRequest(rcNt, pIrp); /* Note. the IoStatus is completely ignored on error. */
1308}
1309
1310
1311/**
1312 * Clean up file handle entry point.
1313 *
1314 * This is called when the last handle reference is released, or something like
1315 * that. In the case of IoGetDeviceObjectPointer, this is called as it closes
1316 * the handle, however it will go on using the file object afterwards...
1317 *
1318 * @param pDevObj Device object.
1319 * @param pIrp Request packet.
1320 */
1321NTSTATUS _stdcall VBoxDrvNtCleanup(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1322{
1323 PSUPDRVDEVEXT pDevExt = SUPDRVNT_GET_DEVEXT(pDevObj);
1324 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1325 PFILE_OBJECT pFileObj = pStack->FileObject;
1326
1327#ifdef VBOX_WITH_HARDENING
1328 if (pDevObj == g_pDevObjStub)
1329 {
1330 PSUPDRVNTPROTECT pNtProtect = (PSUPDRVNTPROTECT)pFileObj->FsContext;
1331 Log(("VBoxDrvNtCleanup: pDevExt=%p pFileObj=%p pNtProtect=%p\n", pDevExt, pFileObj, pNtProtect));
1332 if (pNtProtect)
1333 {
1334 supdrvNtProtectRelease(pNtProtect);
1335 pFileObj->FsContext = NULL;
1336 }
1337 }
1338 else if (pDevObj == g_pDevObjErrorInfo)
1339 supdrvNtErrorInfoCleanupProcess(PsGetCurrentProcessId());
1340 else
1341#endif
1342 {
1343 PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, RTProcSelf(), RTR0ProcHandleSelf(),
1344 (PSUPDRVSESSION *)&pFileObj->FsContext);
1345 Log(("VBoxDrvNtCleanup: pDevExt=%p pFileObj=%p pSession=%p\n", pDevExt, pFileObj, pSession));
1346 if (pSession)
1347 {
1348 supdrvSessionHashTabRemove(pDevExt, pSession, NULL);
1349 supdrvSessionRelease(pSession); /* Drops the reference from supdrvSessionHashTabLookup. */
1350 }
1351 }
1352
1353 return supdrvNtCompleteRequest(STATUS_SUCCESS, pIrp);
1354}
1355
1356
1357/**
1358 * Close file entry point.
1359 *
1360 * @param pDevObj Device object.
1361 * @param pIrp Request packet.
1362 */
1363NTSTATUS _stdcall VBoxDrvNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1364{
1365 PSUPDRVDEVEXT pDevExt = SUPDRVNT_GET_DEVEXT(pDevObj);
1366 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1367 PFILE_OBJECT pFileObj = pStack->FileObject;
1368
1369#ifdef VBOX_WITH_HARDENING
1370 if (pDevObj == g_pDevObjStub)
1371 {
1372 PSUPDRVNTPROTECT pNtProtect = (PSUPDRVNTPROTECT)pFileObj->FsContext;
1373 Log(("VBoxDrvNtClose: pDevExt=%p pFileObj=%p pNtProtect=%p\n", pDevExt, pFileObj, pNtProtect));
1374 if (pNtProtect)
1375 {
1376 supdrvNtProtectRelease(pNtProtect);
1377 pFileObj->FsContext = NULL;
1378 }
1379 }
1380 else if (pDevObj == g_pDevObjErrorInfo)
1381 supdrvNtErrorInfoCleanupProcess(PsGetCurrentProcessId());
1382 else
1383#endif
1384 {
1385 PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, RTProcSelf(), RTR0ProcHandleSelf(),
1386 (PSUPDRVSESSION *)&pFileObj->FsContext);
1387 Log(("VBoxDrvNtCleanup: pDevExt=%p pFileObj=%p pSession=%p\n", pDevExt, pFileObj, pSession));
1388 if (pSession)
1389 {
1390 supdrvSessionHashTabRemove(pDevExt, pSession, NULL);
1391 supdrvSessionRelease(pSession); /* Drops the reference from supdrvSessionHashTabLookup. */
1392 }
1393 }
1394
1395 return supdrvNtCompleteRequest(STATUS_SUCCESS, pIrp);
1396}
1397
1398
1399#ifdef VBOXDRV_WITH_FAST_IO
1400/**
1401 * Fast I/O device control callback.
1402 *
1403 * This performs no buffering, neither on the way in or out.
1404 *
1405 * @returns TRUE if handled, FALSE if the normal I/O control routine should be
1406 * called.
1407 * @param pFileObj The file object.
1408 * @param fWait Whether it's a blocking call
1409 * @param pvInput The input buffer as specified by the user.
1410 * @param cbInput The size of the input buffer.
1411 * @param pvOutput The output buffer as specfied by the user.
1412 * @param cbOutput The size of the output buffer.
1413 * @param uCmd The I/O command/function being invoked.
1414 * @param pIoStatus Where to return the status of the operation.
1415 * @param pDevObj The device object..
1416 */
1417static BOOLEAN _stdcall VBoxDrvNtFastIoDeviceControl(PFILE_OBJECT pFileObj, BOOLEAN fWait, PVOID pvInput, ULONG cbInput,
1418 PVOID pvOutput, ULONG cbOutput, ULONG uCmd,
1419 PIO_STATUS_BLOCK pIoStatus, PDEVICE_OBJECT pDevObj)
1420{
1421 RT_NOREF1(fWait);
1422
1423 /*
1424 * Only the normal devices, not the stub or error info ones.
1425 */
1426 if (pDevObj != g_pDevObjSys && pDevObj != g_pDevObjUsr)
1427 {
1428 pIoStatus->Status = STATUS_NOT_SUPPORTED;
1429 pIoStatus->Information = 0;
1430 return TRUE;
1431 }
1432
1433 /*
1434 * Check the input a little bit and get a the session references.
1435 */
1436 PSUPDRVDEVEXT pDevExt = SUPDRVNT_GET_DEVEXT(pDevObj);
1437 PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, RTProcSelf(), RTR0ProcHandleSelf(),
1438 (PSUPDRVSESSION *)&pFileObj->FsContext);
1439 if (!pSession)
1440 {
1441 pIoStatus->Status = STATUS_TRUST_FAILURE;
1442 pIoStatus->Information = 0;
1443 return TRUE;
1444 }
1445
1446 if (pSession->fUnrestricted)
1447 {
1448#if defined(VBOX_WITH_HARDENING) && !defined(VBOX_WITHOUT_DEBUGGER_CHECKS)
1449 if (supdrvNtIsDebuggerAttached())
1450 {
1451 pIoStatus->Status = STATUS_TRUST_FAILURE;
1452 pIoStatus->Information = 0;
1453 supdrvSessionRelease(pSession);
1454 return TRUE;
1455 }
1456#endif
1457
1458 /*
1459 * Deal with the 2-3 high-speed IOCtl that takes their arguments from
1460 * the session and iCmd, and does not return anything.
1461 */
1462 if ( (uCmd & 3) == METHOD_NEITHER
1463 && (uint32_t)((uCmd - SUP_IOCTL_FAST_DO_FIRST) >> 2) < (uint32_t)32)
1464 {
1465 int rc = supdrvIOCtlFast((uCmd - SUP_IOCTL_FAST_DO_FIRST) >> 2,
1466 (unsigned)(uintptr_t)pvOutput/* VMCPU id */,
1467 pDevExt, pSession);
1468 pIoStatus->Status = RT_SUCCESS(rc) ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER;
1469 pIoStatus->Information = 0; /* Could be used to pass rc if we liked. */
1470 supdrvSessionRelease(pSession);
1471 return TRUE;
1472 }
1473 }
1474
1475 /*
1476 * The normal path.
1477 */
1478 NTSTATUS rcNt;
1479 unsigned cbOut = 0;
1480 int rc = 0;
1481 Log2(("VBoxDrvNtFastIoDeviceControl(%p): ioctl=%#x pvIn=%p cbIn=%#x pvOut=%p cbOut=%#x pSession=%p\n",
1482 pDevExt, uCmd, pvInput, cbInput, pvOutput, cbOutput, pSession));
1483
1484# ifdef RT_ARCH_AMD64
1485 /* Don't allow 32-bit processes to do any I/O controls. */
1486 if (!IoIs32bitProcess(NULL))
1487# endif
1488 {
1489 /*
1490 * In this fast I/O device control path we have to do our own buffering.
1491 */
1492 /* Verify that the I/O control function matches our pattern. */
1493 if ((uCmd & 0x3) == METHOD_BUFFERED)
1494 {
1495 /* Get the header so we can validate it a little bit against the
1496 parameters before allocating any memory kernel for the reqest. */
1497 SUPREQHDR Hdr;
1498 if (cbInput >= sizeof(Hdr) && cbOutput >= sizeof(Hdr))
1499 {
1500 __try
1501 {
1502 RtlCopyMemory(&Hdr, pvInput, sizeof(Hdr));
1503 rcNt = STATUS_SUCCESS;
1504 }
1505 __except(EXCEPTION_EXECUTE_HANDLER)
1506 {
1507 rcNt = GetExceptionCode();
1508 Hdr.cbIn = Hdr.cbOut = 0; /* shut up MSC */
1509 }
1510 }
1511 else
1512 {
1513 Hdr.cbIn = Hdr.cbOut = 0; /* shut up MSC */
1514 rcNt = STATUS_INVALID_PARAMETER;
1515 }
1516 if (NT_SUCCESS(rcNt))
1517 {
1518 /* Verify that the sizes in the request header are correct. */
1519 ULONG cbBuf = RT_MAX(cbInput, cbOutput);
1520 if ( cbInput == Hdr.cbIn
1521 && cbOutput == Hdr.cbOut
1522 && cbBuf < _1M*16)
1523 {
1524 /* Allocate a buffer and copy all the input into it. */
1525 PSUPREQHDR pHdr = (PSUPREQHDR)ExAllocatePoolWithTag(g_enmNonPagedPoolType, cbBuf, 'VBox');
1526 if (pHdr)
1527 {
1528 __try
1529 {
1530 RtlCopyMemory(pHdr, pvInput, cbInput);
1531 if (cbInput < cbBuf)
1532 RtlZeroMemory((uint8_t *)pHdr + cbInput, cbBuf - cbInput);
1533 if (!memcmp(pHdr, &Hdr, sizeof(Hdr)))
1534 rcNt = STATUS_SUCCESS;
1535 else
1536 rcNt = STATUS_INVALID_PARAMETER;
1537 }
1538 __except(EXCEPTION_EXECUTE_HANDLER)
1539 {
1540 rcNt = GetExceptionCode();
1541 }
1542 if (NT_SUCCESS(rcNt))
1543 {
1544 /*
1545 * Now call the common code to do the real work.
1546 */
1547 rc = supdrvIOCtl(uCmd, pDevExt, pSession, pHdr, cbBuf);
1548 if (RT_SUCCESS(rc))
1549 {
1550 /*
1551 * Copy back the result.
1552 */
1553 cbOut = pHdr->cbOut;
1554 if (cbOut > cbOutput)
1555 {
1556 cbOut = cbOutput;
1557 OSDBGPRINT(("VBoxDrvNtFastIoDeviceControl: too much output! %#x > %#x; uCmd=%#x!\n",
1558 pHdr->cbOut, cbOut, uCmd));
1559 }
1560 if (cbOut)
1561 {
1562 __try
1563 {
1564 RtlCopyMemory(pvOutput, pHdr, cbOut);
1565 rcNt = STATUS_SUCCESS;
1566 }
1567 __except(EXCEPTION_EXECUTE_HANDLER)
1568 {
1569 rcNt = GetExceptionCode();
1570 }
1571 }
1572 else
1573 rcNt = STATUS_SUCCESS;
1574 }
1575 else if (rc == VERR_INVALID_PARAMETER)
1576 rcNt = STATUS_INVALID_PARAMETER;
1577 else
1578 rcNt = STATUS_NOT_SUPPORTED;
1579 Log2(("VBoxDrvNtFastIoDeviceControl: returns %#x cbOut=%d rc=%#x\n", rcNt, cbOut, rc));
1580 }
1581 else
1582 Log(("VBoxDrvNtFastIoDeviceControl: Error reading %u bytes of user memory at %p (uCmd=%#x)\n",
1583 cbInput, pvInput, uCmd));
1584 ExFreePoolWithTag(pHdr, 'VBox');
1585 }
1586 else
1587 rcNt = STATUS_NO_MEMORY;
1588 }
1589 else
1590 {
1591 Log(("VBoxDrvNtFastIoDeviceControl: Mismatching sizes (%#x) - Hdr=%#lx/%#lx Irp=%#lx/%#lx!\n",
1592 uCmd, Hdr.cbIn, Hdr.cbOut, cbInput, cbOutput));
1593 rcNt = STATUS_INVALID_PARAMETER;
1594 }
1595 }
1596 }
1597 else
1598 {
1599 Log(("VBoxDrvNtFastIoDeviceControl: not buffered request (%#x) - not supported\n", uCmd));
1600 rcNt = STATUS_NOT_SUPPORTED;
1601 }
1602 }
1603# ifdef RT_ARCH_AMD64
1604 else
1605 {
1606 Log(("VBoxDrvNtFastIoDeviceControl: WOW64 req - not supported\n"));
1607 rcNt = STATUS_NOT_SUPPORTED;
1608 }
1609# endif
1610
1611 /* complete the request. */
1612 pIoStatus->Status = rcNt;
1613 pIoStatus->Information = cbOut;
1614 supdrvSessionRelease(pSession);
1615 return TRUE; /* handled. */
1616}
1617#endif /* VBOXDRV_WITH_FAST_IO */
1618
1619
1620/**
1621 * Device I/O Control entry point.
1622 *
1623 * @param pDevObj Device object.
1624 * @param pIrp Request packet.
1625 */
1626NTSTATUS _stdcall VBoxDrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1627{
1628 VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(pDevObj, pIrp);
1629
1630 PSUPDRVDEVEXT pDevExt = SUPDRVNT_GET_DEVEXT(pDevObj);
1631 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1632 PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, RTProcSelf(), RTR0ProcHandleSelf(),
1633 (PSUPDRVSESSION *)&pStack->FileObject->FsContext);
1634
1635 if (!RT_VALID_PTR(pSession))
1636 return supdrvNtCompleteRequest(STATUS_TRUST_FAILURE, pIrp);
1637
1638 /*
1639 * Deal with the 2-3 high-speed IOCtl that takes their arguments from
1640 * the session and iCmd, and does not return anything.
1641 */
1642 if (pSession->fUnrestricted)
1643 {
1644#if defined(VBOX_WITH_HARDENING) && !defined(VBOX_WITHOUT_DEBUGGER_CHECKS)
1645 if (supdrvNtIsDebuggerAttached())
1646 {
1647 supdrvSessionRelease(pSession);
1648 return supdrvNtCompleteRequest(STATUS_TRUST_FAILURE, pIrp);
1649 }
1650#endif
1651
1652 ULONG uCmd = pStack->Parameters.DeviceIoControl.IoControlCode;
1653 if ( (uCmd & 3) == METHOD_NEITHER
1654 && (uint32_t)((uCmd - SUP_IOCTL_FAST_DO_FIRST) >> 2) < (uint32_t)32)
1655 {
1656 int rc = supdrvIOCtlFast((uCmd - SUP_IOCTL_FAST_DO_FIRST) >> 2,
1657 (unsigned)(uintptr_t)pIrp->UserBuffer /* VMCPU id */,
1658 pDevExt, pSession);
1659
1660 /* Complete the I/O request. */
1661 supdrvSessionRelease(pSession);
1662 return supdrvNtCompleteRequest(RT_SUCCESS(rc) ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER, pIrp);
1663 }
1664 }
1665
1666 return VBoxDrvNtDeviceControlSlow(pDevExt, pSession, pIrp, pStack);
1667}
1668
1669
1670/**
1671 * Worker for VBoxDrvNtDeviceControl that takes the slow IOCtl functions.
1672 *
1673 * @returns NT status code.
1674 *
1675 * @param pDevExt Device extension.
1676 * @param pSession The session.
1677 * @param pIrp Request packet.
1678 * @param pStack The stack location containing the DeviceControl parameters.
1679 */
1680static int VBoxDrvNtDeviceControlSlow(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PIRP pIrp, PIO_STACK_LOCATION pStack)
1681{
1682 NTSTATUS rcNt;
1683 uint32_t cbOut = 0;
1684 int rc = 0;
1685 Log2(("VBoxDrvNtDeviceControlSlow(%p,%p): ioctl=%#x pBuf=%p cbIn=%#x cbOut=%#x pSession=%p\n",
1686 pDevExt, pIrp, pStack->Parameters.DeviceIoControl.IoControlCode,
1687 pIrp->AssociatedIrp.SystemBuffer, pStack->Parameters.DeviceIoControl.InputBufferLength,
1688 pStack->Parameters.DeviceIoControl.OutputBufferLength, pSession));
1689
1690#ifdef RT_ARCH_AMD64
1691 /* Don't allow 32-bit processes to do any I/O controls. */
1692 if (!IoIs32bitProcess(pIrp))
1693#endif
1694 {
1695 /* Verify that it's a buffered CTL. */
1696 if ((pStack->Parameters.DeviceIoControl.IoControlCode & 0x3) == METHOD_BUFFERED)
1697 {
1698 /* Verify that the sizes in the request header are correct. */
1699 PSUPREQHDR pHdr = (PSUPREQHDR)pIrp->AssociatedIrp.SystemBuffer;
1700 if ( pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr)
1701 && pStack->Parameters.DeviceIoControl.InputBufferLength == pHdr->cbIn
1702 && pStack->Parameters.DeviceIoControl.OutputBufferLength == pHdr->cbOut)
1703 {
1704 /* Zero extra output bytes to make sure we don't leak anything. */
1705 if (pHdr->cbIn < pHdr->cbOut)
1706 RtlZeroMemory((uint8_t *)pHdr + pHdr->cbIn, pHdr->cbOut - pHdr->cbIn);
1707
1708 /*
1709 * Do the job.
1710 */
1711 rc = supdrvIOCtl(pStack->Parameters.DeviceIoControl.IoControlCode, pDevExt, pSession, pHdr,
1712 RT_MAX(pHdr->cbIn, pHdr->cbOut));
1713 if (!rc)
1714 {
1715 rcNt = STATUS_SUCCESS;
1716 cbOut = pHdr->cbOut;
1717 if (cbOut > pStack->Parameters.DeviceIoControl.OutputBufferLength)
1718 {
1719 cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
1720 OSDBGPRINT(("VBoxDrvNtDeviceControlSlow: too much output! %#x > %#x; uCmd=%#x!\n",
1721 pHdr->cbOut, cbOut, pStack->Parameters.DeviceIoControl.IoControlCode));
1722 }
1723 }
1724 else
1725 rcNt = STATUS_INVALID_PARAMETER;
1726 Log2(("VBoxDrvNtDeviceControlSlow: returns %#x cbOut=%d rc=%#x\n", rcNt, cbOut, rc));
1727 }
1728 else
1729 {
1730 Log(("VBoxDrvNtDeviceControlSlow: Mismatching sizes (%#x) - Hdr=%#lx/%#lx Irp=%#lx/%#lx!\n",
1731 pStack->Parameters.DeviceIoControl.IoControlCode,
1732 pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cbIn : 0,
1733 pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cbOut : 0,
1734 pStack->Parameters.DeviceIoControl.InputBufferLength,
1735 pStack->Parameters.DeviceIoControl.OutputBufferLength));
1736 rcNt = STATUS_INVALID_PARAMETER;
1737 }
1738 }
1739 else
1740 {
1741 Log(("VBoxDrvNtDeviceControlSlow: not buffered request (%#x) - not supported\n",
1742 pStack->Parameters.DeviceIoControl.IoControlCode));
1743 rcNt = STATUS_NOT_SUPPORTED;
1744 }
1745 }
1746#ifdef RT_ARCH_AMD64
1747 else
1748 {
1749 Log(("VBoxDrvNtDeviceControlSlow: WOW64 req - not supported\n"));
1750 rcNt = STATUS_NOT_SUPPORTED;
1751 }
1752#endif
1753
1754 /* complete the request. */
1755 pIrp->IoStatus.Status = rcNt;
1756 pIrp->IoStatus.Information = cbOut;
1757 supdrvSessionRelease(pSession);
1758 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1759 return rcNt;
1760}
1761
1762
1763/**
1764 * Internal Device I/O Control entry point, used for IDC.
1765 *
1766 * @param pDevObj Device object.
1767 * @param pIrp Request packet.
1768 */
1769NTSTATUS _stdcall VBoxDrvNtInternalDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1770{
1771 VBOXDRV_COMPLETE_IRP_AND_RETURN_IF_STUB_OR_ERROR_INFO_DEV(pDevObj, pIrp);
1772
1773 PSUPDRVDEVEXT pDevExt = SUPDRVNT_GET_DEVEXT(pDevObj);
1774 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1775 PFILE_OBJECT pFileObj = pStack ? pStack->FileObject : NULL;
1776 PSUPDRVSESSION pSession = pFileObj ? (PSUPDRVSESSION)pFileObj->FsContext : NULL;
1777 NTSTATUS rcNt;
1778 unsigned cbOut = 0;
1779 int rc = 0;
1780 Log2(("VBoxDrvNtInternalDeviceControl(%p,%p): ioctl=%#x pBuf=%p cbIn=%#x cbOut=%#x pSession=%p\n",
1781 pDevExt, pIrp, pStack->Parameters.DeviceIoControl.IoControlCode,
1782 pIrp->AssociatedIrp.SystemBuffer, pStack->Parameters.DeviceIoControl.InputBufferLength,
1783 pStack->Parameters.DeviceIoControl.OutputBufferLength, pSession));
1784
1785 /* Verify that it's a buffered CTL. */
1786 if ((pStack->Parameters.DeviceIoControl.IoControlCode & 0x3) == METHOD_BUFFERED)
1787 {
1788 /* Verify the pDevExt in the session. */
1789 if ( pStack->Parameters.DeviceIoControl.IoControlCode != SUPDRV_IDC_REQ_CONNECT
1790 ? RT_VALID_PTR(pSession) && pSession->pDevExt == pDevExt
1791 : !pSession
1792 )
1793 {
1794 /* Verify that the size in the request header is correct. */
1795 PSUPDRVIDCREQHDR pHdr = (PSUPDRVIDCREQHDR)pIrp->AssociatedIrp.SystemBuffer;
1796 if ( pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr)
1797 && pStack->Parameters.DeviceIoControl.InputBufferLength == pHdr->cb
1798 && pStack->Parameters.DeviceIoControl.OutputBufferLength == pHdr->cb)
1799 {
1800 /*
1801 * Call the generic code.
1802 *
1803 * Note! Connect and disconnect requires some extra attention
1804 * in order to get the session handling right.
1805 */
1806 if (pStack->Parameters.DeviceIoControl.IoControlCode == SUPDRV_IDC_REQ_DISCONNECT)
1807 pFileObj->FsContext = NULL;
1808
1809 rc = supdrvIDC(pStack->Parameters.DeviceIoControl.IoControlCode, pDevExt, pSession, pHdr);
1810 if (!rc)
1811 {
1812 if (pStack->Parameters.DeviceIoControl.IoControlCode == SUPDRV_IDC_REQ_CONNECT)
1813 pFileObj->FsContext = ((PSUPDRVIDCREQCONNECT)pHdr)->u.Out.pSession;
1814
1815 rcNt = STATUS_SUCCESS;
1816 cbOut = pHdr->cb;
1817 }
1818 else
1819 {
1820 rcNt = STATUS_INVALID_PARAMETER;
1821 if (pStack->Parameters.DeviceIoControl.IoControlCode == SUPDRV_IDC_REQ_DISCONNECT)
1822 pFileObj->FsContext = pSession;
1823 }
1824 Log2(("VBoxDrvNtInternalDeviceControl: returns %#x/rc=%#x\n", rcNt, rc));
1825 }
1826 else
1827 {
1828 Log(("VBoxDrvNtInternalDeviceControl: Mismatching sizes (%#x) - Hdr=%#lx Irp=%#lx/%#lx!\n",
1829 pStack->Parameters.DeviceIoControl.IoControlCode,
1830 pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cb : 0,
1831 pStack->Parameters.DeviceIoControl.InputBufferLength,
1832 pStack->Parameters.DeviceIoControl.OutputBufferLength));
1833 rcNt = STATUS_INVALID_PARAMETER;
1834 }
1835 }
1836 else
1837 rcNt = STATUS_NOT_SUPPORTED;
1838 }
1839 else
1840 {
1841 Log(("VBoxDrvNtInternalDeviceControl: not buffered request (%#x) - not supported\n",
1842 pStack->Parameters.DeviceIoControl.IoControlCode));
1843 rcNt = STATUS_NOT_SUPPORTED;
1844 }
1845
1846 /* complete the request. */
1847 pIrp->IoStatus.Status = rcNt;
1848 pIrp->IoStatus.Information = cbOut;
1849 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1850 return rcNt;
1851}
1852
1853
1854/**
1855 * Implementation of the read major function for VBoxDrvErrorInfo.
1856 *
1857 * This is a stub function for the other devices.
1858 *
1859 * @returns NT status code.
1860 * @param pDevObj The device object.
1861 * @param pIrp The I/O request packet.
1862 */
1863NTSTATUS _stdcall VBoxDrvNtRead(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1864{
1865 Log(("VBoxDrvNtRead\n"));
1866 RT_NOREF1(pDevObj);
1867
1868 NTSTATUS rcNt;
1869 pIrp->IoStatus.Information = 0;
1870
1871#ifdef VBOX_WITH_HARDENING
1872 /*
1873 * VBoxDrvErrorInfo?
1874 */
1875 if (pDevObj == g_pDevObjErrorInfo)
1876 {
1877 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
1878 if ( pStack
1879 && (pIrp->Flags & IRP_BUFFERED_IO))
1880 {
1881 /*
1882 * Look up the process error information.
1883 */
1884 HANDLE hCurThreadId = PsGetCurrentThreadId();
1885 HANDLE hCurProcessId = PsGetCurrentProcessId();
1886 int rc = RTSemMutexRequestNoResume(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
1887 if (RT_SUCCESS(rc))
1888 {
1889 PSUPDRVNTERRORINFO pMatch = NULL;
1890 PSUPDRVNTERRORINFO pCur;
1891 RTListForEach(&g_ErrorInfoHead, pCur, SUPDRVNTERRORINFO, ListEntry)
1892 {
1893 if ( pCur->hProcessId == hCurProcessId
1894 && pCur->hThreadId == hCurThreadId)
1895 {
1896 pMatch = pCur;
1897 break;
1898 }
1899 }
1900
1901 /*
1902 * Did we find error info and is the caller requesting data within it?
1903 * If so, check the destination buffer and copy the data into it.
1904 */
1905 if ( pMatch
1906 && pStack->Parameters.Read.ByteOffset.QuadPart < pMatch->cchErrorInfo
1907 && pStack->Parameters.Read.ByteOffset.QuadPart >= 0)
1908 {
1909 PVOID pvDstBuf = pIrp->AssociatedIrp.SystemBuffer;
1910 if (pvDstBuf)
1911 {
1912 uint32_t offRead = (uint32_t)pStack->Parameters.Read.ByteOffset.QuadPart;
1913 uint32_t cbToRead = pMatch->cchErrorInfo - offRead;
1914 if (cbToRead < pStack->Parameters.Read.Length)
1915 RT_BZERO((uint8_t *)pvDstBuf + cbToRead, pStack->Parameters.Read.Length - cbToRead);
1916 else
1917 cbToRead = pStack->Parameters.Read.Length;
1918 memcpy(pvDstBuf, &pMatch->szErrorInfo[offRead], cbToRead);
1919 pIrp->IoStatus.Information = cbToRead;
1920
1921 rcNt = STATUS_SUCCESS;
1922 }
1923 else
1924 rcNt = STATUS_INVALID_ADDRESS;
1925 }
1926 /*
1927 * End of file. Free the info.
1928 */
1929 else if (pMatch)
1930 {
1931 RTListNodeRemove(&pMatch->ListEntry);
1932 RTMemFree(pMatch);
1933 rcNt = STATUS_END_OF_FILE;
1934 }
1935 /*
1936 * We found no error info. Return EOF.
1937 */
1938 else
1939 rcNt = STATUS_END_OF_FILE;
1940
1941 RTSemMutexRelease(g_hErrorInfoLock);
1942 }
1943 else
1944 rcNt = STATUS_UNSUCCESSFUL;
1945
1946 /* Paranoia: Clear the buffer on failure. */
1947 if (!NT_SUCCESS(rcNt))
1948 {
1949 PVOID pvDstBuf = pIrp->AssociatedIrp.SystemBuffer;
1950 if ( pvDstBuf
1951 && pStack->Parameters.Read.Length)
1952 RT_BZERO(pvDstBuf, pStack->Parameters.Read.Length);
1953 }
1954 }
1955 else
1956 rcNt = STATUS_INVALID_PARAMETER;
1957 }
1958 else
1959#endif /* VBOX_WITH_HARDENING */
1960 {
1961 /*
1962 * Stub.
1963 */
1964 rcNt = STATUS_NOT_SUPPORTED;
1965 }
1966
1967 /*
1968 * Complete the request.
1969 */
1970 pIrp->IoStatus.Status = rcNt;
1971 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1972 return rcNt;
1973}
1974
1975
1976/**
1977 * Stub function for functions we don't implemented.
1978 *
1979 * @returns STATUS_NOT_SUPPORTED
1980 * @param pDevObj Device object.
1981 * @param pIrp IRP.
1982 */
1983NTSTATUS _stdcall VBoxDrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp)
1984{
1985 Log(("VBoxDrvNtNotSupportedStub\n"));
1986 NOREF(pDevObj);
1987
1988 pIrp->IoStatus.Information = 0;
1989 pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
1990 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
1991
1992 return STATUS_NOT_SUPPORTED;
1993}
1994
1995
1996/**
1997 * ExRegisterCallback handler for power events
1998 *
1999 * @param pCallbackContext User supplied parameter (pDevObj)
2000 * @param pvArgument1 First argument
2001 * @param pvArgument2 Second argument
2002 */
2003VOID _stdcall VBoxPowerDispatchCallback(PVOID pCallbackContext, PVOID pvArgument1, PVOID pvArgument2)
2004{
2005 /*PDEVICE_OBJECT pDevObj = (PDEVICE_OBJECT)pCallbackContext;*/ RT_NOREF1(pCallbackContext);
2006 Log(("VBoxPowerDispatchCallback: %x %x\n", pvArgument1, pvArgument2));
2007
2008 /* Power change imminent? */
2009 if ((uintptr_t)pvArgument1 == PO_CB_SYSTEM_STATE_LOCK)
2010 {
2011 if (pvArgument2 == NULL)
2012 Log(("VBoxPowerDispatchCallback: about to go into suspend mode!\n"));
2013 else
2014 Log(("VBoxPowerDispatchCallback: resumed!\n"));
2015
2016 /* Inform any clients that have registered themselves with IPRT. */
2017 RTPowerSignalEvent(pvArgument2 == NULL ? RTPOWEREVENT_SUSPEND : RTPOWEREVENT_RESUME);
2018 }
2019}
2020
2021
2022/**
2023 * Called to clean up the session structure before it's freed.
2024 *
2025 * @param pDevExt The device globals.
2026 * @param pSession The session that's being cleaned up.
2027 */
2028void VBOXCALL supdrvOSCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
2029{
2030#ifdef VBOX_WITH_HARDENING
2031 if (pSession->pNtProtect)
2032 {
2033 supdrvNtProtectRelease(pSession->pNtProtect);
2034 pSession->pNtProtect = NULL;
2035 }
2036 RT_NOREF1(pDevExt);
2037#else
2038 RT_NOREF2(pDevExt, pSession);
2039#endif
2040#ifdef VBOXDRV_WITH_SID_TO_UID_MAPPING
2041 if (pSession->pNtUserId)
2042 {
2043 supdrvNtUserIdRelease(pSession->pNtUserId);
2044 pSession->pNtUserId = NULL;
2045 }
2046#endif
2047}
2048
2049
2050void VBOXCALL supdrvOSSessionHashTabInserted(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
2051{
2052 NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
2053}
2054
2055
2056void VBOXCALL supdrvOSSessionHashTabRemoved(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
2057{
2058 NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
2059}
2060
2061
2062size_t VBOXCALL supdrvOSGipGetGroupTableSize(PSUPDRVDEVEXT pDevExt)
2063{
2064 NOREF(pDevExt);
2065 uint32_t cMaxCpus = RTMpGetCount();
2066 uint32_t cGroups = RTMpGetMaxCpuGroupCount();
2067
2068 return cGroups * RT_UOFFSETOF(SUPGIPCPUGROUP, aiCpuSetIdxs)
2069 + RT_SIZEOFMEMB(SUPGIPCPUGROUP, aiCpuSetIdxs[0]) * cMaxCpus;
2070}
2071
2072
2073int VBOXCALL supdrvOSInitGipGroupTable(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, size_t cbGipCpuGroups)
2074{
2075 Assert(cbGipCpuGroups > 0); NOREF(cbGipCpuGroups); NOREF(pDevExt);
2076
2077 unsigned const cGroups = RTMpGetMaxCpuGroupCount();
2078 AssertReturn(cGroups > 0 && cGroups < RT_ELEMENTS(pGip->aoffCpuGroup), VERR_INTERNAL_ERROR_2);
2079 pGip->cPossibleCpuGroups = cGroups;
2080
2081 PSUPGIPCPUGROUP pGroup = (PSUPGIPCPUGROUP)&pGip->aCPUs[pGip->cCpus];
2082 for (uint32_t idxGroup = 0; idxGroup < cGroups; idxGroup++)
2083 {
2084 uint32_t cActive = 0;
2085 uint32_t const cMax = RTMpGetCpuGroupCounts(idxGroup, &cActive);
2086 uint32_t const cbNeeded = RT_UOFFSETOF_DYN(SUPGIPCPUGROUP, aiCpuSetIdxs[cMax]);
2087 uintptr_t const offGroup = (uintptr_t)pGroup - (uintptr_t)pGip;
2088 AssertReturn(cbNeeded <= cbGipCpuGroups, VERR_INTERNAL_ERROR_3);
2089 AssertReturn(cActive <= cMax, VERR_INTERNAL_ERROR_4);
2090 AssertReturn(offGroup == (uint32_t)offGroup, VERR_INTERNAL_ERROR_5);
2091
2092 pGip->aoffCpuGroup[idxGroup] = offGroup;
2093 pGroup->cMembers = cActive;
2094 pGroup->cMaxMembers = cMax;
2095 for (uint32_t idxMember = 0; idxMember < cMax; idxMember++)
2096 {
2097 pGroup->aiCpuSetIdxs[idxMember] = RTMpSetIndexFromCpuGroupMember(idxGroup, idxMember);
2098 Assert((unsigned)pGroup->aiCpuSetIdxs[idxMember] < pGip->cPossibleCpus);
2099 }
2100
2101 /* advance. */
2102 cbGipCpuGroups -= cbNeeded;
2103 pGroup = (PSUPGIPCPUGROUP)&pGroup->aiCpuSetIdxs[cMax];
2104 }
2105
2106 return VINF_SUCCESS;
2107}
2108
2109
2110void VBOXCALL supdrvOSGipInitGroupBitsForCpu(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pGipCpu)
2111{
2112 NOREF(pDevExt);
2113
2114 /*
2115 * Translate the CPU index into a group and member.
2116 */
2117 PROCESSOR_NUMBER ProcNum = { 0, (UCHAR)pGipCpu->iCpuSet, 0 };
2118 if (g_pfnKeGetProcessorNumberFromIndex)
2119 {
2120 NTSTATUS rcNt = g_pfnKeGetProcessorNumberFromIndex(pGipCpu->iCpuSet, &ProcNum);
2121 if (NT_SUCCESS(rcNt))
2122 Assert(ProcNum.Group < g_pfnKeQueryMaximumGroupCount());
2123 else
2124 {
2125 AssertFailed();
2126 ProcNum.Group = 0;
2127 ProcNum.Number = pGipCpu->iCpuSet;
2128 }
2129 }
2130 pGipCpu->iCpuGroup = ProcNum.Group;
2131 pGipCpu->iCpuGroupMember = ProcNum.Number;
2132
2133 /*
2134 * Update the group info. Just do this wholesale for now (doesn't scale well).
2135 */
2136 for (uint32_t idxGroup = 0; idxGroup < pGip->cPossibleCpuGroups; idxGroup++)
2137 {
2138 uint32_t offGroup = pGip->aoffCpuGroup[idxGroup];
2139 if (offGroup != UINT32_MAX)
2140 {
2141 PSUPGIPCPUGROUP pGroup = (PSUPGIPCPUGROUP)((uintptr_t)pGip + offGroup);
2142 uint32_t cActive = 0;
2143 uint32_t cMax = RTMpGetCpuGroupCounts(idxGroup, &cActive);
2144
2145 AssertStmt(cMax == pGroup->cMaxMembers, cMax = pGroup->cMaxMembers);
2146 AssertStmt(cActive <= cMax, cActive = cMax);
2147 if (pGroup->cMembers != cActive)
2148 ASMAtomicWriteU16(&pGroup->cMembers, cActive);
2149
2150 for (uint32_t idxMember = 0; idxMember < cMax; idxMember++)
2151 {
2152 int idxCpuSet = RTMpSetIndexFromCpuGroupMember(idxGroup, idxMember);
2153 AssertMsg((unsigned)idxCpuSet < pGip->cPossibleCpus,
2154 ("%d vs %d for %u.%u\n", idxCpuSet, pGip->cPossibleCpus, idxGroup, idxMember));
2155
2156 if (pGroup->aiCpuSetIdxs[idxMember] != idxCpuSet)
2157 ASMAtomicWriteS16(&pGroup->aiCpuSetIdxs[idxMember], idxCpuSet);
2158 }
2159 }
2160 }
2161}
2162
2163
2164/**
2165 * Initializes any OS specific object creator fields.
2166 */
2167void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
2168{
2169 NOREF(pObj);
2170 NOREF(pSession);
2171}
2172
2173
2174/**
2175 * Checks if the session can access the object.
2176 *
2177 * @returns true if a decision has been made.
2178 * @returns false if the default access policy should be applied.
2179 *
2180 * @param pObj The object in question.
2181 * @param pSession The session wanting to access the object.
2182 * @param pszObjName The object name, can be NULL.
2183 * @param prc Where to store the result when returning true.
2184 */
2185bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
2186{
2187 NOREF(pObj);
2188 NOREF(pSession);
2189 NOREF(pszObjName);
2190 NOREF(prc);
2191 return false;
2192}
2193
2194
2195/**
2196 * Force async tsc mode (stub).
2197 */
2198bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
2199{
2200 RT_NOREF1(pDevExt);
2201 return g_Options.fOptForceAsyncTsc != 0;
2202}
2203
2204
2205/**
2206 * Whether the host takes CPUs offline during a suspend/resume operation.
2207 */
2208bool VBOXCALL supdrvOSAreCpusOfflinedOnSuspend(void)
2209{
2210 return false;
2211}
2212
2213
2214/**
2215 * Whether the hardware TSC has been synchronized by the OS.
2216 */
2217bool VBOXCALL supdrvOSAreTscDeltasInSync(void)
2218{
2219 /* If IPRT didn't find KeIpiGenericCall we pretend windows(, the firmware,
2220 or whoever) always configures TSCs perfectly. */
2221 return !RTMpOnPairIsConcurrentExecSupported();
2222}
2223
2224
2225# ifdef VBOX_WITH_MINIMAL_HARDENING
2226/**
2227 * Performs pre-opening of .r0 image checks.
2228 *
2229 * When minimal hardening is enabled, we require the images loaded to be signed
2230 * by the build certificate, thus liminiting what we load to things we have
2231 * built ourselves.
2232 */
2233static int supdrvOSLdrCheckBeforeOpen(PUNICODE_STRING pUniStrPath, HANDLE *phImage)
2234{
2235 /*
2236 * Open the image file, denying write accesses.
2237 */
2238 *phImage = RTNT_INVALID_HANDLE_VALUE;
2239 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
2240
2241 OBJECT_ATTRIBUTES ObjAttr;
2242 InitializeObjectAttributes(&ObjAttr, pUniStrPath, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
2243 ObjAttr.Attributes |= OBJ_KERNEL_HANDLE;
2244
2245 NTSTATUS rcNt = NtCreateFile(phImage,
2246 GENERIC_READ | SYNCHRONIZE,
2247 &ObjAttr,
2248 &Ios,
2249 NULL /* Allocation Size*/,
2250 FILE_ATTRIBUTE_NORMAL,
2251 FILE_SHARE_READ,
2252 FILE_OPEN,
2253 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
2254 NULL /*EaBuffer*/,
2255 0 /*EaLength*/);
2256 if (NT_SUCCESS(rcNt))
2257 rcNt = Ios.Status;
2258 int rc;
2259 if (NT_SUCCESS(rcNt))
2260 {
2261 /*
2262 * Verify the image, requiring the a build certificate.
2263 */
2264 PRTERRINFOSTATIC pErrInfo = (PRTERRINFOSTATIC)RTMemAllocZ(sizeof(*pErrInfo));
2265 bool fIgnored = false;
2266 rc = supHardenedWinVerifyImageByHandle(*phImage, pUniStrPath->Buffer, SUPHNTVI_F_REQUIRE_BUILD_CERT,
2267 fIgnored, &fIgnored, pErrInfo ? RTErrInfoInitStatic(pErrInfo) : NULL);
2268 if (RT_SUCCESS(rc))
2269 Log(("VBoxDrv: '%ls' checks out fine (%d)\n", pUniStrPath->Buffer, rc));
2270 else
2271 SUPR0Printf("VBoxDrv: Checking '%ls' failed: %Rrc%#RTeim\n", pUniStrPath->Buffer, rc, &pErrInfo->Core);
2272 RTMemFree(pErrInfo);
2273
2274 if (RT_FAILURE(rc))
2275 {
2276 NtClose(*phImage);
2277 *phImage = RTNT_INVALID_HANDLE_VALUE;
2278 }
2279 }
2280 else
2281 rc = RTErrConvertFromNtStatus(rcNt);
2282 return rc;
2283}
2284# endif /* VBOX_WITH_MINIMAL_HARDENING */
2285
2286
2287#define MY_SystemLoadGdiDriverInSystemSpaceInformation 54
2288#define MY_SystemUnloadGdiDriverInformation 27
2289
2290typedef struct MYSYSTEMGDIDRIVERINFO
2291{
2292 UNICODE_STRING Name; /**< In: image file name. */
2293 PVOID ImageAddress; /**< Out: the load address. */
2294 PVOID SectionPointer; /**< Out: section object. */
2295 PVOID EntryPointer; /**< Out: entry point address. */
2296 PVOID ExportSectionPointer; /**< Out: export directory/section. */
2297 ULONG ImageLength; /**< Out: SizeOfImage. */
2298} MYSYSTEMGDIDRIVERINFO;
2299
2300extern "C" __declspec(dllimport) NTSTATUS NTAPI ZwSetSystemInformation(ULONG, PVOID, ULONG);
2301
2302int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
2303{
2304 pImage->pvNtSectionObj = NULL;
2305 pImage->hMemLock = NIL_RTR0MEMOBJ;
2306
2307#ifdef VBOX_WITHOUT_NATIVE_R0_LOADER
2308# ifndef RT_ARCH_X86
2309# error "VBOX_WITHOUT_NATIVE_R0_LOADER is only safe on x86."
2310# endif
2311 NOREF(pDevExt); NOREF(pszFilename); NOREF(pImage);
2312 return VERR_NOT_SUPPORTED;
2313
2314#else
2315 /*
2316 * Convert the filename from DOS UTF-8 to NT UTF-16.
2317 */
2318 size_t cwcFilename;
2319 int rc = RTStrCalcUtf16LenEx(pszFilename, RTSTR_MAX, &cwcFilename);
2320 if (RT_FAILURE(rc))
2321 return rc;
2322
2323 PRTUTF16 pwcsFilename = (PRTUTF16)RTMemTmpAlloc((4 + cwcFilename + 1) * sizeof(RTUTF16));
2324 if (!pwcsFilename)
2325 return VERR_NO_TMP_MEMORY;
2326
2327 pwcsFilename[0] = '\\';
2328 pwcsFilename[1] = '?';
2329 pwcsFilename[2] = '?';
2330 pwcsFilename[3] = '\\';
2331 PRTUTF16 pwcsTmp = &pwcsFilename[4];
2332 rc = RTStrToUtf16Ex(pszFilename, RTSTR_MAX, &pwcsTmp, cwcFilename + 1, NULL);
2333 if (RT_SUCCESS(rc))
2334 {
2335 /*
2336 * Pre-screen it.
2337 */
2338 MYSYSTEMGDIDRIVERINFO Info;
2339 RtlInitUnicodeString(&Info.Name, pwcsFilename);
2340# ifdef VBOX_WITH_MINIMAL_HARDENING
2341 HANDLE hImage = NULL;
2342 rc = supdrvOSLdrCheckBeforeOpen(&Info.Name, &hImage);
2343 if (RT_SUCCESS(rc))
2344# endif
2345 {
2346 /*
2347 * Try load it.
2348 */
2349 Info.ImageAddress = NULL;
2350 Info.SectionPointer = NULL;
2351 Info.EntryPointer = NULL;
2352 Info.ExportSectionPointer = NULL;
2353 Info.ImageLength = 0;
2354
2355 NTSTATUS rcNt = ZwSetSystemInformation(MY_SystemLoadGdiDriverInSystemSpaceInformation, &Info, sizeof(Info));
2356 if (NT_SUCCESS(rcNt))
2357 {
2358 pImage->pvImage = Info.ImageAddress;
2359 pImage->pvNtSectionObj = Info.SectionPointer;
2360 Log(("ImageAddress=%p SectionPointer=%p ImageLength=%#x cbImageBits=%#x rcNt=%#x '%ls'\n",
2361 Info.ImageAddress, Info.SectionPointer, Info.ImageLength, pImage->cbImageBits, rcNt, Info.Name.Buffer));
2362# ifdef DEBUG_bird
2363 SUPR0Printf("ImageAddress=%p SectionPointer=%p ImageLength=%#x cbImageBits=%#x rcNt=%#x '%ls'\n",
2364 Info.ImageAddress, Info.SectionPointer, Info.ImageLength, pImage->cbImageBits, rcNt, Info.Name.Buffer);
2365# endif
2366 if (pImage->cbImageBits == Info.ImageLength)
2367 {
2368 /*
2369 * Lock down the entire image, just to be on the safe side.
2370 */
2371 rc = RTR0MemObjLockKernel(&pImage->hMemLock, pImage->pvImage, pImage->cbImageBits, RTMEM_PROT_READ);
2372 if (RT_FAILURE(rc))
2373 {
2374 pImage->hMemLock = NIL_RTR0MEMOBJ;
2375 supdrvOSLdrUnload(pDevExt, pImage);
2376 }
2377 }
2378 else
2379 {
2380 supdrvOSLdrUnload(pDevExt, pImage);
2381 rc = VERR_LDR_MISMATCH_NATIVE;
2382 }
2383 }
2384 else
2385 {
2386 Log(("rcNt=%#x '%ls'\n", rcNt, pwcsFilename));
2387 SUPR0Printf("VBoxDrv: rcNt=%x '%ws'\n", rcNt, pwcsFilename);
2388 switch (rcNt)
2389 {
2390 case /* 0xc0000003 */ STATUS_INVALID_INFO_CLASS:
2391# ifdef RT_ARCH_AMD64
2392 /* Unwind will crash and BSOD, so no fallback here! */
2393 rc = VERR_NOT_IMPLEMENTED;
2394# else
2395 /*
2396 * Use the old way of loading the modules.
2397 *
2398 * Note! We do *NOT* try class 26 because it will probably
2399 * not work correctly on terminal servers and such.
2400 */
2401 rc = VERR_NOT_SUPPORTED;
2402# endif
2403 break;
2404 case /* 0xc0000034 */ STATUS_OBJECT_NAME_NOT_FOUND:
2405 rc = VERR_MODULE_NOT_FOUND;
2406 break;
2407 case /* 0xC0000263 */ STATUS_DRIVER_ENTRYPOINT_NOT_FOUND:
2408 rc = VERR_LDR_IMPORTED_SYMBOL_NOT_FOUND;
2409 break;
2410 case /* 0xC0000428 */ STATUS_INVALID_IMAGE_HASH:
2411 rc = VERR_LDR_IMAGE_HASH;
2412 break;
2413 case /* 0xC000010E */ STATUS_IMAGE_ALREADY_LOADED:
2414 Log(("WARNING: see @bugref{4853} for cause of this failure on Windows 7 x64\n"));
2415 rc = VERR_ALREADY_LOADED;
2416 break;
2417 default:
2418 rc = VERR_LDR_GENERAL_FAILURE;
2419 break;
2420 }
2421
2422 pImage->pvNtSectionObj = NULL;
2423 }
2424# ifdef VBOX_WITH_MINIMAL_HARDENING
2425 NtClose(hImage);
2426# endif
2427 }
2428 }
2429
2430 RTMemTmpFree(pwcsFilename);
2431 NOREF(pDevExt);
2432 return rc;
2433#endif
2434}
2435
2436
2437void VBOXCALL supdrvOSLdrNotifyOpened(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
2438{
2439 NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename);
2440}
2441
2442
2443void VBOXCALL supdrvOSLdrNotifyUnloaded(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
2444{
2445 NOREF(pDevExt); NOREF(pImage);
2446}
2447
2448
2449/**
2450 * Common worker for supdrvOSLdrQuerySymbol and supdrvOSLdrValidatePointer.
2451 *
2452 * @note Similar code in rtR0DbgKrnlNtParseModule.
2453 */
2454static int supdrvOSLdrValidatePointerOrQuerySymbol(PSUPDRVLDRIMAGE pImage, void *pv, const char *pszSymbol,
2455 size_t cchSymbol, void **ppvSymbol)
2456{
2457 AssertReturn(pImage->pvNtSectionObj, VERR_INVALID_STATE);
2458 Assert(pszSymbol || !ppvSymbol);
2459
2460 /*
2461 * Locate the export directory in the loaded image.
2462 */
2463 uint8_t const *pbMapping = (uint8_t const *)pImage->pvImage;
2464 uint32_t const cbMapping = pImage->cbImageBits;
2465 uint32_t const uRvaToValidate = (uint32_t)((uintptr_t)pv - (uintptr_t)pbMapping);
2466 AssertReturn(uRvaToValidate < cbMapping || ppvSymbol, VERR_INTERNAL_ERROR_3);
2467
2468 uint32_t const offNtHdrs = *(uint16_t *)pbMapping == IMAGE_DOS_SIGNATURE
2469 ? ((IMAGE_DOS_HEADER const *)pbMapping)->e_lfanew
2470 : 0;
2471 AssertLogRelReturn(offNtHdrs + sizeof(IMAGE_NT_HEADERS) < cbMapping, VERR_INTERNAL_ERROR_5);
2472
2473 IMAGE_NT_HEADERS const *pNtHdrs = (IMAGE_NT_HEADERS const *)((uintptr_t)pbMapping + offNtHdrs);
2474 AssertLogRelReturn(pNtHdrs->Signature == IMAGE_NT_SIGNATURE, VERR_INVALID_EXE_SIGNATURE);
2475 AssertLogRelReturn(pNtHdrs->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC, VERR_BAD_EXE_FORMAT);
2476 AssertLogRelReturn(pNtHdrs->OptionalHeader.NumberOfRvaAndSizes == IMAGE_NUMBEROF_DIRECTORY_ENTRIES, VERR_BAD_EXE_FORMAT);
2477
2478 uint32_t const offEndSectHdrs = offNtHdrs
2479 + sizeof(*pNtHdrs)
2480 + pNtHdrs->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
2481 AssertReturn(offEndSectHdrs < cbMapping, VERR_BAD_EXE_FORMAT);
2482
2483 /*
2484 * Find the export directory.
2485 */
2486 IMAGE_DATA_DIRECTORY ExpDir = pNtHdrs->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
2487 if (!ExpDir.Size)
2488 {
2489 SUPR0Printf("SUPDrv: No exports in %s!\n", pImage->szName);
2490 return ppvSymbol ? VERR_SYMBOL_NOT_FOUND : VERR_NOT_FOUND;
2491 }
2492 AssertReturn( ExpDir.Size >= sizeof(IMAGE_EXPORT_DIRECTORY)
2493 && ExpDir.VirtualAddress >= offEndSectHdrs
2494 && ExpDir.VirtualAddress < cbMapping
2495 && ExpDir.VirtualAddress + ExpDir.Size <= cbMapping, VERR_BAD_EXE_FORMAT);
2496
2497 IMAGE_EXPORT_DIRECTORY const *pExpDir = (IMAGE_EXPORT_DIRECTORY const *)&pbMapping[ExpDir.VirtualAddress];
2498
2499 uint32_t const cNamedExports = pExpDir->NumberOfNames;
2500 AssertReturn(cNamedExports < _1M, VERR_BAD_EXE_FORMAT);
2501 AssertReturn(pExpDir->NumberOfFunctions < _1M, VERR_BAD_EXE_FORMAT);
2502 if (pExpDir->NumberOfFunctions == 0 || cNamedExports == 0)
2503 {
2504 SUPR0Printf("SUPDrv: No exports in %s!\n", pImage->szName);
2505 return ppvSymbol ? VERR_SYMBOL_NOT_FOUND : VERR_NOT_FOUND;
2506 }
2507
2508 uint32_t const cExports = RT_MAX(cNamedExports, pExpDir->NumberOfFunctions);
2509
2510 AssertReturn( pExpDir->AddressOfFunctions >= offEndSectHdrs
2511 && pExpDir->AddressOfFunctions < cbMapping
2512 && pExpDir->AddressOfFunctions + cExports * sizeof(uint32_t) <= cbMapping,
2513 VERR_BAD_EXE_FORMAT);
2514 uint32_t const * const paoffExports = (uint32_t const *)&pbMapping[pExpDir->AddressOfFunctions];
2515
2516 AssertReturn( pExpDir->AddressOfNames >= offEndSectHdrs
2517 && pExpDir->AddressOfNames < cbMapping
2518 && pExpDir->AddressOfNames + cNamedExports * sizeof(uint32_t) <= cbMapping,
2519 VERR_BAD_EXE_FORMAT);
2520 uint32_t const * const paoffNamedExports = (uint32_t const *)&pbMapping[pExpDir->AddressOfNames];
2521
2522 AssertReturn( pExpDir->AddressOfNameOrdinals >= offEndSectHdrs
2523 && pExpDir->AddressOfNameOrdinals < cbMapping
2524 && pExpDir->AddressOfNameOrdinals + cNamedExports * sizeof(uint32_t) <= cbMapping,
2525 VERR_BAD_EXE_FORMAT);
2526 uint16_t const * const pau16NameOrdinals = (uint16_t const *)&pbMapping[pExpDir->AddressOfNameOrdinals];
2527
2528 /*
2529 * Validate the entrypoint RVA by scanning the export table.
2530 */
2531 uint32_t iExportOrdinal = UINT32_MAX;
2532 if (!ppvSymbol)
2533 {
2534 for (uint32_t i = 0; i < cExports; i++)
2535 if (paoffExports[i] == uRvaToValidate)
2536 {
2537 iExportOrdinal = i;
2538 break;
2539 }
2540 if (iExportOrdinal == UINT32_MAX)
2541 {
2542 SUPR0Printf("SUPDrv: No export with rva %#x (%s) in %s!\n", uRvaToValidate, pszSymbol, pImage->szName);
2543 return VERR_NOT_FOUND;
2544 }
2545 }
2546
2547 /*
2548 * Can we validate the symbol name too or should we find a name?
2549 * If so, just do a linear search.
2550 */
2551 if (pszSymbol && (RT_C_IS_UPPER(*pszSymbol) || ppvSymbol))
2552 {
2553 for (uint32_t i = 0; i < cNamedExports; i++)
2554 {
2555 uint32_t const offName = paoffNamedExports[i];
2556 AssertReturn(offName < cbMapping, VERR_BAD_EXE_FORMAT);
2557 uint32_t const cchMaxName = cbMapping - offName;
2558 const char * const pszName = (const char *)&pbMapping[offName];
2559 const char * const pszEnd = (const char *)memchr(pszName, '\0', cchMaxName);
2560 AssertReturn(pszEnd, VERR_BAD_EXE_FORMAT);
2561
2562 if ( cchSymbol == (size_t)(pszEnd - pszName)
2563 && memcmp(pszName, pszSymbol, cchSymbol) == 0)
2564 {
2565 if (ppvSymbol)
2566 {
2567 iExportOrdinal = pau16NameOrdinals[i];
2568 if ( iExportOrdinal < cExports
2569 && paoffExports[iExportOrdinal] < cbMapping)
2570 {
2571 *ppvSymbol = (void *)(paoffExports[iExportOrdinal] + pbMapping);
2572 return VINF_SUCCESS;
2573 }
2574 }
2575 else if (pau16NameOrdinals[i] == iExportOrdinal)
2576 return VINF_SUCCESS;
2577 else
2578 SUPR0Printf("SUPDrv: Different exports found for %s and rva %#x in %s: %#x vs %#x\n",
2579 pszSymbol, uRvaToValidate, pImage->szName, pau16NameOrdinals[i], iExportOrdinal);
2580 return VERR_LDR_BAD_FIXUP;
2581 }
2582 }
2583 if (!ppvSymbol)
2584 SUPR0Printf("SUPDrv: No export named %s (%#x) in %s!\n", pszSymbol, uRvaToValidate, pImage->szName);
2585 return VERR_SYMBOL_NOT_FOUND;
2586 }
2587 return VINF_SUCCESS;
2588}
2589
2590
2591int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv,
2592 const uint8_t *pbImageBits, const char *pszSymbol)
2593{
2594 RT_NOREF(pDevExt, pbImageBits);
2595 return supdrvOSLdrValidatePointerOrQuerySymbol(pImage, pv, pszSymbol, pszSymbol ? strlen(pszSymbol) : 0, NULL);
2596}
2597
2598
2599int VBOXCALL supdrvOSLdrQuerySymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage,
2600 const char *pszSymbol, size_t cchSymbol, void **ppvSymbol)
2601{
2602 RT_NOREF(pDevExt);
2603 AssertReturn(ppvSymbol, VERR_INVALID_PARAMETER);
2604 AssertReturn(pszSymbol, VERR_INVALID_PARAMETER);
2605 return supdrvOSLdrValidatePointerOrQuerySymbol(pImage, NULL, pszSymbol, cchSymbol, ppvSymbol);
2606}
2607
2608
2609/**
2610 * memcmp + errormsg + log.
2611 *
2612 * @returns Same as memcmp.
2613 * @param pImage The image.
2614 * @param pbImageBits The image bits ring-3 uploads.
2615 * @param uRva The RVA to start comparing at.
2616 * @param cb The number of bytes to compare.
2617 * @param pReq The load request.
2618 */
2619static int supdrvNtCompare(PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, uint32_t uRva, uint32_t cb, PSUPLDRLOAD pReq)
2620{
2621 int iDiff = memcmp((uint8_t const *)pImage->pvImage + uRva, pbImageBits + uRva, cb);
2622 if (iDiff)
2623 {
2624 uint32_t cbLeft = cb;
2625 const uint8_t *pbNativeBits = (const uint8_t *)pImage->pvImage;
2626 for (size_t off = uRva; cbLeft > 0; off++, cbLeft--)
2627 if (pbNativeBits[off] != pbImageBits[off])
2628 {
2629 /* Note! We need to copy image bits into a temporary stack buffer here as we'd
2630 otherwise risk overwriting them while formatting the error message. */
2631 uint8_t abBytes[64];
2632 memcpy(abBytes, &pbImageBits[off], RT_MIN(64, cbLeft));
2633 supdrvLdrLoadError(VERR_LDR_MISMATCH_NATIVE, pReq,
2634 "Mismatch at %#x (%p) of %s loaded at %p:\n"
2635 "ntld: %.*Rhxs\n"
2636 "iprt: %.*Rhxs",
2637 off, &pbNativeBits[off], pImage->szName, pImage->pvImage,
2638 RT_MIN(64, cbLeft), &pbNativeBits[off],
2639 RT_MIN(64, cbLeft), &abBytes[0]);
2640 SUPR0Printf("VBoxDrv: %s", pReq->u.Out.szError);
2641 break;
2642 }
2643 }
2644 return iDiff;
2645}
2646
2647/** Image compare exclusion regions. */
2648typedef struct SUPDRVNTEXCLREGIONS
2649{
2650 /** Number of regions. */
2651 uint32_t cRegions;
2652 /** The regions. */
2653 struct SUPDRVNTEXCLREGION
2654 {
2655 uint32_t uRva;
2656 uint32_t cb;
2657 } aRegions[20];
2658} SUPDRVNTEXCLREGIONS;
2659
2660/**
2661 * Adds an exclusion region to the collection.
2662 */
2663static bool supdrvNtAddExclRegion(SUPDRVNTEXCLREGIONS *pRegions, uint32_t uRvaRegion, uint32_t cbRegion)
2664{
2665 uint32_t const cRegions = pRegions->cRegions;
2666 AssertReturn(cRegions + 1 <= RT_ELEMENTS(pRegions->aRegions), false);
2667 uint32_t i = 0;
2668 for (; i < cRegions; i++)
2669 if (uRvaRegion < pRegions->aRegions[i].uRva)
2670 break;
2671 if (i != cRegions)
2672 memmove(&pRegions->aRegions[i + 1], &pRegions->aRegions[i], (cRegions - i) * sizeof(pRegions->aRegions[0]));
2673 pRegions->aRegions[i].uRva = uRvaRegion;
2674 pRegions->aRegions[i].cb = cbRegion;
2675 pRegions->cRegions++;
2676 return true;
2677}
2678
2679
2680int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
2681{
2682 NOREF(pDevExt);
2683 if (pImage->pvNtSectionObj)
2684 {
2685 /*
2686 * Usually, the entire image matches exactly.
2687 */
2688 if (!memcmp(pImage->pvImage, pbImageBits, pImage->cbImageBits))
2689 return VINF_SUCCESS;
2690
2691 /*
2692 * On Windows 10 the ImageBase member of the optional header is sometimes
2693 * updated with the actual load address and sometimes not.
2694 * On older windows versions (builds <= 9200?), a user mode address is
2695 * sometimes found in the image base field after upgrading to VC++ 14.2.
2696 */
2697 uint32_t const offNtHdrs = *(uint16_t *)pbImageBits == IMAGE_DOS_SIGNATURE
2698 ? ((IMAGE_DOS_HEADER const *)pbImageBits)->e_lfanew
2699 : 0;
2700 AssertLogRelReturn(offNtHdrs + sizeof(IMAGE_NT_HEADERS) < pImage->cbImageBits, VERR_INTERNAL_ERROR_5);
2701 IMAGE_NT_HEADERS const *pNtHdrsIprt = (IMAGE_NT_HEADERS const *)(pbImageBits + offNtHdrs);
2702 IMAGE_NT_HEADERS const *pNtHdrsNtLd = (IMAGE_NT_HEADERS const *)((uintptr_t)pImage->pvImage + offNtHdrs);
2703
2704 uint32_t const offImageBase = offNtHdrs + RT_UOFFSETOF(IMAGE_NT_HEADERS, OptionalHeader.ImageBase);
2705 uint32_t const cbImageBase = RT_SIZEOFMEMB(IMAGE_NT_HEADERS, OptionalHeader.ImageBase);
2706 if ( pNtHdrsNtLd->OptionalHeader.ImageBase != pNtHdrsIprt->OptionalHeader.ImageBase
2707 && pNtHdrsIprt->Signature == IMAGE_NT_SIGNATURE
2708 && pNtHdrsIprt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC
2709 && !memcmp(pImage->pvImage, pbImageBits, offImageBase)
2710 && !memcmp((uint8_t const *)pImage->pvImage + offImageBase + cbImageBase,
2711 pbImageBits + offImageBase + cbImageBase,
2712 pImage->cbImageBits - offImageBase - cbImageBase))
2713 return VINF_SUCCESS;
2714
2715 /*
2716 * On Windows Server 2003 (sp2 x86) both import thunk tables are fixed
2717 * up and we typically get a mismatch in the INIT section.
2718 *
2719 * So, lets see if everything matches when excluding the
2720 * OriginalFirstThunk tables and (maybe) the ImageBase member.
2721 * For simplicity the max number of exclusion regions is set to 16.
2722 */
2723 if ( pNtHdrsIprt->Signature == IMAGE_NT_SIGNATURE
2724 && pNtHdrsIprt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC
2725 && pNtHdrsIprt->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IMPORT
2726 && pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size >= sizeof(IMAGE_IMPORT_DESCRIPTOR)
2727 && pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress > sizeof(IMAGE_NT_HEADERS)
2728 && pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress < pImage->cbImageBits
2729 && pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size >= sizeof(IMAGE_LOAD_CONFIG_DIRECTORY)
2730 && pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress > sizeof(IMAGE_NT_HEADERS)
2731 && pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress < pImage->cbImageBits)
2732 {
2733 SUPDRVNTEXCLREGIONS ExcludeRegions;
2734 ExcludeRegions.cRegions = 0;
2735
2736 /* ImageBase: */
2737 if (pNtHdrsNtLd->OptionalHeader.ImageBase != pNtHdrsIprt->OptionalHeader.ImageBase)
2738 supdrvNtAddExclRegion(&ExcludeRegions, offImageBase, cbImageBase);
2739
2740 /* Imports: */
2741 uint32_t cImpsLeft = pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
2742 / sizeof(IMAGE_IMPORT_DESCRIPTOR);
2743 uint32_t offImps = pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
2744 AssertLogRelReturn(offImps + cImpsLeft * sizeof(IMAGE_IMPORT_DESCRIPTOR) <= pImage->cbImageBits, VERR_INTERNAL_ERROR_3);
2745 IMAGE_IMPORT_DESCRIPTOR const *pImp = (IMAGE_IMPORT_DESCRIPTOR const *)(pbImageBits + offImps);
2746 while ( cImpsLeft-- > 0
2747 && ExcludeRegions.cRegions < RT_ELEMENTS(ExcludeRegions.aRegions))
2748 {
2749 uint32_t uRvaThunk = pImp->OriginalFirstThunk;
2750 if ( uRvaThunk > sizeof(IMAGE_NT_HEADERS)
2751 && uRvaThunk <= pImage->cbImageBits - sizeof(IMAGE_THUNK_DATA)
2752 && uRvaThunk != pImp->FirstThunk)
2753 {
2754 /* Find the size of the thunk table. */
2755 IMAGE_THUNK_DATA const *paThunk = (IMAGE_THUNK_DATA const *)(pbImageBits + uRvaThunk);
2756 uint32_t cMaxThunks = (pImage->cbImageBits - uRvaThunk) / sizeof(IMAGE_THUNK_DATA);
2757 uint32_t cThunks = 0;
2758 while (cThunks < cMaxThunks && paThunk[cThunks].u1.Function != 0)
2759 cThunks++;
2760 supdrvNtAddExclRegion(&ExcludeRegions, uRvaThunk, cThunks * sizeof(IMAGE_THUNK_DATA));
2761 }
2762
2763#if 0 /* Useful for VMMR0 hacking, not for production use. See also SUPDrvLdr.cpp. */
2764 /* Exclude the other thunk table if ntoskrnl.exe. */
2765 uint32_t uRvaName = pImp->Name;
2766 if ( uRvaName > sizeof(IMAGE_NT_HEADERS)
2767 && uRvaName < pImage->cbImageBits - sizeof("ntoskrnl.exe")
2768 && memcmp(&pbImageBits[uRvaName], RT_STR_TUPLE("ntoskrnl.exe")) == 0)
2769 {
2770 uRvaThunk = pImp->FirstThunk;
2771 if ( uRvaThunk > sizeof(IMAGE_NT_HEADERS)
2772 && uRvaThunk <= pImage->cbImageBits - sizeof(IMAGE_THUNK_DATA))
2773 {
2774 /* Find the size of the thunk table. */
2775 IMAGE_THUNK_DATA const *paThunk = (IMAGE_THUNK_DATA const *)(pbImageBits + uRvaThunk);
2776 uint32_t cMaxThunks = (pImage->cbImageBits - uRvaThunk) / sizeof(IMAGE_THUNK_DATA);
2777 uint32_t cThunks = 0;
2778 while (cThunks < cMaxThunks && paThunk[cThunks].u1.Function != 0)
2779 cThunks++;
2780 supdrvNtAddExclRegion(&ExcludeRegions, uRvaThunk, cThunks * sizeof(IMAGE_THUNK_DATA));
2781 }
2782 }
2783#endif
2784
2785 /* advance */
2786 pImp++;
2787 }
2788
2789 /* Exclude the security cookie if present. */
2790 /*uint32_t const cbCfg = pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size; */
2791 uint32_t const offCfg = pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress;
2792 IMAGE_LOAD_CONFIG_DIRECTORY const * const pCfg = (IMAGE_LOAD_CONFIG_DIRECTORY const *)&pbImageBits[offCfg];
2793 /** @todo validate offsets/sizes better here! */
2794 if ( pCfg->Size >= RT_UOFFSET_AFTER(IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie)
2795 && pCfg->SecurityCookie != NULL)
2796 supdrvNtAddExclRegion(&ExcludeRegions, (uintptr_t)pCfg->SecurityCookie - (uintptr_t)pImage->pvImage, sizeof(void *));
2797
2798 /* Also exclude the GuardCFCheckFunctionPointer and GuardCFDispatchFunctionPointer pointer variables. */
2799 if ( pCfg->Size >= RT_UOFFSET_AFTER(IMAGE_LOAD_CONFIG_DIRECTORY, GuardCFCheckFunctionPointer)
2800 && pCfg->GuardCFCheckFunctionPointer != NULL)
2801 supdrvNtAddExclRegion(&ExcludeRegions, (uintptr_t)pCfg->GuardCFCheckFunctionPointer - (uintptr_t)pImage->pvImage, sizeof(void *));
2802 if ( pCfg->Size >= RT_UOFFSET_AFTER(IMAGE_LOAD_CONFIG_DIRECTORY, GuardCFDispatchFunctionPointer)
2803 && pCfg->GuardCFDispatchFunctionPointer != NULL)
2804 supdrvNtAddExclRegion(&ExcludeRegions, (uintptr_t)pCfg->GuardCFDispatchFunctionPointer - (uintptr_t)pImage->pvImage, sizeof(void *));
2805
2806 /* Ditto for the XFG variants: */
2807 if ( pCfg->Size >= RT_UOFFSET_AFTER(IMAGE_LOAD_CONFIG_DIRECTORY, GuardXFGCheckFunctionPointer)
2808 && pCfg->GuardXFGCheckFunctionPointer != NULL)
2809 supdrvNtAddExclRegion(&ExcludeRegions, (uintptr_t)pCfg->GuardXFGCheckFunctionPointer - (uintptr_t)pImage->pvImage, sizeof(void *));
2810 if ( pCfg->Size >= RT_UOFFSET_AFTER(IMAGE_LOAD_CONFIG_DIRECTORY, GuardXFGDispatchFunctionPointer)
2811 && pCfg->GuardXFGDispatchFunctionPointer != NULL)
2812 supdrvNtAddExclRegion(&ExcludeRegions, (uintptr_t)pCfg->GuardXFGDispatchFunctionPointer - (uintptr_t)pImage->pvImage, sizeof(void *));
2813
2814 /** @todo What about GuardRFVerifyStackPointerFunctionPointer and
2815 * GuardRFFailureRoutineFunctionPointer? Ignore for now as the compiler we're
2816 * using (19.26.28805) sets them to zero from what I can tell. */
2817
2818 /*
2819 * Ok, do the comparison.
2820 */
2821 int iDiff = 0;
2822 uint32_t uRvaNext = 0;
2823 for (unsigned i = 0; !iDiff && i < ExcludeRegions.cRegions; i++)
2824 {
2825 if (uRvaNext < ExcludeRegions.aRegions[i].uRva)
2826 iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, ExcludeRegions.aRegions[i].uRva - uRvaNext, pReq);
2827 uRvaNext = ExcludeRegions.aRegions[i].uRva + ExcludeRegions.aRegions[i].cb;
2828 }
2829 if (!iDiff && uRvaNext < pImage->cbImageBits)
2830 iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, pImage->cbImageBits - uRvaNext, pReq);
2831 if (!iDiff)
2832 {
2833 /*
2834 * If there is a cookie init export, call it.
2835 *
2836 * This typically just does:
2837 * __security_cookie = (rdtsc ^ &__security_cookie) & 0xffffffffffff;
2838 * __security_cookie_complement = ~__security_cookie;
2839 */
2840 PFNRT pfnModuleInitSecurityCookie = NULL;
2841 int rcSym = supdrvOSLdrQuerySymbol(pDevExt, pImage, RT_STR_TUPLE("ModuleInitSecurityCookie"),
2842 (void **)&pfnModuleInitSecurityCookie);
2843 if (RT_SUCCESS(rcSym) && pfnModuleInitSecurityCookie)
2844 pfnModuleInitSecurityCookie();
2845
2846 return VINF_SUCCESS;
2847 }
2848 }
2849 else
2850 supdrvNtCompare(pImage, pbImageBits, 0, pImage->cbImageBits, pReq);
2851 return VERR_LDR_MISMATCH_NATIVE;
2852 }
2853 return supdrvLdrLoadError(VERR_INTERNAL_ERROR_4, pReq, "No NT section object! Impossible!");
2854}
2855
2856
2857void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
2858{
2859 if (pImage->pvNtSectionObj)
2860 {
2861 if (pImage->hMemLock != NIL_RTR0MEMOBJ)
2862 {
2863 RTR0MemObjFree(pImage->hMemLock, false /*fFreeMappings*/);
2864 pImage->hMemLock = NIL_RTR0MEMOBJ;
2865 }
2866
2867 NTSTATUS rcNt = ZwSetSystemInformation(MY_SystemUnloadGdiDriverInformation,
2868 &pImage->pvNtSectionObj, sizeof(pImage->pvNtSectionObj));
2869 if (rcNt != STATUS_SUCCESS)
2870 SUPR0Printf("VBoxDrv: failed to unload '%s', rcNt=%#x\n", pImage->szName, rcNt);
2871 pImage->pvNtSectionObj = NULL;
2872 }
2873 NOREF(pDevExt);
2874}
2875
2876
2877void VBOXCALL supdrvOSLdrRetainWrapperModule(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
2878{
2879 RT_NOREF(pDevExt, pImage);
2880 AssertFailed();
2881}
2882
2883
2884void VBOXCALL supdrvOSLdrReleaseWrapperModule(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
2885{
2886 RT_NOREF(pDevExt, pImage);
2887 AssertFailed();
2888}
2889
2890
2891#ifdef SUPDRV_WITH_MSR_PROBER
2892
2893#if 1
2894/** @todo make this selectable. */
2895# define AMD_MSR_PASSCODE 0x9c5a203a
2896#else
2897# define ASMRdMsrEx(a, b, c) ASMRdMsr(a)
2898# define ASMWrMsrEx(a, b, c) ASMWrMsr(a,c)
2899#endif
2900
2901
2902/**
2903 * Argument package used by supdrvOSMsrProberRead and supdrvOSMsrProberWrite.
2904 */
2905typedef struct SUPDRVNTMSPROBERARGS
2906{
2907 uint32_t uMsr;
2908 uint64_t uValue;
2909 bool fGp;
2910} SUPDRVNTMSPROBERARGS;
2911
2912/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberRead.} */
2913static DECLCALLBACK(void) supdrvNtMsProberReadOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
2914{
2915 /*
2916 * rdmsr and wrmsr faults can be caught even with interrupts disabled.
2917 * (At least on 32-bit XP.)
2918 */
2919 SUPDRVNTMSPROBERARGS *pArgs = (SUPDRVNTMSPROBERARGS *)pvUser1; NOREF(idCpu); NOREF(pvUser2);
2920 RTCCUINTREG fOldFlags = ASMIntDisableFlags();
2921 __try
2922 {
2923 pArgs->uValue = ASMRdMsrEx(pArgs->uMsr, AMD_MSR_PASSCODE);
2924 pArgs->fGp = false;
2925 }
2926 __except(EXCEPTION_EXECUTE_HANDLER)
2927 {
2928 pArgs->fGp = true;
2929 pArgs->uValue = 0;
2930 }
2931 ASMSetFlags(fOldFlags);
2932}
2933
2934
2935int VBOXCALL supdrvOSMsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue)
2936{
2937 SUPDRVNTMSPROBERARGS Args;
2938 Args.uMsr = uMsr;
2939 Args.uValue = 0;
2940 Args.fGp = true;
2941
2942 if (idCpu == NIL_RTCPUID)
2943 supdrvNtMsProberReadOnCpu(idCpu, &Args, NULL);
2944 else
2945 {
2946 int rc = RTMpOnSpecific(idCpu, supdrvNtMsProberReadOnCpu, &Args, NULL);
2947 if (RT_FAILURE(rc))
2948 return rc;
2949 }
2950
2951 if (Args.fGp)
2952 return VERR_ACCESS_DENIED;
2953 *puValue = Args.uValue;
2954 return VINF_SUCCESS;
2955}
2956
2957
2958/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberWrite.} */
2959static DECLCALLBACK(void) supdrvNtMsProberWriteOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
2960{
2961 /*
2962 * rdmsr and wrmsr faults can be caught even with interrupts disabled.
2963 * (At least on 32-bit XP.)
2964 */
2965 SUPDRVNTMSPROBERARGS *pArgs = (SUPDRVNTMSPROBERARGS *)pvUser1; NOREF(idCpu); NOREF(pvUser2);
2966 RTCCUINTREG fOldFlags = ASMIntDisableFlags();
2967 __try
2968 {
2969 ASMWrMsrEx(pArgs->uMsr, AMD_MSR_PASSCODE, pArgs->uValue);
2970 pArgs->fGp = false;
2971 }
2972 __except(EXCEPTION_EXECUTE_HANDLER)
2973 {
2974 pArgs->fGp = true;
2975 }
2976 ASMSetFlags(fOldFlags);
2977}
2978
2979int VBOXCALL supdrvOSMsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue)
2980{
2981 SUPDRVNTMSPROBERARGS Args;
2982 Args.uMsr = uMsr;
2983 Args.uValue = uValue;
2984 Args.fGp = true;
2985
2986 if (idCpu == NIL_RTCPUID)
2987 supdrvNtMsProberWriteOnCpu(idCpu, &Args, NULL);
2988 else
2989 {
2990 int rc = RTMpOnSpecific(idCpu, supdrvNtMsProberWriteOnCpu, &Args, NULL);
2991 if (RT_FAILURE(rc))
2992 return rc;
2993 }
2994
2995 if (Args.fGp)
2996 return VERR_ACCESS_DENIED;
2997 return VINF_SUCCESS;
2998}
2999
3000/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberModify.} */
3001static DECLCALLBACK(void) supdrvNtMsProberModifyOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
3002{
3003 PSUPMSRPROBER pReq = (PSUPMSRPROBER)pvUser1;
3004 register uint32_t uMsr = pReq->u.In.uMsr;
3005 bool const fFaster = pReq->u.In.enmOp == SUPMSRPROBEROP_MODIFY_FASTER;
3006 uint64_t uBefore = 0;
3007 uint64_t uWritten = 0;
3008 uint64_t uAfter = 0;
3009 bool fBeforeGp = true;
3010 bool fModifyGp = true;
3011 bool fAfterGp = true;
3012 bool fRestoreGp = true;
3013 RTCCUINTREG fOldFlags;
3014 RT_NOREF2(idCpu, pvUser2);
3015
3016 /*
3017 * Do the job.
3018 */
3019 fOldFlags = ASMIntDisableFlags();
3020 ASMCompilerBarrier(); /* paranoia */
3021 if (!fFaster)
3022 ASMWriteBackAndInvalidateCaches();
3023
3024 __try
3025 {
3026 uBefore = ASMRdMsrEx(uMsr, AMD_MSR_PASSCODE);
3027 fBeforeGp = false;
3028 }
3029 __except(EXCEPTION_EXECUTE_HANDLER)
3030 {
3031 fBeforeGp = true;
3032 }
3033 if (!fBeforeGp)
3034 {
3035 register uint64_t uRestore = uBefore;
3036
3037 /* Modify. */
3038 uWritten = uRestore;
3039 uWritten &= pReq->u.In.uArgs.Modify.fAndMask;
3040 uWritten |= pReq->u.In.uArgs.Modify.fOrMask;
3041 __try
3042 {
3043 ASMWrMsrEx(uMsr, AMD_MSR_PASSCODE, uWritten);
3044 fModifyGp = false;
3045 }
3046 __except(EXCEPTION_EXECUTE_HANDLER)
3047 {
3048 fModifyGp = true;
3049 }
3050
3051 /* Read modified value. */
3052 __try
3053 {
3054 uAfter = ASMRdMsrEx(uMsr, AMD_MSR_PASSCODE);
3055 fAfterGp = false;
3056 }
3057 __except(EXCEPTION_EXECUTE_HANDLER)
3058 {
3059 fAfterGp = true;
3060 }
3061
3062 /* Restore original value. */
3063 __try
3064 {
3065 ASMWrMsrEx(uMsr, AMD_MSR_PASSCODE, uRestore);
3066 fRestoreGp = false;
3067 }
3068 __except(EXCEPTION_EXECUTE_HANDLER)
3069 {
3070 fRestoreGp = true;
3071 }
3072
3073 /* Invalid everything we can. */
3074 if (!fFaster)
3075 {
3076 ASMWriteBackAndInvalidateCaches();
3077 ASMReloadCR3();
3078 ASMNopPause();
3079 }
3080 }
3081
3082 ASMCompilerBarrier(); /* paranoia */
3083 ASMSetFlags(fOldFlags);
3084
3085 /*
3086 * Write out the results.
3087 */
3088 pReq->u.Out.uResults.Modify.uBefore = uBefore;
3089 pReq->u.Out.uResults.Modify.uWritten = uWritten;
3090 pReq->u.Out.uResults.Modify.uAfter = uAfter;
3091 pReq->u.Out.uResults.Modify.fBeforeGp = fBeforeGp;
3092 pReq->u.Out.uResults.Modify.fModifyGp = fModifyGp;
3093 pReq->u.Out.uResults.Modify.fAfterGp = fAfterGp;
3094 pReq->u.Out.uResults.Modify.fRestoreGp = fRestoreGp;
3095 RT_ZERO(pReq->u.Out.uResults.Modify.afReserved);
3096}
3097
3098
3099int VBOXCALL supdrvOSMsrProberModify(RTCPUID idCpu, PSUPMSRPROBER pReq)
3100{
3101 if (idCpu == NIL_RTCPUID)
3102 {
3103 supdrvNtMsProberModifyOnCpu(idCpu, pReq, NULL);
3104 return VINF_SUCCESS;
3105 }
3106 return RTMpOnSpecific(idCpu, supdrvNtMsProberModifyOnCpu, pReq, NULL);
3107}
3108
3109#endif /* SUPDRV_WITH_MSR_PROBER */
3110
3111
3112/**
3113 * Converts an IPRT error code to an nt status code.
3114 *
3115 * @returns corresponding nt status code.
3116 * @param rc IPRT error status code.
3117 */
3118static NTSTATUS VBoxDrvNtErr2NtStatus(int rc)
3119{
3120 switch (rc)
3121 {
3122 case VINF_SUCCESS: return STATUS_SUCCESS;
3123 case VERR_GENERAL_FAILURE: return STATUS_NOT_SUPPORTED;
3124 case VERR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER;
3125 case VERR_INVALID_MAGIC: return STATUS_UNKNOWN_REVISION;
3126 case VERR_INVALID_HANDLE: return STATUS_INVALID_HANDLE;
3127 case VERR_INVALID_POINTER: return STATUS_INVALID_ADDRESS;
3128 case VERR_LOCK_FAILED: return STATUS_NOT_LOCKED;
3129 case VERR_ALREADY_LOADED: return STATUS_IMAGE_ALREADY_LOADED;
3130 case VERR_PERMISSION_DENIED: return STATUS_ACCESS_DENIED;
3131 case VERR_VERSION_MISMATCH: return STATUS_REVISION_MISMATCH;
3132 }
3133
3134 if (rc < 0)
3135 {
3136 if (((uint32_t)rc & UINT32_C(0xffff0000)) == UINT32_C(0xffff0000))
3137 return (NTSTATUS)( ((uint32_t)rc & UINT32_C(0xffff)) | SUP_NT_STATUS_BASE );
3138 }
3139 return STATUS_UNSUCCESSFUL;
3140}
3141
3142
3143SUPR0DECL(int) SUPR0PrintfV(const char *pszFormat, va_list va)
3144{
3145 char szMsg[384];
3146 size_t cch = RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
3147 szMsg[sizeof(szMsg) - 1] = '\0';
3148
3149 RTLogWriteDebugger(szMsg, cch);
3150 return 0;
3151}
3152
3153
3154SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void)
3155{
3156 return 0;
3157}
3158
3159
3160SUPR0DECL(bool) SUPR0FpuBegin(bool fCtxHook)
3161{
3162 RT_NOREF(fCtxHook);
3163 return false;
3164}
3165
3166
3167SUPR0DECL(void) SUPR0FpuEnd(bool fCtxHook)
3168{
3169 RT_NOREF(fCtxHook);
3170}
3171
3172
3173SUPR0DECL(int) SUPR0IoCtlSetupForHandle(PSUPDRVSESSION pSession, intptr_t hHandle, uint32_t fFlags, PSUPR0IOCTLCTX *ppCtx)
3174{
3175 /*
3176 * Validate input.
3177 */
3178 AssertPtrReturn(ppCtx, VERR_INVALID_POINTER);
3179 *ppCtx = NULL;
3180 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
3181 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
3182
3183 /*
3184 * Turn the partition handle into a file object and related device object
3185 * so that we can issue direct I/O control calls to the pair later.
3186 */
3187 PFILE_OBJECT pFileObject = NULL;
3188 OBJECT_HANDLE_INFORMATION HandleInfo = { 0, 0 };
3189 NTSTATUS rcNt = ObReferenceObjectByHandle((HANDLE)hHandle, /*FILE_WRITE_DATA*/0, *IoFileObjectType,
3190 UserMode, (void **)&pFileObject, &HandleInfo);
3191 if (!NT_SUCCESS(rcNt))
3192 return RTErrConvertFromNtStatus(rcNt);
3193 AssertPtrReturn(pFileObject, VERR_INTERNAL_ERROR_3);
3194
3195 PDEVICE_OBJECT pDevObject = IoGetRelatedDeviceObject(pFileObject);
3196 AssertMsgReturnStmt(RT_VALID_PTR(pDevObject), ("pDevObject=%p\n", pDevObject),
3197 ObDereferenceObject(pFileObject), VERR_INTERNAL_ERROR_2);
3198
3199 /*
3200 * Allocate a context structure and fill it in.
3201 */
3202 PSUPR0IOCTLCTX pCtx = (PSUPR0IOCTLCTX)RTMemAllocZ(sizeof(*pCtx));
3203 if (pCtx)
3204 {
3205 pCtx->u32Magic = SUPR0IOCTLCTX_MAGIC;
3206 pCtx->cRefs = 1;
3207 pCtx->pFileObject = pFileObject;
3208 pCtx->pDeviceObject = pDevObject;
3209
3210 PDRIVER_OBJECT pDrvObject = pDevObject->DriverObject;
3211 if ( RT_VALID_PTR(pDrvObject->FastIoDispatch)
3212 && RT_VALID_PTR(pDrvObject->FastIoDispatch->FastIoDeviceControl))
3213 pCtx->pfnFastIoDeviceControl = pDrvObject->FastIoDispatch->FastIoDeviceControl;
3214 else
3215 pCtx->pfnFastIoDeviceControl = NULL;
3216 *ppCtx = pCtx;
3217 return VINF_SUCCESS;
3218 }
3219
3220 ObDereferenceObject(pFileObject);
3221 return VERR_NO_MEMORY;
3222}
3223
3224
3225/**
3226 * I/O control destructor for NT.
3227 *
3228 * @param pCtx The context to destroy.
3229 */
3230static void supdrvNtIoCtlContextDestroy(PSUPR0IOCTLCTX pCtx)
3231{
3232 PFILE_OBJECT pFileObject = pCtx->pFileObject;
3233 pCtx->pfnFastIoDeviceControl = NULL;
3234 pCtx->pFileObject = NULL;
3235 pCtx->pDeviceObject = NULL;
3236 ASMAtomicWriteU32(&pCtx->u32Magic, ~SUPR0IOCTLCTX_MAGIC);
3237
3238 if (RT_VALID_PTR(pFileObject))
3239 ObDereferenceObject(pFileObject);
3240 RTMemFree(pCtx);
3241}
3242
3243
3244SUPR0DECL(int) SUPR0IoCtlCleanup(PSUPR0IOCTLCTX pCtx)
3245{
3246 if (pCtx != NULL)
3247 {
3248 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
3249 AssertReturn(pCtx->u32Magic == SUPR0IOCTLCTX_MAGIC, VERR_INVALID_PARAMETER);
3250
3251 uint32_t cRefs = ASMAtomicDecU32(&pCtx->cRefs);
3252 Assert(cRefs < _4K);
3253 if (cRefs == 0)
3254 supdrvNtIoCtlContextDestroy(pCtx);
3255 }
3256 return VINF_SUCCESS;
3257}
3258
3259
3260SUPR0DECL(int) SUPR0IoCtlPerform(PSUPR0IOCTLCTX pCtx, uintptr_t uFunction,
3261 void *pvInput, RTR3PTR pvInputUser, size_t cbInput,
3262 void *pvOutput, RTR3PTR pvOutputUser, size_t cbOutput,
3263 int32_t *piNativeRc)
3264{
3265 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
3266 AssertReturn(pCtx->u32Magic == SUPR0IOCTLCTX_MAGIC, VERR_INVALID_PARAMETER);
3267
3268 /* Reference the context. */
3269 uint32_t cRefs = ASMAtomicIncU32(&pCtx->cRefs);
3270 Assert(cRefs > 1 && cRefs < _4K);
3271
3272 /*
3273 * Try fast I/O control path first.
3274 */
3275 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
3276 if (pCtx->pfnFastIoDeviceControl)
3277 {
3278 /* Must pass user addresses here as that's what's being expected. */
3279 BOOLEAN fHandled = pCtx->pfnFastIoDeviceControl(pCtx->pFileObject,
3280 TRUE /*Wait*/,
3281 (void *)pvInputUser, (ULONG)cbInput,
3282 (void *)pvOutputUser, (ULONG)cbOutput,
3283 uFunction,
3284 &Ios,
3285 pCtx->pDeviceObject);
3286 if (fHandled)
3287 {
3288 /* Relase the context. */
3289 cRefs = ASMAtomicDecU32(&pCtx->cRefs);
3290 Assert(cRefs < _4K);
3291 if (cRefs == 0)
3292 supdrvNtIoCtlContextDestroy(pCtx);
3293
3294 /* Set/convert status and return. */
3295 if (piNativeRc)
3296 {
3297 *piNativeRc = Ios.Status;
3298 return VINF_SUCCESS;
3299 }
3300 if (NT_SUCCESS(Ios.Status))
3301 return VINF_SUCCESS;
3302 return RTErrConvertFromNtStatus(Ios.Status);
3303 }
3304
3305 /*
3306 * Fall back on IRP if not handled.
3307 *
3308 * Note! Perhaps we should rather fail, because VID.SYS will crash getting
3309 * the partition ID with the code below. It tries to zero the output
3310 * buffer as if it were as system buffer...
3311 */
3312 RTNT_IO_STATUS_BLOCK_REINIT(&Ios);
3313 }
3314
3315 /*
3316 * For directly accessed buffers we must supply user mode addresses or
3317 * we'll fail ProbeForWrite validation.
3318 */
3319 switch (uFunction & 3)
3320 {
3321 case METHOD_BUFFERED:
3322 /* For buffered accesses, we can supply kernel buffers. */
3323 break;
3324
3325 case METHOD_IN_DIRECT:
3326 pvInput = (void *)pvInputUser;
3327 break;
3328
3329 case METHOD_NEITHER:
3330 pvInput = (void *)pvInputUser;
3331 RT_FALL_THRU();
3332
3333 case METHOD_OUT_DIRECT:
3334 pvOutput = (void *)pvOutputUser;
3335 break;
3336 }
3337
3338 /*
3339 * Build the request.
3340 */
3341 int rc;
3342 KEVENT Event;
3343 KeInitializeEvent(&Event, NotificationEvent, FALSE);
3344
3345 PIRP pIrp = IoBuildDeviceIoControlRequest(uFunction, pCtx->pDeviceObject,
3346 pvInput, (ULONG)cbInput, pvOutput, (ULONG)cbOutput,
3347 FALSE /* InternalDeviceControl */, &Event, &Ios);
3348 if (pIrp)
3349 {
3350 IoGetNextIrpStackLocation(pIrp)->FileObject = pCtx->pFileObject;
3351
3352 /*
3353 * Make the call.
3354 */
3355 NTSTATUS rcNt = IoCallDriver(pCtx->pDeviceObject, pIrp);
3356 if (rcNt == STATUS_PENDING)
3357 {
3358 rcNt = KeWaitForSingleObject(&Event, /* Object */
3359 Executive, /* WaitReason */
3360 KernelMode, /* WaitMode */
3361 FALSE, /* Alertable */
3362 NULL); /* TimeOut */
3363 AssertMsg(rcNt == STATUS_SUCCESS, ("rcNt=%#x\n", rcNt));
3364 rcNt = Ios.Status;
3365 }
3366 else if (NT_SUCCESS(rcNt) && Ios.Status != STATUS_SUCCESS)
3367 rcNt = Ios.Status;
3368
3369 /* Set/convert return code. */
3370 if (piNativeRc)
3371 {
3372 *piNativeRc = rcNt;
3373 rc = VINF_SUCCESS;
3374 }
3375 else if (NT_SUCCESS(rcNt))
3376 rc = VINF_SUCCESS;
3377 else
3378 rc = RTErrConvertFromNtStatus(rcNt);
3379 }
3380 else
3381 {
3382 if (piNativeRc)
3383 *piNativeRc = STATUS_NO_MEMORY;
3384 rc = VERR_NO_MEMORY;
3385 }
3386
3387 /* Relase the context. */
3388 cRefs = ASMAtomicDecU32(&pCtx->cRefs);
3389 Assert(cRefs < _4K);
3390 if (cRefs == 0)
3391 supdrvNtIoCtlContextDestroy(pCtx);
3392
3393 return rc;
3394}
3395
3396
3397#ifdef VBOX_WITH_HARDENING
3398
3399/** @name Identifying Special Processes: CSRSS.EXE
3400 * @{ */
3401
3402
3403/**
3404 * Checks if the process is a system32 process by the given name.
3405 *
3406 * @returns true / false.
3407 * @param pProcess The process to check.
3408 * @param pszName The lower case process name (no path!).
3409 */
3410static bool supdrvNtProtectIsSystem32ProcessMatch(PEPROCESS pProcess, const char *pszName)
3411{
3412 Assert(strlen(pszName) < 16); /* see buffer below */
3413
3414 /*
3415 * This test works on XP+.
3416 */
3417 const char *pszImageFile = (const char *)PsGetProcessImageFileName(pProcess);
3418 if (!pszImageFile)
3419 return false;
3420
3421 if (RTStrICmp(pszImageFile, pszName) != 0)
3422 return false;
3423
3424 /*
3425 * This test requires a Vista+ API.
3426 */
3427 if (g_pfnPsReferenceProcessFilePointer)
3428 {
3429 PFILE_OBJECT pFile = NULL;
3430 NTSTATUS rcNt = g_pfnPsReferenceProcessFilePointer(pProcess, &pFile);
3431 if (!NT_SUCCESS(rcNt))
3432 return false;
3433
3434 union
3435 {
3436 OBJECT_NAME_INFORMATION Info;
3437 uint8_t abBuffer[sizeof(g_System32NtPath) + 16 * sizeof(WCHAR)];
3438 } Buf;
3439 ULONG cbIgn;
3440 rcNt = ObQueryNameString(pFile, &Buf.Info, sizeof(Buf) - sizeof(WCHAR), &cbIgn);
3441 ObDereferenceObject(pFile);
3442 if (!NT_SUCCESS(rcNt))
3443 return false;
3444
3445 /* Terminate the name. */
3446 PRTUTF16 pwszName = Buf.Info.Name.Buffer;
3447 pwszName[Buf.Info.Name.Length / sizeof(RTUTF16)] = '\0';
3448
3449 /* Match the name against the system32 directory path. */
3450 uint32_t cbSystem32 = g_System32NtPath.UniStr.Length;
3451 if (Buf.Info.Name.Length < cbSystem32)
3452 return false;
3453 if (memcmp(pwszName, g_System32NtPath.UniStr.Buffer, cbSystem32))
3454 return false;
3455 pwszName += cbSystem32 / sizeof(RTUTF16);
3456 if (*pwszName++ != '\\')
3457 return false;
3458
3459 /* Compare the name. */
3460 const char *pszRight = pszName;
3461 for (;;)
3462 {
3463 WCHAR wchLeft = *pwszName++;
3464 char chRight = *pszRight++;
3465 Assert(chRight == RT_C_TO_LOWER(chRight));
3466
3467 if ( wchLeft != chRight
3468 && RT_C_TO_LOWER(wchLeft) != chRight)
3469 return false;
3470 if (!chRight)
3471 break;
3472 }
3473 }
3474
3475 return true;
3476}
3477
3478
3479/**
3480 * Checks if the current process is likely to be CSRSS.
3481 *
3482 * @returns true/false.
3483 * @param pProcess The process.
3484 */
3485static bool supdrvNtProtectIsCsrssByProcess(PEPROCESS pProcess)
3486{
3487 /*
3488 * On Windows 8.1 CSRSS.EXE is a protected process.
3489 */
3490 if (g_pfnPsIsProtectedProcessLight)
3491 {
3492 if (!g_pfnPsIsProtectedProcessLight(pProcess))
3493 return false;
3494 }
3495
3496 /*
3497 * The name tests.
3498 */
3499 if (!supdrvNtProtectIsSystem32ProcessMatch(pProcess, "csrss.exe"))
3500 return false;
3501
3502 /** @todo Could extend the CSRSS.EXE check with that the TokenUser of the
3503 * current process must be "NT AUTHORITY\SYSTEM" (S-1-5-18). */
3504
3505 return true;
3506}
3507
3508
3509/**
3510 * Helper for supdrvNtProtectGetAlpcPortObjectType that tries out a name.
3511 *
3512 * @returns true if done, false if not.
3513 * @param pwszPortNm The port path.
3514 * @param ppObjType The object type return variable, updated when
3515 * returning true.
3516 */
3517static bool supdrvNtProtectGetAlpcPortObjectType2(PCRTUTF16 pwszPortNm, POBJECT_TYPE *ppObjType)
3518{
3519 bool fDone = false;
3520
3521 UNICODE_STRING UniStrPortNm;
3522 UniStrPortNm.Buffer = (WCHAR *)pwszPortNm;
3523 UniStrPortNm.Length = (USHORT)(RTUtf16Len(pwszPortNm) * sizeof(WCHAR));
3524 UniStrPortNm.MaximumLength = UniStrPortNm.Length + sizeof(WCHAR);
3525
3526 OBJECT_ATTRIBUTES ObjAttr;
3527 InitializeObjectAttributes(&ObjAttr, &UniStrPortNm, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
3528
3529 HANDLE hPort;
3530 NTSTATUS rcNt = g_pfnZwAlpcCreatePort(&hPort, &ObjAttr, NULL /*pPortAttribs*/);
3531 if (NT_SUCCESS(rcNt))
3532 {
3533 PVOID pvObject;
3534 rcNt = ObReferenceObjectByHandle(hPort, 0 /*DesiredAccess*/, NULL /*pObjectType*/,
3535 KernelMode, &pvObject, NULL /*pHandleInfo*/);
3536 if (NT_SUCCESS(rcNt))
3537 {
3538 POBJECT_TYPE pObjType = g_pfnObGetObjectType(pvObject);
3539 if (pObjType)
3540 {
3541 SUPR0Printf("vboxdrv: ALPC Port Object Type %p (vs %p)\n", pObjType, *ppObjType);
3542 *ppObjType = pObjType;
3543 fDone = true;
3544 }
3545 ObDereferenceObject(pvObject);
3546 }
3547 NtClose(hPort);
3548 }
3549 return fDone;
3550}
3551
3552
3553/**
3554 * Attempts to retrieve the ALPC Port object type.
3555 *
3556 * We've had at least three reports that using LpcPortObjectType when trying to
3557 * get at the ApiPort object results in STATUS_OBJECT_TYPE_MISMATCH errors.
3558 * It's not known who has modified LpcPortObjectType or AlpcPortObjectType (not
3559 * exported) so that it differs from the actual ApiPort type, or maybe this
3560 * unknown entity is intercepting our attempt to reference the port and
3561 * tries to mislead us. The paranoid explanataion is of course that some evil
3562 * root kit like software is messing with the OS, however, it's possible that
3563 * this is valid kernel behavior that 99.8% of our users and 100% of the
3564 * developers are not triggering for some reason.
3565 *
3566 * The code here creates an ALPC port object and gets it's type. It will cache
3567 * the result in g_pAlpcPortObjectType2 on success.
3568 *
3569 * @returns Object type.
3570 * @param uSessionId The session id.
3571 * @param pszSessionId The session id formatted as a string.
3572 */
3573static POBJECT_TYPE supdrvNtProtectGetAlpcPortObjectType(uint32_t uSessionId, const char *pszSessionId)
3574{
3575 POBJECT_TYPE pObjType = *LpcPortObjectType;
3576
3577 if ( g_pfnZwAlpcCreatePort
3578 && g_pfnObGetObjectType)
3579 {
3580 int rc;
3581 ssize_t cchTmp; NOREF(cchTmp);
3582 char szTmp[16];
3583 RTUTF16 wszPortNm[128];
3584 size_t offRand;
3585
3586 /*
3587 * First attempt is in the session directory.
3588 */
3589 rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\Sessions\\");
3590 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), pszSessionId);
3591 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\VBoxDrv-");
3592 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), (uint32_t)(uintptr_t)PsGetProcessId(PsGetCurrentProcess()), 16, 0, 0, 0);
3593 Assert(cchTmp > 0);
3594 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3595 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "-");
3596 offRand = RTUtf16Len(wszPortNm);
3597 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
3598 Assert(cchTmp > 0);
3599 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3600 AssertRCSuccess(rc);
3601
3602 bool fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
3603 if (!fDone)
3604 {
3605 wszPortNm[offRand] = '\0';
3606 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0); Assert(cchTmp > 0);
3607 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3608 AssertRCSuccess(rc);
3609
3610 fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
3611 }
3612 if (!fDone)
3613 {
3614 /*
3615 * Try base names.
3616 */
3617 if (uSessionId == 0)
3618 rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\BaseNamedObjects\\VBoxDrv-");
3619 else
3620 {
3621 rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\Sessions\\");
3622 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), pszSessionId);
3623 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\BaseNamedObjects\\VBoxDrv-");
3624 }
3625 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), (uint32_t)(uintptr_t)PsGetProcessId(PsGetCurrentProcess()), 16, 0, 0, 0);
3626 Assert(cchTmp > 0);
3627 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3628 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "-");
3629 offRand = RTUtf16Len(wszPortNm);
3630 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
3631 Assert(cchTmp > 0);
3632 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3633 AssertRCSuccess(rc);
3634
3635 fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
3636 if (!fDone)
3637 {
3638 wszPortNm[offRand] = '\0';
3639 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
3640 Assert(cchTmp > 0);
3641 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3642 AssertRCSuccess(rc);
3643
3644 fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
3645 }
3646 }
3647
3648 /* Cache the result in g_pAlpcPortObjectType2. */
3649 if ( g_pAlpcPortObjectType2 == NULL
3650 && pObjType != g_pAlpcPortObjectType1
3651 && fDone)
3652 g_pAlpcPortObjectType2 = pObjType;
3653
3654 }
3655
3656 return pObjType;
3657}
3658
3659
3660/**
3661 * Called in the context of VBoxDrvNtCreate to determin the CSRSS for the
3662 * current process.
3663 *
3664 * The Client/Server Runtime Subsystem (CSRSS) process needs to be allowed some
3665 * additional access right so we need to make 101% sure we correctly identify
3666 * the CSRSS process a process is associated with.
3667 *
3668 * @returns IPRT status code.
3669 * @param pNtProtect The NT protected process structure. The
3670 * hCsrssPid member will be updated on success.
3671 */
3672static int supdrvNtProtectFindAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect)
3673{
3674 Assert(pNtProtect->AvlCore.Key == PsGetCurrentProcessId());
3675 Assert(pNtProtect->pCsrssProcess == NULL);
3676 Assert(pNtProtect->hCsrssPid == NULL);
3677
3678 /*
3679 * We'll try use the ApiPort LPC object for the session we're in to track
3680 * down the CSRSS process. So, we start by constructing a path to it.
3681 */
3682 int rc;
3683 uint32_t uSessionId = PsGetProcessSessionId(PsGetCurrentProcess());
3684 char szSessionId[16];
3685 WCHAR wszApiPort[48];
3686 if (uSessionId == 0)
3687 {
3688 szSessionId[0] = '0';
3689 szSessionId[1] = '\0';
3690 rc = RTUtf16CopyAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Windows\\ApiPort");
3691 }
3692 else
3693 {
3694 ssize_t cchTmp = RTStrFormatU32(szSessionId, sizeof(szSessionId), uSessionId, 10, 0, 0, 0);
3695 AssertReturn(cchTmp > 0, (int)cchTmp);
3696 rc = RTUtf16CopyAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Sessions\\");
3697 if (RT_SUCCESS(rc))
3698 rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), szSessionId);
3699 if (RT_SUCCESS(rc))
3700 rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Windows\\ApiPort");
3701 }
3702 AssertRCReturn(rc, rc);
3703
3704 UNICODE_STRING ApiPortStr;
3705 ApiPortStr.Buffer = wszApiPort;
3706 ApiPortStr.Length = (USHORT)(RTUtf16Len(wszApiPort) * sizeof(RTUTF16));
3707 ApiPortStr.MaximumLength = ApiPortStr.Length + sizeof(RTUTF16);
3708
3709 /*
3710 * The object cannot be opened, but we can reference it by name.
3711 */
3712 void *pvApiPortObj = NULL;
3713 NTSTATUS rcNt = ObReferenceObjectByName(&ApiPortStr,
3714 0,
3715 NULL /*pAccessState*/,
3716 STANDARD_RIGHTS_READ,
3717 g_pAlpcPortObjectType1,
3718 KernelMode,
3719 NULL /*pvParseContext*/,
3720 &pvApiPortObj);
3721 if ( rcNt == STATUS_OBJECT_TYPE_MISMATCH
3722 && g_pAlpcPortObjectType2 != NULL)
3723 rcNt = ObReferenceObjectByName(&ApiPortStr,
3724 0,
3725 NULL /*pAccessState*/,
3726 STANDARD_RIGHTS_READ,
3727 g_pAlpcPortObjectType2,
3728 KernelMode,
3729 NULL /*pvParseContext*/,
3730 &pvApiPortObj);
3731 if ( rcNt == STATUS_OBJECT_TYPE_MISMATCH
3732 && g_pfnObGetObjectType
3733 && g_pfnZwAlpcCreatePort)
3734 rcNt = ObReferenceObjectByName(&ApiPortStr,
3735 0,
3736 NULL /*pAccessState*/,
3737 STANDARD_RIGHTS_READ,
3738 supdrvNtProtectGetAlpcPortObjectType(uSessionId, szSessionId),
3739 KernelMode,
3740 NULL /*pvParseContext*/,
3741 &pvApiPortObj);
3742 if (!NT_SUCCESS(rcNt))
3743 {
3744 SUPR0Printf("vboxdrv: Error opening '%ls': %#x\n", wszApiPort, rcNt);
3745 return rcNt == STATUS_OBJECT_TYPE_MISMATCH ? VERR_SUPDRV_APIPORT_OPEN_ERROR_TYPE : VERR_SUPDRV_APIPORT_OPEN_ERROR;
3746 }
3747
3748 /*
3749 * Query the processes in the system so we can locate CSRSS.EXE candidates.
3750 * Note! Attempts at using SystemSessionProcessInformation failed with
3751 * STATUS_ACCESS_VIOLATION.
3752 * Note! The 32 bytes on the size of to counteract the allocation header
3753 * that rtR0MemAllocEx slaps on everything.
3754 */
3755 ULONG cbNeeded = _64K - 32;
3756 uint32_t cbBuf;
3757 uint8_t *pbBuf = NULL;
3758 do
3759 {
3760 cbBuf = RT_ALIGN(cbNeeded + _4K, _64K) - 32;
3761 pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
3762 if (!pbBuf)
3763 break;
3764
3765 cbNeeded = 0;
3766#if 0 /* doesn't work. */
3767 SYSTEM_SESSION_PROCESS_INFORMATION Req;
3768 Req.SessionId = uSessionId;
3769 Req.BufferLength = cbBuf;
3770 Req.Buffer = pbBuf;
3771 rcNt = NtQuerySystemInformation(SystemSessionProcessInformation, &Req, sizeof(Req), &cbNeeded);
3772#else
3773 rcNt = NtQuerySystemInformation(SystemProcessInformation, pbBuf, cbBuf, &cbNeeded);
3774#endif
3775 if (NT_SUCCESS(rcNt))
3776 break;
3777
3778 RTMemFree(pbBuf);
3779 pbBuf = NULL;
3780 } while ( rcNt == STATUS_INFO_LENGTH_MISMATCH
3781 && cbNeeded > cbBuf
3782 && cbNeeded < 32U*_1M);
3783
3784 if ( pbBuf
3785 && NT_SUCCESS(rcNt)
3786 && cbNeeded >= sizeof(SYSTEM_PROCESS_INFORMATION))
3787 {
3788 /*
3789 * Walk the returned data and look for the process associated with the
3790 * ApiPort object. The ApiPort object keeps the EPROCESS address of
3791 * the owner process (i.e. CSRSS) relatively early in the structure. On
3792 * 64-bit windows 8.1 it's at offset 0x18. So, obtain the EPROCESS
3793 * pointer to likely CSRSS processes and check for a match in the first
3794 * 0x40 bytes of the ApiPort object.
3795 */
3796 rc = VERR_SUPDRV_CSRSS_NOT_FOUND;
3797 for (uint32_t offBuf = 0; offBuf <= cbNeeded - sizeof(SYSTEM_PROCESS_INFORMATION);)
3798 {
3799 PRTNT_SYSTEM_PROCESS_INFORMATION pProcInfo = (PRTNT_SYSTEM_PROCESS_INFORMATION)&pbBuf[offBuf];
3800 if ( pProcInfo->ProcessName.Length == 9 * sizeof(WCHAR)
3801 && pProcInfo->NumberOfThreads > 2 /* Very low guess. */
3802 && pProcInfo->HandleCount > 32 /* Very low guess, I hope. */
3803 && (uintptr_t)pProcInfo->ProcessName.Buffer - (uintptr_t)pbBuf < cbNeeded
3804 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[0]) == 'c'
3805 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[1]) == 's'
3806 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[2]) == 'r'
3807 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[3]) == 's'
3808 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[4]) == 's'
3809 && pProcInfo->ProcessName.Buffer[5] == '.'
3810 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[6]) == 'e'
3811 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[7]) == 'x'
3812 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[8]) == 'e' )
3813 {
3814
3815 /* Get the process structure and perform some more thorough
3816 process checks. */
3817 PEPROCESS pProcess;
3818 rcNt = PsLookupProcessByProcessId(pProcInfo->UniqueProcessId, &pProcess);
3819 if (NT_SUCCESS(rcNt))
3820 {
3821 if (supdrvNtProtectIsCsrssByProcess(pProcess))
3822 {
3823 if (PsGetProcessSessionId(pProcess) == uSessionId)
3824 {
3825 /* Final test, check the ApiPort.
3826 Note! The old LPC (pre Vista) objects has the PID
3827 much earlier in the structure. Might be
3828 worth looking for it instead. */
3829 bool fThatsIt = false;
3830 __try
3831 {
3832 PEPROCESS *ppPortProc = (PEPROCESS *)pvApiPortObj;
3833 uint32_t cTests = g_uNtVerCombined >= SUP_NT_VER_VISTA ? 16 : 38; /* ALPC since Vista. */
3834 do
3835 {
3836 fThatsIt = *ppPortProc == pProcess;
3837 ppPortProc++;
3838 } while (!fThatsIt && --cTests > 0);
3839 }
3840 __except(EXCEPTION_EXECUTE_HANDLER)
3841 {
3842 fThatsIt = false;
3843 }
3844 if (fThatsIt)
3845 {
3846 /* Ok, we found it! Keep the process structure
3847 reference as well as the PID so we can
3848 safely identify it later on. */
3849 pNtProtect->hCsrssPid = pProcInfo->UniqueProcessId;
3850 pNtProtect->pCsrssProcess = pProcess;
3851 rc = VINF_SUCCESS;
3852 break;
3853 }
3854 }
3855 }
3856
3857 ObDereferenceObject(pProcess);
3858 }
3859 }
3860
3861 /* Advance. */
3862 if (!pProcInfo->NextEntryOffset)
3863 break;
3864 offBuf += pProcInfo->NextEntryOffset;
3865 }
3866 }
3867 else
3868 rc = VERR_SUPDRV_SESSION_PROCESS_ENUM_ERROR;
3869 RTMemFree(pbBuf);
3870 ObDereferenceObject(pvApiPortObj);
3871 return rc;
3872}
3873
3874
3875/**
3876 * Checks that the given process is the CSRSS process associated with protected
3877 * process.
3878 *
3879 * @returns true / false.
3880 * @param pNtProtect The NT protection structure.
3881 * @param pCsrss The process structure of the alleged CSRSS.EXE
3882 * process.
3883 */
3884static bool supdrvNtProtectIsAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect, PEPROCESS pCsrss)
3885{
3886 if (pNtProtect->pCsrssProcess == pCsrss)
3887 {
3888 if (pNtProtect->hCsrssPid == PsGetProcessId(pCsrss))
3889 {
3890 return true;
3891 }
3892 }
3893 return false;
3894}
3895
3896
3897/**
3898 * Checks if the given process is the stupid themes service.
3899 *
3900 * The caller does some screening of access masks and what not. We do the rest.
3901 *
3902 * @returns true / false.
3903 * @param pNtProtect The NT protection structure.
3904 * @param pAnnoyingProcess The process structure of an process that might
3905 * happen to be the annoying themes process.
3906 */
3907static bool supdrvNtProtectIsFrigginThemesService(PSUPDRVNTPROTECT pNtProtect, PEPROCESS pAnnoyingProcess)
3908{
3909 RT_NOREF1(pNtProtect);
3910
3911 /*
3912 * Check the process name.
3913 */
3914 if (!supdrvNtProtectIsSystem32ProcessMatch(pAnnoyingProcess, "svchost.exe"))
3915 return false;
3916
3917 /** @todo Come up with more checks. */
3918
3919 return true;
3920}
3921
3922
3923#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
3924/**
3925 * Checks if the given process is one of the whitelisted debuggers.
3926 *
3927 * @returns true / false.
3928 * @param pProcess The process to check.
3929 */
3930static bool supdrvNtProtectIsWhitelistedDebugger(PEPROCESS pProcess)
3931{
3932 const char *pszImageFile = (const char *)PsGetProcessImageFileName(pProcess);
3933 if (!pszImageFile)
3934 return false;
3935
3936 if (pszImageFile[0] == 'w' || pszImageFile[0] == 'W')
3937 {
3938 if (RTStrICmp(pszImageFile, "windbg.exe") == 0)
3939 return true;
3940 if (RTStrICmp(pszImageFile, "werfault.exe") == 0)
3941 return true;
3942 if (RTStrICmp(pszImageFile, "werfaultsecure.exe") == 0)
3943 return true;
3944 }
3945 else if (pszImageFile[0] == 'd' || pszImageFile[0] == 'D')
3946 {
3947 if (RTStrICmp(pszImageFile, "drwtsn32.exe") == 0)
3948 return true;
3949 if (RTStrICmp(pszImageFile, "dwwin.exe") == 0)
3950 return true;
3951 }
3952
3953 return false;
3954}
3955#endif /* VBOX_WITHOUT_DEBUGGER_CHECKS */
3956
3957
3958/** @} */
3959
3960
3961/** @name Process Creation Callbacks.
3962 * @{ */
3963
3964
3965/**
3966 * Cleans up VBoxDrv or VBoxDrvStub error info not collected by the dead process.
3967 *
3968 * @param hProcessId The ID of the dead process.
3969 */
3970static void supdrvNtErrorInfoCleanupProcess(HANDLE hProcessId)
3971{
3972 int rc = RTSemMutexRequestNoResume(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
3973 if (RT_SUCCESS(rc))
3974 {
3975 PSUPDRVNTERRORINFO pCur, pNext;
3976 RTListForEachSafe(&g_ErrorInfoHead, pCur, pNext, SUPDRVNTERRORINFO, ListEntry)
3977 {
3978 if (pCur->hProcessId == hProcessId)
3979 {
3980 RTListNodeRemove(&pCur->ListEntry);
3981 RTMemFree(pCur);
3982 }
3983 }
3984 RTSemMutexRelease(g_hErrorInfoLock);
3985 }
3986}
3987
3988
3989/**
3990 * Common worker used by the process creation hooks as well as the process
3991 * handle creation hooks to check if a VM process is being created.
3992 *
3993 * @returns true if likely to be a VM process, false if not.
3994 * @param pNtStub The NT protection structure for the possible
3995 * stub process.
3996 * @param hParentPid The parent pid.
3997 * @param hChildPid The child pid.
3998 */
3999static bool supdrvNtProtectIsSpawningStubProcess(PSUPDRVNTPROTECT pNtStub, HANDLE hParentPid, HANDLE hChildPid)
4000{
4001 bool fRc = false;
4002 if (pNtStub->AvlCore.Key == hParentPid) /* paranoia */
4003 {
4004 if (pNtStub->enmProcessKind == kSupDrvNtProtectKind_StubSpawning)
4005 {
4006 /* Compare short names. */
4007 PEPROCESS pStubProcess;
4008 NTSTATUS rcNt = PsLookupProcessByProcessId(hParentPid, &pStubProcess);
4009 if (NT_SUCCESS(rcNt))
4010 {
4011 PEPROCESS pChildProcess;
4012 rcNt = PsLookupProcessByProcessId(hChildPid, &pChildProcess);
4013 if (NT_SUCCESS(rcNt))
4014 {
4015 const char *pszStub = (const char *)PsGetProcessImageFileName(pStubProcess);
4016 const char *pszChild = (const char *)PsGetProcessImageFileName(pChildProcess);
4017 fRc = pszStub != NULL
4018 && pszChild != NULL
4019 && strcmp(pszStub, pszChild) == 0;
4020
4021 /** @todo check that the full image names matches. */
4022
4023 ObDereferenceObject(pChildProcess);
4024 }
4025 ObDereferenceObject(pStubProcess);
4026 }
4027 }
4028 }
4029 return fRc;
4030}
4031
4032
4033/**
4034 * Common code used by the notifies to protect a child process.
4035 *
4036 * @returns VBox status code.
4037 * @param pNtStub The NT protect structure for the parent.
4038 * @param hChildPid The child pid.
4039 */
4040static int supdrvNtProtectProtectNewStubChild(PSUPDRVNTPROTECT pNtParent, HANDLE hChildPid)
4041{
4042 /*
4043 * Create a child protection struction.
4044 */
4045 PSUPDRVNTPROTECT pNtChild;
4046 int rc = supdrvNtProtectCreate(&pNtChild, hChildPid, kSupDrvNtProtectKind_VmProcessUnconfirmed, false /*fLink*/);
4047 if (RT_SUCCESS(rc))
4048 {
4049 pNtChild->fFirstProcessCreateHandle = true;
4050 pNtChild->fFirstThreadCreateHandle = true;
4051 pNtChild->fCsrssFirstProcessCreateHandle = true;
4052 pNtChild->cCsrssFirstProcessDuplicateHandle = ARCH_BITS == 32 ? 2 : 1;
4053 pNtChild->fThemesFirstProcessCreateHandle = true;
4054 pNtChild->hParentPid = pNtParent->AvlCore.Key;
4055 pNtChild->hCsrssPid = pNtParent->hCsrssPid;
4056 pNtChild->pCsrssProcess = pNtParent->pCsrssProcess;
4057 if (pNtChild->pCsrssProcess)
4058 ObReferenceObject(pNtChild->pCsrssProcess);
4059
4060 /*
4061 * Take the spinlock, recheck parent conditions and link things.
4062 */
4063 RTSpinlockAcquire(g_hNtProtectLock);
4064 if (pNtParent->enmProcessKind == kSupDrvNtProtectKind_StubSpawning)
4065 {
4066 bool fSuccess = RTAvlPVInsert(&g_NtProtectTree, &pNtChild->AvlCore);
4067 if (fSuccess)
4068 {
4069 pNtChild->fInTree = true;
4070 pNtParent->u.pChild = pNtChild; /* Parent keeps the initial reference. */
4071 pNtParent->enmProcessKind = kSupDrvNtProtectKind_StubParent;
4072 pNtChild->u.pParent = pNtParent;
4073
4074 RTSpinlockRelease(g_hNtProtectLock);
4075 return VINF_SUCCESS;
4076 }
4077
4078 rc = VERR_INTERNAL_ERROR_2;
4079 }
4080 else
4081 rc = VERR_WRONG_ORDER;
4082 pNtChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
4083 RTSpinlockRelease(g_hNtProtectLock);
4084
4085 supdrvNtProtectRelease(pNtChild);
4086 }
4087 return rc;
4088}
4089
4090
4091/**
4092 * Common process termination code.
4093 *
4094 * Transitions protected process to the dead states, protecting against handle
4095 * PID reuse (esp. with unconfirmed VM processes) and handle cleanup issues.
4096 *
4097 * @param hDeadPid The PID of the dead process.
4098 */
4099static void supdrvNtProtectUnprotectDeadProcess(HANDLE hDeadPid)
4100{
4101 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(hDeadPid);
4102 if (pNtProtect)
4103 {
4104 PSUPDRVNTPROTECT pNtChild = NULL;
4105
4106 RTSpinlockAcquire(g_hNtProtectLock);
4107
4108 /*
4109 * If this is an unconfirmed VM process, we must release the reference
4110 * the parent structure holds.
4111 */
4112 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4113 {
4114 PSUPDRVNTPROTECT pNtParent = pNtProtect->u.pParent;
4115 AssertRelease(pNtParent); AssertRelease(pNtParent->u.pChild == pNtProtect);
4116 pNtParent->u.pChild = NULL;
4117 pNtProtect->u.pParent = NULL;
4118 pNtChild = pNtProtect;
4119 }
4120 /*
4121 * If this is a stub exitting before the VM process gets confirmed,
4122 * release the protection of the potential VM process as this is not
4123 * the prescribed behavior.
4124 */
4125 else if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent
4126 && pNtProtect->u.pChild)
4127 {
4128 pNtChild = pNtProtect->u.pChild;
4129 pNtProtect->u.pChild = NULL;
4130 pNtChild->u.pParent = NULL;
4131 pNtChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
4132 }
4133
4134 /*
4135 * Transition it to the dead state to prevent it from opening the
4136 * support driver again or be posthumously abused as a vm process parent.
4137 */
4138 if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
4139 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessConfirmed)
4140 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
4141 else if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent
4142 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubSpawning
4143 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubUnverified)
4144 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_StubDead;
4145
4146 RTSpinlockRelease(g_hNtProtectLock);
4147
4148 supdrvNtProtectRelease(pNtProtect);
4149 supdrvNtProtectRelease(pNtChild);
4150
4151 /*
4152 * Do session cleanups.
4153 */
4154 AssertReturnVoid((HANDLE)(uintptr_t)RTProcSelf() == hDeadPid);
4155 if (g_pDevObjSys)
4156 {
4157 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
4158 PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, (RTPROCESS)(uintptr_t)hDeadPid,
4159 RTR0ProcHandleSelf(), NULL);
4160 if (pSession)
4161 {
4162 supdrvSessionHashTabRemove(pDevExt, pSession, NULL);
4163 supdrvSessionRelease(pSession); /* Drops the reference from supdrvSessionHashTabLookup. */
4164 }
4165 }
4166 }
4167}
4168
4169
4170/**
4171 * Common worker for the process creation callback that verifies a new child
4172 * being created by the handle creation callback code.
4173 *
4174 * @param pNtStub The parent.
4175 * @param pNtVm The child.
4176 * @param fCallerChecks The result of any additional tests the caller made.
4177 * This is in order to avoid duplicating the failure
4178 * path code.
4179 */
4180static void supdrvNtProtectVerifyNewChildProtection(PSUPDRVNTPROTECT pNtStub, PSUPDRVNTPROTECT pNtVm, bool fCallerChecks)
4181{
4182 if ( fCallerChecks
4183 && pNtStub->enmProcessKind == kSupDrvNtProtectKind_StubParent
4184 && pNtVm->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
4185 && pNtVm->u.pParent == pNtStub
4186 && pNtStub->u.pChild == pNtVm)
4187 {
4188 /* Fine, reset the CSRSS hack (fixes ViRobot APT Shield 2.0 issue). */
4189 pNtVm->fFirstProcessCreateHandle = true;
4190 return;
4191 }
4192
4193 LogRel(("vboxdrv: Misdetected vm stub; hParentPid=%p hChildPid=%p\n", pNtStub->AvlCore.Key, pNtVm->AvlCore.Key));
4194 if (pNtStub->enmProcessKind != kSupDrvNtProtectKind_VmProcessConfirmed)
4195 supdrvNtProtectUnprotectDeadProcess(pNtVm->AvlCore.Key);
4196}
4197
4198
4199/**
4200 * Old style callback (since forever).
4201 *
4202 * @param hParentPid The parent PID.
4203 * @param hNewPid The PID of the new child.
4204 * @param fCreated TRUE if it's a creation notification,
4205 * FALSE if termination.
4206 * @remarks ASSUMES this arrives before the handle creation callback.
4207 */
4208static VOID __stdcall
4209supdrvNtProtectCallback_ProcessCreateNotify(HANDLE hParentPid, HANDLE hNewPid, BOOLEAN fCreated)
4210{
4211 /*
4212 * Is it a new process that needs protection?
4213 */
4214 if (fCreated)
4215 {
4216 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(hParentPid);
4217 if (pNtStub)
4218 {
4219 PSUPDRVNTPROTECT pNtVm = supdrvNtProtectLookup(hNewPid);
4220 if (!pNtVm)
4221 {
4222 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, hParentPid, hNewPid))
4223 supdrvNtProtectProtectNewStubChild(pNtStub, hNewPid);
4224 }
4225 else
4226 {
4227 supdrvNtProtectVerifyNewChildProtection(pNtStub, pNtVm, true);
4228 supdrvNtProtectRelease(pNtVm);
4229 }
4230 supdrvNtProtectRelease(pNtStub);
4231 }
4232 }
4233 /*
4234 * Process termination, do clean ups.
4235 */
4236 else
4237 {
4238 supdrvNtProtectUnprotectDeadProcess(hNewPid);
4239 supdrvNtErrorInfoCleanupProcess(hNewPid);
4240 }
4241}
4242
4243
4244/**
4245 * New style callback (Vista SP1+ / w2k8).
4246 *
4247 * @param pNewProcess The new process.
4248 * @param hNewPid The PID of the new process.
4249 * @param pInfo Process creation details. NULL if process
4250 * termination notification.
4251 * @remarks ASSUMES this arrives before the handle creation callback.
4252 */
4253static VOID __stdcall
4254supdrvNtProtectCallback_ProcessCreateNotifyEx(PEPROCESS pNewProcess, HANDLE hNewPid, PPS_CREATE_NOTIFY_INFO pInfo)
4255{
4256 RT_NOREF1(pNewProcess);
4257
4258 /*
4259 * Is it a new process that needs protection?
4260 */
4261 if (pInfo)
4262 {
4263 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(pInfo->CreatingThreadId.UniqueProcess);
4264
4265 Log(("vboxdrv/NewProcessEx: ctx=%04zx/%p pid=%04zx ppid=%04zx ctor=%04zx/%04zx rcNt=%#x %.*ls\n",
4266 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4267 hNewPid, pInfo->ParentProcessId,
4268 pInfo->CreatingThreadId.UniqueProcess, pInfo->CreatingThreadId.UniqueThread, pInfo->CreationStatus,
4269 pInfo->FileOpenNameAvailable && pInfo->ImageFileName ? (size_t)pInfo->ImageFileName->Length / 2 : 0,
4270 pInfo->FileOpenNameAvailable && pInfo->ImageFileName ? pInfo->ImageFileName->Buffer : NULL));
4271
4272 if (pNtStub)
4273 {
4274 PSUPDRVNTPROTECT pNtVm = supdrvNtProtectLookup(hNewPid);
4275 if (!pNtVm)
4276 {
4277 /* Parent must be creator. */
4278 if (pInfo->CreatingThreadId.UniqueProcess == pInfo->ParentProcessId)
4279 {
4280 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, pInfo->ParentProcessId, hNewPid))
4281 supdrvNtProtectProtectNewStubChild(pNtStub, hNewPid);
4282 }
4283 }
4284 else
4285 {
4286 /* Parent must be creator (as above). */
4287 supdrvNtProtectVerifyNewChildProtection(pNtStub, pNtVm,
4288 pInfo->CreatingThreadId.UniqueProcess == pInfo->ParentProcessId);
4289 supdrvNtProtectRelease(pNtVm);
4290 }
4291 supdrvNtProtectRelease(pNtStub);
4292 }
4293 }
4294 /*
4295 * Process termination, do clean ups.
4296 */
4297 else
4298 {
4299 supdrvNtProtectUnprotectDeadProcess(hNewPid);
4300 supdrvNtErrorInfoCleanupProcess(hNewPid);
4301 }
4302}
4303
4304/** @} */
4305
4306
4307/** @name Process Handle Callbacks.
4308 * @{ */
4309
4310/** Process rights that we allow for handles to stub and VM processes. */
4311# define SUPDRV_NT_ALLOW_PROCESS_RIGHTS \
4312 ( PROCESS_TERMINATE \
4313 | PROCESS_VM_READ \
4314 | PROCESS_QUERY_INFORMATION \
4315 | PROCESS_QUERY_LIMITED_INFORMATION \
4316 | PROCESS_SUSPEND_RESUME \
4317 | DELETE \
4318 | READ_CONTROL \
4319 | SYNCHRONIZE)
4320
4321/** Evil process rights. */
4322# define SUPDRV_NT_EVIL_PROCESS_RIGHTS \
4323 ( PROCESS_CREATE_THREAD \
4324 | PROCESS_SET_SESSIONID /*?*/ \
4325 | PROCESS_VM_OPERATION \
4326 | PROCESS_VM_WRITE \
4327 | PROCESS_DUP_HANDLE \
4328 | PROCESS_CREATE_PROCESS /*?*/ \
4329 | PROCESS_SET_QUOTA /*?*/ \
4330 | PROCESS_SET_INFORMATION \
4331 | PROCESS_SET_LIMITED_INFORMATION /*?*/ \
4332 | 0)
4333AssertCompile((SUPDRV_NT_ALLOW_PROCESS_RIGHTS & SUPDRV_NT_EVIL_PROCESS_RIGHTS) == 0);
4334
4335
4336static OB_PREOP_CALLBACK_STATUS __stdcall
4337supdrvNtProtectCallback_ProcessHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMATION pOpInfo)
4338{
4339 Assert(pvUser == NULL); RT_NOREF1(pvUser);
4340 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
4341 Assert(pOpInfo->ObjectType == *PsProcessType);
4342
4343 /*
4344 * Protected? Kludge required for NtOpenProcess calls comming in before
4345 * the create process hook triggers on Windows 8.1 (possibly others too).
4346 */
4347 HANDLE hObjPid = PsGetProcessId((PEPROCESS)pOpInfo->Object);
4348 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(hObjPid);
4349 if (!pNtProtect)
4350 {
4351 HANDLE hParentPid = PsGetProcessInheritedFromUniqueProcessId((PEPROCESS)pOpInfo->Object);
4352 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(hParentPid);
4353 if (pNtStub)
4354 {
4355 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, hParentPid, hObjPid))
4356 {
4357 supdrvNtProtectProtectNewStubChild(pNtStub, hObjPid);
4358 pNtProtect = supdrvNtProtectLookup(hObjPid);
4359 }
4360 supdrvNtProtectRelease(pNtStub);
4361 }
4362 }
4363 pOpInfo->CallContext = pNtProtect; /* Just for reference. */
4364 if (pNtProtect)
4365 {
4366 /*
4367 * Ok, it's a protected process. Strip rights as required or possible.
4368 */
4369 static ACCESS_MASK const s_fCsrssStupidDesires = 0x1fffff;
4370 ACCESS_MASK fAllowedRights = SUPDRV_NT_ALLOW_PROCESS_RIGHTS;
4371
4372 if (pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE)
4373 {
4374 /* Don't restrict the process accessing itself. */
4375 if ((PEPROCESS)pOpInfo->Object == PsGetCurrentProcess())
4376 {
4377 pOpInfo->CallContext = NULL; /* don't assert */
4378 pNtProtect->fFirstProcessCreateHandle = false;
4379
4380 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s\n",
4381 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4382 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
4383 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
4384 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4385 }
4386#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
4387 /* Allow debuggers full access. */
4388 else if (supdrvNtProtectIsWhitelistedDebugger(PsGetCurrentProcess()))
4389 {
4390 pOpInfo->CallContext = NULL; /* don't assert */
4391 pNtProtect->fFirstProcessCreateHandle = false;
4392
4393 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s [debugger]\n",
4394 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4395 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
4396 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
4397 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4398 }
4399#endif
4400 else
4401 {
4402 ACCESS_MASK const fDesiredAccess = pOpInfo->Parameters->CreateHandleInformation.DesiredAccess;
4403
4404 /* Special case 1 on Vista, 7 & 8:
4405 The CreateProcess code passes the handle over to CSRSS.EXE
4406 and the code inBaseSrvCreateProcess will duplicate the
4407 handle with 0x1fffff as access mask. NtDuplicateObject will
4408 fail this call before it ever gets down here.
4409
4410 Special case 2 on 8.1:
4411 The CreateProcess code requires additional rights for
4412 something, we'll drop these in the stub code. */
4413 if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
4414 && pNtProtect->fFirstProcessCreateHandle
4415 && pOpInfo->KernelHandle == 0
4416 && pNtProtect->hParentPid == PsGetProcessId(PsGetCurrentProcess())
4417 && ExGetPreviousMode() != KernelMode)
4418 {
4419 if ( !pOpInfo->KernelHandle
4420 && fDesiredAccess == s_fCsrssStupidDesires)
4421 {
4422 if (g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3))
4423 fAllowedRights |= s_fCsrssStupidDesires;
4424 else
4425 fAllowedRights = fAllowedRights
4426 | PROCESS_VM_OPERATION
4427 | PROCESS_VM_WRITE
4428 | PROCESS_SET_INFORMATION
4429 | PROCESS_SET_LIMITED_INFORMATION
4430 | 0;
4431 pOpInfo->CallContext = NULL; /* don't assert this. */
4432 }
4433 pNtProtect->fFirstProcessCreateHandle = false;
4434 }
4435
4436 /* Special case 3 on 8.1:
4437 The interaction between the CreateProcess code and CSRSS.EXE
4438 has changed to the better with Windows 8.1. CSRSS.EXE no
4439 longer duplicates the process (thread too) handle, but opens
4440 it, thus allowing us to do our job. */
4441 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3)
4442 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
4443 && pNtProtect->fCsrssFirstProcessCreateHandle
4444 && pOpInfo->KernelHandle == 0
4445 && ExGetPreviousMode() == UserMode
4446 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
4447 {
4448 pNtProtect->fCsrssFirstProcessCreateHandle = false;
4449 if (fDesiredAccess == s_fCsrssStupidDesires)
4450 {
4451 /* Not needed: PROCESS_CREATE_THREAD, PROCESS_SET_SESSIONID,
4452 PROCESS_CREATE_PROCESS */
4453 fAllowedRights = fAllowedRights
4454 | PROCESS_VM_OPERATION
4455 | PROCESS_VM_WRITE
4456 | PROCESS_DUP_HANDLE /* Needed for CreateProcess/VBoxTestOGL. */
4457 | 0;
4458 pOpInfo->CallContext = NULL; /* don't assert this. */
4459 }
4460 }
4461
4462 /* Special case 4, Windows 7, Vista, possibly 8, but not 8.1:
4463 The Themes service requires PROCESS_DUP_HANDLE access to our
4464 process or we won't get any menus and dialogs will be half
4465 unreadable. This is _very_ unfortunate and more work will
4466 go into making this more secure. */
4467 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0)
4468 && g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 2)
4469 && fDesiredAccess == 0x1478 /* 6.1.7600.16385 (win7_rtm.090713-1255) */
4470 && pNtProtect->fThemesFirstProcessCreateHandle
4471 && pOpInfo->KernelHandle == 0
4472 && ExGetPreviousMode() == UserMode
4473 && supdrvNtProtectIsFrigginThemesService(pNtProtect, PsGetCurrentProcess()) )
4474 {
4475 pNtProtect->fThemesFirstProcessCreateHandle = true; /* Only once! */
4476 fAllowedRights |= PROCESS_DUP_HANDLE;
4477 pOpInfo->CallContext = NULL; /* don't assert this. */
4478 }
4479
4480 /* Special case 6a, Windows 10+: AudioDG.exe opens the process with the
4481 PROCESS_SET_LIMITED_INFORMATION right. It seems like it need it for
4482 some myserious and weirdly placed cpu set management of our process.
4483 I'd love to understand what that's all about...
4484 Currently playing safe and only grand this right, however limited, to
4485 audiodg.exe. */
4486 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(10, 0)
4487 && ( fDesiredAccess == PROCESS_SET_LIMITED_INFORMATION
4488 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION) /* expected fix #1 */
4489 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_INFORMATION) /* expected fix #2 */
4490 )
4491 && pOpInfo->KernelHandle == 0
4492 && ExGetPreviousMode() == UserMode
4493 && supdrvNtProtectIsSystem32ProcessMatch(PsGetCurrentProcess(), "audiodg.exe") )
4494 {
4495 fAllowedRights |= PROCESS_SET_LIMITED_INFORMATION;
4496 pOpInfo->CallContext = NULL; /* don't assert this. */
4497 }
4498
4499 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p/pid=%04zx [%d], allow %#x => %#x; %s [prev=%#x]\n",
4500 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4501 fDesiredAccess, pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
4502 fAllowedRights, fDesiredAccess & fAllowedRights,
4503 PsGetProcessImageFileName(PsGetCurrentProcess()), ExGetPreviousMode() ));
4504
4505 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess &= fAllowedRights;
4506 }
4507 }
4508 else
4509 {
4510 /* Don't restrict the process accessing itself. */
4511 if ( (PEPROCESS)pOpInfo->Object == PsGetCurrentProcess()
4512 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == pOpInfo->Object)
4513 {
4514 Log(("vboxdrv/ProcessHandlePre: ctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] %s\n",
4515 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4516 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
4517 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
4518 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
4519 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
4520 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
4521 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4522
4523 pOpInfo->CallContext = NULL; /* don't assert */
4524 }
4525 else
4526 {
4527 ACCESS_MASK const fDesiredAccess = pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess;
4528
4529 /* Special case 5 on Vista, 7 & 8:
4530 This is the CSRSS.EXE end of special case #1. */
4531 if ( g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3)
4532 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
4533 && pNtProtect->cCsrssFirstProcessDuplicateHandle > 0
4534 && pOpInfo->KernelHandle == 0
4535 && fDesiredAccess == s_fCsrssStupidDesires
4536 && pNtProtect->hParentPid
4537 == PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess)
4538 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
4539 && ExGetPreviousMode() == UserMode
4540 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()))
4541 {
4542 if (ASMAtomicDecS32(&pNtProtect->cCsrssFirstProcessDuplicateHandle) >= 0)
4543 {
4544 /* Not needed: PROCESS_CREATE_THREAD, PROCESS_SET_SESSIONID,
4545 PROCESS_CREATE_PROCESS, PROCESS_DUP_HANDLE */
4546 fAllowedRights = fAllowedRights
4547 | PROCESS_VM_OPERATION
4548 | PROCESS_VM_WRITE
4549 | PROCESS_DUP_HANDLE /* Needed for launching VBoxTestOGL. */
4550 | 0;
4551 pOpInfo->CallContext = NULL; /* don't assert this. */
4552 }
4553 }
4554
4555 /* Special case 6b, Windows 10+: AudioDG.exe duplicates the handle it opened above. */
4556 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(10, 0)
4557 && ( fDesiredAccess == PROCESS_SET_LIMITED_INFORMATION
4558 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION) /* expected fix #1 */
4559 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_INFORMATION) /* expected fix #2 */
4560 )
4561 && pOpInfo->KernelHandle == 0
4562 && ExGetPreviousMode() == UserMode
4563 && supdrvNtProtectIsSystem32ProcessMatch(PsGetCurrentProcess(), "audiodg.exe") )
4564 {
4565 fAllowedRights |= PROCESS_SET_LIMITED_INFORMATION;
4566 pOpInfo->CallContext = NULL; /* don't assert this. */
4567 }
4568
4569 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] %s\n",
4570 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4571 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
4572 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
4573 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
4574 fDesiredAccess,
4575 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
4576 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4577
4578 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= fAllowedRights;
4579 }
4580 }
4581 supdrvNtProtectRelease(pNtProtect);
4582 }
4583
4584 return OB_PREOP_SUCCESS;
4585}
4586
4587
4588static VOID __stdcall
4589supdrvNtProtectCallback_ProcessHandlePost(PVOID pvUser, POB_POST_OPERATION_INFORMATION pOpInfo)
4590{
4591 Assert(pvUser == NULL); RT_NOREF1(pvUser);
4592 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
4593 Assert(pOpInfo->ObjectType == *PsProcessType);
4594
4595 if ( pOpInfo->CallContext
4596 && NT_SUCCESS(pOpInfo->ReturnStatus))
4597 {
4598 ACCESS_MASK const fGrantedAccess = pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE
4599 ? pOpInfo->Parameters->CreateHandleInformation.GrantedAccess
4600 : pOpInfo->Parameters->DuplicateHandleInformation.GrantedAccess;
4601 AssertReleaseMsg( !(fGrantedAccess & ~( SUPDRV_NT_ALLOW_PROCESS_RIGHTS
4602 | WRITE_OWNER | WRITE_DAC /* these two might be forced upon us */
4603 | PROCESS_UNKNOWN_4000 /* Seen set on win 8.1 */
4604 /*| PROCESS_UNKNOWN_8000 */ ) )
4605 || pOpInfo->KernelHandle,
4606 ("GrantedAccess=%#x - we allow %#x - we did not allow %#x\n",
4607 fGrantedAccess, SUPDRV_NT_ALLOW_PROCESS_RIGHTS, fGrantedAccess & ~SUPDRV_NT_ALLOW_PROCESS_RIGHTS));
4608 }
4609}
4610
4611# undef SUPDRV_NT_ALLOW_PROCESS_RIGHTS
4612
4613/** @} */
4614
4615
4616/** @name Thread Handle Callbacks
4617 * @{ */
4618
4619/* From ntifs.h */
4620extern "C" NTKERNELAPI PEPROCESS __stdcall IoThreadToProcess(PETHREAD);
4621
4622/** Thread rights that we allow for handles to stub and VM processes. */
4623# define SUPDRV_NT_ALLOWED_THREAD_RIGHTS \
4624 ( THREAD_TERMINATE \
4625 | THREAD_GET_CONTEXT \
4626 | THREAD_QUERY_INFORMATION \
4627 | THREAD_QUERY_LIMITED_INFORMATION \
4628 | DELETE \
4629 | READ_CONTROL \
4630 | SYNCHRONIZE)
4631/** @todo consider THREAD_SET_LIMITED_INFORMATION & THREAD_RESUME */
4632
4633/** Evil thread rights.
4634 * @remarks THREAD_RESUME is not included as it seems to be forced upon us by
4635 * Windows 8.1, at least for some processes. We dont' actively
4636 * allow it though, just tollerate it when forced to. */
4637# define SUPDRV_NT_EVIL_THREAD_RIGHTS \
4638 ( THREAD_SUSPEND_RESUME \
4639 | THREAD_SET_CONTEXT \
4640 | THREAD_SET_INFORMATION \
4641 | THREAD_SET_LIMITED_INFORMATION /*?*/ \
4642 | THREAD_SET_THREAD_TOKEN /*?*/ \
4643 | THREAD_IMPERSONATE /*?*/ \
4644 | THREAD_DIRECT_IMPERSONATION /*?*/ \
4645 /*| THREAD_RESUME - see remarks. */ \
4646 | 0)
4647AssertCompile((SUPDRV_NT_EVIL_THREAD_RIGHTS & SUPDRV_NT_ALLOWED_THREAD_RIGHTS) == 0);
4648
4649
4650static OB_PREOP_CALLBACK_STATUS __stdcall
4651supdrvNtProtectCallback_ThreadHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMATION pOpInfo)
4652{
4653 Assert(pvUser == NULL); RT_NOREF1(pvUser);
4654 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
4655 Assert(pOpInfo->ObjectType == *PsThreadType);
4656
4657 PEPROCESS pProcess = IoThreadToProcess((PETHREAD)pOpInfo->Object);
4658 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(PsGetProcessId(pProcess));
4659 pOpInfo->CallContext = pNtProtect; /* Just for reference. */
4660 if (pNtProtect)
4661 {
4662 static ACCESS_MASK const s_fCsrssStupidDesires = 0x1fffff;
4663 ACCESS_MASK fAllowedRights = SUPDRV_NT_ALLOWED_THREAD_RIGHTS;
4664
4665 if (pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE)
4666 {
4667 /* Don't restrict the process accessing its own threads. */
4668 if (pProcess == PsGetCurrentProcess())
4669 {
4670 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] self\n",
4671 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4672 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
4673 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind));
4674 pOpInfo->CallContext = NULL; /* don't assert */
4675 pNtProtect->fFirstThreadCreateHandle = false;
4676 }
4677#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
4678 /* Allow debuggers full access. */
4679 else if (supdrvNtProtectIsWhitelistedDebugger(PsGetCurrentProcess()))
4680 {
4681 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s [debugger]\n",
4682 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4683 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
4684 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
4685 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4686 pOpInfo->CallContext = NULL; /* don't assert */
4687 }
4688#endif
4689 else
4690 {
4691 /* Special case 1 on Vista, 7, 8:
4692 The CreateProcess code passes the handle over to CSRSS.EXE
4693 and the code inBaseSrvCreateProcess will duplicate the
4694 handle with 0x1fffff as access mask. NtDuplicateObject will
4695 fail this call before it ever gets down here. */
4696 if ( g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3)
4697 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
4698 && pNtProtect->fFirstThreadCreateHandle
4699 && pOpInfo->KernelHandle == 0
4700 && ExGetPreviousMode() == UserMode
4701 && pNtProtect->hParentPid == PsGetProcessId(PsGetCurrentProcess()) )
4702 {
4703 if ( !pOpInfo->KernelHandle
4704 && pOpInfo->Parameters->CreateHandleInformation.DesiredAccess == s_fCsrssStupidDesires)
4705 {
4706 fAllowedRights |= s_fCsrssStupidDesires;
4707 pOpInfo->CallContext = NULL; /* don't assert this. */
4708 }
4709 pNtProtect->fFirstThreadCreateHandle = false;
4710 }
4711
4712 /* Special case 2 on 8.1, possibly also Vista, 7, 8:
4713 When creating a process like VBoxTestOGL from the VM process,
4714 CSRSS.EXE will try talk to the calling thread and, it
4715 appears, impersonate it. We unfortunately need to allow
4716 this or there will be no 3D support. Typical DbgPrint:
4717 "SXS: BasepCreateActCtx() Calling csrss server failed. Status = 0xc00000a5" */
4718 SUPDRVNTPROTECTKIND enmProcessKind;
4719 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 0, 0, 0)
4720 && ( (enmProcessKind = pNtProtect->enmProcessKind) == kSupDrvNtProtectKind_VmProcessConfirmed
4721 || enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4722 && pOpInfo->KernelHandle == 0
4723 && ExGetPreviousMode() == UserMode
4724 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
4725 {
4726 fAllowedRights |= THREAD_IMPERSONATE;
4727 fAllowedRights |= THREAD_DIRECT_IMPERSONATION;
4728 //fAllowedRights |= THREAD_SET_LIMITED_INFORMATION; - try without this one
4729 pOpInfo->CallContext = NULL; /* don't assert this. */
4730 }
4731
4732 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d], allow %#x => %#x; %s [prev=%#x]\n",
4733 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4734 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
4735 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind, fAllowedRights,
4736 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess & fAllowedRights,
4737 PsGetProcessImageFileName(PsGetCurrentProcess()), ExGetPreviousMode()));
4738
4739 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess &= fAllowedRights;
4740 }
4741 }
4742 else
4743 {
4744 /* Don't restrict the process accessing its own threads. */
4745 if ( pProcess == PsGetCurrentProcess()
4746 && (PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == pProcess)
4747 {
4748 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] self\n",
4749 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4750 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
4751 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
4752 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
4753 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
4754 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
4755 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4756 pOpInfo->CallContext = NULL; /* don't assert */
4757 }
4758 else
4759 {
4760 /* Special case 3 on Vista, 7, 8:
4761 This is the follow up to special case 1. */
4762 SUPDRVNTPROTECTKIND enmProcessKind;
4763 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 0, 0, 0)
4764 && ( (enmProcessKind = pNtProtect->enmProcessKind) == kSupDrvNtProtectKind_VmProcessConfirmed
4765 || enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4766 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
4767 && pOpInfo->KernelHandle == 0
4768 && ExGetPreviousMode() == UserMode
4769 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
4770 {
4771 fAllowedRights |= THREAD_IMPERSONATE;
4772 fAllowedRights |= THREAD_DIRECT_IMPERSONATION;
4773 //fAllowedRights |= THREAD_SET_LIMITED_INFORMATION; - try without this one
4774 pOpInfo->CallContext = NULL; /* don't assert this. */
4775 }
4776
4777 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d], allow %#x => %#x; %s\n",
4778 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4779 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
4780 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
4781 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
4782 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
4783 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind, fAllowedRights,
4784 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess & fAllowedRights,
4785 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4786
4787 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= fAllowedRights;
4788 }
4789 }
4790
4791 supdrvNtProtectRelease(pNtProtect);
4792 }
4793
4794 return OB_PREOP_SUCCESS;
4795}
4796
4797
4798static VOID __stdcall
4799supdrvNtProtectCallback_ThreadHandlePost(PVOID pvUser, POB_POST_OPERATION_INFORMATION pOpInfo)
4800{
4801 Assert(pvUser == NULL); RT_NOREF1(pvUser);
4802 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
4803 Assert(pOpInfo->ObjectType == *PsThreadType);
4804
4805 if ( pOpInfo->CallContext
4806 && NT_SUCCESS(pOpInfo->ReturnStatus))
4807 {
4808 ACCESS_MASK const fGrantedAccess = pOpInfo->Parameters->CreateHandleInformation.GrantedAccess;
4809 AssertReleaseMsg( !(fGrantedAccess & ~( SUPDRV_NT_ALLOWED_THREAD_RIGHTS
4810 | WRITE_OWNER | WRITE_DAC /* these two might be forced upon us */
4811 | THREAD_RESUME /* This seems to be force upon us too with 8.1. */
4812 ) )
4813 || pOpInfo->KernelHandle,
4814 ("GrantedAccess=%#x - we allow %#x - we did not allow %#x\n",
4815 fGrantedAccess, SUPDRV_NT_ALLOWED_THREAD_RIGHTS, fGrantedAccess & ~SUPDRV_NT_ALLOWED_THREAD_RIGHTS));
4816 }
4817}
4818
4819# undef SUPDRV_NT_ALLOWED_THREAD_RIGHTS
4820
4821/** @} */
4822
4823
4824/**
4825 * Creates a new process protection structure.
4826 *
4827 * @returns VBox status code.
4828 * @param ppNtProtect Where to return the pointer to the structure
4829 * on success.
4830 * @param hPid The process ID of the process to protect.
4831 * @param enmProcessKind The kind of process we're protecting.
4832 * @param fLink Whether to link the structure into the tree.
4833 */
4834static int supdrvNtProtectCreate(PSUPDRVNTPROTECT *ppNtProtect, HANDLE hPid, SUPDRVNTPROTECTKIND enmProcessKind, bool fLink)
4835{
4836 AssertReturn(g_hNtProtectLock != NIL_RTSPINLOCK, VERR_WRONG_ORDER);
4837
4838 PSUPDRVNTPROTECT pNtProtect = (PSUPDRVNTPROTECT)RTMemAllocZ(sizeof(*pNtProtect));
4839 if (!pNtProtect)
4840 return VERR_NO_MEMORY;
4841
4842 pNtProtect->AvlCore.Key = hPid;
4843 pNtProtect->u32Magic = SUPDRVNTPROTECT_MAGIC;
4844 pNtProtect->cRefs = 1;
4845 pNtProtect->enmProcessKind = enmProcessKind;
4846 pNtProtect->hParentPid = NULL;
4847 pNtProtect->hOpenTid = NULL;
4848 pNtProtect->hCsrssPid = NULL;
4849 pNtProtect->pCsrssProcess = NULL;
4850
4851 if (fLink)
4852 {
4853 RTSpinlockAcquire(g_hNtProtectLock);
4854 bool fSuccess = RTAvlPVInsert(&g_NtProtectTree, &pNtProtect->AvlCore);
4855 pNtProtect->fInTree = fSuccess;
4856 RTSpinlockRelease(g_hNtProtectLock);
4857
4858 if (!fSuccess)
4859 {
4860 /* Duplicate entry, fail. */
4861 pNtProtect->u32Magic = SUPDRVNTPROTECT_MAGIC_DEAD;
4862 LogRel(("supdrvNtProtectCreate: Duplicate (%#x).\n", pNtProtect->AvlCore.Key));
4863 RTMemFree(pNtProtect);
4864 return VERR_DUPLICATE;
4865 }
4866 }
4867
4868 *ppNtProtect = pNtProtect;
4869 return VINF_SUCCESS;
4870}
4871
4872
4873/**
4874 * Releases a reference to a NT protection structure.
4875 *
4876 * @param pNtProtect The NT protection structure.
4877 */
4878static void supdrvNtProtectRelease(PSUPDRVNTPROTECT pNtProtect)
4879{
4880 if (!pNtProtect)
4881 return;
4882 AssertReturnVoid(pNtProtect->u32Magic == SUPDRVNTPROTECT_MAGIC);
4883
4884 RTSpinlockAcquire(g_hNtProtectLock);
4885 uint32_t cRefs = ASMAtomicDecU32(&pNtProtect->cRefs);
4886 if (cRefs != 0)
4887 RTSpinlockRelease(g_hNtProtectLock);
4888 else
4889 {
4890 /*
4891 * That was the last reference. Remove it from the tree, invalidate it
4892 * and free the resources associated with it. Also, release any
4893 * child/parent references related to this protection structure.
4894 */
4895 ASMAtomicWriteU32(&pNtProtect->u32Magic, SUPDRVNTPROTECT_MAGIC_DEAD);
4896 if (pNtProtect->fInTree)
4897 {
4898 PSUPDRVNTPROTECT pRemoved = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pNtProtect->AvlCore.Key);
4899 Assert(pRemoved == pNtProtect); RT_NOREF_PV(pRemoved);
4900 pNtProtect->fInTree = false;
4901 }
4902
4903 PSUPDRVNTPROTECT pChild = NULL;
4904 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent)
4905 {
4906 pChild = pNtProtect->u.pChild;
4907 if (pChild)
4908 {
4909 pNtProtect->u.pChild = NULL;
4910 pChild->u.pParent = NULL;
4911 pChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
4912 uint32_t cChildRefs = ASMAtomicDecU32(&pChild->cRefs);
4913 if (!cChildRefs)
4914 {
4915 Assert(pChild->fInTree);
4916 if (pChild->fInTree)
4917 {
4918 PSUPDRVNTPROTECT pRemovedChild = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pChild->AvlCore.Key);
4919 Assert(pRemovedChild == pChild); RT_NOREF_PV(pRemovedChild);
4920 pChild->fInTree = false;
4921 }
4922 }
4923 else
4924 pChild = NULL;
4925 }
4926 }
4927 else
4928 AssertRelease(pNtProtect->enmProcessKind != kSupDrvNtProtectKind_VmProcessUnconfirmed);
4929
4930 RTSpinlockRelease(g_hNtProtectLock);
4931
4932 if (pNtProtect->pCsrssProcess)
4933 {
4934 ObDereferenceObject(pNtProtect->pCsrssProcess);
4935 pNtProtect->pCsrssProcess = NULL;
4936 }
4937
4938 RTMemFree(pNtProtect);
4939 if (pChild)
4940 RTMemFree(pChild);
4941 }
4942}
4943
4944
4945/**
4946 * Looks up a PID in the NT protect tree.
4947 *
4948 * @returns Pointer to a NT protection structure (with a referenced) on success,
4949 * NULL if not found.
4950 * @param hPid The process ID.
4951 */
4952static PSUPDRVNTPROTECT supdrvNtProtectLookup(HANDLE hPid)
4953{
4954 RTSpinlockAcquire(g_hNtProtectLock);
4955 PSUPDRVNTPROTECT pFound = (PSUPDRVNTPROTECT)RTAvlPVGet(&g_NtProtectTree, hPid);
4956 if (pFound)
4957 ASMAtomicIncU32(&pFound->cRefs);
4958 RTSpinlockRelease(g_hNtProtectLock);
4959 return pFound;
4960}
4961
4962
4963/**
4964 * Validates a few facts about the stub process when the VM process opens
4965 * vboxdrv.
4966 *
4967 * This makes sure the stub process is still around and that it has neither
4968 * debugger nor extra threads in it.
4969 *
4970 * @returns VBox status code.
4971 * @param pNtProtect The unconfirmed VM process currently trying to
4972 * open vboxdrv.
4973 * @param pErrInfo Additional error information.
4974 */
4975static int supdrvNtProtectVerifyStubForVmProcess(PSUPDRVNTPROTECT pNtProtect, PRTERRINFO pErrInfo)
4976{
4977 /*
4978 * Grab a reference to the parent stub process.
4979 */
4980 SUPDRVNTPROTECTKIND enmStub = kSupDrvNtProtectKind_Invalid;
4981 PSUPDRVNTPROTECT pNtStub = NULL;
4982 RTSpinlockAcquire(g_hNtProtectLock);
4983 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4984 {
4985 pNtStub = pNtProtect->u.pParent; /* weak reference. */
4986 if (pNtStub)
4987 {
4988 enmStub = pNtStub->enmProcessKind;
4989 if (enmStub == kSupDrvNtProtectKind_StubParent)
4990 {
4991 uint32_t cRefs = ASMAtomicIncU32(&pNtStub->cRefs);
4992 Assert(cRefs > 0 && cRefs < 1024); RT_NOREF_PV(cRefs);
4993 }
4994 else
4995 pNtStub = NULL;
4996 }
4997 }
4998 RTSpinlockRelease(g_hNtProtectLock);
4999
5000 /*
5001 * We require the stub process to be present.
5002 */
5003 if (!pNtStub)
5004 return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_NOT_FOUND, "Missing stub process (enmStub=%d).", enmStub);
5005
5006 /*
5007 * Open the parent process and thread so we can check for debuggers and unwanted threads.
5008 */
5009 int rc;
5010 PEPROCESS pStubProcess;
5011 NTSTATUS rcNt = PsLookupProcessByProcessId(pNtStub->AvlCore.Key, &pStubProcess);
5012 if (NT_SUCCESS(rcNt))
5013 {
5014 HANDLE hStubProcess;
5015 rcNt = ObOpenObjectByPointer(pStubProcess, OBJ_KERNEL_HANDLE, NULL /*PassedAccessState*/,
5016 0 /*DesiredAccess*/, *PsProcessType, KernelMode, &hStubProcess);
5017 if (NT_SUCCESS(rcNt))
5018 {
5019 PETHREAD pStubThread;
5020 rcNt = PsLookupThreadByThreadId(pNtStub->hOpenTid, &pStubThread);
5021 if (NT_SUCCESS(rcNt))
5022 {
5023 HANDLE hStubThread;
5024 rcNt = ObOpenObjectByPointer(pStubThread, OBJ_KERNEL_HANDLE, NULL /*PassedAccessState*/,
5025 0 /*DesiredAccess*/, *PsThreadType, KernelMode, &hStubThread);
5026 if (NT_SUCCESS(rcNt))
5027 {
5028 /*
5029 * Do some simple sanity checking.
5030 */
5031 rc = supHardNtVpDebugger(hStubProcess, pErrInfo);
5032 if (RT_SUCCESS(rc))
5033 rc = supHardNtVpThread(hStubProcess, hStubThread, pErrInfo);
5034
5035 /* Clean up. */
5036 rcNt = NtClose(hStubThread); AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt));
5037 }
5038 else
5039 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_THREAD_OPEN_ERROR,
5040 "Error opening stub thread %p (tid %p, pid %p): %#x",
5041 pStubThread, pNtStub->hOpenTid, pNtStub->AvlCore.Key, rcNt);
5042 }
5043 else
5044 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_THREAD_NOT_FOUND,
5045 "Failed to locate thread %p in %p: %#x", pNtStub->hOpenTid, pNtStub->AvlCore.Key, rcNt);
5046 rcNt = NtClose(hStubProcess); AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt));
5047 }
5048 else
5049 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_OPEN_ERROR,
5050 "Error opening stub process %p (pid %p): %#x", pStubProcess, pNtStub->AvlCore.Key, rcNt);
5051 ObDereferenceObject(pStubProcess);
5052 }
5053 else
5054 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_NOT_FOUND,
5055 "Failed to locate stub process %p: %#x", pNtStub->AvlCore.Key, rcNt);
5056
5057 supdrvNtProtectRelease(pNtStub);
5058 return rc;
5059}
5060
5061
5062static const char *supdrvNtProtectHandleTypeIndexToName(ULONG idxType, char *pszName, size_t cbName)
5063{
5064 /*
5065 * Query the object types.
5066 */
5067 uint32_t cbBuf = _8K;
5068 uint8_t *pbBuf = (uint8_t *)RTMemAllocZ(_8K);
5069 ULONG cbNeeded = cbBuf;
5070 NTSTATUS rcNt = NtQueryObject(NULL, ObjectTypesInformation, pbBuf, cbBuf, &cbNeeded);
5071 while (rcNt == STATUS_INFO_LENGTH_MISMATCH)
5072 {
5073 cbBuf = RT_ALIGN_32(cbNeeded + 256, _64K);
5074 RTMemFree(pbBuf);
5075 pbBuf = (uint8_t *)RTMemAllocZ(cbBuf);
5076 if (pbBuf)
5077 rcNt = NtQueryObject(NULL, ObjectTypesInformation, pbBuf, cbBuf, &cbNeeded);
5078 else
5079 break;
5080 }
5081 if (NT_SUCCESS(rcNt))
5082 {
5083 Assert(cbNeeded <= cbBuf);
5084
5085 POBJECT_TYPES_INFORMATION pObjTypes = (OBJECT_TYPES_INFORMATION *)pbBuf;
5086 POBJECT_TYPE_INFORMATION pCurType = &pObjTypes->FirstType;
5087 ULONG cLeft = pObjTypes->NumberOfTypes;
5088 while (cLeft-- > 0 && (uintptr_t)&pCurType[1] - (uintptr_t)pbBuf < cbNeeded)
5089 {
5090 if (pCurType->TypeIndex == idxType)
5091 {
5092 PCRTUTF16 const pwszSrc = pCurType->TypeName.Buffer;
5093 AssertBreak(pwszSrc);
5094 size_t idxName = pCurType->TypeName.Length / sizeof(RTUTF16);
5095 AssertBreak(idxName > 0);
5096 AssertBreak(idxName < 128);
5097 if (idxName >= cbName)
5098 idxName = cbName - 1;
5099 pszName[idxName] = '\0';
5100 while (idxName-- > 0)
5101 pszName[idxName] = (char )pwszSrc[idxName];
5102 RTMemFree(pbBuf);
5103 return pszName;
5104 }
5105
5106 /* next */
5107 pCurType = (POBJECT_TYPE_INFORMATION)( (uintptr_t)pCurType->TypeName.Buffer
5108 + RT_ALIGN_32(pCurType->TypeName.MaximumLength, sizeof(uintptr_t)));
5109 }
5110 }
5111
5112 RTMemFree(pbBuf);
5113 return "unknown";
5114}
5115
5116
5117/**
5118 * Worker for supdrvNtProtectVerifyProcess that verifies the handles to a VM
5119 * process and its thread.
5120 *
5121 * @returns VBox status code.
5122 * @param pNtProtect The NT protect structure for getting information
5123 * about special processes.
5124 * @param pErrInfo Where to return additional error details.
5125 */
5126static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNtProtect, PRTERRINFO pErrInfo)
5127{
5128 /*
5129 * What to protect.
5130 */
5131 PEPROCESS pProtectedProcess = PsGetCurrentProcess();
5132 HANDLE hProtectedPid = PsGetProcessId(pProtectedProcess);
5133 PETHREAD pProtectedThread = PsGetCurrentThread();
5134 AssertReturn(pNtProtect->AvlCore.Key == hProtectedPid, VERR_INTERNAL_ERROR_5);
5135
5136 /*
5137 * Take a snapshot of all the handles in the system.
5138 * Note! The 32 bytes on the size of to counteract the allocation header
5139 * that rtR0MemAllocEx slaps on everything.
5140 */
5141 uint32_t cbBuf = _256K - 32;
5142 uint8_t *pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
5143 ULONG cbNeeded = cbBuf;
5144 NTSTATUS rcNt = NtQuerySystemInformation(SystemExtendedHandleInformation, pbBuf, cbBuf, &cbNeeded);
5145 if (!NT_SUCCESS(rcNt))
5146 {
5147 while ( rcNt == STATUS_INFO_LENGTH_MISMATCH
5148 && cbNeeded > cbBuf
5149 && cbBuf <= 32U*_1M)
5150 {
5151 cbBuf = RT_ALIGN_32(cbNeeded + _4K, _64K) - 32;
5152 RTMemFree(pbBuf);
5153 pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
5154 if (!pbBuf)
5155 return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Error allocating %zu bytes for querying handles.", cbBuf);
5156 rcNt = NtQuerySystemInformation(SystemExtendedHandleInformation, pbBuf, cbBuf, &cbNeeded);
5157 }
5158 if (!NT_SUCCESS(rcNt))
5159 {
5160 RTMemFree(pbBuf);
5161 return RTErrInfoSetF(pErrInfo, RTErrConvertFromNtStatus(rcNt),
5162 "NtQuerySystemInformation/SystemExtendedHandleInformation failed: %#x\n", rcNt);
5163 }
5164 }
5165
5166 /*
5167 * Walk the information and look for handles to the two objects we're protecting.
5168 */
5169 int rc = VINF_SUCCESS;
5170# ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
5171 HANDLE idLastDebugger = (HANDLE)~(uintptr_t)0;
5172# endif
5173
5174 uint32_t cCsrssProcessHandles = 0;
5175 uint32_t cSystemProcessHandles = 0;
5176 uint32_t cEvilProcessHandles = 0;
5177 uint32_t cBenignProcessHandles = 0;
5178
5179 uint32_t cCsrssThreadHandles = 0;
5180 uint32_t cEvilThreadHandles = 0;
5181 uint32_t cBenignThreadHandles = 0;
5182
5183 uint32_t cEvilInheritableHandles = 0;
5184 uint32_t cBenignInheritableHandles = 0;
5185 char szTmpName[32];
5186
5187 SYSTEM_HANDLE_INFORMATION_EX const *pInfo = (SYSTEM_HANDLE_INFORMATION_EX const *)pbBuf;
5188 ULONG_PTR i = pInfo->NumberOfHandles;
5189 AssertRelease(RT_UOFFSETOF_DYN(SYSTEM_HANDLE_INFORMATION_EX, Handles[i]) == cbNeeded);
5190 while (i-- > 0)
5191 {
5192 const char *pszType;
5193 SYSTEM_HANDLE_ENTRY_INFO_EX const *pHandleInfo = &pInfo->Handles[i];
5194 if (pHandleInfo->Object == pProtectedProcess)
5195 {
5196 /* Handles within the protected process are fine. */
5197 if ( !(pHandleInfo->GrantedAccess & SUPDRV_NT_EVIL_PROCESS_RIGHTS)
5198 || pHandleInfo->UniqueProcessId == hProtectedPid)
5199 {
5200 cBenignProcessHandles++;
5201 continue;
5202 }
5203
5204 /* CSRSS is allowed to have one evil process handle.
5205 See the special cases in the hook code. */
5206 if ( cCsrssProcessHandles < 1
5207 && pHandleInfo->UniqueProcessId == pNtProtect->hCsrssPid)
5208 {
5209 cCsrssProcessHandles++;
5210 continue;
5211 }
5212
5213 /* The system process is allowed having two open process handle in
5214 Windows 8.1 and later, and one in earlier. This is probably a
5215 little overly paranoid as I think we can safely trust the
5216 system process... */
5217 if ( cSystemProcessHandles < (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3) ? UINT32_C(2) : UINT32_C(1))
5218 && pHandleInfo->UniqueProcessId == PsGetProcessId(PsInitialSystemProcess))
5219 {
5220 cSystemProcessHandles++;
5221 continue;
5222 }
5223
5224 cEvilProcessHandles++;
5225 pszType = "process";
5226 }
5227 else if (pHandleInfo->Object == pProtectedThread)
5228 {
5229 /* Handles within the protected process is fine. */
5230 if ( !(pHandleInfo->GrantedAccess & SUPDRV_NT_EVIL_THREAD_RIGHTS)
5231 || pHandleInfo->UniqueProcessId == hProtectedPid)
5232 {
5233 cBenignThreadHandles++;
5234 continue;
5235 }
5236
5237 /* CSRSS is allowed to have one evil handle to the primary thread
5238 for LPC purposes. See the hook for special case. */
5239 if ( cCsrssThreadHandles < 1
5240 && pHandleInfo->UniqueProcessId == pNtProtect->hCsrssPid)
5241 {
5242 cCsrssThreadHandles++;
5243 continue;
5244 }
5245
5246 cEvilThreadHandles++;
5247 pszType = "thread";
5248 }
5249 else if ( (pHandleInfo->HandleAttributes & OBJ_INHERIT)
5250 && pHandleInfo->UniqueProcessId == hProtectedPid)
5251 {
5252 /* No handles should be marked inheritable, except files and two events.
5253 Handles to NT 'directory' objects are especially evil, because of
5254 KnownDlls faking. See bugref{10294} for details.
5255
5256 Correlating the ObjectTypeIndex to a type is complicated, so instead
5257 we try referecing the handle and check the type that way. So, only
5258 file and events objects are allowed to be marked inheritable at the
5259 moment. Add more in whitelist fashion if needed. */
5260 void *pvObject = NULL;
5261 rcNt = ObReferenceObjectByHandle(pHandleInfo->HandleValue, 0, *IoFileObjectType, KernelMode, &pvObject, NULL);
5262 if (rcNt == STATUS_OBJECT_TYPE_MISMATCH)
5263 rcNt = ObReferenceObjectByHandle(pHandleInfo->HandleValue, 0, *ExEventObjectType, KernelMode, &pvObject, NULL);
5264 if (NT_SUCCESS(rcNt))
5265 {
5266 ObDereferenceObject(pvObject);
5267 cBenignInheritableHandles++;
5268 continue;
5269 }
5270
5271 if (rcNt != STATUS_OBJECT_TYPE_MISMATCH)
5272 {
5273 cBenignInheritableHandles++;
5274 continue;
5275 }
5276
5277 cEvilInheritableHandles++;
5278 pszType = supdrvNtProtectHandleTypeIndexToName(pHandleInfo->ObjectTypeIndex, szTmpName, sizeof(szTmpName));
5279 }
5280 else
5281 continue;
5282
5283# ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
5284 /* Ignore whitelisted debuggers. */
5285 if (pHandleInfo->UniqueProcessId == idLastDebugger)
5286 continue;
5287 PEPROCESS pDbgProc;
5288 rcNt = PsLookupProcessByProcessId(pHandleInfo->UniqueProcessId, &pDbgProc);
5289 if (NT_SUCCESS(rcNt))
5290 {
5291 bool fIsDebugger = supdrvNtProtectIsWhitelistedDebugger(pDbgProc);
5292 ObDereferenceObject(pDbgProc);
5293 if (fIsDebugger)
5294 {
5295 idLastDebugger = pHandleInfo->UniqueProcessId;
5296 continue;
5297 }
5298 }
5299# endif
5300
5301 /* Found evil handle. Currently ignoring on pre-Vista. */
5302# ifndef VBOX_WITH_VISTA_NO_SP
5303 if ( g_uNtVerCombined >= SUP_NT_VER_VISTA
5304# else
5305 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0)
5306# endif
5307 || g_pfnObRegisterCallbacks)
5308 {
5309 LogRel(("vboxdrv: Found evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s (%u)\n",
5310 pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
5311 pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType, pHandleInfo->ObjectTypeIndex));
5312 rc = RTErrInfoAddF(pErrInfo, VERR_SUPDRV_HARDENING_EVIL_HANDLE,
5313 *pErrInfo->pszMsg
5314 ? "\nFound evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s (%u)"
5315 : "Found evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s (%u)",
5316 pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
5317 pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType, pHandleInfo->ObjectTypeIndex);
5318
5319 /* Try add the process name. */
5320 PEPROCESS pOffendingProcess;
5321 rcNt = PsLookupProcessByProcessId(pHandleInfo->UniqueProcessId, &pOffendingProcess);
5322 if (NT_SUCCESS(rcNt))
5323 {
5324 const char *pszName = (const char *)PsGetProcessImageFileName(pOffendingProcess);
5325 if (pszName && *pszName)
5326 rc = RTErrInfoAddF(pErrInfo, rc, " [%s]", pszName);
5327
5328 ObDereferenceObject(pOffendingProcess);
5329 }
5330 }
5331 }
5332
5333 RTMemFree(pbBuf);
5334 return rc;
5335}
5336
5337
5338/**
5339 * Checks if the current process checks out as a VM process stub.
5340 *
5341 * @returns VBox status code.
5342 * @param pNtProtect The NT protect structure. This is upgraded to a
5343 * final protection kind (state) on success.
5344 */
5345static int supdrvNtProtectVerifyProcess(PSUPDRVNTPROTECT pNtProtect)
5346{
5347 AssertReturn(PsGetProcessId(PsGetCurrentProcess()) == pNtProtect->AvlCore.Key, VERR_INTERNAL_ERROR_3);
5348
5349 /*
5350 * Do the verification. The handle restriction checks are only preformed
5351 * on VM processes.
5352 */
5353 int rc = VINF_SUCCESS;
5354 PSUPDRVNTERRORINFO pErrorInfo = (PSUPDRVNTERRORINFO)RTMemAllocZ(sizeof(*pErrorInfo));
5355 if (RT_SUCCESS(rc))
5356 {
5357 pErrorInfo->hProcessId = PsGetCurrentProcessId();
5358 pErrorInfo->hThreadId = PsGetCurrentThreadId();
5359 RTERRINFO ErrInfo;
5360 RTErrInfoInit(&ErrInfo, pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo));
5361
5362 if (pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
5363 rc = supdrvNtProtectRestrictHandlesToProcessAndThread(pNtProtect, &ErrInfo);
5364 if (RT_SUCCESS(rc))
5365 {
5366 rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_VERIFY_ONLY, 0 /*fFlags*/,
5367 NULL /*pcFixes*/, &ErrInfo);
5368 if (RT_SUCCESS(rc) && pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
5369 rc = supdrvNtProtectVerifyStubForVmProcess(pNtProtect, &ErrInfo);
5370 }
5371 }
5372 else
5373 rc = VERR_NO_MEMORY;
5374
5375 /*
5376 * Upgrade and return.
5377 */
5378 HANDLE hOpenTid = PsGetCurrentThreadId();
5379 RTSpinlockAcquire(g_hNtProtectLock);
5380
5381 /* Stub process verficiation is pretty much straight forward. */
5382 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubUnverified)
5383 {
5384 pNtProtect->enmProcessKind = RT_SUCCESS(rc) ? kSupDrvNtProtectKind_StubSpawning : kSupDrvNtProtectKind_StubDead;
5385 pNtProtect->hOpenTid = hOpenTid;
5386 }
5387 /* The VM process verification is a little bit more complicated
5388 because we need to drop the parent process reference as well. */
5389 else if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
5390 {
5391 AssertRelease(pNtProtect->cRefs >= 2); /* Parent + Caller */
5392 PSUPDRVNTPROTECT pParent = pNtProtect->u.pParent;
5393 AssertRelease(pParent);
5394 AssertRelease(pParent->u.pParent == pNtProtect);
5395 AssertRelease(pParent->enmProcessKind == kSupDrvNtProtectKind_StubParent);
5396 pParent->u.pParent = NULL;
5397
5398 pNtProtect->u.pParent = NULL;
5399 ASMAtomicDecU32(&pNtProtect->cRefs);
5400
5401 if (RT_SUCCESS(rc))
5402 {
5403 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessConfirmed;
5404 pNtProtect->hOpenTid = hOpenTid;
5405 }
5406 else
5407 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
5408 }
5409
5410 /* Since the stub and VM processes are only supposed to have one thread,
5411 we're not supposed to be subject to any races from within the processes.
5412
5413 There is a race between VM process verification and the stub process
5414 exiting, though. We require the stub process to be alive until the new
5415 VM process has made it thru the validation. So, when the stub
5416 terminates the notification handler will change the state of both stub
5417 and VM process to dead.
5418
5419 Also, I'm not entirely certain where the process
5420 termination notification is triggered from, so that can theorically
5421 create a race in both cases. */
5422 else
5423 {
5424 AssertReleaseMsg( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubDead
5425 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessDead,
5426 ("enmProcessKind=%d rc=%Rrc\n", pNtProtect->enmProcessKind, rc));
5427 if (RT_SUCCESS(rc))
5428 rc = VERR_INVALID_STATE; /* There should be no races here. */
5429 }
5430
5431 RTSpinlockRelease(g_hNtProtectLock);
5432
5433 /*
5434 * Free error info on success, keep it on failure.
5435 */
5436 if (RT_SUCCESS(rc))
5437 RTMemFree(pErrorInfo);
5438 else if (pErrorInfo)
5439 {
5440 pErrorInfo->cchErrorInfo = (uint32_t)strlen(pErrorInfo->szErrorInfo);
5441 if (!pErrorInfo->cchErrorInfo)
5442 pErrorInfo->cchErrorInfo = (uint32_t)RTStrPrintf(pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo),
5443 "supdrvNtProtectVerifyProcess: rc=%d", rc);
5444 RTLogWriteDebugger(pErrorInfo->szErrorInfo, pErrorInfo->cchErrorInfo);
5445
5446 int rc2 = RTSemMutexRequest(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
5447 if (RT_SUCCESS(rc2))
5448 {
5449 pErrorInfo->uCreatedMsTs = RTTimeMilliTS();
5450
5451 /* Free old entries. */
5452 PSUPDRVNTERRORINFO pCur;
5453 while ( (pCur = RTListGetFirst(&g_ErrorInfoHead, SUPDRVNTERRORINFO, ListEntry)) != NULL
5454 && (int64_t)(pErrorInfo->uCreatedMsTs - pCur->uCreatedMsTs) > 60000 /*60sec*/)
5455 {
5456 RTListNodeRemove(&pCur->ListEntry);
5457 RTMemFree(pCur);
5458 }
5459
5460 /* Insert our new entry. */
5461 RTListAppend(&g_ErrorInfoHead, &pErrorInfo->ListEntry);
5462
5463 RTSemMutexRelease(g_hErrorInfoLock);
5464 }
5465 else
5466 RTMemFree(pErrorInfo);
5467 }
5468
5469 return rc;
5470}
5471
5472
5473# ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
5474/**
5475 * Checks if the current process is being debugged.
5476 * @return @c true if debugged, @c false if not.
5477 */
5478static bool supdrvNtIsDebuggerAttached(void)
5479{
5480 return PsIsProcessBeingDebugged(PsGetCurrentProcess()) != FALSE;
5481}
5482# endif /* !VBOX_WITHOUT_DEBUGGER_CHECKS */
5483
5484#endif /* VBOX_WITH_HARDENING */
5485#if defined(VBOX_WITH_HARDENING) || defined(VBOX_WITH_MINIMAL_HARDENING)
5486
5487/**
5488 * Terminates the hardening bits.
5489 */
5490static void supdrvNtProtectTerm(void)
5491{
5492# ifdef VBOX_WITH_HARDENING
5493 /*
5494 * Stop intercepting process and thread handle creation calls.
5495 */
5496 if (g_pvObCallbacksCookie)
5497 {
5498 g_pfnObUnRegisterCallbacks(g_pvObCallbacksCookie);
5499 g_pvObCallbacksCookie = NULL;
5500 }
5501
5502 /*
5503 * Stop intercepting process creation and termination notifications.
5504 */
5505 NTSTATUS rcNt;
5506 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
5507 rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
5508 else
5509 rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
5510 AssertMsg(NT_SUCCESS(rcNt), ("rcNt=%#x\n", rcNt));
5511
5512 Assert(g_NtProtectTree == NULL);
5513
5514 /*
5515 * Clean up globals.
5516 */
5517 RTSpinlockDestroy(g_hNtProtectLock);
5518 g_NtProtectTree = NIL_RTSPINLOCK;
5519
5520 RTSemMutexDestroy(g_hErrorInfoLock);
5521 g_hErrorInfoLock = NIL_RTSEMMUTEX;
5522
5523 PSUPDRVNTERRORINFO pCur;
5524 while ((pCur = RTListGetFirst(&g_ErrorInfoHead, SUPDRVNTERRORINFO, ListEntry)) != NULL)
5525 {
5526 RTListNodeRemove(&pCur->ListEntry);
5527 RTMemFree(pCur);
5528 }
5529# endif /* VBOX_WITH_HARDENING */
5530
5531 supHardenedWinTermImageVerifier();
5532}
5533
5534# ifdef VBOX_WITH_HARDENING
5535# ifdef RT_ARCH_X86
5536DECLASM(void) supdrvNtQueryVirtualMemory_0xAF(void);
5537DECLASM(void) supdrvNtQueryVirtualMemory_0xB0(void);
5538DECLASM(void) supdrvNtQueryVirtualMemory_0xB1(void);
5539DECLASM(void) supdrvNtQueryVirtualMemory_0xB2(void);
5540DECLASM(void) supdrvNtQueryVirtualMemory_0xB3(void);
5541DECLASM(void) supdrvNtQueryVirtualMemory_0xB4(void);
5542DECLASM(void) supdrvNtQueryVirtualMemory_0xB5(void);
5543DECLASM(void) supdrvNtQueryVirtualMemory_0xB6(void);
5544DECLASM(void) supdrvNtQueryVirtualMemory_0xB7(void);
5545DECLASM(void) supdrvNtQueryVirtualMemory_0xB8(void);
5546DECLASM(void) supdrvNtQueryVirtualMemory_0xB9(void);
5547DECLASM(void) supdrvNtQueryVirtualMemory_0xBA(void);
5548DECLASM(void) supdrvNtQueryVirtualMemory_0xBB(void);
5549DECLASM(void) supdrvNtQueryVirtualMemory_0xBC(void);
5550DECLASM(void) supdrvNtQueryVirtualMemory_0xBD(void);
5551DECLASM(void) supdrvNtQueryVirtualMemory_0xBE(void);
5552# elif defined(RT_ARCH_AMD64)
5553DECLASM(void) supdrvNtQueryVirtualMemory_0x1F(void);
5554DECLASM(void) supdrvNtQueryVirtualMemory_0x20(void);
5555DECLASM(void) supdrvNtQueryVirtualMemory_0x21(void);
5556DECLASM(void) supdrvNtQueryVirtualMemory_0x22(void);
5557DECLASM(void) supdrvNtQueryVirtualMemory_0x23(void);
5558extern "C" NTSYSAPI NTSTATUS NTAPI ZwRequestWaitReplyPort(HANDLE, PVOID, PVOID);
5559# endif
5560# endif /* VBOX_WITH_HARDENING */
5561
5562
5563/**
5564 * Initalizes the hardening bits.
5565 *
5566 * @returns NT status code.
5567 */
5568static NTSTATUS supdrvNtProtectInit(void)
5569{
5570 /*
5571 * Initialize the globals.
5572 */
5573
5574# ifdef VBOX_WITH_HARDENING
5575 /* Resolve methods we want but isn't available everywhere. */
5576 UNICODE_STRING RoutineName;
5577
5578 RtlInitUnicodeString(&RoutineName, L"ObGetObjectType");
5579 g_pfnObGetObjectType = (PFNOBGETOBJECTTYPE)MmGetSystemRoutineAddress(&RoutineName);
5580
5581 RtlInitUnicodeString(&RoutineName, L"ObRegisterCallbacks");
5582 g_pfnObRegisterCallbacks = (PFNOBREGISTERCALLBACKS)MmGetSystemRoutineAddress(&RoutineName);
5583
5584 RtlInitUnicodeString(&RoutineName, L"ObUnRegisterCallbacks");
5585 g_pfnObUnRegisterCallbacks = (PFNOBUNREGISTERCALLBACKS)MmGetSystemRoutineAddress(&RoutineName);
5586
5587 RtlInitUnicodeString(&RoutineName, L"PsSetCreateProcessNotifyRoutineEx");
5588 g_pfnPsSetCreateProcessNotifyRoutineEx = (PFNPSSETCREATEPROCESSNOTIFYROUTINEEX)MmGetSystemRoutineAddress(&RoutineName);
5589
5590 RtlInitUnicodeString(&RoutineName, L"PsReferenceProcessFilePointer");
5591 g_pfnPsReferenceProcessFilePointer = (PFNPSREFERENCEPROCESSFILEPOINTER)MmGetSystemRoutineAddress(&RoutineName);
5592
5593 RtlInitUnicodeString(&RoutineName, L"PsIsProtectedProcessLight");
5594 g_pfnPsIsProtectedProcessLight = (PFNPSISPROTECTEDPROCESSLIGHT)MmGetSystemRoutineAddress(&RoutineName);
5595
5596 RtlInitUnicodeString(&RoutineName, L"ZwAlpcCreatePort");
5597 g_pfnZwAlpcCreatePort = (PFNZWALPCCREATEPORT)MmGetSystemRoutineAddress(&RoutineName);
5598
5599 RtlInitUnicodeString(&RoutineName, L"ZwQueryVirtualMemory"); /* Yes, using Zw version here. */
5600 g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)MmGetSystemRoutineAddress(&RoutineName);
5601 if (!g_pfnNtQueryVirtualMemory && g_uNtVerCombined < SUP_NT_VER_VISTA)
5602 {
5603 /* XP & W2K3 doesn't have this function exported, so we've cooked up a
5604 few alternative in the assembly helper file that uses the code in
5605 ZwReadFile with a different eax value. We figure the syscall number
5606 by inspecting ZwQueryVolumeInformationFile as it's the next number. */
5607# ifdef RT_ARCH_X86
5608 uint8_t const *pbCode = (uint8_t const *)(uintptr_t)ZwQueryVolumeInformationFile;
5609 if (*pbCode == 0xb8) /* mov eax, dword */
5610 switch (*(uint32_t const *)&pbCode[1])
5611 {
5612 case 0xb0: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xAF; break; /* just in case */
5613 case 0xb1: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB0; break; /* just in case */
5614 case 0xb2: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB1; break; /* just in case */
5615 case 0xb3: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB2; break; /* XP SP3 */
5616 case 0xb4: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB2; break; /* just in case */
5617 case 0xb5: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB3; break; /* just in case */
5618 case 0xb6: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB4; break; /* just in case */
5619 case 0xb7: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB5; break; /* just in case */
5620 case 0xb8: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB6; break; /* just in case */
5621 case 0xb9: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB7; break; /* just in case */
5622 case 0xba: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB8; break; /* just in case */
5623 case 0xbb: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBA; break; /* W2K3 R2 SP2 */
5624 case 0xbc: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBB; break; /* just in case */
5625 case 0xbd: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBC; break; /* just in case */
5626 case 0xbe: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBD; break; /* just in case */
5627 case 0xbf: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBE; break; /* just in case */
5628 }
5629# elif defined(RT_ARCH_AMD64)
5630 uint8_t const *pbCode = (uint8_t const *)(uintptr_t)ZwRequestWaitReplyPort;
5631 if ( pbCode[ 0] == 0x48 /* mov rax, rsp */
5632 && pbCode[ 1] == 0x8b
5633 && pbCode[ 2] == 0xc4
5634 && pbCode[ 3] == 0xfa /* cli */
5635 && pbCode[ 4] == 0x48 /* sub rsp, 10h */
5636 && pbCode[ 5] == 0x83
5637 && pbCode[ 6] == 0xec
5638 && pbCode[ 7] == 0x10
5639 && pbCode[ 8] == 0x50 /* push rax */
5640 && pbCode[ 9] == 0x9c /* pushfq */
5641 && pbCode[10] == 0x6a /* push 10 */
5642 && pbCode[11] == 0x10
5643 && pbCode[12] == 0x48 /* lea rax, [nt!KiServiceLinkage] */
5644 && pbCode[13] == 0x8d
5645 && pbCode[14] == 0x05
5646 && pbCode[19] == 0x50 /* push rax */
5647 && pbCode[20] == 0xb8 /* mov eax,1fh <- the syscall no. */
5648 /*&& pbCode[21] == 0x1f*/
5649 && pbCode[22] == 0x00
5650 && pbCode[23] == 0x00
5651 && pbCode[24] == 0x00
5652 && pbCode[25] == 0xe9 /* jmp KiServiceInternal */
5653 )
5654 {
5655 uint8_t const *pbKiServiceInternal = &pbCode[30] + *(int32_t const *)&pbCode[26];
5656 uint8_t const *pbKiServiceLinkage = &pbCode[19] + *(int32_t const *)&pbCode[15];
5657 if (*pbKiServiceLinkage == 0xc3)
5658 {
5659 g_pfnKiServiceInternal = (PFNRT)pbKiServiceInternal;
5660 g_pfnKiServiceLinkage = (PFNRT)pbKiServiceLinkage;
5661 switch (pbCode[21])
5662 {
5663 case 0x1e: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x1F; break;
5664 case 0x1f: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x20; break;
5665 case 0x20: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x21; break;
5666 case 0x21: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x22; break;
5667 case 0x22: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x23; break;
5668 }
5669 }
5670 }
5671# endif
5672 }
5673 if (!g_pfnNtQueryVirtualMemory)
5674 {
5675 LogRel(("vboxdrv: Cannot locate ZwQueryVirtualMemory in ntoskrnl, nor were we able to cook up a replacement.\n"));
5676 return STATUS_PROCEDURE_NOT_FOUND;
5677 }
5678
5679# else /* !VBOX_WITH_HARDENING */
5680 /* Always present on arm64 and more recent systems. */
5681 g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)ZwQueryVirtualMemory;
5682# endif /* !VBOX_WITH_HARDENING */
5683
5684 NTSTATUS rcNt;
5685 int rc;
5686
5687# ifdef VBOX_WITH_HARDENING
5688# ifdef VBOX_STRICT
5689 if ( g_uNtVerCombined >= SUP_NT_VER_W70
5690 && ( g_pfnObGetObjectType == NULL
5691 || g_pfnZwAlpcCreatePort == NULL) )
5692 {
5693 LogRel(("vboxdrv: g_pfnObGetObjectType=%p g_pfnZwAlpcCreatePort=%p.\n", g_pfnObGetObjectType, g_pfnZwAlpcCreatePort));
5694 return STATUS_PROCEDURE_NOT_FOUND;
5695 }
5696# endif
5697
5698 /* LPC object type. */
5699 g_pAlpcPortObjectType1 = *LpcPortObjectType;
5700
5701 /* The spinlock protecting our structures. */
5702 rc = RTSpinlockCreate(&g_hNtProtectLock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "NtProtectLock");
5703 if (RT_FAILURE(rc))
5704 return VBoxDrvNtErr2NtStatus(rc);
5705 g_NtProtectTree = NULL;
5706
5707 /* The mutex protecting the error information. */
5708 RTListInit(&g_ErrorInfoHead);
5709 rc = RTSemMutexCreate(&g_hErrorInfoLock);
5710 if (RT_SUCCESS(rc))
5711 {
5712# endif /* VBOX_WITH_HARDENING */
5713 /* Image stuff + certificates. */
5714 rc = supHardenedWinInitImageVerifier(NULL);
5715 if (RT_SUCCESS(rc))
5716 {
5717# ifdef VBOX_WITH_HARDENING
5718 /*
5719 * Intercept process creation and termination.
5720 */
5721 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
5722 rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, FALSE /*fRemove*/);
5723 else
5724 rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, FALSE /*fRemove*/);
5725 if (NT_SUCCESS(rcNt))
5726 {
5727 /*
5728 * Intercept process and thread handle creation calls.
5729 * The preferred method is only available on Vista SP1+.
5730 */
5731 if (g_pfnObRegisterCallbacks && g_pfnObUnRegisterCallbacks)
5732 {
5733 static OB_OPERATION_REGISTRATION s_aObOperations[] =
5734 {
5735 {
5736 0, /* PsProcessType - imported, need runtime init, better do it explicitly. */
5737 OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
5738 supdrvNtProtectCallback_ProcessHandlePre,
5739 supdrvNtProtectCallback_ProcessHandlePost,
5740 },
5741 {
5742 0, /* PsThreadType - imported, need runtime init, better do it explicitly. */
5743 OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
5744 supdrvNtProtectCallback_ThreadHandlePre,
5745 supdrvNtProtectCallback_ThreadHandlePost,
5746 },
5747 };
5748 s_aObOperations[0].ObjectType = PsProcessType;
5749 s_aObOperations[1].ObjectType = PsThreadType;
5750
5751 static OB_CALLBACK_REGISTRATION s_ObCallbackReg =
5752 {
5753 /* .Version = */ OB_FLT_REGISTRATION_VERSION,
5754 /* .OperationRegistrationCount = */ RT_ELEMENTS(s_aObOperations),
5755 /* .Altitude.Length = */ { 0,
5756 /* .Altitude.MaximumLength = */ 0,
5757 /* .Altitude.Buffer = */ NULL },
5758 /* .RegistrationContext = */ NULL,
5759 /* .OperationRegistration = */ &s_aObOperations[0]
5760 };
5761 static WCHAR const *s_apwszAltitudes[] = /** @todo get a valid number */
5762 {
5763 L"48596.98940", L"46935.19485", L"49739.39704", L"40334.74976",
5764 L"66667.98940", L"69888.19485", L"69889.39704", L"60364.74976",
5765 L"85780.98940", L"88978.19485", L"89939.39704", L"80320.74976",
5766 L"329879.98940", L"326787.19485", L"328915.39704", L"320314.74976",
5767 };
5768
5769 rcNt = STATUS_FLT_INSTANCE_ALTITUDE_COLLISION;
5770 for (uint32_t i = 0; i < RT_ELEMENTS(s_apwszAltitudes) && rcNt == STATUS_FLT_INSTANCE_ALTITUDE_COLLISION; i++)
5771 {
5772 s_ObCallbackReg.Altitude.Buffer = (WCHAR *)s_apwszAltitudes[i];
5773 s_ObCallbackReg.Altitude.Length = (uint16_t)RTUtf16Len(s_apwszAltitudes[i]) * sizeof(WCHAR);
5774 s_ObCallbackReg.Altitude.MaximumLength = s_ObCallbackReg.Altitude.Length + sizeof(WCHAR);
5775
5776 rcNt = g_pfnObRegisterCallbacks(&s_ObCallbackReg, &g_pvObCallbacksCookie);
5777 if (NT_SUCCESS(rcNt))
5778 {
5779# endif /* VBOX_WITH_HARDENING */
5780 /*
5781 * Happy ending.
5782 */
5783 return STATUS_SUCCESS;
5784# ifdef VBOX_WITH_HARDENING
5785 }
5786 }
5787 DbgPrint("VBoxSup: ObRegisterCallbacks failed with rcNt=%#x\n", rcNt); /* temp for @bugref{10657} */
5788 LogRel(("vboxdrv: ObRegisterCallbacks failed with rcNt=%#x\n", rcNt));
5789
5790 g_pvObCallbacksCookie = NULL;
5791 }
5792 else
5793 {
5794 /*
5795 * For the time being, we do not implement extra process
5796 * protection on pre-Vista-SP1 systems as they are lacking
5797 * necessary KPIs. XP is end of life, we do not wish to
5798 * spend more time on it, so we don't put up a fuss there.
5799 * Vista users without SP1 can install SP1 (or later), darn it,
5800 * so refuse to load.
5801 */
5802 /** @todo Hack up an XP solution - will require hooking kernel APIs or doing bad
5803 * stuff to a couple of object types. */
5804# ifndef VBOX_WITH_VISTA_NO_SP
5805 if (g_uNtVerCombined >= SUP_NT_VER_VISTA)
5806# else
5807 if (g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0))
5808# endif
5809 {
5810 DbgPrint("vboxdrv: ObRegisterCallbacks was not found. Please make sure you got the latest updates and service packs installed\n");
5811 rcNt = STATUS_SXS_VERSION_CONFLICT;
5812 }
5813 else
5814 {
5815 Log(("vboxdrv: ObRegisterCallbacks was not found; ignored pre-Vista\n"));
5816 return rcNt = STATUS_SUCCESS;
5817 }
5818 g_pvObCallbacksCookie = NULL;
5819 }
5820
5821 /*
5822 * Drop process create/term notifications.
5823 */
5824 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
5825 g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
5826 else
5827 PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
5828 }
5829 else
5830 {
5831 DbgPrint("VBoxSup: PsSetCreateProcessNotifyRoutine%s failed with rcNt=%#x!\n",
5832 g_pfnPsSetCreateProcessNotifyRoutineEx ? "Ex" : "", rcNt); /* temp for @bugref{10657} */
5833 LogRel(("vboxdrv: PsSetCreateProcessNotifyRoutine%s failed with rcNt=%#x\n",
5834 g_pfnPsSetCreateProcessNotifyRoutineEx ? "Ex" : "", rcNt));
5835 }
5836 supHardenedWinTermImageVerifier();
5837# endif /* VBOX_WITH_HARDENING */
5838 }
5839 else
5840 rcNt = VBoxDrvNtErr2NtStatus(rc);
5841
5842# ifdef VBOX_WITH_HARDENING
5843 RTSemMutexDestroy(g_hErrorInfoLock);
5844 g_hErrorInfoLock = NIL_RTSEMMUTEX;
5845 }
5846 else
5847 rcNt = VBoxDrvNtErr2NtStatus(rc);
5848
5849 RTSpinlockDestroy(g_hNtProtectLock);
5850 g_NtProtectTree = NIL_RTSPINLOCK;
5851# endif
5852 return rcNt;
5853}
5854
5855#endif /* VBOX_WITH_HARDENING || VBOX_WITH_MINIMAL_HARDENING */
5856
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette