VirtualBox

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

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

*: Made RT_UOFFSETOF, RT_OFFSETOF, RT_UOFFSETOF_ADD and RT_OFFSETOF_ADD work like builtin_offsetof() and require compile time resolvable requests, adding RT_UOFFSETOF_DYN for the dynamic questions that can only be answered at runtime.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 205.3 KB
Line 
1/* $Id: SUPDrv-win.cpp 73097 2018-07-12 21:06:33Z 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 '%ws'\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
2090int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, const uint8_t *pbImageBits)
2091{
2092 NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits);
2093 return VINF_SUCCESS;
2094}
2095
2096
2097/**
2098 * memcmp + errormsg + log.
2099 *
2100 * @returns Same as memcmp.
2101 * @param pImage The image.
2102 * @param pbImageBits The image bits ring-3 uploads.
2103 * @param uRva The RVA to start comparing at.
2104 * @param cb The number of bytes to compare.
2105 * @param pReq The load request.
2106 */
2107static int supdrvNtCompare(PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, uint32_t uRva, uint32_t cb, PSUPLDRLOAD pReq)
2108{
2109 int iDiff = memcmp((uint8_t const *)pImage->pvImage + uRva, pbImageBits + uRva, cb);
2110 if (iDiff)
2111 {
2112 uint32_t cbLeft = cb;
2113 const uint8_t *pbNativeBits = (const uint8_t *)pImage->pvImage;
2114 for (size_t off = uRva; cbLeft > 0; off++, cbLeft--)
2115 if (pbNativeBits[off] != pbImageBits[off])
2116 {
2117 /* Note! We need to copy image bits into a temporary stack buffer here as we'd
2118 otherwise risk overwriting them while formatting the error message. */
2119 uint8_t abBytes[64];
2120 memcpy(abBytes, &pbImageBits[off], RT_MIN(64, cbLeft));
2121 supdrvLdrLoadError(VERR_LDR_MISMATCH_NATIVE, pReq,
2122 "Mismatch at %#x (%p) of %s loaded at %p:\n"
2123 "ntld: %.*Rhxs\n"
2124 "iprt: %.*Rhxs",
2125 off, &pbNativeBits[off], pImage->szName, pImage->pvImage,
2126 RT_MIN(64, cbLeft), &pbNativeBits[off],
2127 RT_MIN(64, cbLeft), &abBytes[0]);
2128 SUPR0Printf("VBoxDrv: %s", pReq->u.Out.szError);
2129 break;
2130 }
2131 }
2132 return iDiff;
2133}
2134
2135/** Image compare exclusion regions. */
2136typedef struct SUPDRVNTEXCLREGIONS
2137{
2138 /** Number of regions. */
2139 uint32_t cRegions;
2140 /** The regions. */
2141 struct SUPDRVNTEXCLREGION
2142 {
2143 uint32_t uRva;
2144 uint32_t cb;
2145 } aRegions[16];
2146} SUPDRVNTEXCLREGIONS;
2147
2148/**
2149 * Adds an exclusion region to the collection.
2150 */
2151static bool supdrvNtAddExclRegion(SUPDRVNTEXCLREGIONS *pRegions, uint32_t uRvaRegion, uint32_t cbRegion)
2152{
2153 uint32_t const cRegions = pRegions->cRegions;
2154 AssertReturn(cRegions + 1 <= RT_ELEMENTS(pRegions->aRegions), false);
2155 uint32_t i = 0;
2156 for (; i < cRegions; i++)
2157 if (uRvaRegion < pRegions->aRegions[i].uRva)
2158 break;
2159 if (i != cRegions)
2160 memmove(&pRegions->aRegions[i + 1], &pRegions->aRegions[i], (cRegions - i) * sizeof(pRegions->aRegions[0]));
2161 pRegions->aRegions[i].uRva = uRvaRegion;
2162 pRegions->aRegions[i].cb = cbRegion;
2163 pRegions->cRegions++;
2164 return true;
2165}
2166
2167
2168int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
2169{
2170 NOREF(pDevExt);
2171 if (pImage->pvNtSectionObj)
2172 {
2173 /*
2174 * Usually, the entire image matches exactly.
2175 */
2176 if (!memcmp(pImage->pvImage, pbImageBits, pImage->cbImageBits))
2177 return VINF_SUCCESS;
2178
2179 /*
2180 * On Windows 10 the ImageBase member of the optional header is sometimes
2181 * updated with the actual load address and sometimes not. Try compare
2182 *
2183 */
2184 uint32_t const offNtHdrs = *(uint16_t *)pbImageBits == IMAGE_DOS_SIGNATURE
2185 ? ((IMAGE_DOS_HEADER const *)pbImageBits)->e_lfanew
2186 : 0;
2187 AssertLogRelReturn(offNtHdrs + sizeof(IMAGE_NT_HEADERS) < pImage->cbImageBits, VERR_INTERNAL_ERROR_5);
2188 IMAGE_NT_HEADERS const *pNtHdrsIprt = (IMAGE_NT_HEADERS const *)(pbImageBits + offNtHdrs);
2189 IMAGE_NT_HEADERS const *pNtHdrsNtLd = (IMAGE_NT_HEADERS const *)((uintptr_t)pImage->pvImage + offNtHdrs);
2190
2191 uint32_t const offImageBase = offNtHdrs + RT_UOFFSETOF(IMAGE_NT_HEADERS, OptionalHeader.ImageBase);
2192 uint32_t const cbImageBase = RT_SIZEOFMEMB(IMAGE_NT_HEADERS, OptionalHeader.ImageBase);
2193 if ( pNtHdrsNtLd->OptionalHeader.ImageBase != pNtHdrsIprt->OptionalHeader.ImageBase
2194 && ( pNtHdrsNtLd->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage
2195 || pNtHdrsIprt->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage)
2196 && pNtHdrsIprt->Signature == IMAGE_NT_SIGNATURE
2197 && pNtHdrsIprt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC
2198 && !memcmp(pImage->pvImage, pbImageBits, offImageBase)
2199 && !memcmp((uint8_t const *)pImage->pvImage + offImageBase + cbImageBase,
2200 pbImageBits + offImageBase + cbImageBase,
2201 pImage->cbImageBits - offImageBase - cbImageBase))
2202 return VINF_SUCCESS;
2203
2204 /*
2205 * On Windows Server 2003 (sp2 x86) both import thunk tables are fixed
2206 * up and we typically get a mismatch in the INIT section.
2207 *
2208 * So, lets see if everything matches when excluding the
2209 * OriginalFirstThunk tables and (maybe) the ImageBase member.
2210 * For simplicity the max number of exclusion regions is set to 16.
2211 */
2212 if ( pNtHdrsIprt->Signature == IMAGE_NT_SIGNATURE
2213 && pNtHdrsIprt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR_MAGIC
2214 && pNtHdrsIprt->OptionalHeader.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_IMPORT
2215 && pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size >= sizeof(IMAGE_IMPORT_DESCRIPTOR)
2216 && pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress > sizeof(IMAGE_NT_HEADERS)
2217 && pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress < pImage->cbImageBits
2218 )
2219 {
2220 SUPDRVNTEXCLREGIONS ExcludeRegions;
2221 ExcludeRegions.cRegions = 0;
2222
2223 /* ImageBase: */
2224 if ( pNtHdrsNtLd->OptionalHeader.ImageBase != pNtHdrsIprt->OptionalHeader.ImageBase
2225 && ( pNtHdrsNtLd->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage
2226 || pNtHdrsIprt->OptionalHeader.ImageBase == (uintptr_t)pImage->pvImage) )
2227 supdrvNtAddExclRegion(&ExcludeRegions, offImageBase, cbImageBase);
2228
2229 /* Imports: */
2230 uint32_t cImpsLeft = pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
2231 / sizeof(IMAGE_IMPORT_DESCRIPTOR);
2232 uint32_t offImps = pNtHdrsIprt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
2233 AssertLogRelReturn(offImps + cImpsLeft * sizeof(IMAGE_IMPORT_DESCRIPTOR) <= pImage->cbImageBits, VERR_INTERNAL_ERROR_3);
2234 IMAGE_IMPORT_DESCRIPTOR const *pImp = (IMAGE_IMPORT_DESCRIPTOR const *)(pbImageBits + offImps);
2235 while ( cImpsLeft-- > 0
2236 && ExcludeRegions.cRegions < RT_ELEMENTS(ExcludeRegions.aRegions))
2237 {
2238 uint32_t uRvaThunk = pImp->OriginalFirstThunk;
2239 if ( uRvaThunk > sizeof(IMAGE_NT_HEADERS)
2240 && uRvaThunk <= pImage->cbImageBits - sizeof(IMAGE_THUNK_DATA)
2241 && uRvaThunk != pImp->FirstThunk)
2242 {
2243 /* Find the size of the thunk table. */
2244 IMAGE_THUNK_DATA const *paThunk = (IMAGE_THUNK_DATA const *)(pbImageBits + uRvaThunk);
2245 uint32_t cMaxThunks = (pImage->cbImageBits - uRvaThunk) / sizeof(IMAGE_THUNK_DATA);
2246 uint32_t cThunks = 0;
2247 while (cThunks < cMaxThunks && paThunk[cThunks].u1.Function != 0)
2248 cThunks++;
2249 supdrvNtAddExclRegion(&ExcludeRegions, uRvaThunk, cThunks * sizeof(IMAGE_THUNK_DATA));
2250 }
2251
2252#if 0 /* Useful for VMMR0 hacking, not for production use. See also SUPDrvLdr.cpp. */
2253 /* Exclude the other thunk table if ntoskrnl.exe. */
2254 uint32_t uRvaName = pImp->Name;
2255 if ( uRvaName > sizeof(IMAGE_NT_HEADERS)
2256 && uRvaName < pImage->cbImageBits - sizeof("ntoskrnl.exe")
2257 && memcmp(&pbImageBits[uRvaName], RT_STR_TUPLE("ntoskrnl.exe")) == 0)
2258 {
2259 uRvaThunk = pImp->FirstThunk;
2260 if ( uRvaThunk > sizeof(IMAGE_NT_HEADERS)
2261 && uRvaThunk <= pImage->cbImageBits - sizeof(IMAGE_THUNK_DATA))
2262 {
2263 /* Find the size of the thunk table. */
2264 IMAGE_THUNK_DATA const *paThunk = (IMAGE_THUNK_DATA const *)(pbImageBits + uRvaThunk);
2265 uint32_t cMaxThunks = (pImage->cbImageBits - uRvaThunk) / sizeof(IMAGE_THUNK_DATA);
2266 uint32_t cThunks = 0;
2267 while (cThunks < cMaxThunks && paThunk[cThunks].u1.Function != 0)
2268 cThunks++;
2269 supdrvNtAddExclRegion(&ExcludeRegions, uRvaThunk, cThunks * sizeof(IMAGE_THUNK_DATA));
2270 }
2271 }
2272#endif
2273
2274 /* advance */
2275 pImp++;
2276 }
2277
2278 /*
2279 * Ok, do the comparison.
2280 */
2281 int iDiff = 0;
2282 uint32_t uRvaNext = 0;
2283 for (unsigned i = 0; !iDiff && i < ExcludeRegions.cRegions; i++)
2284 {
2285 if (uRvaNext < ExcludeRegions.aRegions[i].uRva)
2286 iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, ExcludeRegions.aRegions[i].uRva - uRvaNext, pReq);
2287 uRvaNext = ExcludeRegions.aRegions[i].uRva + ExcludeRegions.aRegions[i].cb;
2288 }
2289 if (!iDiff && uRvaNext < pImage->cbImageBits)
2290 iDiff = supdrvNtCompare(pImage, pbImageBits, uRvaNext, pImage->cbImageBits - uRvaNext, pReq);
2291 if (!iDiff)
2292 return VINF_SUCCESS;
2293 }
2294 else
2295 supdrvNtCompare(pImage, pbImageBits, 0, pImage->cbImageBits, pReq);
2296 return VERR_LDR_MISMATCH_NATIVE;
2297 }
2298 return supdrvLdrLoadError(VERR_INTERNAL_ERROR_4, pReq, "No NT section object! Impossible!");
2299}
2300
2301
2302void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
2303{
2304 if (pImage->pvNtSectionObj)
2305 {
2306 if (pImage->hMemLock != NIL_RTR0MEMOBJ)
2307 {
2308 RTR0MemObjFree(pImage->hMemLock, false /*fFreeMappings*/);
2309 pImage->hMemLock = NIL_RTR0MEMOBJ;
2310 }
2311
2312 NTSTATUS rcNt = ZwSetSystemInformation(MY_SystemUnloadGdiDriverInformation,
2313 &pImage->pvNtSectionObj, sizeof(pImage->pvNtSectionObj));
2314 if (rcNt != STATUS_SUCCESS)
2315 SUPR0Printf("VBoxDrv: failed to unload '%s', rcNt=%#x\n", pImage->szName, rcNt);
2316 pImage->pvNtSectionObj = NULL;
2317 }
2318 NOREF(pDevExt);
2319}
2320
2321
2322#ifdef SUPDRV_WITH_MSR_PROBER
2323
2324#if 1
2325/** @todo make this selectable. */
2326# define AMD_MSR_PASSCODE 0x9c5a203a
2327#else
2328# define ASMRdMsrEx(a, b, c) ASMRdMsr(a)
2329# define ASMWrMsrEx(a, b, c) ASMWrMsr(a,c)
2330#endif
2331
2332
2333/**
2334 * Argument package used by supdrvOSMsrProberRead and supdrvOSMsrProberWrite.
2335 */
2336typedef struct SUPDRVNTMSPROBERARGS
2337{
2338 uint32_t uMsr;
2339 uint64_t uValue;
2340 bool fGp;
2341} SUPDRVNTMSPROBERARGS;
2342
2343/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberRead.} */
2344static DECLCALLBACK(void) supdrvNtMsProberReadOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
2345{
2346 /*
2347 * rdmsr and wrmsr faults can be caught even with interrupts disabled.
2348 * (At least on 32-bit XP.)
2349 */
2350 SUPDRVNTMSPROBERARGS *pArgs = (SUPDRVNTMSPROBERARGS *)pvUser1; NOREF(idCpu); NOREF(pvUser2);
2351 RTCCUINTREG fOldFlags = ASMIntDisableFlags();
2352 __try
2353 {
2354 pArgs->uValue = ASMRdMsrEx(pArgs->uMsr, AMD_MSR_PASSCODE);
2355 pArgs->fGp = false;
2356 }
2357 __except(EXCEPTION_EXECUTE_HANDLER)
2358 {
2359 pArgs->fGp = true;
2360 pArgs->uValue = 0;
2361 }
2362 ASMSetFlags(fOldFlags);
2363}
2364
2365
2366int VBOXCALL supdrvOSMsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue)
2367{
2368 SUPDRVNTMSPROBERARGS Args;
2369 Args.uMsr = uMsr;
2370 Args.uValue = 0;
2371 Args.fGp = true;
2372
2373 if (idCpu == NIL_RTCPUID)
2374 supdrvNtMsProberReadOnCpu(idCpu, &Args, NULL);
2375 else
2376 {
2377 int rc = RTMpOnSpecific(idCpu, supdrvNtMsProberReadOnCpu, &Args, NULL);
2378 if (RT_FAILURE(rc))
2379 return rc;
2380 }
2381
2382 if (Args.fGp)
2383 return VERR_ACCESS_DENIED;
2384 *puValue = Args.uValue;
2385 return VINF_SUCCESS;
2386}
2387
2388
2389/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberWrite.} */
2390static DECLCALLBACK(void) supdrvNtMsProberWriteOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
2391{
2392 /*
2393 * rdmsr and wrmsr faults can be caught even with interrupts disabled.
2394 * (At least on 32-bit XP.)
2395 */
2396 SUPDRVNTMSPROBERARGS *pArgs = (SUPDRVNTMSPROBERARGS *)pvUser1; NOREF(idCpu); NOREF(pvUser2);
2397 RTCCUINTREG fOldFlags = ASMIntDisableFlags();
2398 __try
2399 {
2400 ASMWrMsrEx(pArgs->uMsr, AMD_MSR_PASSCODE, pArgs->uValue);
2401 pArgs->fGp = false;
2402 }
2403 __except(EXCEPTION_EXECUTE_HANDLER)
2404 {
2405 pArgs->fGp = true;
2406 }
2407 ASMSetFlags(fOldFlags);
2408}
2409
2410int VBOXCALL supdrvOSMsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue)
2411{
2412 SUPDRVNTMSPROBERARGS Args;
2413 Args.uMsr = uMsr;
2414 Args.uValue = uValue;
2415 Args.fGp = true;
2416
2417 if (idCpu == NIL_RTCPUID)
2418 supdrvNtMsProberWriteOnCpu(idCpu, &Args, NULL);
2419 else
2420 {
2421 int rc = RTMpOnSpecific(idCpu, supdrvNtMsProberWriteOnCpu, &Args, NULL);
2422 if (RT_FAILURE(rc))
2423 return rc;
2424 }
2425
2426 if (Args.fGp)
2427 return VERR_ACCESS_DENIED;
2428 return VINF_SUCCESS;
2429}
2430
2431/** @callback_method_impl{FNRTMPWORKER, Worker for supdrvOSMsrProberModify.} */
2432static DECLCALLBACK(void) supdrvNtMsProberModifyOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
2433{
2434 PSUPMSRPROBER pReq = (PSUPMSRPROBER)pvUser1;
2435 register uint32_t uMsr = pReq->u.In.uMsr;
2436 bool const fFaster = pReq->u.In.enmOp == SUPMSRPROBEROP_MODIFY_FASTER;
2437 uint64_t uBefore = 0;
2438 uint64_t uWritten = 0;
2439 uint64_t uAfter = 0;
2440 bool fBeforeGp = true;
2441 bool fModifyGp = true;
2442 bool fAfterGp = true;
2443 bool fRestoreGp = true;
2444 RTCCUINTREG fOldFlags;
2445 RT_NOREF2(idCpu, pvUser2);
2446
2447 /*
2448 * Do the job.
2449 */
2450 fOldFlags = ASMIntDisableFlags();
2451 ASMCompilerBarrier(); /* paranoia */
2452 if (!fFaster)
2453 ASMWriteBackAndInvalidateCaches();
2454
2455 __try
2456 {
2457 uBefore = ASMRdMsrEx(uMsr, AMD_MSR_PASSCODE);
2458 fBeforeGp = false;
2459 }
2460 __except(EXCEPTION_EXECUTE_HANDLER)
2461 {
2462 fBeforeGp = true;
2463 }
2464 if (!fBeforeGp)
2465 {
2466 register uint64_t uRestore = uBefore;
2467
2468 /* Modify. */
2469 uWritten = uRestore;
2470 uWritten &= pReq->u.In.uArgs.Modify.fAndMask;
2471 uWritten |= pReq->u.In.uArgs.Modify.fOrMask;
2472 __try
2473 {
2474 ASMWrMsrEx(uMsr, AMD_MSR_PASSCODE, uWritten);
2475 fModifyGp = false;
2476 }
2477 __except(EXCEPTION_EXECUTE_HANDLER)
2478 {
2479 fModifyGp = true;
2480 }
2481
2482 /* Read modified value. */
2483 __try
2484 {
2485 uAfter = ASMRdMsrEx(uMsr, AMD_MSR_PASSCODE);
2486 fAfterGp = false;
2487 }
2488 __except(EXCEPTION_EXECUTE_HANDLER)
2489 {
2490 fAfterGp = true;
2491 }
2492
2493 /* Restore original value. */
2494 __try
2495 {
2496 ASMWrMsrEx(uMsr, AMD_MSR_PASSCODE, uRestore);
2497 fRestoreGp = false;
2498 }
2499 __except(EXCEPTION_EXECUTE_HANDLER)
2500 {
2501 fRestoreGp = true;
2502 }
2503
2504 /* Invalid everything we can. */
2505 if (!fFaster)
2506 {
2507 ASMWriteBackAndInvalidateCaches();
2508 ASMReloadCR3();
2509 ASMNopPause();
2510 }
2511 }
2512
2513 ASMCompilerBarrier(); /* paranoia */
2514 ASMSetFlags(fOldFlags);
2515
2516 /*
2517 * Write out the results.
2518 */
2519 pReq->u.Out.uResults.Modify.uBefore = uBefore;
2520 pReq->u.Out.uResults.Modify.uWritten = uWritten;
2521 pReq->u.Out.uResults.Modify.uAfter = uAfter;
2522 pReq->u.Out.uResults.Modify.fBeforeGp = fBeforeGp;
2523 pReq->u.Out.uResults.Modify.fModifyGp = fModifyGp;
2524 pReq->u.Out.uResults.Modify.fAfterGp = fAfterGp;
2525 pReq->u.Out.uResults.Modify.fRestoreGp = fRestoreGp;
2526 RT_ZERO(pReq->u.Out.uResults.Modify.afReserved);
2527}
2528
2529
2530int VBOXCALL supdrvOSMsrProberModify(RTCPUID idCpu, PSUPMSRPROBER pReq)
2531{
2532 if (idCpu == NIL_RTCPUID)
2533 {
2534 supdrvNtMsProberModifyOnCpu(idCpu, pReq, NULL);
2535 return VINF_SUCCESS;
2536 }
2537 return RTMpOnSpecific(idCpu, supdrvNtMsProberModifyOnCpu, pReq, NULL);
2538}
2539
2540#endif /* SUPDRV_WITH_MSR_PROBER */
2541
2542
2543/**
2544 * Converts an IPRT error code to an nt status code.
2545 *
2546 * @returns corresponding nt status code.
2547 * @param rc IPRT error status code.
2548 */
2549static NTSTATUS VBoxDrvNtErr2NtStatus(int rc)
2550{
2551 switch (rc)
2552 {
2553 case VINF_SUCCESS: return STATUS_SUCCESS;
2554 case VERR_GENERAL_FAILURE: return STATUS_NOT_SUPPORTED;
2555 case VERR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER;
2556 case VERR_INVALID_MAGIC: return STATUS_UNKNOWN_REVISION;
2557 case VERR_INVALID_HANDLE: return STATUS_INVALID_HANDLE;
2558 case VERR_INVALID_POINTER: return STATUS_INVALID_ADDRESS;
2559 case VERR_LOCK_FAILED: return STATUS_NOT_LOCKED;
2560 case VERR_ALREADY_LOADED: return STATUS_IMAGE_ALREADY_LOADED;
2561 case VERR_PERMISSION_DENIED: return STATUS_ACCESS_DENIED;
2562 case VERR_VERSION_MISMATCH: return STATUS_REVISION_MISMATCH;
2563 }
2564
2565 if (rc < 0)
2566 {
2567 if (((uint32_t)rc & UINT32_C(0xffff0000)) == UINT32_C(0xffff0000))
2568 return (NTSTATUS)( ((uint32_t)rc & UINT32_C(0xffff)) | SUP_NT_STATUS_BASE );
2569 }
2570 return STATUS_UNSUCCESSFUL;
2571}
2572
2573
2574/**
2575 * Alternative version of SUPR0Printf for Windows.
2576 *
2577 * @returns 0.
2578 * @param pszFormat The format string.
2579 */
2580SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...)
2581{
2582 va_list va;
2583 char szMsg[384];
2584
2585 va_start(va, pszFormat);
2586 size_t cch = RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
2587 szMsg[sizeof(szMsg) - 1] = '\0';
2588 va_end(va);
2589
2590 RTLogWriteDebugger(szMsg, cch);
2591 return 0;
2592}
2593
2594
2595SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void)
2596{
2597 return 0;
2598}
2599
2600
2601SUPR0DECL(int) SUPR0IoCtlSetupForHandle(PSUPDRVSESSION pSession, intptr_t hHandle, uint32_t fFlags, PSUPR0IOCTLCTX *ppCtx)
2602{
2603 /*
2604 * Validate input.
2605 */
2606 AssertPtrReturn(ppCtx, VERR_INVALID_POINTER);
2607 *ppCtx = NULL;
2608 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
2609 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
2610
2611 /*
2612 * Turn the partition handle into a file object and related device object
2613 * so that we can issue direct I/O control calls to the pair later.
2614 */
2615 PFILE_OBJECT pFileObject = NULL;
2616 OBJECT_HANDLE_INFORMATION HandleInfo = { 0, 0 };
2617 NTSTATUS rcNt = ObReferenceObjectByHandle((HANDLE)hHandle, /*FILE_WRITE_DATA*/0, *IoFileObjectType,
2618 UserMode, (void **)&pFileObject, &HandleInfo);
2619 if (!NT_SUCCESS(rcNt))
2620 return RTErrConvertFromNtStatus(rcNt);
2621 AssertPtrReturn(pFileObject, VERR_INTERNAL_ERROR_3);
2622
2623 PDEVICE_OBJECT pDevObject = IoGetRelatedDeviceObject(pFileObject);
2624 AssertMsgReturnStmt(RT_VALID_PTR(pDevObject), ("pDevObject=%p\n", pDevObject),
2625 ObDereferenceObject(pFileObject), VERR_INTERNAL_ERROR_2);
2626
2627 /*
2628 * Allocate a context structure and fill it in.
2629 */
2630 PSUPR0IOCTLCTX pCtx = (PSUPR0IOCTLCTX)RTMemAllocZ(sizeof(*pCtx));
2631 if (pCtx)
2632 {
2633 pCtx->u32Magic = SUPR0IOCTLCTX_MAGIC;
2634 pCtx->cRefs = 1;
2635 pCtx->pFileObject = pFileObject;
2636 pCtx->pDeviceObject = pDevObject;
2637
2638 PDRIVER_OBJECT pDrvObject = pDevObject->DriverObject;
2639 if ( RT_VALID_PTR(pDrvObject->FastIoDispatch)
2640 && RT_VALID_PTR(pDrvObject->FastIoDispatch->FastIoDeviceControl))
2641 pCtx->pfnFastIoDeviceControl = pDrvObject->FastIoDispatch->FastIoDeviceControl;
2642 else
2643 pCtx->pfnFastIoDeviceControl = NULL;
2644 *ppCtx = pCtx;
2645 return VINF_SUCCESS;
2646 }
2647
2648 ObDereferenceObject(pFileObject);
2649 return VERR_NO_MEMORY;
2650}
2651
2652
2653/**
2654 * I/O control destructor for NT.
2655 *
2656 * @param pCtx The context to destroy.
2657 */
2658static void supdrvNtIoCtlContextDestroy(PSUPR0IOCTLCTX pCtx)
2659{
2660 PFILE_OBJECT pFileObject = pCtx->pFileObject;
2661 pCtx->pfnFastIoDeviceControl = NULL;
2662 pCtx->pFileObject = NULL;
2663 pCtx->pDeviceObject = NULL;
2664 ASMAtomicWriteU32(&pCtx->u32Magic, ~SUPR0IOCTLCTX_MAGIC);
2665
2666 if (RT_VALID_PTR(pFileObject))
2667 ObDereferenceObject(pFileObject);
2668 RTMemFree(pCtx);
2669}
2670
2671
2672SUPR0DECL(int) SUPR0IoCtlCleanup(PSUPR0IOCTLCTX pCtx)
2673{
2674 if (pCtx != NULL)
2675 {
2676 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
2677 AssertReturn(pCtx->u32Magic == SUPR0IOCTLCTX_MAGIC, VERR_INVALID_PARAMETER);
2678
2679 uint32_t cRefs = ASMAtomicDecU32(&pCtx->cRefs);
2680 Assert(cRefs < _4K);
2681 if (cRefs == 0)
2682 supdrvNtIoCtlContextDestroy(pCtx);
2683 }
2684 return VINF_SUCCESS;
2685}
2686
2687
2688SUPR0DECL(int) SUPR0IoCtlPerform(PSUPR0IOCTLCTX pCtx, uintptr_t uFunction,
2689 void *pvInput, RTR3PTR pvInputUser, size_t cbInput,
2690 void *pvOutput, RTR3PTR pvOutputUser, size_t cbOutput,
2691 int32_t *piNativeRc)
2692{
2693 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
2694 AssertReturn(pCtx->u32Magic == SUPR0IOCTLCTX_MAGIC, VERR_INVALID_PARAMETER);
2695
2696 /* Reference the context. */
2697 uint32_t cRefs = ASMAtomicIncU32(&pCtx->cRefs);
2698 Assert(cRefs > 1 && cRefs < _4K);
2699
2700 /*
2701 * Try fast I/O control path first.
2702 */
2703 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
2704 if (pCtx->pfnFastIoDeviceControl)
2705 {
2706 /* Must pass user addresses here as that's what's being expected. */
2707 BOOLEAN fHandled = pCtx->pfnFastIoDeviceControl(pCtx->pFileObject,
2708 TRUE /*Wait*/,
2709 (void *)pvInputUser, (ULONG)cbInput,
2710 (void *)pvOutputUser, (ULONG)cbOutput,
2711 uFunction,
2712 &Ios,
2713 pCtx->pDeviceObject);
2714 if (fHandled)
2715 {
2716 /* Relase the context. */
2717 cRefs = ASMAtomicDecU32(&pCtx->cRefs);
2718 Assert(cRefs < _4K);
2719 if (cRefs == 0)
2720 supdrvNtIoCtlContextDestroy(pCtx);
2721
2722 /* Set/convert status and return. */
2723 if (piNativeRc)
2724 {
2725 *piNativeRc = Ios.Status;
2726 return VINF_SUCCESS;
2727 }
2728 if (NT_SUCCESS(Ios.Status))
2729 return VINF_SUCCESS;
2730 return RTErrConvertFromNtStatus(Ios.Status);
2731 }
2732
2733 /*
2734 * Fall back on IRP if not handled.
2735 *
2736 * Note! Perhaps we should rather fail, because VID.SYS will crash getting
2737 * the partition ID with the code below. It tries to zero the output
2738 * buffer as if it were as system buffer...
2739 */
2740 RTNT_IO_STATUS_BLOCK_REINIT(&Ios);
2741 }
2742
2743 /*
2744 * For directly accessed buffers we must supply user mode addresses or
2745 * we'll fail ProbeForWrite validation.
2746 */
2747 switch (uFunction & 3)
2748 {
2749 case METHOD_BUFFERED:
2750 /* For buffered accesses, we can supply kernel buffers. */
2751 break;
2752
2753 case METHOD_IN_DIRECT:
2754 pvInput = (void *)pvInputUser;
2755 break;
2756
2757 case METHOD_NEITHER:
2758 pvInput = (void *)pvInputUser;
2759 RT_FALL_THRU();
2760
2761 case METHOD_OUT_DIRECT:
2762 pvOutput = (void *)pvOutputUser;
2763 break;
2764 }
2765
2766 /*
2767 * Build the request.
2768 */
2769 int rc;
2770 KEVENT Event;
2771 KeInitializeEvent(&Event, NotificationEvent, FALSE);
2772
2773 PIRP pIrp = IoBuildDeviceIoControlRequest(uFunction, pCtx->pDeviceObject,
2774 pvInput, (ULONG)cbInput, pvOutput, (ULONG)cbOutput,
2775 FALSE /* InternalDeviceControl */, &Event, &Ios);
2776 if (pIrp)
2777 {
2778 IoGetNextIrpStackLocation(pIrp)->FileObject = pCtx->pFileObject;
2779
2780 /*
2781 * Make the call.
2782 */
2783 NTSTATUS rcNt = IoCallDriver(pCtx->pDeviceObject, pIrp);
2784 if (rcNt == STATUS_PENDING)
2785 {
2786 rcNt = KeWaitForSingleObject(&Event, /* Object */
2787 Executive, /* WaitReason */
2788 KernelMode, /* WaitMode */
2789 FALSE, /* Alertable */
2790 NULL); /* TimeOut */
2791 AssertMsg(rcNt == STATUS_SUCCESS, ("rcNt=%#x\n", rcNt));
2792 rcNt = Ios.Status;
2793 }
2794 else if (NT_SUCCESS(rcNt) && Ios.Status != STATUS_SUCCESS)
2795 rcNt = Ios.Status;
2796
2797 /* Set/convert return code. */
2798 if (piNativeRc)
2799 {
2800 *piNativeRc = rcNt;
2801 rc = VINF_SUCCESS;
2802 }
2803 else if (NT_SUCCESS(rcNt))
2804 rc = VINF_SUCCESS;
2805 else
2806 rc = RTErrConvertFromNtStatus(rcNt);
2807 }
2808 else
2809 {
2810 if (piNativeRc)
2811 *piNativeRc = STATUS_NO_MEMORY;
2812 rc = VERR_NO_MEMORY;
2813 }
2814
2815 /* Relase the context. */
2816 cRefs = ASMAtomicDecU32(&pCtx->cRefs);
2817 Assert(cRefs < _4K);
2818 if (cRefs == 0)
2819 supdrvNtIoCtlContextDestroy(pCtx);
2820
2821 return rc;
2822}
2823
2824
2825#ifdef VBOX_WITH_HARDENING
2826
2827/** @name Identifying Special Processes: CSRSS.EXE
2828 * @{ */
2829
2830
2831/**
2832 * Checks if the process is a system32 process by the given name.
2833 *
2834 * @returns true / false.
2835 * @param pProcess The process to check.
2836 * @param pszName The lower case process name (no path!).
2837 */
2838static bool supdrvNtProtectIsSystem32ProcessMatch(PEPROCESS pProcess, const char *pszName)
2839{
2840 Assert(strlen(pszName) < 16); /* see buffer below */
2841
2842 /*
2843 * This test works on XP+.
2844 */
2845 const char *pszImageFile = (const char *)PsGetProcessImageFileName(pProcess);
2846 if (!pszImageFile)
2847 return false;
2848
2849 if (RTStrICmp(pszImageFile, pszName) != 0)
2850 return false;
2851
2852 /*
2853 * This test requires a Vista+ API.
2854 */
2855 if (g_pfnPsReferenceProcessFilePointer)
2856 {
2857 PFILE_OBJECT pFile = NULL;
2858 NTSTATUS rcNt = g_pfnPsReferenceProcessFilePointer(pProcess, &pFile);
2859 if (!NT_SUCCESS(rcNt))
2860 return false;
2861
2862 union
2863 {
2864 OBJECT_NAME_INFORMATION Info;
2865 uint8_t abBuffer[sizeof(g_System32NtPath) + 16 * sizeof(WCHAR)];
2866 } Buf;
2867 ULONG cbIgn;
2868 rcNt = ObQueryNameString(pFile, &Buf.Info, sizeof(Buf) - sizeof(WCHAR), &cbIgn);
2869 ObDereferenceObject(pFile);
2870 if (!NT_SUCCESS(rcNt))
2871 return false;
2872
2873 /* Terminate the name. */
2874 PRTUTF16 pwszName = Buf.Info.Name.Buffer;
2875 pwszName[Buf.Info.Name.Length / sizeof(RTUTF16)] = '\0';
2876
2877 /* Match the name against the system32 directory path. */
2878 uint32_t cbSystem32 = g_System32NtPath.UniStr.Length;
2879 if (Buf.Info.Name.Length < cbSystem32)
2880 return false;
2881 if (memcmp(pwszName, g_System32NtPath.UniStr.Buffer, cbSystem32))
2882 return false;
2883 pwszName += cbSystem32 / sizeof(RTUTF16);
2884 if (*pwszName++ != '\\')
2885 return false;
2886
2887 /* Compare the name. */
2888 const char *pszRight = pszName;
2889 for (;;)
2890 {
2891 WCHAR wchLeft = *pwszName++;
2892 char chRight = *pszRight++;
2893 Assert(chRight == RT_C_TO_LOWER(chRight));
2894
2895 if ( wchLeft != chRight
2896 && RT_C_TO_LOWER(wchLeft) != chRight)
2897 return false;
2898 if (!chRight)
2899 break;
2900 }
2901 }
2902
2903 return true;
2904}
2905
2906
2907/**
2908 * Checks if the current process is likely to be CSRSS.
2909 *
2910 * @returns true/false.
2911 * @param pProcess The process.
2912 */
2913static bool supdrvNtProtectIsCsrssByProcess(PEPROCESS pProcess)
2914{
2915 /*
2916 * On Windows 8.1 CSRSS.EXE is a protected process.
2917 */
2918 if (g_pfnPsIsProtectedProcessLight)
2919 {
2920 if (!g_pfnPsIsProtectedProcessLight(pProcess))
2921 return false;
2922 }
2923
2924 /*
2925 * The name tests.
2926 */
2927 if (!supdrvNtProtectIsSystem32ProcessMatch(pProcess, "csrss.exe"))
2928 return false;
2929
2930 /** @todo Could extend the CSRSS.EXE check with that the TokenUser of the
2931 * current process must be "NT AUTHORITY\SYSTEM" (S-1-5-18). */
2932
2933 return true;
2934}
2935
2936
2937/**
2938 * Helper for supdrvNtProtectGetAlpcPortObjectType that tries out a name.
2939 *
2940 * @returns true if done, false if not.
2941 * @param pwszPortNm The port path.
2942 * @param ppObjType The object type return variable, updated when
2943 * returning true.
2944 */
2945static bool supdrvNtProtectGetAlpcPortObjectType2(PCRTUTF16 pwszPortNm, POBJECT_TYPE *ppObjType)
2946{
2947 bool fDone = false;
2948
2949 UNICODE_STRING UniStrPortNm;
2950 UniStrPortNm.Buffer = (WCHAR *)pwszPortNm;
2951 UniStrPortNm.Length = (USHORT)(RTUtf16Len(pwszPortNm) * sizeof(WCHAR));
2952 UniStrPortNm.MaximumLength = UniStrPortNm.Length + sizeof(WCHAR);
2953
2954 OBJECT_ATTRIBUTES ObjAttr;
2955 InitializeObjectAttributes(&ObjAttr, &UniStrPortNm, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
2956
2957 HANDLE hPort;
2958 NTSTATUS rcNt = g_pfnZwAlpcCreatePort(&hPort, &ObjAttr, NULL /*pPortAttribs*/);
2959 if (NT_SUCCESS(rcNt))
2960 {
2961 PVOID pvObject;
2962 rcNt = ObReferenceObjectByHandle(hPort, 0 /*DesiredAccess*/, NULL /*pObjectType*/,
2963 KernelMode, &pvObject, NULL /*pHandleInfo*/);
2964 if (NT_SUCCESS(rcNt))
2965 {
2966 POBJECT_TYPE pObjType = g_pfnObGetObjectType(pvObject);
2967 if (pObjType)
2968 {
2969 SUPR0Printf("vboxdrv: ALPC Port Object Type %p (vs %p)\n", pObjType, *ppObjType);
2970 *ppObjType = pObjType;
2971 fDone = true;
2972 }
2973 ObDereferenceObject(pvObject);
2974 }
2975 NtClose(hPort);
2976 }
2977 return fDone;
2978}
2979
2980
2981/**
2982 * Attempts to retrieve the ALPC Port object type.
2983 *
2984 * We've had at least three reports that using LpcPortObjectType when trying to
2985 * get at the ApiPort object results in STATUS_OBJECT_TYPE_MISMATCH errors.
2986 * It's not known who has modified LpcPortObjectType or AlpcPortObjectType (not
2987 * exported) so that it differs from the actual ApiPort type, or maybe this
2988 * unknown entity is intercepting our attempt to reference the port and
2989 * tries to mislead us. The paranoid explanataion is of course that some evil
2990 * root kit like software is messing with the OS, however, it's possible that
2991 * this is valid kernel behavior that 99.8% of our users and 100% of the
2992 * developers are not triggering for some reason.
2993 *
2994 * The code here creates an ALPC port object and gets it's type. It will cache
2995 * the result in g_pAlpcPortObjectType2 on success.
2996 *
2997 * @returns Object type.
2998 * @param uSessionId The session id.
2999 * @param pszSessionId The session id formatted as a string.
3000 */
3001static POBJECT_TYPE supdrvNtProtectGetAlpcPortObjectType(uint32_t uSessionId, const char *pszSessionId)
3002{
3003 POBJECT_TYPE pObjType = *LpcPortObjectType;
3004
3005 if ( g_pfnZwAlpcCreatePort
3006 && g_pfnObGetObjectType)
3007 {
3008 int rc;
3009 ssize_t cchTmp; NOREF(cchTmp);
3010 char szTmp[16];
3011 RTUTF16 wszPortNm[128];
3012 size_t offRand;
3013
3014 /*
3015 * First attempt is in the session directory.
3016 */
3017 rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\Sessions\\");
3018 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), pszSessionId);
3019 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\VBoxDrv-");
3020 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), (uint32_t)(uintptr_t)PsGetProcessId(PsGetCurrentProcess()), 16, 0, 0, 0);
3021 Assert(cchTmp > 0);
3022 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3023 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "-");
3024 offRand = RTUtf16Len(wszPortNm);
3025 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
3026 Assert(cchTmp > 0);
3027 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3028 AssertRCSuccess(rc);
3029
3030 bool fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
3031 if (!fDone)
3032 {
3033 wszPortNm[offRand] = '\0';
3034 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0); Assert(cchTmp > 0);
3035 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3036 AssertRCSuccess(rc);
3037
3038 fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
3039 }
3040 if (!fDone)
3041 {
3042 /*
3043 * Try base names.
3044 */
3045 if (uSessionId == 0)
3046 rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\BaseNamedObjects\\VBoxDrv-");
3047 else
3048 {
3049 rc = RTUtf16CopyAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\Sessions\\");
3050 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), pszSessionId);
3051 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "\\BaseNamedObjects\\VBoxDrv-");
3052 }
3053 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), (uint32_t)(uintptr_t)PsGetProcessId(PsGetCurrentProcess()), 16, 0, 0, 0);
3054 Assert(cchTmp > 0);
3055 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3056 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), "-");
3057 offRand = RTUtf16Len(wszPortNm);
3058 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
3059 Assert(cchTmp > 0);
3060 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3061 AssertRCSuccess(rc);
3062
3063 bool fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
3064 if (!fDone)
3065 {
3066 wszPortNm[offRand] = '\0';
3067 cchTmp = RTStrFormatU32(szTmp, sizeof(szTmp), RTRandU32(), 16, 0, 0, 0);
3068 Assert(cchTmp > 0);
3069 rc |= RTUtf16CatAscii(wszPortNm, RT_ELEMENTS(wszPortNm), szTmp);
3070 AssertRCSuccess(rc);
3071
3072 fDone = supdrvNtProtectGetAlpcPortObjectType2(wszPortNm, &pObjType);
3073 }
3074 }
3075
3076 /* Cache the result in g_pAlpcPortObjectType2. */
3077 if ( g_pAlpcPortObjectType2 == NULL
3078 && pObjType != g_pAlpcPortObjectType1
3079 && fDone)
3080 g_pAlpcPortObjectType2 = pObjType;
3081
3082 }
3083
3084 return pObjType;
3085}
3086
3087
3088/**
3089 * Called in the context of VBoxDrvNtCreate to determin the CSRSS for the
3090 * current process.
3091 *
3092 * The Client/Server Runtime Subsystem (CSRSS) process needs to be allowed some
3093 * additional access right so we need to make 101% sure we correctly identify
3094 * the CSRSS process a process is associated with.
3095 *
3096 * @returns IPRT status code.
3097 * @param pNtProtect The NT protected process structure. The
3098 * hCsrssPid member will be updated on success.
3099 */
3100static int supdrvNtProtectFindAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect)
3101{
3102 Assert(pNtProtect->AvlCore.Key == PsGetCurrentProcessId());
3103 Assert(pNtProtect->pCsrssProcess == NULL);
3104 Assert(pNtProtect->hCsrssPid == NULL);
3105
3106 /*
3107 * We'll try use the ApiPort LPC object for the session we're in to track
3108 * down the CSRSS process. So, we start by constructing a path to it.
3109 */
3110 int rc;
3111 uint32_t uSessionId = PsGetProcessSessionId(PsGetCurrentProcess());
3112 char szSessionId[16];
3113 WCHAR wszApiPort[48];
3114 if (uSessionId == 0)
3115 {
3116 szSessionId[0] = '0';
3117 szSessionId[1] = '\0';
3118 rc = RTUtf16CopyAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Windows\\ApiPort");
3119 }
3120 else
3121 {
3122 ssize_t cchTmp = RTStrFormatU32(szSessionId, sizeof(szSessionId), uSessionId, 10, 0, 0, 0);
3123 AssertReturn(cchTmp > 0, (int)cchTmp);
3124 rc = RTUtf16CopyAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Sessions\\");
3125 if (RT_SUCCESS(rc))
3126 rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), szSessionId);
3127 if (RT_SUCCESS(rc))
3128 rc = RTUtf16CatAscii(wszApiPort, RT_ELEMENTS(wszApiPort), "\\Windows\\ApiPort");
3129 }
3130 AssertRCReturn(rc, rc);
3131
3132 UNICODE_STRING ApiPortStr;
3133 ApiPortStr.Buffer = wszApiPort;
3134 ApiPortStr.Length = (USHORT)(RTUtf16Len(wszApiPort) * sizeof(RTUTF16));
3135 ApiPortStr.MaximumLength = ApiPortStr.Length + sizeof(RTUTF16);
3136
3137 /*
3138 * The object cannot be opened, but we can reference it by name.
3139 */
3140 void *pvApiPortObj = NULL;
3141 NTSTATUS rcNt = ObReferenceObjectByName(&ApiPortStr,
3142 0,
3143 NULL /*pAccessState*/,
3144 STANDARD_RIGHTS_READ,
3145 g_pAlpcPortObjectType1,
3146 KernelMode,
3147 NULL /*pvParseContext*/,
3148 &pvApiPortObj);
3149 if ( rcNt == STATUS_OBJECT_TYPE_MISMATCH
3150 && g_pAlpcPortObjectType2 != NULL)
3151 rcNt = ObReferenceObjectByName(&ApiPortStr,
3152 0,
3153 NULL /*pAccessState*/,
3154 STANDARD_RIGHTS_READ,
3155 g_pAlpcPortObjectType2,
3156 KernelMode,
3157 NULL /*pvParseContext*/,
3158 &pvApiPortObj);
3159 if ( rcNt == STATUS_OBJECT_TYPE_MISMATCH
3160 && g_pfnObGetObjectType
3161 && g_pfnZwAlpcCreatePort)
3162 rcNt = ObReferenceObjectByName(&ApiPortStr,
3163 0,
3164 NULL /*pAccessState*/,
3165 STANDARD_RIGHTS_READ,
3166 supdrvNtProtectGetAlpcPortObjectType(uSessionId, szSessionId),
3167 KernelMode,
3168 NULL /*pvParseContext*/,
3169 &pvApiPortObj);
3170 if (!NT_SUCCESS(rcNt))
3171 {
3172 SUPR0Printf("vboxdrv: Error opening '%ls': %#x\n", wszApiPort, rcNt);
3173 return rcNt == STATUS_OBJECT_TYPE_MISMATCH ? VERR_SUPDRV_APIPORT_OPEN_ERROR_TYPE : VERR_SUPDRV_APIPORT_OPEN_ERROR;
3174 }
3175
3176 /*
3177 * Query the processes in the system so we can locate CSRSS.EXE candidates.
3178 * Note! Attempts at using SystemSessionProcessInformation failed with
3179 * STATUS_ACCESS_VIOLATION.
3180 * Note! The 32 bytes on the size of to counteract the allocation header
3181 * that rtR0MemAllocEx slaps on everything.
3182 */
3183 ULONG cbNeeded = _64K - 32;
3184 uint32_t cbBuf;
3185 uint8_t *pbBuf = NULL;
3186 do
3187 {
3188 cbBuf = RT_ALIGN(cbNeeded + _4K, _64K) - 32;
3189 pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
3190 if (!pbBuf)
3191 break;
3192
3193 cbNeeded = 0;
3194#if 0 /* doesn't work. */
3195 SYSTEM_SESSION_PROCESS_INFORMATION Req;
3196 Req.SessionId = uSessionId;
3197 Req.BufferLength = cbBuf;
3198 Req.Buffer = pbBuf;
3199 rcNt = NtQuerySystemInformation(SystemSessionProcessInformation, &Req, sizeof(Req), &cbNeeded);
3200#else
3201 rcNt = NtQuerySystemInformation(SystemProcessInformation, pbBuf, cbBuf, &cbNeeded);
3202#endif
3203 if (NT_SUCCESS(rcNt))
3204 break;
3205
3206 RTMemFree(pbBuf);
3207 pbBuf = NULL;
3208 } while ( rcNt == STATUS_INFO_LENGTH_MISMATCH
3209 && cbNeeded > cbBuf
3210 && cbNeeded < 32U*_1M);
3211
3212 if ( pbBuf
3213 && NT_SUCCESS(rcNt)
3214 && cbNeeded >= sizeof(SYSTEM_PROCESS_INFORMATION))
3215 {
3216 /*
3217 * Walk the returned data and look for the process associated with the
3218 * ApiPort object. The ApiPort object keeps the EPROCESS address of
3219 * the owner process (i.e. CSRSS) relatively early in the structure. On
3220 * 64-bit windows 8.1 it's at offset 0x18. So, obtain the EPROCESS
3221 * pointer to likely CSRSS processes and check for a match in the first
3222 * 0x40 bytes of the ApiPort object.
3223 */
3224 rc = VERR_SUPDRV_CSRSS_NOT_FOUND;
3225 for (uint32_t offBuf = 0; offBuf <= cbNeeded - sizeof(SYSTEM_PROCESS_INFORMATION);)
3226 {
3227 PRTNT_SYSTEM_PROCESS_INFORMATION pProcInfo = (PRTNT_SYSTEM_PROCESS_INFORMATION)&pbBuf[offBuf];
3228 if ( pProcInfo->ProcessName.Length == 9 * sizeof(WCHAR)
3229 && pProcInfo->NumberOfThreads > 2 /* Very low guess. */
3230 && pProcInfo->HandleCount > 32 /* Very low guess, I hope. */
3231 && (uintptr_t)pProcInfo->ProcessName.Buffer - (uintptr_t)pbBuf < cbNeeded
3232 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[0]) == 'c'
3233 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[1]) == 's'
3234 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[2]) == 'r'
3235 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[3]) == 's'
3236 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[4]) == 's'
3237 && pProcInfo->ProcessName.Buffer[5] == '.'
3238 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[6]) == 'e'
3239 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[7]) == 'x'
3240 && RT_C_TO_LOWER(pProcInfo->ProcessName.Buffer[8]) == 'e' )
3241 {
3242
3243 /* Get the process structure and perform some more thorough
3244 process checks. */
3245 PEPROCESS pProcess;
3246 rcNt = PsLookupProcessByProcessId(pProcInfo->UniqueProcessId, &pProcess);
3247 if (NT_SUCCESS(rcNt))
3248 {
3249 if (supdrvNtProtectIsCsrssByProcess(pProcess))
3250 {
3251 if (PsGetProcessSessionId(pProcess) == uSessionId)
3252 {
3253 /* Final test, check the ApiPort.
3254 Note! The old LPC (pre Vista) objects has the PID
3255 much earlier in the structure. Might be
3256 worth looking for it instead. */
3257 bool fThatsIt = false;
3258 __try
3259 {
3260 PEPROCESS *ppPortProc = (PEPROCESS *)pvApiPortObj;
3261 uint32_t cTests = g_uNtVerCombined >= SUP_NT_VER_VISTA ? 16 : 38; /* ALPC since Vista. */
3262 do
3263 {
3264 fThatsIt = *ppPortProc == pProcess;
3265 ppPortProc++;
3266 } while (!fThatsIt && --cTests > 0);
3267 }
3268 __except(EXCEPTION_EXECUTE_HANDLER)
3269 {
3270 fThatsIt = false;
3271 }
3272 if (fThatsIt)
3273 {
3274 /* Ok, we found it! Keep the process structure
3275 reference as well as the PID so we can
3276 safely identify it later on. */
3277 pNtProtect->hCsrssPid = pProcInfo->UniqueProcessId;
3278 pNtProtect->pCsrssProcess = pProcess;
3279 rc = VINF_SUCCESS;
3280 break;
3281 }
3282 }
3283 }
3284
3285 ObDereferenceObject(pProcess);
3286 }
3287 }
3288
3289 /* Advance. */
3290 if (!pProcInfo->NextEntryOffset)
3291 break;
3292 offBuf += pProcInfo->NextEntryOffset;
3293 }
3294 }
3295 else
3296 rc = VERR_SUPDRV_SESSION_PROCESS_ENUM_ERROR;
3297 RTMemFree(pbBuf);
3298 ObDereferenceObject(pvApiPortObj);
3299 return rc;
3300}
3301
3302
3303/**
3304 * Checks that the given process is the CSRSS process associated with protected
3305 * process.
3306 *
3307 * @returns true / false.
3308 * @param pNtProtect The NT protection structure.
3309 * @param pCsrss The process structure of the alleged CSRSS.EXE
3310 * process.
3311 */
3312static bool supdrvNtProtectIsAssociatedCsrss(PSUPDRVNTPROTECT pNtProtect, PEPROCESS pCsrss)
3313{
3314 if (pNtProtect->pCsrssProcess == pCsrss)
3315 {
3316 if (pNtProtect->hCsrssPid == PsGetProcessId(pCsrss))
3317 {
3318 return true;
3319 }
3320 }
3321 return false;
3322}
3323
3324
3325/**
3326 * Checks if the given process is the stupid themes service.
3327 *
3328 * The caller does some screening of access masks and what not. We do the rest.
3329 *
3330 * @returns true / false.
3331 * @param pNtProtect The NT protection structure.
3332 * @param pAnnoyingProcess The process structure of an process that might
3333 * happen to be the annoying themes process.
3334 */
3335static bool supdrvNtProtectIsFrigginThemesService(PSUPDRVNTPROTECT pNtProtect, PEPROCESS pAnnoyingProcess)
3336{
3337 RT_NOREF1(pNtProtect);
3338
3339 /*
3340 * Check the process name.
3341 */
3342 if (!supdrvNtProtectIsSystem32ProcessMatch(pAnnoyingProcess, "svchost.exe"))
3343 return false;
3344
3345 /** @todo Come up with more checks. */
3346
3347 return true;
3348}
3349
3350
3351#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
3352/**
3353 * Checks if the given process is one of the whitelisted debuggers.
3354 *
3355 * @returns true / false.
3356 * @param pProcess The process to check.
3357 */
3358static bool supdrvNtProtectIsWhitelistedDebugger(PEPROCESS pProcess)
3359{
3360 const char *pszImageFile = (const char *)PsGetProcessImageFileName(pProcess);
3361 if (!pszImageFile)
3362 return false;
3363
3364 if (pszImageFile[0] == 'w' || pszImageFile[0] == 'W')
3365 {
3366 if (RTStrICmp(pszImageFile, "windbg.exe") == 0)
3367 return true;
3368 if (RTStrICmp(pszImageFile, "werfault.exe") == 0)
3369 return true;
3370 if (RTStrICmp(pszImageFile, "werfaultsecure.exe") == 0)
3371 return true;
3372 }
3373 else if (pszImageFile[0] == 'd' || pszImageFile[0] == 'D')
3374 {
3375 if (RTStrICmp(pszImageFile, "drwtsn32.exe") == 0)
3376 return true;
3377 if (RTStrICmp(pszImageFile, "dwwin.exe") == 0)
3378 return true;
3379 }
3380
3381 return false;
3382}
3383#endif /* VBOX_WITHOUT_DEBUGGER_CHECKS */
3384
3385
3386/** @} */
3387
3388
3389/** @name Process Creation Callbacks.
3390 * @{ */
3391
3392
3393/**
3394 * Cleans up VBoxDrv or VBoxDrvStub error info not collected by the dead process.
3395 *
3396 * @param hProcessId The ID of the dead process.
3397 */
3398static void supdrvNtErrorInfoCleanupProcess(HANDLE hProcessId)
3399{
3400 int rc = RTSemMutexRequestNoResume(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
3401 if (RT_SUCCESS(rc))
3402 {
3403 PSUPDRVNTERRORINFO pCur, pNext;
3404 RTListForEachSafe(&g_ErrorInfoHead, pCur, pNext, SUPDRVNTERRORINFO, ListEntry)
3405 {
3406 if (pCur->hProcessId == hProcessId)
3407 {
3408 RTListNodeRemove(&pCur->ListEntry);
3409 RTMemFree(pCur);
3410 }
3411 }
3412 RTSemMutexRelease(g_hErrorInfoLock);
3413 }
3414}
3415
3416
3417/**
3418 * Common worker used by the process creation hooks as well as the process
3419 * handle creation hooks to check if a VM process is being created.
3420 *
3421 * @returns true if likely to be a VM process, false if not.
3422 * @param pNtStub The NT protection structure for the possible
3423 * stub process.
3424 * @param hParentPid The parent pid.
3425 * @param hChildPid The child pid.
3426 */
3427static bool supdrvNtProtectIsSpawningStubProcess(PSUPDRVNTPROTECT pNtStub, HANDLE hParentPid, HANDLE hChildPid)
3428{
3429 bool fRc = false;
3430 if (pNtStub->AvlCore.Key == hParentPid) /* paranoia */
3431 {
3432 if (pNtStub->enmProcessKind == kSupDrvNtProtectKind_StubSpawning)
3433 {
3434 /* Compare short names. */
3435 PEPROCESS pStubProcess;
3436 NTSTATUS rcNt = PsLookupProcessByProcessId(hParentPid, &pStubProcess);
3437 if (NT_SUCCESS(rcNt))
3438 {
3439 PEPROCESS pChildProcess;
3440 rcNt = PsLookupProcessByProcessId(hChildPid, &pChildProcess);
3441 if (NT_SUCCESS(rcNt))
3442 {
3443 const char *pszStub = (const char *)PsGetProcessImageFileName(pStubProcess);
3444 const char *pszChild = (const char *)PsGetProcessImageFileName(pChildProcess);
3445 fRc = pszStub != NULL
3446 && pszChild != NULL
3447 && strcmp(pszStub, pszChild) == 0;
3448
3449 /** @todo check that the full image names matches. */
3450
3451 ObDereferenceObject(pChildProcess);
3452 }
3453 ObDereferenceObject(pStubProcess);
3454 }
3455 }
3456 }
3457 return fRc;
3458}
3459
3460
3461/**
3462 * Common code used by the notifies to protect a child process.
3463 *
3464 * @returns VBox status code.
3465 * @param pNtStub The NT protect structure for the parent.
3466 * @param hChildPid The child pid.
3467 */
3468static int supdrvNtProtectProtectNewStubChild(PSUPDRVNTPROTECT pNtParent, HANDLE hChildPid)
3469{
3470 /*
3471 * Create a child protection struction.
3472 */
3473 PSUPDRVNTPROTECT pNtChild;
3474 int rc = supdrvNtProtectCreate(&pNtChild, hChildPid, kSupDrvNtProtectKind_VmProcessUnconfirmed, false /*fLink*/);
3475 if (RT_SUCCESS(rc))
3476 {
3477 pNtChild->fFirstProcessCreateHandle = true;
3478 pNtChild->fFirstThreadCreateHandle = true;
3479 pNtChild->fCsrssFirstProcessCreateHandle = true;
3480 pNtChild->cCsrssFirstProcessDuplicateHandle = ARCH_BITS == 32 ? 2 : 1;
3481 pNtChild->fThemesFirstProcessCreateHandle = true;
3482 pNtChild->hParentPid = pNtParent->AvlCore.Key;
3483 pNtChild->hCsrssPid = pNtParent->hCsrssPid;
3484 pNtChild->pCsrssProcess = pNtParent->pCsrssProcess;
3485 if (pNtChild->pCsrssProcess)
3486 ObReferenceObject(pNtChild->pCsrssProcess);
3487
3488 /*
3489 * Take the spinlock, recheck parent conditions and link things.
3490 */
3491 RTSpinlockAcquire(g_hNtProtectLock);
3492 if (pNtParent->enmProcessKind == kSupDrvNtProtectKind_StubSpawning)
3493 {
3494 bool fSuccess = RTAvlPVInsert(&g_NtProtectTree, &pNtChild->AvlCore);
3495 if (fSuccess)
3496 {
3497 pNtChild->fInTree = true;
3498 pNtParent->u.pChild = pNtChild; /* Parent keeps the initial reference. */
3499 pNtParent->enmProcessKind = kSupDrvNtProtectKind_StubParent;
3500 pNtChild->u.pParent = pNtParent;
3501
3502 RTSpinlockRelease(g_hNtProtectLock);
3503 return VINF_SUCCESS;
3504 }
3505
3506 rc = VERR_INTERNAL_ERROR_2;
3507 }
3508 else
3509 rc = VERR_WRONG_ORDER;
3510 pNtChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
3511 RTSpinlockRelease(g_hNtProtectLock);
3512
3513 supdrvNtProtectRelease(pNtChild);
3514 }
3515 return rc;
3516}
3517
3518
3519/**
3520 * Common process termination code.
3521 *
3522 * Transitions protected process to the dead states, protecting against handle
3523 * PID reuse (esp. with unconfirmed VM processes) and handle cleanup issues.
3524 *
3525 * @param hDeadPid The PID of the dead process.
3526 */
3527static void supdrvNtProtectUnprotectDeadProcess(HANDLE hDeadPid)
3528{
3529 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(hDeadPid);
3530 if (pNtProtect)
3531 {
3532 PSUPDRVNTPROTECT pNtChild = NULL;
3533
3534 RTSpinlockAcquire(g_hNtProtectLock);
3535
3536 /*
3537 * If this is an unconfirmed VM process, we must release the reference
3538 * the parent structure holds.
3539 */
3540 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
3541 {
3542 PSUPDRVNTPROTECT pNtParent = pNtProtect->u.pParent;
3543 AssertRelease(pNtParent); AssertRelease(pNtParent->u.pChild == pNtProtect);
3544 pNtParent->u.pChild = NULL;
3545 pNtProtect->u.pParent = NULL;
3546 pNtChild = pNtProtect;
3547 }
3548 /*
3549 * If this is a stub exitting before the VM process gets confirmed,
3550 * release the protection of the potential VM process as this is not
3551 * the prescribed behavior.
3552 */
3553 else if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent
3554 && pNtProtect->u.pChild)
3555 {
3556 pNtChild = pNtProtect->u.pChild;
3557 pNtProtect->u.pChild = NULL;
3558 pNtChild->u.pParent = NULL;
3559 pNtChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
3560 }
3561
3562 /*
3563 * Transition it to the dead state to prevent it from opening the
3564 * support driver again or be posthumously abused as a vm process parent.
3565 */
3566 if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3567 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessConfirmed)
3568 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
3569 else if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent
3570 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubSpawning
3571 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubUnverified)
3572 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_StubDead;
3573
3574 RTSpinlockRelease(g_hNtProtectLock);
3575
3576 supdrvNtProtectRelease(pNtProtect);
3577 supdrvNtProtectRelease(pNtChild);
3578
3579 /*
3580 * Do session cleanups.
3581 */
3582 AssertReturnVoid((HANDLE)(uintptr_t)RTProcSelf() == hDeadPid);
3583 if (g_pDevObjSys)
3584 {
3585 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)g_pDevObjSys->DeviceExtension;
3586 PSUPDRVSESSION pSession = supdrvSessionHashTabLookup(pDevExt, (RTPROCESS)(uintptr_t)hDeadPid,
3587 RTR0ProcHandleSelf(), NULL);
3588 if (pSession)
3589 {
3590 supdrvSessionHashTabRemove(pDevExt, pSession, NULL);
3591 supdrvSessionRelease(pSession); /* Drops the reference from supdrvSessionHashTabLookup. */
3592 }
3593 }
3594 }
3595}
3596
3597
3598/**
3599 * Common worker for the process creation callback that verifies a new child
3600 * being created by the handle creation callback code.
3601 *
3602 * @param pNtStub The parent.
3603 * @param pNtVm The child.
3604 * @param fCallerChecks The result of any additional tests the caller made.
3605 * This is in order to avoid duplicating the failure
3606 * path code.
3607 */
3608static void supdrvNtProtectVerifyNewChildProtection(PSUPDRVNTPROTECT pNtStub, PSUPDRVNTPROTECT pNtVm, bool fCallerChecks)
3609{
3610 if ( fCallerChecks
3611 && pNtStub->enmProcessKind == kSupDrvNtProtectKind_StubParent
3612 && pNtVm->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3613 && pNtVm->u.pParent == pNtStub
3614 && pNtStub->u.pChild == pNtVm)
3615 {
3616 /* Fine, reset the CSRSS hack (fixes ViRobot APT Shield 2.0 issue). */
3617 pNtVm->fFirstProcessCreateHandle = true;
3618 return;
3619 }
3620
3621 LogRel(("vboxdrv: Misdetected vm stub; hParentPid=%p hChildPid=%p\n", pNtStub->AvlCore.Key, pNtVm->AvlCore.Key));
3622 if (pNtStub->enmProcessKind != kSupDrvNtProtectKind_VmProcessConfirmed)
3623 supdrvNtProtectUnprotectDeadProcess(pNtVm->AvlCore.Key);
3624}
3625
3626
3627/**
3628 * Old style callback (since forever).
3629 *
3630 * @param hParentPid The parent PID.
3631 * @param hNewPid The PID of the new child.
3632 * @param fCreated TRUE if it's a creation notification,
3633 * FALSE if termination.
3634 * @remarks ASSUMES this arrives before the handle creation callback.
3635 */
3636static VOID __stdcall
3637supdrvNtProtectCallback_ProcessCreateNotify(HANDLE hParentPid, HANDLE hNewPid, BOOLEAN fCreated)
3638{
3639 /*
3640 * Is it a new process that needs protection?
3641 */
3642 if (fCreated)
3643 {
3644 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(hParentPid);
3645 if (pNtStub)
3646 {
3647 PSUPDRVNTPROTECT pNtVm = supdrvNtProtectLookup(hNewPid);
3648 if (!pNtVm)
3649 {
3650 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, hParentPid, hNewPid))
3651 supdrvNtProtectProtectNewStubChild(pNtStub, hNewPid);
3652 }
3653 else
3654 {
3655 supdrvNtProtectVerifyNewChildProtection(pNtStub, pNtVm, true);
3656 supdrvNtProtectRelease(pNtVm);
3657 }
3658 supdrvNtProtectRelease(pNtStub);
3659 }
3660 }
3661 /*
3662 * Process termination, do clean ups.
3663 */
3664 else
3665 {
3666 supdrvNtProtectUnprotectDeadProcess(hNewPid);
3667 supdrvNtErrorInfoCleanupProcess(hNewPid);
3668 }
3669}
3670
3671
3672/**
3673 * New style callback (Vista SP1+ / w2k8).
3674 *
3675 * @param pNewProcess The new process.
3676 * @param hNewPid The PID of the new process.
3677 * @param pInfo Process creation details. NULL if process
3678 * termination notification.
3679 * @remarks ASSUMES this arrives before the handle creation callback.
3680 */
3681static VOID __stdcall
3682supdrvNtProtectCallback_ProcessCreateNotifyEx(PEPROCESS pNewProcess, HANDLE hNewPid, PPS_CREATE_NOTIFY_INFO pInfo)
3683{
3684 RT_NOREF1(pNewProcess);
3685
3686 /*
3687 * Is it a new process that needs protection?
3688 */
3689 if (pInfo)
3690 {
3691 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(pInfo->CreatingThreadId.UniqueProcess);
3692
3693 Log(("vboxdrv/NewProcessEx: ctx=%04zx/%p pid=%04zx ppid=%04zx ctor=%04zx/%04zx rcNt=%#x %.*ls\n",
3694 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3695 hNewPid, pInfo->ParentProcessId,
3696 pInfo->CreatingThreadId.UniqueProcess, pInfo->CreatingThreadId.UniqueThread, pInfo->CreationStatus,
3697 pInfo->FileOpenNameAvailable && pInfo->ImageFileName ? (size_t)pInfo->ImageFileName->Length / 2 : 0,
3698 pInfo->FileOpenNameAvailable && pInfo->ImageFileName ? pInfo->ImageFileName->Buffer : NULL));
3699
3700 if (pNtStub)
3701 {
3702 PSUPDRVNTPROTECT pNtVm = supdrvNtProtectLookup(hNewPid);
3703 if (!pNtVm)
3704 {
3705 /* Parent must be creator. */
3706 if (pInfo->CreatingThreadId.UniqueProcess == pInfo->ParentProcessId)
3707 {
3708 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, pInfo->ParentProcessId, hNewPid))
3709 supdrvNtProtectProtectNewStubChild(pNtStub, hNewPid);
3710 }
3711 }
3712 else
3713 {
3714 /* Parent must be creator (as above). */
3715 supdrvNtProtectVerifyNewChildProtection(pNtStub, pNtVm,
3716 pInfo->CreatingThreadId.UniqueProcess == pInfo->ParentProcessId);
3717 supdrvNtProtectRelease(pNtVm);
3718 }
3719 supdrvNtProtectRelease(pNtStub);
3720 }
3721 }
3722 /*
3723 * Process termination, do clean ups.
3724 */
3725 else
3726 {
3727 supdrvNtProtectUnprotectDeadProcess(hNewPid);
3728 supdrvNtErrorInfoCleanupProcess(hNewPid);
3729 }
3730}
3731
3732/** @} */
3733
3734
3735/** @name Process Handle Callbacks.
3736 * @{ */
3737
3738/** Process rights that we allow for handles to stub and VM processes. */
3739# define SUPDRV_NT_ALLOW_PROCESS_RIGHTS \
3740 ( PROCESS_TERMINATE \
3741 | PROCESS_VM_READ \
3742 | PROCESS_QUERY_INFORMATION \
3743 | PROCESS_QUERY_LIMITED_INFORMATION \
3744 | PROCESS_SUSPEND_RESUME \
3745 | DELETE \
3746 | READ_CONTROL \
3747 | SYNCHRONIZE)
3748
3749/** Evil process rights. */
3750# define SUPDRV_NT_EVIL_PROCESS_RIGHTS \
3751 ( PROCESS_CREATE_THREAD \
3752 | PROCESS_SET_SESSIONID /*?*/ \
3753 | PROCESS_VM_OPERATION \
3754 | PROCESS_VM_WRITE \
3755 | PROCESS_DUP_HANDLE \
3756 | PROCESS_CREATE_PROCESS /*?*/ \
3757 | PROCESS_SET_QUOTA /*?*/ \
3758 | PROCESS_SET_INFORMATION \
3759 | PROCESS_SET_LIMITED_INFORMATION /*?*/ \
3760 | 0)
3761AssertCompile((SUPDRV_NT_ALLOW_PROCESS_RIGHTS & SUPDRV_NT_EVIL_PROCESS_RIGHTS) == 0);
3762
3763
3764static OB_PREOP_CALLBACK_STATUS __stdcall
3765supdrvNtProtectCallback_ProcessHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMATION pOpInfo)
3766{
3767 Assert(pvUser == NULL); RT_NOREF1(pvUser);
3768 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
3769 Assert(pOpInfo->ObjectType == *PsProcessType);
3770
3771 /*
3772 * Protected? Kludge required for NtOpenProcess calls comming in before
3773 * the create process hook triggers on Windows 8.1 (possibly others too).
3774 */
3775 HANDLE hObjPid = PsGetProcessId((PEPROCESS)pOpInfo->Object);
3776 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(hObjPid);
3777 if (!pNtProtect)
3778 {
3779 HANDLE hParentPid = PsGetProcessInheritedFromUniqueProcessId((PEPROCESS)pOpInfo->Object);
3780 PSUPDRVNTPROTECT pNtStub = supdrvNtProtectLookup(hParentPid);
3781 if (pNtStub)
3782 {
3783 if (supdrvNtProtectIsSpawningStubProcess(pNtStub, hParentPid, hObjPid))
3784 {
3785 supdrvNtProtectProtectNewStubChild(pNtStub, hObjPid);
3786 pNtProtect = supdrvNtProtectLookup(hObjPid);
3787 }
3788 supdrvNtProtectRelease(pNtStub);
3789 }
3790 }
3791 pOpInfo->CallContext = pNtProtect; /* Just for reference. */
3792 if (pNtProtect)
3793 {
3794 /*
3795 * Ok, it's a protected process. Strip rights as required or possible.
3796 */
3797 static ACCESS_MASK const s_fCsrssStupidDesires = 0x1fffff;
3798 ACCESS_MASK fAllowedRights = SUPDRV_NT_ALLOW_PROCESS_RIGHTS;
3799
3800 if (pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE)
3801 {
3802 /* Don't restrict the process accessing itself. */
3803 if ((PEPROCESS)pOpInfo->Object == PsGetCurrentProcess())
3804 {
3805 pOpInfo->CallContext = NULL; /* don't assert */
3806 pNtProtect->fFirstProcessCreateHandle = false;
3807
3808 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s\n",
3809 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3810 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3811 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3812 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3813 }
3814#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
3815 /* Allow debuggers full access. */
3816 else if (supdrvNtProtectIsWhitelistedDebugger(PsGetCurrentProcess()))
3817 {
3818 pOpInfo->CallContext = NULL; /* don't assert */
3819 pNtProtect->fFirstProcessCreateHandle = false;
3820
3821 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s [debugger]\n",
3822 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3823 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
3824 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3825 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3826 }
3827#endif
3828 else
3829 {
3830 ACCESS_MASK const fDesiredAccess = pOpInfo->Parameters->CreateHandleInformation.DesiredAccess;
3831
3832 /* Special case 1 on Vista, 7 & 8:
3833 The CreateProcess code passes the handle over to CSRSS.EXE
3834 and the code inBaseSrvCreateProcess will duplicate the
3835 handle with 0x1fffff as access mask. NtDuplicateObject will
3836 fail this call before it ever gets down here.
3837
3838 Special case 2 on 8.1:
3839 The CreateProcess code requires additional rights for
3840 something, we'll drop these in the stub code. */
3841 if ( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3842 && pNtProtect->fFirstProcessCreateHandle
3843 && pOpInfo->KernelHandle == 0
3844 && pNtProtect->hParentPid == PsGetProcessId(PsGetCurrentProcess())
3845 && ExGetPreviousMode() != KernelMode)
3846 {
3847 if ( !pOpInfo->KernelHandle
3848 && fDesiredAccess == s_fCsrssStupidDesires)
3849 {
3850 if (g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3))
3851 fAllowedRights |= s_fCsrssStupidDesires;
3852 else
3853 fAllowedRights = fAllowedRights
3854 | PROCESS_VM_OPERATION
3855 | PROCESS_VM_WRITE
3856 | PROCESS_SET_INFORMATION
3857 | PROCESS_SET_LIMITED_INFORMATION
3858 | 0;
3859 pOpInfo->CallContext = NULL; /* don't assert this. */
3860 }
3861 pNtProtect->fFirstProcessCreateHandle = false;
3862 }
3863
3864 /* Special case 3 on 8.1:
3865 The interaction between the CreateProcess code and CSRSS.EXE
3866 has changed to the better with Windows 8.1. CSRSS.EXE no
3867 longer duplicates the process (thread too) handle, but opens
3868 it, thus allowing us to do our job. */
3869 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3)
3870 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3871 && pNtProtect->fCsrssFirstProcessCreateHandle
3872 && pOpInfo->KernelHandle == 0
3873 && ExGetPreviousMode() == UserMode
3874 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
3875 {
3876 pNtProtect->fCsrssFirstProcessCreateHandle = false;
3877 if (fDesiredAccess == s_fCsrssStupidDesires)
3878 {
3879 /* Not needed: PROCESS_CREATE_THREAD, PROCESS_SET_SESSIONID,
3880 PROCESS_CREATE_PROCESS */
3881 fAllowedRights = fAllowedRights
3882 | PROCESS_VM_OPERATION
3883 | PROCESS_VM_WRITE
3884 | PROCESS_DUP_HANDLE /* Needed for CreateProcess/VBoxTestOGL. */
3885 | 0;
3886 pOpInfo->CallContext = NULL; /* don't assert this. */
3887 }
3888 }
3889
3890 /* Special case 4, Windows 7, Vista, possibly 8, but not 8.1:
3891 The Themes service requires PROCESS_DUP_HANDLE access to our
3892 process or we won't get any menus and dialogs will be half
3893 unreadable. This is _very_ unfortunate and more work will
3894 go into making this more secure. */
3895 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 0)
3896 && g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 2)
3897 && fDesiredAccess == 0x1478 /* 6.1.7600.16385 (win7_rtm.090713-1255) */
3898 && pNtProtect->fThemesFirstProcessCreateHandle
3899 && pOpInfo->KernelHandle == 0
3900 && ExGetPreviousMode() == UserMode
3901 && supdrvNtProtectIsFrigginThemesService(pNtProtect, PsGetCurrentProcess()) )
3902 {
3903 pNtProtect->fThemesFirstProcessCreateHandle = true; /* Only once! */
3904 fAllowedRights |= PROCESS_DUP_HANDLE;
3905 pOpInfo->CallContext = NULL; /* don't assert this. */
3906 }
3907
3908 /* Special case 6a, Windows 10+: AudioDG.exe opens the process with the
3909 PROCESS_SET_LIMITED_INFORMATION right. It seems like it need it for
3910 some myserious and weirdly placed cpu set management of our process.
3911 I'd love to understand what that's all about...
3912 Currently playing safe and only grand this right, however limited, to
3913 audiodg.exe. */
3914 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(10, 0)
3915 && ( fDesiredAccess == PROCESS_SET_LIMITED_INFORMATION
3916 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION) /* expected fix #1 */
3917 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_INFORMATION) /* expected fix #2 */
3918 )
3919 && pOpInfo->KernelHandle == 0
3920 && ExGetPreviousMode() == UserMode
3921 && supdrvNtProtectIsSystem32ProcessMatch(PsGetCurrentProcess(), "audiodg.exe") )
3922 {
3923 fAllowedRights |= PROCESS_SET_LIMITED_INFORMATION;
3924 pOpInfo->CallContext = NULL; /* don't assert this. */
3925 }
3926
3927 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p wants %#x to %p/pid=%04zx [%d], allow %#x => %#x; %s [prev=%#x]\n",
3928 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3929 fDesiredAccess, pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3930 fAllowedRights, fDesiredAccess & fAllowedRights,
3931 PsGetProcessImageFileName(PsGetCurrentProcess()), ExGetPreviousMode() ));
3932
3933 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess &= fAllowedRights;
3934 }
3935 }
3936 else
3937 {
3938 /* Don't restrict the process accessing itself. */
3939 if ( (PEPROCESS)pOpInfo->Object == PsGetCurrentProcess()
3940 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == pOpInfo->Object)
3941 {
3942 Log(("vboxdrv/ProcessHandlePre: ctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] %s\n",
3943 PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3944 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
3945 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
3946 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
3947 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
3948 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
3949 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
3950
3951 pOpInfo->CallContext = NULL; /* don't assert */
3952 }
3953 else
3954 {
3955 ACCESS_MASK const fDesiredAccess = pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess;
3956
3957 /* Special case 5 on Vista, 7 & 8:
3958 This is the CSRSS.EXE end of special case #1. */
3959 if ( g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3)
3960 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
3961 && pNtProtect->cCsrssFirstProcessDuplicateHandle > 0
3962 && pOpInfo->KernelHandle == 0
3963 && fDesiredAccess == s_fCsrssStupidDesires
3964 && pNtProtect->hParentPid
3965 == PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess)
3966 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
3967 && ExGetPreviousMode() == UserMode
3968 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()))
3969 {
3970 if (ASMAtomicDecS32(&pNtProtect->cCsrssFirstProcessDuplicateHandle) >= 0)
3971 {
3972 /* Not needed: PROCESS_CREATE_THREAD, PROCESS_SET_SESSIONID,
3973 PROCESS_CREATE_PROCESS, PROCESS_DUP_HANDLE */
3974 fAllowedRights = fAllowedRights
3975 | PROCESS_VM_OPERATION
3976 | PROCESS_VM_WRITE
3977 | PROCESS_DUP_HANDLE /* Needed for launching VBoxTestOGL. */
3978 | 0;
3979 pOpInfo->CallContext = NULL; /* don't assert this. */
3980 }
3981 }
3982
3983 /* Special case 6b, Windows 10+: AudioDG.exe duplicates the handle it opened above. */
3984 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(10, 0)
3985 && ( fDesiredAccess == PROCESS_SET_LIMITED_INFORMATION
3986 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION) /* expected fix #1 */
3987 || fDesiredAccess == (PROCESS_SET_LIMITED_INFORMATION | PROCESS_QUERY_INFORMATION) /* expected fix #2 */
3988 )
3989 && pOpInfo->KernelHandle == 0
3990 && ExGetPreviousMode() == UserMode
3991 && supdrvNtProtectIsSystem32ProcessMatch(PsGetCurrentProcess(), "audiodg.exe") )
3992 {
3993 fAllowedRights |= PROCESS_SET_LIMITED_INFORMATION;
3994 pOpInfo->CallContext = NULL; /* don't assert this. */
3995 }
3996
3997 Log(("vboxdrv/ProcessHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] %s\n",
3998 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
3999 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
4000 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
4001 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
4002 fDesiredAccess,
4003 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
4004 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4005
4006 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= fAllowedRights;
4007 }
4008 }
4009 supdrvNtProtectRelease(pNtProtect);
4010 }
4011
4012 return OB_PREOP_SUCCESS;
4013}
4014
4015
4016static VOID __stdcall
4017supdrvNtProtectCallback_ProcessHandlePost(PVOID pvUser, POB_POST_OPERATION_INFORMATION pOpInfo)
4018{
4019 Assert(pvUser == NULL); RT_NOREF1(pvUser);
4020 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
4021 Assert(pOpInfo->ObjectType == *PsProcessType);
4022
4023 if ( pOpInfo->CallContext
4024 && NT_SUCCESS(pOpInfo->ReturnStatus))
4025 {
4026 ACCESS_MASK const fGrantedAccess = pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE
4027 ? pOpInfo->Parameters->CreateHandleInformation.GrantedAccess
4028 : pOpInfo->Parameters->DuplicateHandleInformation.GrantedAccess;
4029 AssertReleaseMsg( !(fGrantedAccess & ~( SUPDRV_NT_ALLOW_PROCESS_RIGHTS
4030 | WRITE_OWNER | WRITE_DAC /* these two might be forced upon us */
4031 | PROCESS_UNKNOWN_4000 /* Seen set on win 8.1 */
4032 /*| PROCESS_UNKNOWN_8000 */ ) )
4033 || pOpInfo->KernelHandle,
4034 ("GrantedAccess=%#x - we allow %#x - we did not allow %#x\n",
4035 fGrantedAccess, SUPDRV_NT_ALLOW_PROCESS_RIGHTS, fGrantedAccess & ~SUPDRV_NT_ALLOW_PROCESS_RIGHTS));
4036 }
4037}
4038
4039# undef SUPDRV_NT_ALLOW_PROCESS_RIGHTS
4040
4041/** @} */
4042
4043
4044/** @name Thread Handle Callbacks
4045 * @{ */
4046
4047/* From ntifs.h */
4048extern "C" NTKERNELAPI PEPROCESS __stdcall IoThreadToProcess(PETHREAD);
4049
4050/** Thread rights that we allow for handles to stub and VM processes. */
4051# define SUPDRV_NT_ALLOWED_THREAD_RIGHTS \
4052 ( THREAD_TERMINATE \
4053 | THREAD_GET_CONTEXT \
4054 | THREAD_QUERY_INFORMATION \
4055 | THREAD_QUERY_LIMITED_INFORMATION \
4056 | DELETE \
4057 | READ_CONTROL \
4058 | SYNCHRONIZE)
4059/** @todo consider THREAD_SET_LIMITED_INFORMATION & THREAD_RESUME */
4060
4061/** Evil thread rights.
4062 * @remarks THREAD_RESUME is not included as it seems to be forced upon us by
4063 * Windows 8.1, at least for some processes. We dont' actively
4064 * allow it though, just tollerate it when forced to. */
4065# define SUPDRV_NT_EVIL_THREAD_RIGHTS \
4066 ( THREAD_SUSPEND_RESUME \
4067 | THREAD_SET_CONTEXT \
4068 | THREAD_SET_INFORMATION \
4069 | THREAD_SET_LIMITED_INFORMATION /*?*/ \
4070 | THREAD_SET_THREAD_TOKEN /*?*/ \
4071 | THREAD_IMPERSONATE /*?*/ \
4072 | THREAD_DIRECT_IMPERSONATION /*?*/ \
4073 /*| THREAD_RESUME - see remarks. */ \
4074 | 0)
4075AssertCompile((SUPDRV_NT_EVIL_THREAD_RIGHTS & SUPDRV_NT_ALLOWED_THREAD_RIGHTS) == 0);
4076
4077
4078static OB_PREOP_CALLBACK_STATUS __stdcall
4079supdrvNtProtectCallback_ThreadHandlePre(PVOID pvUser, POB_PRE_OPERATION_INFORMATION pOpInfo)
4080{
4081 Assert(pvUser == NULL); RT_NOREF1(pvUser);
4082 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
4083 Assert(pOpInfo->ObjectType == *PsThreadType);
4084
4085 PEPROCESS pProcess = IoThreadToProcess((PETHREAD)pOpInfo->Object);
4086 PSUPDRVNTPROTECT pNtProtect = supdrvNtProtectLookup(PsGetProcessId(pProcess));
4087 pOpInfo->CallContext = pNtProtect; /* Just for reference. */
4088 if (pNtProtect)
4089 {
4090 static ACCESS_MASK const s_fCsrssStupidDesires = 0x1fffff;
4091 ACCESS_MASK fAllowedRights = SUPDRV_NT_ALLOWED_THREAD_RIGHTS;
4092
4093 if (pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE)
4094 {
4095 /* Don't restrict the process accessing its own threads. */
4096 if (pProcess == PsGetCurrentProcess())
4097 {
4098 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] self\n",
4099 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4100 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
4101 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind));
4102 pOpInfo->CallContext = NULL; /* don't assert */
4103 pNtProtect->fFirstThreadCreateHandle = false;
4104 }
4105#ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
4106 /* Allow debuggers full access. */
4107 else if (supdrvNtProtectIsWhitelistedDebugger(PsGetCurrentProcess()))
4108 {
4109 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d] %s [debugger]\n",
4110 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4111 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
4112 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
4113 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4114 pOpInfo->CallContext = NULL; /* don't assert */
4115 }
4116#endif
4117 else
4118 {
4119 /* Special case 1 on Vista, 7, 8:
4120 The CreateProcess code passes the handle over to CSRSS.EXE
4121 and the code inBaseSrvCreateProcess will duplicate the
4122 handle with 0x1fffff as access mask. NtDuplicateObject will
4123 fail this call before it ever gets down here. */
4124 if ( g_uNtVerCombined < SUP_MAKE_NT_VER_SIMPLE(6, 3)
4125 && pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed
4126 && pNtProtect->fFirstThreadCreateHandle
4127 && pOpInfo->KernelHandle == 0
4128 && ExGetPreviousMode() == UserMode
4129 && pNtProtect->hParentPid == PsGetProcessId(PsGetCurrentProcess()) )
4130 {
4131 if ( !pOpInfo->KernelHandle
4132 && pOpInfo->Parameters->CreateHandleInformation.DesiredAccess == s_fCsrssStupidDesires)
4133 {
4134 fAllowedRights |= s_fCsrssStupidDesires;
4135 pOpInfo->CallContext = NULL; /* don't assert this. */
4136 }
4137 pNtProtect->fFirstThreadCreateHandle = false;
4138 }
4139
4140 /* Special case 2 on 8.1, possibly also Vista, 7, 8:
4141 When creating a process like VBoxTestOGL from the VM process,
4142 CSRSS.EXE will try talk to the calling thread and, it
4143 appears, impersonate it. We unfortunately need to allow
4144 this or there will be no 3D support. Typical DbgPrint:
4145 "SXS: BasepCreateActCtx() Calling csrss server failed. Status = 0xc00000a5" */
4146 SUPDRVNTPROTECTKIND enmProcessKind;
4147 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 0, 0, 0)
4148 && ( (enmProcessKind = pNtProtect->enmProcessKind) == kSupDrvNtProtectKind_VmProcessConfirmed
4149 || enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4150 && pOpInfo->KernelHandle == 0
4151 && ExGetPreviousMode() == UserMode
4152 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
4153 {
4154 fAllowedRights |= THREAD_IMPERSONATE;
4155 fAllowedRights |= THREAD_DIRECT_IMPERSONATION;
4156 //fAllowedRights |= THREAD_SET_LIMITED_INFORMATION; - try without this one
4157 pOpInfo->CallContext = NULL; /* don't assert this. */
4158 }
4159
4160 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p wants %#x to %p in pid=%04zx [%d], allow %#x => %#x; %s [prev=%#x]\n",
4161 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4162 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess,
4163 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind, fAllowedRights,
4164 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess & fAllowedRights,
4165 PsGetProcessImageFileName(PsGetCurrentProcess()), ExGetPreviousMode()));
4166
4167 pOpInfo->Parameters->CreateHandleInformation.DesiredAccess &= fAllowedRights;
4168 }
4169 }
4170 else
4171 {
4172 /* Don't restrict the process accessing its own threads. */
4173 if ( pProcess == PsGetCurrentProcess()
4174 && (PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == pProcess)
4175 {
4176 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d] self\n",
4177 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4178 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
4179 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
4180 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
4181 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
4182 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind,
4183 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4184 pOpInfo->CallContext = NULL; /* don't assert */
4185 }
4186 else
4187 {
4188 /* Special case 3 on Vista, 7, 8:
4189 This is the follow up to special case 1. */
4190 SUPDRVNTPROTECTKIND enmProcessKind;
4191 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 0, 0, 0)
4192 && ( (enmProcessKind = pNtProtect->enmProcessKind) == kSupDrvNtProtectKind_VmProcessConfirmed
4193 || enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4194 && pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess == PsGetCurrentProcess()
4195 && pOpInfo->KernelHandle == 0
4196 && ExGetPreviousMode() == UserMode
4197 && supdrvNtProtectIsAssociatedCsrss(pNtProtect, PsGetCurrentProcess()) )
4198 {
4199 fAllowedRights |= THREAD_IMPERSONATE;
4200 fAllowedRights |= THREAD_DIRECT_IMPERSONATION;
4201 //fAllowedRights |= THREAD_SET_LIMITED_INFORMATION; - try without this one
4202 pOpInfo->CallContext = NULL; /* don't assert this. */
4203 }
4204
4205 Log(("vboxdrv/ThreadHandlePre: %sctx=%04zx/%p[%p] dup from %04zx/%p with %#x to %p in pid=%04zx [%d], allow %#x => %#x; %s\n",
4206 pOpInfo->KernelHandle ? "k" : "", PsGetProcessId(PsGetCurrentProcess()), PsGetCurrentProcess(),
4207 pOpInfo->Parameters->DuplicateHandleInformation.TargetProcess,
4208 PsGetProcessId((PEPROCESS)pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess),
4209 pOpInfo->Parameters->DuplicateHandleInformation.SourceProcess,
4210 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess,
4211 pOpInfo->Object, pNtProtect->AvlCore.Key, pNtProtect->enmProcessKind, fAllowedRights,
4212 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess & fAllowedRights,
4213 PsGetProcessImageFileName(PsGetCurrentProcess()) ));
4214
4215 pOpInfo->Parameters->DuplicateHandleInformation.DesiredAccess &= fAllowedRights;
4216 }
4217 }
4218
4219 supdrvNtProtectRelease(pNtProtect);
4220 }
4221
4222 return OB_PREOP_SUCCESS;
4223}
4224
4225
4226static VOID __stdcall
4227supdrvNtProtectCallback_ThreadHandlePost(PVOID pvUser, POB_POST_OPERATION_INFORMATION pOpInfo)
4228{
4229 Assert(pvUser == NULL); RT_NOREF1(pvUser);
4230 Assert(pOpInfo->Operation == OB_OPERATION_HANDLE_CREATE || pOpInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE);
4231 Assert(pOpInfo->ObjectType == *PsThreadType);
4232
4233 if ( pOpInfo->CallContext
4234 && NT_SUCCESS(pOpInfo->ReturnStatus))
4235 {
4236 ACCESS_MASK const fGrantedAccess = pOpInfo->Parameters->CreateHandleInformation.GrantedAccess;
4237 AssertReleaseMsg( !(fGrantedAccess & ~( SUPDRV_NT_ALLOWED_THREAD_RIGHTS
4238 | WRITE_OWNER | WRITE_DAC /* these two might be forced upon us */
4239 | THREAD_RESUME /* This seems to be force upon us too with 8.1. */
4240 ) )
4241 || pOpInfo->KernelHandle,
4242 ("GrantedAccess=%#x - we allow %#x - we did not allow %#x\n",
4243 fGrantedAccess, SUPDRV_NT_ALLOWED_THREAD_RIGHTS, fGrantedAccess & ~SUPDRV_NT_ALLOWED_THREAD_RIGHTS));
4244 }
4245}
4246
4247# undef SUPDRV_NT_ALLOWED_THREAD_RIGHTS
4248
4249/** @} */
4250
4251
4252/**
4253 * Creates a new process protection structure.
4254 *
4255 * @returns VBox status code.
4256 * @param ppNtProtect Where to return the pointer to the structure
4257 * on success.
4258 * @param hPid The process ID of the process to protect.
4259 * @param enmProcessKind The kind of process we're protecting.
4260 * @param fLink Whether to link the structure into the tree.
4261 */
4262static int supdrvNtProtectCreate(PSUPDRVNTPROTECT *ppNtProtect, HANDLE hPid, SUPDRVNTPROTECTKIND enmProcessKind, bool fLink)
4263{
4264 AssertReturn(g_hNtProtectLock != NIL_RTSPINLOCK, VERR_WRONG_ORDER);
4265
4266 PSUPDRVNTPROTECT pNtProtect = (PSUPDRVNTPROTECT)RTMemAllocZ(sizeof(*pNtProtect));
4267 if (!pNtProtect)
4268 return VERR_NO_MEMORY;
4269
4270 pNtProtect->AvlCore.Key = hPid;
4271 pNtProtect->u32Magic = SUPDRVNTPROTECT_MAGIC;
4272 pNtProtect->cRefs = 1;
4273 pNtProtect->enmProcessKind = enmProcessKind;
4274 pNtProtect->hParentPid = NULL;
4275 pNtProtect->hOpenTid = NULL;
4276 pNtProtect->hCsrssPid = NULL;
4277 pNtProtect->pCsrssProcess = NULL;
4278
4279 if (fLink)
4280 {
4281 RTSpinlockAcquire(g_hNtProtectLock);
4282 bool fSuccess = RTAvlPVInsert(&g_NtProtectTree, &pNtProtect->AvlCore);
4283 pNtProtect->fInTree = fSuccess;
4284 RTSpinlockRelease(g_hNtProtectLock);
4285
4286 if (!fSuccess)
4287 {
4288 /* Duplicate entry, fail. */
4289 pNtProtect->u32Magic = SUPDRVNTPROTECT_MAGIC_DEAD;
4290 LogRel(("supdrvNtProtectCreate: Duplicate (%#x).\n", pNtProtect->AvlCore.Key));
4291 RTMemFree(pNtProtect);
4292 return VERR_DUPLICATE;
4293 }
4294 }
4295
4296 *ppNtProtect = pNtProtect;
4297 return VINF_SUCCESS;
4298}
4299
4300
4301/**
4302 * Releases a reference to a NT protection structure.
4303 *
4304 * @param pNtProtect The NT protection structure.
4305 */
4306static void supdrvNtProtectRelease(PSUPDRVNTPROTECT pNtProtect)
4307{
4308 if (!pNtProtect)
4309 return;
4310 AssertReturnVoid(pNtProtect->u32Magic == SUPDRVNTPROTECT_MAGIC);
4311
4312 RTSpinlockAcquire(g_hNtProtectLock);
4313 uint32_t cRefs = ASMAtomicDecU32(&pNtProtect->cRefs);
4314 if (cRefs != 0)
4315 RTSpinlockRelease(g_hNtProtectLock);
4316 else
4317 {
4318 /*
4319 * That was the last reference. Remove it from the tree, invalidate it
4320 * and free the resources associated with it. Also, release any
4321 * child/parent references related to this protection structure.
4322 */
4323 ASMAtomicWriteU32(&pNtProtect->u32Magic, SUPDRVNTPROTECT_MAGIC_DEAD);
4324 if (pNtProtect->fInTree)
4325 {
4326 PSUPDRVNTPROTECT pRemoved = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pNtProtect->AvlCore.Key);
4327 Assert(pRemoved == pNtProtect); RT_NOREF_PV(pRemoved);
4328 pNtProtect->fInTree = false;
4329 }
4330
4331 PSUPDRVNTPROTECT pChild = NULL;
4332 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubParent)
4333 {
4334 pChild = pNtProtect->u.pChild;
4335 if (pChild)
4336 {
4337 pNtProtect->u.pChild = NULL;
4338 pChild->u.pParent = NULL;
4339 pChild->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
4340 uint32_t cChildRefs = ASMAtomicDecU32(&pChild->cRefs);
4341 if (!cChildRefs)
4342 {
4343 Assert(pChild->fInTree);
4344 if (pChild->fInTree)
4345 {
4346 PSUPDRVNTPROTECT pRemovedChild = (PSUPDRVNTPROTECT)RTAvlPVRemove(&g_NtProtectTree, pChild->AvlCore.Key);
4347 Assert(pRemovedChild == pChild); RT_NOREF_PV(pRemovedChild);
4348 pChild->fInTree = false;
4349 }
4350 }
4351 else
4352 pChild = NULL;
4353 }
4354 }
4355 else
4356 AssertRelease(pNtProtect->enmProcessKind != kSupDrvNtProtectKind_VmProcessUnconfirmed);
4357
4358 RTSpinlockRelease(g_hNtProtectLock);
4359
4360 if (pNtProtect->pCsrssProcess)
4361 {
4362 ObDereferenceObject(pNtProtect->pCsrssProcess);
4363 pNtProtect->pCsrssProcess = NULL;
4364 }
4365
4366 RTMemFree(pNtProtect);
4367 if (pChild)
4368 RTMemFree(pChild);
4369 }
4370}
4371
4372
4373/**
4374 * Looks up a PID in the NT protect tree.
4375 *
4376 * @returns Pointer to a NT protection structure (with a referenced) on success,
4377 * NULL if not found.
4378 * @param hPid The process ID.
4379 */
4380static PSUPDRVNTPROTECT supdrvNtProtectLookup(HANDLE hPid)
4381{
4382 RTSpinlockAcquire(g_hNtProtectLock);
4383 PSUPDRVNTPROTECT pFound = (PSUPDRVNTPROTECT)RTAvlPVGet(&g_NtProtectTree, hPid);
4384 if (pFound)
4385 ASMAtomicIncU32(&pFound->cRefs);
4386 RTSpinlockRelease(g_hNtProtectLock);
4387 return pFound;
4388}
4389
4390
4391/**
4392 * Validates a few facts about the stub process when the VM process opens
4393 * vboxdrv.
4394 *
4395 * This makes sure the stub process is still around and that it has neither
4396 * debugger nor extra threads in it.
4397 *
4398 * @returns VBox status code.
4399 * @param pNtProtect The unconfirmed VM process currently trying to
4400 * open vboxdrv.
4401 * @param pErrInfo Additional error information.
4402 */
4403static int supdrvNtProtectVerifyStubForVmProcess(PSUPDRVNTPROTECT pNtProtect, PRTERRINFO pErrInfo)
4404{
4405 /*
4406 * Grab a reference to the parent stub process.
4407 */
4408 SUPDRVNTPROTECTKIND enmStub = kSupDrvNtProtectKind_Invalid;
4409 PSUPDRVNTPROTECT pNtStub = NULL;
4410 RTSpinlockAcquire(g_hNtProtectLock);
4411 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4412 {
4413 pNtStub = pNtProtect->u.pParent; /* weak reference. */
4414 if (pNtStub)
4415 {
4416 enmStub = pNtStub->enmProcessKind;
4417 if (enmStub == kSupDrvNtProtectKind_StubParent)
4418 {
4419 uint32_t cRefs = ASMAtomicIncU32(&pNtStub->cRefs);
4420 Assert(cRefs > 0 && cRefs < 1024); RT_NOREF_PV(cRefs);
4421 }
4422 else
4423 pNtStub = NULL;
4424 }
4425 }
4426 RTSpinlockRelease(g_hNtProtectLock);
4427
4428 /*
4429 * We require the stub process to be present.
4430 */
4431 if (!pNtStub)
4432 return RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_NOT_FOUND, "Missing stub process (enmStub=%d).", enmStub);
4433
4434 /*
4435 * Open the parent process and thread so we can check for debuggers and unwanted threads.
4436 */
4437 int rc;
4438 PEPROCESS pStubProcess;
4439 NTSTATUS rcNt = PsLookupProcessByProcessId(pNtStub->AvlCore.Key, &pStubProcess);
4440 if (NT_SUCCESS(rcNt))
4441 {
4442 HANDLE hStubProcess;
4443 rcNt = ObOpenObjectByPointer(pStubProcess, OBJ_KERNEL_HANDLE, NULL /*PassedAccessState*/,
4444 0 /*DesiredAccess*/, *PsProcessType, KernelMode, &hStubProcess);
4445 if (NT_SUCCESS(rcNt))
4446 {
4447 PETHREAD pStubThread;
4448 rcNt = PsLookupThreadByThreadId(pNtStub->hOpenTid, &pStubThread);
4449 if (NT_SUCCESS(rcNt))
4450 {
4451 HANDLE hStubThread;
4452 rcNt = ObOpenObjectByPointer(pStubThread, OBJ_KERNEL_HANDLE, NULL /*PassedAccessState*/,
4453 0 /*DesiredAccess*/, *PsThreadType, KernelMode, &hStubThread);
4454 if (NT_SUCCESS(rcNt))
4455 {
4456 /*
4457 * Do some simple sanity checking.
4458 */
4459 rc = supHardNtVpDebugger(hStubProcess, pErrInfo);
4460 if (RT_SUCCESS(rc))
4461 rc = supHardNtVpThread(hStubProcess, hStubThread, pErrInfo);
4462
4463 /* Clean up. */
4464 rcNt = NtClose(hStubThread); AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt));
4465 }
4466 else
4467 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_THREAD_OPEN_ERROR,
4468 "Error opening stub thread %p (tid %p, pid %p): %#x",
4469 pStubThread, pNtStub->hOpenTid, pNtStub->AvlCore.Key, rcNt);
4470 }
4471 else
4472 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_THREAD_NOT_FOUND,
4473 "Failed to locate thread %p in %p: %#x", pNtStub->hOpenTid, pNtStub->AvlCore.Key, rcNt);
4474 rcNt = NtClose(hStubProcess); AssertMsg(NT_SUCCESS(rcNt), ("%#x\n", rcNt));
4475 }
4476 else
4477 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_OPEN_ERROR,
4478 "Error opening stub process %p (pid %p): %#x", pStubProcess, pNtStub->AvlCore.Key, rcNt);
4479 ObDereferenceObject(pStubProcess);
4480 }
4481 else
4482 rc = RTErrInfoSetF(pErrInfo, VERR_SUP_VP_STUB_NOT_FOUND,
4483 "Failed to locate stub process %p: %#x", pNtStub->AvlCore.Key, rcNt);
4484
4485 supdrvNtProtectRelease(pNtStub);
4486 return rc;
4487}
4488
4489
4490/**
4491 * Worker for supdrvNtProtectVerifyProcess that verifies the handles to a VM
4492 * process and its thread.
4493 *
4494 * @returns VBox status code.
4495 * @param pNtProtect The NT protect structure for getting information
4496 * about special processes.
4497 * @param pErrInfo Where to return additional error details.
4498 */
4499static int supdrvNtProtectRestrictHandlesToProcessAndThread(PSUPDRVNTPROTECT pNtProtect, PRTERRINFO pErrInfo)
4500{
4501 /*
4502 * What to protect.
4503 */
4504 PEPROCESS pProtectedProcess = PsGetCurrentProcess();
4505 HANDLE hProtectedPid = PsGetProcessId(pProtectedProcess);
4506 PETHREAD pProtectedThread = PsGetCurrentThread();
4507 AssertReturn(pNtProtect->AvlCore.Key == hProtectedPid, VERR_INTERNAL_ERROR_5);
4508
4509 /*
4510 * Take a snapshot of all the handles in the system.
4511 * Note! The 32 bytes on the size of to counteract the allocation header
4512 * that rtR0MemAllocEx slaps on everything.
4513 */
4514 uint32_t cbBuf = _256K - 32;
4515 uint8_t *pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
4516 ULONG cbNeeded = cbBuf;
4517 NTSTATUS rcNt = NtQuerySystemInformation(SystemExtendedHandleInformation, pbBuf, cbBuf, &cbNeeded);
4518 if (!NT_SUCCESS(rcNt))
4519 {
4520 while ( rcNt == STATUS_INFO_LENGTH_MISMATCH
4521 && cbNeeded > cbBuf
4522 && cbBuf <= 32U*_1M)
4523 {
4524 cbBuf = RT_ALIGN_32(cbNeeded + _4K, _64K) - 32;
4525 RTMemFree(pbBuf);
4526 pbBuf = (uint8_t *)RTMemAlloc(cbBuf);
4527 if (!pbBuf)
4528 return RTErrInfoSetF(pErrInfo, VERR_NO_MEMORY, "Error allocating %zu bytes for querying handles.", cbBuf);
4529 rcNt = NtQuerySystemInformation(SystemExtendedHandleInformation, pbBuf, cbBuf, &cbNeeded);
4530 }
4531 if (!NT_SUCCESS(rcNt))
4532 {
4533 RTMemFree(pbBuf);
4534 return RTErrInfoSetF(pErrInfo, RTErrConvertFromNtStatus(rcNt),
4535 "NtQuerySystemInformation/SystemExtendedHandleInformation failed: %#x\n", rcNt);
4536 }
4537 }
4538
4539 /*
4540 * Walk the information and look for handles to the two objects we're protecting.
4541 */
4542 int rc = VINF_SUCCESS;
4543# ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
4544 HANDLE idLastDebugger = (HANDLE)~(uintptr_t)0;
4545# endif
4546
4547 uint32_t cCsrssProcessHandles = 0;
4548 uint32_t cSystemProcessHandles = 0;
4549 uint32_t cEvilProcessHandles = 0;
4550 uint32_t cBenignProcessHandles = 0;
4551
4552 uint32_t cCsrssThreadHandles = 0;
4553 uint32_t cEvilThreadHandles = 0;
4554 uint32_t cBenignThreadHandles = 0;
4555
4556 SYSTEM_HANDLE_INFORMATION_EX const *pInfo = (SYSTEM_HANDLE_INFORMATION_EX const *)pbBuf;
4557 ULONG_PTR i = pInfo->NumberOfHandles;
4558 AssertRelease(RT_UOFFSETOF_DYN(SYSTEM_HANDLE_INFORMATION_EX, Handles[i]) == cbNeeded);
4559 while (i-- > 0)
4560 {
4561 const char *pszType;
4562 SYSTEM_HANDLE_ENTRY_INFO_EX const *pHandleInfo = &pInfo->Handles[i];
4563 if (pHandleInfo->Object == pProtectedProcess)
4564 {
4565 /* Handles within the protected process are fine. */
4566 if ( !(pHandleInfo->GrantedAccess & SUPDRV_NT_EVIL_PROCESS_RIGHTS)
4567 || pHandleInfo->UniqueProcessId == hProtectedPid)
4568 {
4569 cBenignProcessHandles++;
4570 continue;
4571 }
4572
4573 /* CSRSS is allowed to have one evil process handle.
4574 See the special cases in the hook code. */
4575 if ( cCsrssProcessHandles < 1
4576 && pHandleInfo->UniqueProcessId == pNtProtect->hCsrssPid)
4577 {
4578 cCsrssProcessHandles++;
4579 continue;
4580 }
4581
4582 /* The system process is allowed having two open process handle in
4583 Windows 8.1 and later, and one in earlier. This is probably a
4584 little overly paranoid as I think we can safely trust the
4585 system process... */
4586 if ( cSystemProcessHandles < (g_uNtVerCombined >= SUP_MAKE_NT_VER_SIMPLE(6, 3) ? UINT32_C(2) : UINT32_C(1))
4587 && pHandleInfo->UniqueProcessId == PsGetProcessId(PsInitialSystemProcess))
4588 {
4589 cSystemProcessHandles++;
4590 continue;
4591 }
4592
4593 cEvilProcessHandles++;
4594 pszType = "process";
4595 }
4596 else if (pHandleInfo->Object == pProtectedThread)
4597 {
4598 /* Handles within the protected process is fine. */
4599 if ( !(pHandleInfo->GrantedAccess & SUPDRV_NT_EVIL_THREAD_RIGHTS)
4600 || pHandleInfo->UniqueProcessId == hProtectedPid)
4601 {
4602 cBenignThreadHandles++;
4603 continue;
4604 }
4605
4606 /* CSRSS is allowed to have one evil handle to the primary thread
4607 for LPC purposes. See the hook for special case. */
4608 if ( cCsrssThreadHandles < 1
4609 && pHandleInfo->UniqueProcessId == pNtProtect->hCsrssPid)
4610 {
4611 cCsrssThreadHandles++;
4612 continue;
4613 }
4614
4615 cEvilThreadHandles++;
4616 pszType = "thread";
4617 }
4618 else
4619 continue;
4620
4621# ifdef VBOX_WITHOUT_DEBUGGER_CHECKS
4622 /* Ignore whitelisted debuggers. */
4623 if (pHandleInfo->UniqueProcessId == idLastDebugger)
4624 continue;
4625 PEPROCESS pDbgProc;
4626 NTSTATUS rcNt = PsLookupProcessByProcessId(pHandleInfo->UniqueProcessId, &pDbgProc);
4627 if (NT_SUCCESS(rcNt))
4628 {
4629 bool fIsDebugger = supdrvNtProtectIsWhitelistedDebugger(pDbgProc);
4630 ObDereferenceObject(pDbgProc);
4631 if (fIsDebugger)
4632 {
4633 idLastDebugger = pHandleInfo->UniqueProcessId;
4634 continue;
4635 }
4636 }
4637# endif
4638
4639 /* Found evil handle. Currently ignoring on pre-Vista. */
4640# ifndef VBOX_WITH_VISTA_NO_SP
4641 if ( g_uNtVerCombined >= SUP_NT_VER_VISTA
4642# else
4643 if ( g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0)
4644# endif
4645 || g_pfnObRegisterCallbacks)
4646 {
4647 LogRel(("vboxdrv: Found evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s\n",
4648 pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
4649 pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType));
4650 rc = RTErrInfoAddF(pErrInfo, VERR_SUPDRV_HARDENING_EVIL_HANDLE,
4651 *pErrInfo->pszMsg
4652 ? "\nFound evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s"
4653 : "Found evil handle to budding VM process: pid=%p h=%p acc=%#x attr=%#x type=%s",
4654 pHandleInfo->UniqueProcessId, pHandleInfo->HandleValue,
4655 pHandleInfo->GrantedAccess, pHandleInfo->HandleAttributes, pszType);
4656
4657 /* Try add the process name. */
4658 PEPROCESS pOffendingProcess;
4659 rcNt = PsLookupProcessByProcessId(pHandleInfo->UniqueProcessId, &pOffendingProcess);
4660 if (NT_SUCCESS(rcNt))
4661 {
4662 const char *pszName = (const char *)PsGetProcessImageFileName(pOffendingProcess);
4663 if (pszName && *pszName)
4664 rc = RTErrInfoAddF(pErrInfo, rc, " [%s]", pszName);
4665
4666 ObDereferenceObject(pOffendingProcess);
4667 }
4668 }
4669 }
4670
4671 RTMemFree(pbBuf);
4672 return rc;
4673}
4674
4675
4676/**
4677 * Checks if the current process checks out as a VM process stub.
4678 *
4679 * @returns VBox status code.
4680 * @param pNtProtect The NT protect structure. This is upgraded to a
4681 * final protection kind (state) on success.
4682 */
4683static int supdrvNtProtectVerifyProcess(PSUPDRVNTPROTECT pNtProtect)
4684{
4685 AssertReturn(PsGetProcessId(PsGetCurrentProcess()) == pNtProtect->AvlCore.Key, VERR_INTERNAL_ERROR_3);
4686
4687 /*
4688 * Do the verification. The handle restriction checks are only preformed
4689 * on VM processes.
4690 */
4691 int rc = VINF_SUCCESS;
4692 PSUPDRVNTERRORINFO pErrorInfo = (PSUPDRVNTERRORINFO)RTMemAllocZ(sizeof(*pErrorInfo));
4693 if (RT_SUCCESS(rc))
4694 {
4695 pErrorInfo->hProcessId = PsGetCurrentProcessId();
4696 pErrorInfo->hThreadId = PsGetCurrentThreadId();
4697 RTERRINFO ErrInfo;
4698 RTErrInfoInit(&ErrInfo, pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo));
4699
4700 if (pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
4701 rc = supdrvNtProtectRestrictHandlesToProcessAndThread(pNtProtect, &ErrInfo);
4702 if (RT_SUCCESS(rc))
4703 {
4704 rc = supHardenedWinVerifyProcess(NtCurrentProcess(), NtCurrentThread(), SUPHARDNTVPKIND_VERIFY_ONLY, 0 /*fFlags*/,
4705 NULL /*pcFixes*/, &ErrInfo);
4706 if (RT_SUCCESS(rc) && pNtProtect->enmProcessKind >= kSupDrvNtProtectKind_VmProcessUnconfirmed)
4707 rc = supdrvNtProtectVerifyStubForVmProcess(pNtProtect, &ErrInfo);
4708 }
4709 }
4710 else
4711 rc = VERR_NO_MEMORY;
4712
4713 /*
4714 * Upgrade and return.
4715 */
4716 HANDLE hOpenTid = PsGetCurrentThreadId();
4717 RTSpinlockAcquire(g_hNtProtectLock);
4718
4719 /* Stub process verficiation is pretty much straight forward. */
4720 if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubUnverified)
4721 {
4722 pNtProtect->enmProcessKind = RT_SUCCESS(rc) ? kSupDrvNtProtectKind_StubSpawning : kSupDrvNtProtectKind_StubDead;
4723 pNtProtect->hOpenTid = hOpenTid;
4724 }
4725 /* The VM process verification is a little bit more complicated
4726 because we need to drop the parent process reference as well. */
4727 else if (pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessUnconfirmed)
4728 {
4729 AssertRelease(pNtProtect->cRefs >= 2); /* Parent + Caller */
4730 PSUPDRVNTPROTECT pParent = pNtProtect->u.pParent;
4731 AssertRelease(pParent);
4732 AssertRelease(pParent->u.pParent == pNtProtect);
4733 AssertRelease(pParent->enmProcessKind == kSupDrvNtProtectKind_StubParent);
4734 pParent->u.pParent = NULL;
4735
4736 pNtProtect->u.pParent = NULL;
4737 ASMAtomicDecU32(&pNtProtect->cRefs);
4738
4739 if (RT_SUCCESS(rc))
4740 {
4741 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessConfirmed;
4742 pNtProtect->hOpenTid = hOpenTid;
4743 }
4744 else
4745 pNtProtect->enmProcessKind = kSupDrvNtProtectKind_VmProcessDead;
4746 }
4747
4748 /* Since the stub and VM processes are only supposed to have one thread,
4749 we're not supposed to be subject to any races from within the processes.
4750
4751 There is a race between VM process verification and the stub process
4752 exiting, though. We require the stub process to be alive until the new
4753 VM process has made it thru the validation. So, when the stub
4754 terminates the notification handler will change the state of both stub
4755 and VM process to dead.
4756
4757 Also, I'm not entirely certain where the process
4758 termination notification is triggered from, so that can theorically
4759 create a race in both cases. */
4760 else
4761 {
4762 AssertReleaseMsg( pNtProtect->enmProcessKind == kSupDrvNtProtectKind_StubDead
4763 || pNtProtect->enmProcessKind == kSupDrvNtProtectKind_VmProcessDead,
4764 ("enmProcessKind=%d rc=%Rrc\n", pNtProtect->enmProcessKind, rc));
4765 if (RT_SUCCESS(rc))
4766 rc = VERR_INVALID_STATE; /* There should be no races here. */
4767 }
4768
4769 RTSpinlockRelease(g_hNtProtectLock);
4770
4771 /*
4772 * Free error info on success, keep it on failure.
4773 */
4774 if (RT_SUCCESS(rc))
4775 RTMemFree(pErrorInfo);
4776 else if (pErrorInfo)
4777 {
4778 pErrorInfo->cchErrorInfo = (uint32_t)strlen(pErrorInfo->szErrorInfo);
4779 if (!pErrorInfo->cchErrorInfo)
4780 pErrorInfo->cchErrorInfo = (uint32_t)RTStrPrintf(pErrorInfo->szErrorInfo, sizeof(pErrorInfo->szErrorInfo),
4781 "supdrvNtProtectVerifyProcess: rc=%d", rc);
4782 RTLogWriteDebugger(pErrorInfo->szErrorInfo, pErrorInfo->cchErrorInfo);
4783
4784 int rc2 = RTSemMutexRequest(g_hErrorInfoLock, RT_INDEFINITE_WAIT);
4785 if (RT_SUCCESS(rc2))
4786 {
4787 pErrorInfo->uCreatedMsTs = RTTimeMilliTS();
4788
4789 /* Free old entries. */
4790 PSUPDRVNTERRORINFO pCur;
4791 while ( (pCur = RTListGetFirst(&g_ErrorInfoHead, SUPDRVNTERRORINFO, ListEntry)) != NULL
4792 && (int64_t)(pErrorInfo->uCreatedMsTs - pCur->uCreatedMsTs) > 60000 /*60sec*/)
4793 {
4794 RTListNodeRemove(&pCur->ListEntry);
4795 RTMemFree(pCur);
4796 }
4797
4798 /* Insert our new entry. */
4799 RTListAppend(&g_ErrorInfoHead, &pErrorInfo->ListEntry);
4800
4801 RTSemMutexRelease(g_hErrorInfoLock);
4802 }
4803 else
4804 RTMemFree(pErrorInfo);
4805 }
4806
4807 return rc;
4808}
4809
4810
4811# ifndef VBOX_WITHOUT_DEBUGGER_CHECKS
4812
4813/**
4814 * Checks if the current process is being debugged.
4815 * @return @c true if debugged, @c false if not.
4816 */
4817static bool supdrvNtIsDebuggerAttached(void)
4818{
4819 return PsIsProcessBeingDebugged(PsGetCurrentProcess()) != FALSE;
4820}
4821
4822# endif /* !VBOX_WITHOUT_DEBUGGER_CHECKS */
4823
4824
4825/**
4826 * Terminates the hardening bits.
4827 */
4828static void supdrvNtProtectTerm(void)
4829{
4830 /*
4831 * Stop intercepting process and thread handle creation calls.
4832 */
4833 if (g_pvObCallbacksCookie)
4834 {
4835 g_pfnObUnRegisterCallbacks(g_pvObCallbacksCookie);
4836 g_pvObCallbacksCookie = NULL;
4837 }
4838
4839 /*
4840 * Stop intercepting process creation and termination notifications.
4841 */
4842 NTSTATUS rcNt;
4843 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
4844 rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
4845 else
4846 rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
4847 AssertMsg(NT_SUCCESS(rcNt), ("rcNt=%#x\n", rcNt));
4848
4849 Assert(g_NtProtectTree == NULL);
4850
4851 /*
4852 * Clean up globals.
4853 */
4854 RTSpinlockDestroy(g_hNtProtectLock);
4855 g_NtProtectTree = NIL_RTSPINLOCK;
4856
4857 RTSemMutexDestroy(g_hErrorInfoLock);
4858 g_hErrorInfoLock = NIL_RTSEMMUTEX;
4859
4860 PSUPDRVNTERRORINFO pCur;
4861 while ((pCur = RTListGetFirst(&g_ErrorInfoHead, SUPDRVNTERRORINFO, ListEntry)) != NULL)
4862 {
4863 RTListNodeRemove(&pCur->ListEntry);
4864 RTMemFree(pCur);
4865 }
4866
4867 supHardenedWinTermImageVerifier();
4868}
4869
4870# ifdef RT_ARCH_X86
4871DECLASM(void) supdrvNtQueryVirtualMemory_0xAF(void);
4872DECLASM(void) supdrvNtQueryVirtualMemory_0xB0(void);
4873DECLASM(void) supdrvNtQueryVirtualMemory_0xB1(void);
4874DECLASM(void) supdrvNtQueryVirtualMemory_0xB2(void);
4875DECLASM(void) supdrvNtQueryVirtualMemory_0xB3(void);
4876DECLASM(void) supdrvNtQueryVirtualMemory_0xB4(void);
4877DECLASM(void) supdrvNtQueryVirtualMemory_0xB5(void);
4878DECLASM(void) supdrvNtQueryVirtualMemory_0xB6(void);
4879DECLASM(void) supdrvNtQueryVirtualMemory_0xB7(void);
4880DECLASM(void) supdrvNtQueryVirtualMemory_0xB8(void);
4881DECLASM(void) supdrvNtQueryVirtualMemory_0xB9(void);
4882DECLASM(void) supdrvNtQueryVirtualMemory_0xBA(void);
4883DECLASM(void) supdrvNtQueryVirtualMemory_0xBB(void);
4884DECLASM(void) supdrvNtQueryVirtualMemory_0xBC(void);
4885DECLASM(void) supdrvNtQueryVirtualMemory_0xBD(void);
4886DECLASM(void) supdrvNtQueryVirtualMemory_0xBE(void);
4887# elif defined(RT_ARCH_AMD64)
4888DECLASM(void) supdrvNtQueryVirtualMemory_0x1F(void);
4889DECLASM(void) supdrvNtQueryVirtualMemory_0x20(void);
4890DECLASM(void) supdrvNtQueryVirtualMemory_0x21(void);
4891DECLASM(void) supdrvNtQueryVirtualMemory_0x22(void);
4892DECLASM(void) supdrvNtQueryVirtualMemory_0x23(void);
4893extern "C" NTSYSAPI NTSTATUS NTAPI ZwRequestWaitReplyPort(HANDLE, PVOID, PVOID);
4894# endif
4895
4896
4897/**
4898 * Initalizes the hardening bits.
4899 *
4900 * @returns NT status code.
4901 */
4902static NTSTATUS supdrvNtProtectInit(void)
4903{
4904 /*
4905 * Initialize the globals.
4906 */
4907
4908 /* The NT version. */
4909 ULONG uMajor, uMinor, uBuild;
4910 PsGetVersion(&uMajor, &uMinor, &uBuild, NULL);
4911 g_uNtVerCombined = SUP_MAKE_NT_VER_COMBINED(uMajor, uMinor, uBuild, 0, 0);
4912
4913 /* Resolve methods we want but isn't available everywhere. */
4914 UNICODE_STRING RoutineName;
4915
4916 RtlInitUnicodeString(&RoutineName, L"ObGetObjectType");
4917 g_pfnObGetObjectType = (PFNOBGETOBJECTTYPE)MmGetSystemRoutineAddress(&RoutineName);
4918
4919 RtlInitUnicodeString(&RoutineName, L"ObRegisterCallbacks");
4920 g_pfnObRegisterCallbacks = (PFNOBREGISTERCALLBACKS)MmGetSystemRoutineAddress(&RoutineName);
4921
4922 RtlInitUnicodeString(&RoutineName, L"ObUnRegisterCallbacks");
4923 g_pfnObUnRegisterCallbacks = (PFNOBUNREGISTERCALLBACKS)MmGetSystemRoutineAddress(&RoutineName);
4924
4925 RtlInitUnicodeString(&RoutineName, L"PsSetCreateProcessNotifyRoutineEx");
4926 g_pfnPsSetCreateProcessNotifyRoutineEx = (PFNPSSETCREATEPROCESSNOTIFYROUTINEEX)MmGetSystemRoutineAddress(&RoutineName);
4927
4928 RtlInitUnicodeString(&RoutineName, L"PsReferenceProcessFilePointer");
4929 g_pfnPsReferenceProcessFilePointer = (PFNPSREFERENCEPROCESSFILEPOINTER)MmGetSystemRoutineAddress(&RoutineName);
4930
4931 RtlInitUnicodeString(&RoutineName, L"PsIsProtectedProcessLight");
4932 g_pfnPsIsProtectedProcessLight = (PFNPSISPROTECTEDPROCESSLIGHT)MmGetSystemRoutineAddress(&RoutineName);
4933
4934 RtlInitUnicodeString(&RoutineName, L"ZwAlpcCreatePort");
4935 g_pfnZwAlpcCreatePort = (PFNZWALPCCREATEPORT)MmGetSystemRoutineAddress(&RoutineName);
4936
4937 RtlInitUnicodeString(&RoutineName, L"ZwQueryVirtualMemory"); /* Yes, using Zw version here. */
4938 g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)MmGetSystemRoutineAddress(&RoutineName);
4939 if (!g_pfnNtQueryVirtualMemory && g_uNtVerCombined < SUP_NT_VER_VISTA)
4940 {
4941 /* XP & W2K3 doesn't have this function exported, so we've cooked up a
4942 few alternative in the assembly helper file that uses the code in
4943 ZwReadFile with a different eax value. We figure the syscall number
4944 by inspecting ZwQueryVolumeInformationFile as it's the next number. */
4945# ifdef RT_ARCH_X86
4946 uint8_t const *pbCode = (uint8_t const *)(uintptr_t)ZwQueryVolumeInformationFile;
4947 if (*pbCode == 0xb8) /* mov eax, dword */
4948 switch (*(uint32_t const *)&pbCode[1])
4949 {
4950 case 0xb0: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xAF; break; /* just in case */
4951 case 0xb1: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB0; break; /* just in case */
4952 case 0xb2: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB1; break; /* just in case */
4953 case 0xb3: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB2; break; /* XP SP3 */
4954 case 0xb4: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB2; break; /* just in case */
4955 case 0xb5: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB3; break; /* just in case */
4956 case 0xb6: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB4; break; /* just in case */
4957 case 0xb7: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB5; break; /* just in case */
4958 case 0xb8: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB6; break; /* just in case */
4959 case 0xb9: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB7; break; /* just in case */
4960 case 0xba: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xB8; break; /* just in case */
4961 case 0xbb: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBA; break; /* W2K3 R2 SP2 */
4962 case 0xbc: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBB; break; /* just in case */
4963 case 0xbd: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBC; break; /* just in case */
4964 case 0xbe: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBD; break; /* just in case */
4965 case 0xbf: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0xBE; break; /* just in case */
4966 }
4967# elif defined(RT_ARCH_AMD64)
4968 uint8_t const *pbCode = (uint8_t const *)(uintptr_t)ZwRequestWaitReplyPort;
4969 if ( pbCode[ 0] == 0x48 /* mov rax, rsp */
4970 && pbCode[ 1] == 0x8b
4971 && pbCode[ 2] == 0xc4
4972 && pbCode[ 3] == 0xfa /* cli */
4973 && pbCode[ 4] == 0x48 /* sub rsp, 10h */
4974 && pbCode[ 5] == 0x83
4975 && pbCode[ 6] == 0xec
4976 && pbCode[ 7] == 0x10
4977 && pbCode[ 8] == 0x50 /* push rax */
4978 && pbCode[ 9] == 0x9c /* pushfq */
4979 && pbCode[10] == 0x6a /* push 10 */
4980 && pbCode[11] == 0x10
4981 && pbCode[12] == 0x48 /* lea rax, [nt!KiServiceLinkage] */
4982 && pbCode[13] == 0x8d
4983 && pbCode[14] == 0x05
4984 && pbCode[19] == 0x50 /* push rax */
4985 && pbCode[20] == 0xb8 /* mov eax,1fh <- the syscall no. */
4986 /*&& pbCode[21] == 0x1f*/
4987 && pbCode[22] == 0x00
4988 && pbCode[23] == 0x00
4989 && pbCode[24] == 0x00
4990 && pbCode[25] == 0xe9 /* jmp KiServiceInternal */
4991 )
4992 {
4993 uint8_t const *pbKiServiceInternal = &pbCode[30] + *(int32_t const *)&pbCode[26];
4994 uint8_t const *pbKiServiceLinkage = &pbCode[19] + *(int32_t const *)&pbCode[15];
4995 if (*pbKiServiceLinkage == 0xc3)
4996 {
4997 g_pfnKiServiceInternal = (PFNRT)pbKiServiceInternal;
4998 g_pfnKiServiceLinkage = (PFNRT)pbKiServiceLinkage;
4999 switch (pbCode[21])
5000 {
5001 case 0x1e: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x1F; break;
5002 case 0x1f: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x20; break;
5003 case 0x20: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x21; break;
5004 case 0x21: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x22; break;
5005 case 0x22: g_pfnNtQueryVirtualMemory = (PFNNTQUERYVIRTUALMEMORY)supdrvNtQueryVirtualMemory_0x23; break;
5006 }
5007 }
5008 }
5009# endif
5010 }
5011 if (!g_pfnNtQueryVirtualMemory)
5012 {
5013 LogRel(("vboxdrv: Cannot locate ZwQueryVirtualMemory in ntoskrnl, nor were we able to cook up a replacement.\n"));
5014 return STATUS_PROCEDURE_NOT_FOUND;
5015 }
5016
5017# ifdef VBOX_STRICT
5018 if ( g_uNtVerCombined >= SUP_NT_VER_W70
5019 && ( g_pfnObGetObjectType == NULL
5020 || g_pfnZwAlpcCreatePort == NULL) )
5021 {
5022 LogRel(("vboxdrv: g_pfnObGetObjectType=%p g_pfnZwAlpcCreatePort=%p.\n", g_pfnObGetObjectType, g_pfnZwAlpcCreatePort));
5023 return STATUS_PROCEDURE_NOT_FOUND;
5024 }
5025# endif
5026
5027 /* LPC object type. */
5028 g_pAlpcPortObjectType1 = *LpcPortObjectType;
5029
5030 /* The spinlock protecting our structures. */
5031 int rc = RTSpinlockCreate(&g_hNtProtectLock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "NtProtectLock");
5032 if (RT_FAILURE(rc))
5033 return VBoxDrvNtErr2NtStatus(rc);
5034 g_NtProtectTree = NULL;
5035
5036 NTSTATUS rcNt;
5037
5038 /* The mutex protecting the error information. */
5039 RTListInit(&g_ErrorInfoHead);
5040 rc = RTSemMutexCreate(&g_hErrorInfoLock);
5041 if (RT_SUCCESS(rc))
5042 {
5043 /* Image stuff + certificates. */
5044 rc = supHardenedWinInitImageVerifier(NULL);
5045 if (RT_SUCCESS(rc))
5046 {
5047 /*
5048 * Intercept process creation and termination.
5049 */
5050 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
5051 rcNt = g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, FALSE /*fRemove*/);
5052 else
5053 rcNt = PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, FALSE /*fRemove*/);
5054 if (NT_SUCCESS(rcNt))
5055 {
5056 /*
5057 * Intercept process and thread handle creation calls.
5058 * The preferred method is only available on Vista SP1+.
5059 */
5060 if (g_pfnObRegisterCallbacks && g_pfnObUnRegisterCallbacks)
5061 {
5062 static OB_OPERATION_REGISTRATION s_aObOperations[] =
5063 {
5064 {
5065 0, /* PsProcessType - imported, need runtime init, better do it explicitly. */
5066 OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
5067 supdrvNtProtectCallback_ProcessHandlePre,
5068 supdrvNtProtectCallback_ProcessHandlePost,
5069 },
5070 {
5071 0, /* PsThreadType - imported, need runtime init, better do it explicitly. */
5072 OB_OPERATION_HANDLE_CREATE | OB_OPERATION_HANDLE_DUPLICATE,
5073 supdrvNtProtectCallback_ThreadHandlePre,
5074 supdrvNtProtectCallback_ThreadHandlePost,
5075 },
5076 };
5077 s_aObOperations[0].ObjectType = PsProcessType;
5078 s_aObOperations[1].ObjectType = PsThreadType;
5079
5080 static OB_CALLBACK_REGISTRATION s_ObCallbackReg =
5081 {
5082 /* .Version = */ OB_FLT_REGISTRATION_VERSION,
5083 /* .OperationRegistrationCount = */ RT_ELEMENTS(s_aObOperations),
5084 /* .Altitude.Length = */ 0,
5085 /* .Altitude.MaximumLength = */ 0,
5086 /* .Altitude.Buffer = */ NULL,
5087 /* .RegistrationContext = */ NULL,
5088 /* .OperationRegistration = */ &s_aObOperations[0]
5089 };
5090 static WCHAR const *s_apwszAltitudes[] = /** @todo get a valid number */
5091 {
5092 L"48596.98940", L"46935.19485", L"49739.39704", L"40334.74976",
5093 L"66667.98940", L"69888.19485", L"69889.39704", L"60364.74976",
5094 L"85780.98940", L"88978.19485", L"89939.39704", L"80320.74976",
5095 L"329879.98940", L"326787.19485", L"328915.39704", L"320314.74976",
5096 };
5097
5098 rcNt = STATUS_FLT_INSTANCE_ALTITUDE_COLLISION;
5099 for (uint32_t i = 0; i < RT_ELEMENTS(s_apwszAltitudes) && rcNt == STATUS_FLT_INSTANCE_ALTITUDE_COLLISION; i++)
5100 {
5101 s_ObCallbackReg.Altitude.Buffer = (WCHAR *)s_apwszAltitudes[i];
5102 s_ObCallbackReg.Altitude.Length = (uint16_t)RTUtf16Len(s_apwszAltitudes[i]) * sizeof(WCHAR);
5103 s_ObCallbackReg.Altitude.MaximumLength = s_ObCallbackReg.Altitude.Length + sizeof(WCHAR);
5104
5105 rcNt = g_pfnObRegisterCallbacks(&s_ObCallbackReg, &g_pvObCallbacksCookie);
5106 if (NT_SUCCESS(rcNt))
5107 {
5108 /*
5109 * Happy ending.
5110 */
5111 return STATUS_SUCCESS;
5112 }
5113 }
5114 LogRel(("vboxdrv: ObRegisterCallbacks failed with rcNt=%#x\n", rcNt));
5115 g_pvObCallbacksCookie = NULL;
5116 }
5117 else
5118 {
5119 /*
5120 * For the time being, we do not implement extra process
5121 * protection on pre-Vista-SP1 systems as they are lacking
5122 * necessary KPIs. XP is end of life, we do not wish to
5123 * spend more time on it, so we don't put up a fuss there.
5124 * Vista users without SP1 can install SP1 (or later), darn it,
5125 * so refuse to load.
5126 */
5127 /** @todo Hack up an XP solution - will require hooking kernel APIs or doing bad
5128 * stuff to a couple of object types. */
5129# ifndef VBOX_WITH_VISTA_NO_SP
5130 if (g_uNtVerCombined >= SUP_NT_VER_VISTA)
5131# else
5132 if (g_uNtVerCombined >= SUP_MAKE_NT_VER_COMBINED(6, 0, 6001, 0, 0))
5133# endif
5134 {
5135 DbgPrint("vboxdrv: ObRegisterCallbacks was not found. Please make sure you got the latest updates and service packs installed\n");
5136 rcNt = STATUS_SXS_VERSION_CONFLICT;
5137 }
5138 else
5139 {
5140 Log(("vboxdrv: ObRegisterCallbacks was not found; ignored pre-Vista\n"));
5141 return rcNt = STATUS_SUCCESS;
5142 }
5143 g_pvObCallbacksCookie = NULL;
5144 }
5145
5146 /*
5147 * Drop process create/term notifications.
5148 */
5149 if (g_pfnPsSetCreateProcessNotifyRoutineEx)
5150 g_pfnPsSetCreateProcessNotifyRoutineEx(supdrvNtProtectCallback_ProcessCreateNotifyEx, TRUE /*fRemove*/);
5151 else
5152 PsSetCreateProcessNotifyRoutine(supdrvNtProtectCallback_ProcessCreateNotify, TRUE /*fRemove*/);
5153 }
5154 else
5155 LogRel(("vboxdrv: PsSetCreateProcessNotifyRoutine%s failed with rcNt=%#x\n",
5156 g_pfnPsSetCreateProcessNotifyRoutineEx ? "Ex" : "", rcNt));
5157 supHardenedWinTermImageVerifier();
5158 }
5159 else
5160 rcNt = VBoxDrvNtErr2NtStatus(rc);
5161
5162 RTSemMutexDestroy(g_hErrorInfoLock);
5163 g_hErrorInfoLock = NIL_RTSEMMUTEX;
5164 }
5165 else
5166 rcNt = VBoxDrvNtErr2NtStatus(rc);
5167
5168 RTSpinlockDestroy(g_hNtProtectLock);
5169 g_NtProtectTree = NIL_RTSPINLOCK;
5170 return rcNt;
5171}
5172
5173#endif /* VBOX_WITH_HARDENING */
5174
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