VirtualBox

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

Last change on this file since 94063 was 93325, checked in by vboxsync, 3 years ago

/Config.kmk,SUPDrv-win.cpp: Hardened ASAN build adjustments. bugref:8492 bugref:9841

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