VirtualBox

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

Last change on this file since 75003 was 75003, checked in by vboxsync, 6 years ago

SUPDrv: Adjusted ep validation a little in prep for bugref:9232

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