VirtualBox

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

Last change on this file since 106897 was 106625, checked in by vboxsync, 4 months ago

SUPDrv: Making it build on win.arm64... jiraref:VBP-1253

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

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